Skip to content

Commit 7e8a4cf

Browse files
committed
Avoid thread termination in scoped_released
Do not call `PyEval_RestoreThread()` from `~gil_scoped_release()` if python runtime is finalizing, as it will result in thread termination in Python runtime newer than 3.6, as documented in https://docs.python.org/3/c-api/init.html#c.PyEval_RestoreThread Similarly do not call `PyThreadState_DeleteCurrent` from `~gil_scoped_acquire()` if runtime is finalizing. Discovered while debugging PyTorch crash using Python-3.9 described in pytorch/pytorch#47776
1 parent 02746cb commit 7e8a4cf

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

include/pybind11/pybind11.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,7 +2121,12 @@ class gil_scoped_acquire {
21212121
pybind11_fail("scoped_acquire::dec_ref(): internal error!");
21222122
#endif
21232123
PyThreadState_Clear(tstate);
2124+
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 6) && !defined(Py_LIMITED_API)
2125+
if (!_Py_IsFinalizing())
2126+
PyThreadState_DeleteCurrent();
2127+
#else
21242128
PyThreadState_DeleteCurrent();
2129+
#endif
21252130
PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
21262131
release = false;
21272132
}
@@ -2153,7 +2158,14 @@ class gil_scoped_release {
21532158
~gil_scoped_release() {
21542159
if (!tstate)
21552160
return;
2161+
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 6) && !defined(Py_LIMITED_API)
2162+
// PyEval_RestoreThread() should not be called if runtime is finilizing
2163+
// See https://docs.python.org/3/c-api/init.html#c.PyEval_RestoreThread
2164+
if (!_Py_IsFinalizing())
2165+
PyEval_RestoreThread(tstate);
2166+
#else
21562167
PyEval_RestoreThread(tstate);
2168+
#endif
21572169
if (disassoc) {
21582170
auto key = detail::get_internals().tstate;
21592171
PYBIND11_TLS_REPLACE_VALUE(key, tstate);

0 commit comments

Comments
 (0)