Skip to content

Commit 493649f

Browse files
fix: valgrind-detected after-freeing access of PyMethodDef (macOS Python 3.9.0 segfaults) (#2576)
* Check if valgrind-detected after-freeing access of PyMethodDef causes macOS Python 3.9 segfaults * fix: only apply leak on 3.9.0 * fix: faster check * fix: better naming thanks to @bstaletic Co-authored-by: Henry Schreiner <[email protected]>
1 parent 645d838 commit 493649f

File tree

2 files changed

+15
-7
lines changed

2 files changed

+15
-7
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ jobs:
7070
python: pypy3
7171
arch: x64
7272

73-
# TODO: renable
74-
# Currently segfaults on macOS Python 3.9
75-
- runs-on: macos-latest
76-
python: 3.9
77-
arch: x64
78-
7973
name: "🐍 ${{ matrix.python }} • ${{ matrix.runs-on }} • ${{ matrix.arch }} ${{ matrix.args }}"
8074
runs-on: ${{ matrix.runs-on }}
8175

include/pybind11/pybind11.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,12 @@ class cpp_function : public function {
452452

453453
/// When a cpp_function is GCed, release any memory allocated by pybind11
454454
static void destruct(detail::function_record *rec) {
455+
// If on Python 3.9, check the interpreter "MICRO" (patch) version.
456+
// If this is running on 3.9.0, we have to work around a bug.
457+
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
458+
static bool is_zero = Py_GetVersion()[4] == '0';
459+
#endif
460+
455461
while (rec) {
456462
detail::function_record *next = rec->next;
457463
if (rec->free_data)
@@ -466,7 +472,15 @@ class cpp_function : public function {
466472
}
467473
if (rec->def) {
468474
std::free(const_cast<char *>(rec->def->ml_doc));
469-
delete rec->def;
475+
// Python 3.9.0 decref's these in the wrong order; rec->def
476+
// If loaded on 3.9.0, let these leak (use Python 3.9.1 at runtime to fix)
477+
// See https://github.com/python/cpython/pull/22670
478+
#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9
479+
if (!is_zero)
480+
delete rec->def;
481+
#else
482+
delete rec->def;
483+
#endif
470484
}
471485
delete rec;
472486
rec = next;

0 commit comments

Comments
 (0)