Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
12 changes: 9 additions & 3 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3313,14 +3313,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)
{
Expand Down
16 changes: 9 additions & 7 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1638,21 +1638,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;
}
Expand Down
Loading