https://github.com/python/cpython/commit/44e92d4a5922dd8fa61f75834784c2772fdd34ab
commit: 44e92d4a5922dd8fa61f75834784c2772fdd34ab
branch: main
author: Neil Schemenauer <[email protected]>
committer: nascheme <[email protected]>
date: 2026-08-11T09:48:19-07:00
summary:
gh-155363: Fix QSBR slot leak on thread state creation failure (gh-155365)
In the free-threaded build, new_threadstate() reserves a QSBR thread-state
slot before it can still fail for other reasons, but the failure paths only
called free_threadstate(), which does not know about the reservation.
Restructure code so failure path doesn't leak.
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-13-40-12.gh-issue-155363.Qk3Vt9.rst
M Include/internal/pycore_code.h
M Objects/codeobject.c
M Python/pystate.c
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index 5b1fddbe15b98b8..32242f89b812e69 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -582,6 +582,10 @@ PyAPI_FUNC(_Py_CODEUNIT *) _PyCode_GetTLBC(PyCodeObject
*co);
// Returns the reserved index or -1 on error.
extern int32_t _Py_ReserveTLBCIndex(PyInterpreterState *interp);
+// Release an index returned by _Py_ReserveTLBCIndex() that was never stored
+// in a PyThreadState.
+extern void _Py_UnreserveTLBCIndex(PyInterpreterState *interp, int32_t index);
+
// Release the current thread's index into thread-local bytecode arrays
extern void _Py_ClearTLBCIndex(_PyThreadStateImpl *tstate);
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-13-40-12.gh-issue-155363.Qk3Vt9.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-13-40-12.gh-issue-155363.Qk3Vt9.rst
new file mode 100644
index 000000000000000..52200bb9d2fd59f
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-08-07-13-40-12.gh-issue-155363.Qk3Vt9.rst
@@ -0,0 +1,4 @@
+Fix a leak in the :term:`free-threaded build` when creating a thread state
+fails after an internal QSBR slot has been reserved for it. The slot could
+never be reclaimed, so the QSBR array grew without bound across repeated
+failures.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index d7955cc7390a7ab..58811d63c7e318c 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -3314,14 +3314,20 @@ _Py_ReserveTLBCIndex(PyInterpreterState *interp)
}
void
-_Py_ClearTLBCIndex(_PyThreadStateImpl *tstate)
+_Py_UnreserveTLBCIndex(PyInterpreterState *interp, int32_t index)
{
- PyInterpreterState *interp = ((PyThreadState *)tstate)->interp;
if (interp->config.tlbc_enabled) {
- _PyIndexPool_FreeIndex(&interp->tlbc_indices, tstate->tlbc_index);
+ _PyIndexPool_FreeIndex(&interp->tlbc_indices, index);
}
}
+void
+_Py_ClearTLBCIndex(_PyThreadStateImpl *tstate)
+{
+ PyInterpreterState *interp = ((PyThreadState *)tstate)->interp;
+ _Py_UnreserveTLBCIndex(interp, tstate->tlbc_index);
+}
+
static _PyCodeArray *
_PyCodeArray_New(Py_ssize_t size)
{
diff --git a/Python/pystate.c b/Python/pystate.c
index d10b38def32911d..646c157007d4ac1 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1667,21 +1667,23 @@ new_threadstate(PyInterpreterState *interp, int whence)
return NULL;
}
-#ifdef Py_GIL_DISABLED
- Py_ssize_t qsbr_idx = _Py_qsbr_reserve(interp);
- if (qsbr_idx < 0) {
+#ifdef Py_STATS
+ // The PyStats structure is quite large and is allocated separated from
+ // tstate.
+ if (!_PyStats_ThreadInit(interp, tstate)) {
free_threadstate(tstate);
return NULL;
}
+#endif
+#ifdef Py_GIL_DISABLED
int32_t tlbc_idx = _Py_ReserveTLBCIndex(interp);
if (tlbc_idx < 0) {
free_threadstate(tstate);
return NULL;
}
-#endif
-#ifdef Py_STATS
- // The PyStats structure is quite large and is allocated separated from
tstate.
- if (!_PyStats_ThreadInit(interp, tstate)) {
+ Py_ssize_t qsbr_idx = _Py_qsbr_reserve(interp);
+ if (qsbr_idx < 0) {
+ _Py_UnreserveTLBCIndex(interp, tlbc_idx);
free_threadstate(tstate);
return NULL;
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]