-
-
Notifications
You must be signed in to change notification settings - Fork 31k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-104690: thread_run() checks for tstate dangling pointer #109056
Conversation
thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c.
This change provides a better error message rather than a blind crash. It should help debugging complicated crashes. Example:
Patch to reintroduce the bug: diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 49f34fcb9f..f5fc209e88 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -1158,11 +1161,13 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
"thread is not supported for isolated subinterpreters");
return NULL;
}
+#if 0
if (interp->finalizing) {
PyErr_SetString(PyExc_RuntimeError,
"can't create new thread at interpreter shutdown");
return NULL;
}
+#endif
struct bootstate *boot = PyMem_NEW(struct bootstate, 1);
if (boot == NULL) { Script import atexit
import threading
def t0():
pass
def t1():
threading.Thread(target=t0).start()
def f():
threading.Thread(target=t1).start()
atexit.register(f)
exit() |
I don't think that it's related, but in a recent job on Windows x86, the following assertion failed while running test_threading() in a test worker process:
Related code: static void
bind_tstate(PyThreadState *tstate)
{
assert(tstate != NULL);
assert(tstate_is_alive(tstate) && !tstate->_status.bound); /// <=== HERE, line 245
assert(!tstate->_status.unbound); // just in case
assert(!tstate->_status.bound_gilstate);
assert(tstate != gilstate_tss_get(tstate->interp->runtime));
assert(!tstate->_status.active);
assert(tstate->thread_id == 0);
assert(tstate->native_thread_id == 0); I don't know if it would be worth it to repeat the See: #108987 |
Oh! I managed to reproduce issue #108987 on Windows 32-bit with my PR and I get:
So apparently, thread_run() is called after PyInterpreterState_Delete() has been called! |
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.11. |
Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.12. |
Sorry, @vstinner, I could not cleanly backport this to |
Sorry, @vstinner, I could not cleanly backport this to |
…hon#109056) thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer when Python is built in debug mode. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c. (cherry picked from commit f63d378)
GH-109133 is a backport of this pull request to the 3.12 branch. |
GH-109134 is a backport of this pull request to the 3.11 branch. |
…hon#109056) thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer when Python is built in debug mode. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c. (cherry picked from commit f63d378)
…09056) (#109134) gh-104690: thread_run() checks for tstate dangling pointer (#109056) thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer when Python is built in debug mode. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c. (cherry picked from commit f63d378)
…09056) (#109133) gh-104690: thread_run() checks for tstate dangling pointer (#109056) thread_run() of _threadmodule.c now calls _PyThreadState_CheckConsistency() to check if tstate is a dangling pointer when Python is built in debug mode. Rename ceval_gil.c is_tstate_valid() to _PyThreadState_CheckConsistency() to reuse it in _threadmodule.c. (cherry picked from commit f63d378)
thread_run() of _threadmodule.c now calls
_PyThreadState_CheckConsistency() to check if tstate is a dangling pointer.
Rename ceval_gil.c is_tstate_valid() to
_PyThreadState_CheckConsistency() to reuse it in _threadmodule.c.