Skip to content

Commit 9ecb5b5

Browse files
committed
I think this works.
1 parent 16dcb57 commit 9ecb5b5

File tree

3 files changed

+25
-0
lines changed

3 files changed

+25
-0
lines changed

Include/internal/pycore_pystate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ _Py_AssertHoldsTstateFunc(const char *func)
296296
#define _Py_AssertHoldsTstate()
297297
#endif
298298

299+
void _PyThreadState_Decref(PyThreadState *tstate);
300+
void _PyThreadState_Incref(PyThreadState *tstate);
301+
299302
#ifdef __cplusplus
300303
}
301304
#endif

Python/ceval.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,14 +2467,20 @@ PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *arg)
24672467
_PyRuntimeState *runtime = &_PyRuntime;
24682468
HEAD_LOCK(runtime);
24692469
PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
2470+
/* gh-132296: We need to prevent the thread state
2471+
from getting concurrently deallocated.
2472+
We can't stop-the-world because _PyEval_SetTrace() is re-entrant. */
2473+
_PyThreadState_Incref(ts);
24702474
HEAD_UNLOCK(runtime);
24712475

24722476
while (ts) {
24732477
if (_PyEval_SetTrace(ts, func, arg) < 0) {
24742478
PyErr_FormatUnraisable("Exception ignored in PyEval_SetTraceAllThreads");
24752479
}
24762480
HEAD_LOCK(runtime);
2481+
PyThreadState *old = ts;
24772482
ts = PyThreadState_Next(ts);
2483+
_PyThreadState_Decref(old);
24782484
HEAD_UNLOCK(runtime);
24792485
}
24802486
}

Python/pystate.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,22 @@ decref_threadstate(_PyThreadStateImpl *tstate)
14851485
}
14861486
}
14871487

1488+
static void
1489+
_PyThreadState_Decref(PyThreadState *tstate)
1490+
{
1491+
assert(tstate != NULL);
1492+
_PyThreadStateImpl *impl = (_PyThreadStateImpl *)tstate;
1493+
decref_threadstate(tstate);
1494+
}
1495+
1496+
static void
1497+
_PyThreadState_Incref(PyThreadState *tstate)
1498+
{
1499+
assert(tstate != NULL);
1500+
_PyThreadStateImpl *impl = (_PyThreadStateImpl *)tstate;
1501+
_Py_atomic_add_ssize(&impl->refcount, 1);
1502+
}
1503+
14881504
/* Get the thread state to a minimal consistent state.
14891505
Further init happens in pylifecycle.c before it can be used.
14901506
All fields not initialized here are expected to be zeroed out,

0 commit comments

Comments
 (0)