From 3d9dc83c0daade8a76973d683e7bbc4a8dae5f24 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:01:44 +0000 Subject: [PATCH 1/3] fix deadlock --- Python/pystate.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 642d680ba20b1f2..04ad8113d3ac4dd 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -810,7 +810,12 @@ new_threadstate(PyInterpreterState *interp) { PyThreadState *tstate; _PyRuntimeState *runtime = interp->runtime; - + // Allocate eagerly without lock + PyThreadState *new_tstate = alloc_threadstate(); + int used_newtstate; + if (new_tstate == NULL) { + return NULL; + } /* We serialize concurrent creation to protect global state. */ HEAD_LOCK(runtime); @@ -822,18 +827,15 @@ new_threadstate(PyInterpreterState *interp) if (old_head == NULL) { // It's the interpreter's initial thread state. assert(id == 1); - + used_newtstate = 0; tstate = &interp->_initial_thread; } else { // Every valid interpreter must have at least one thread. assert(id > 1); assert(old_head->prev == NULL); - - tstate = alloc_threadstate(); - if (tstate == NULL) { - goto error; - } + used_newtstate = 1; + tstate = new_tstate; // Set to _PyThreadState_INIT. memcpy(tstate, &initial._main_interpreter._initial_thread, @@ -844,11 +846,11 @@ new_threadstate(PyInterpreterState *interp) init_threadstate(tstate, interp, id, old_head); HEAD_UNLOCK(runtime); + if (!used_newtstate) { + // Must be called with lock unlocked to avoid re-entrancy deadlock. + PyMem_RawFree(new_tstate); + } return tstate; - -error: - HEAD_UNLOCK(runtime); - return NULL; } PyThreadState * From 1941785371adc102e3bb4175e541aec0fb6cf5ac Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 19 Aug 2022 17:21:50 +0000 Subject: [PATCH 2/3] add news --- .../2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst b/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst new file mode 100644 index 000000000000000..37653ffac12418b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-08-19-06-51-17.gh-issue-96071.mVgPAo.rst @@ -0,0 +1 @@ +Fix a deadlock in :c:func:`PyGILState_Ensure` when allocating new thread state. Patch by Kumar Aditya. From 1f75cb4d7ebffebff75fb4f231eb4cc325763afc Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Sat, 20 Aug 2022 00:34:01 +0530 Subject: [PATCH 3/3] Update Python/pystate.c Co-authored-by: Eric Snow --- Python/pystate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 04ad8113d3ac4dd..a11f1622ecd4ab5 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -810,7 +810,10 @@ new_threadstate(PyInterpreterState *interp) { PyThreadState *tstate; _PyRuntimeState *runtime = interp->runtime; - // Allocate eagerly without lock + // We don't need to allocate a thread state for the main interpreter + // (the common case), but doing it later for the other case revealed a + // reentrancy problem (deadlock). So for now we always allocate before + // taking the interpreters lock. See GH-96071. PyThreadState *new_tstate = alloc_threadstate(); int used_newtstate; if (new_tstate == NULL) {