gh-119585: Fix crash involving PyGILState_Release() and PyThreadState_Clear() (#119753)

Make sure that `gilstate_counter` is not zero in when calling
`PyThreadState_Clear()`. A destructor called from `PyThreadState_Clear()` may
call back into `PyGILState_Ensure()` and `PyGILState_Release()`. If
`gilstate_counter` is zero, it will try to create a new thread state before
the current active thread state is destroyed, leading to an assertion failure
or crash.
This commit is contained in:
Sam Gross 2024-05-31 10:50:52 -04:00 committed by GitHub
parent 891c1e36f4
commit bcc1be39cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 0 deletions

View file

@ -2808,12 +2808,18 @@ PyGILState_Release(PyGILState_STATE oldstate)
/* can't have been locked when we created it */
assert(oldstate == PyGILState_UNLOCKED);
// XXX Unbind tstate here.
// gh-119585: `PyThreadState_Clear()` may call destructors that
// themselves use PyGILState_Ensure and PyGILState_Release, so make
// sure that gilstate_counter is not zero when calling it.
++tstate->gilstate_counter;
PyThreadState_Clear(tstate);
--tstate->gilstate_counter;
/* Delete the thread-state. Note this releases the GIL too!
* It's vital that the GIL be held here, to avoid shutdown
* races; see bugs 225673 and 1061968 (that nasty bug has a
* habit of coming back).
*/
assert(tstate->gilstate_counter == 0);
assert(current_fast_get() == tstate);
_PyThreadState_DeleteCurrent(tstate);
}