gh-137400: Fix thread-safety issues when profiling all threads (gh-137518)

There were a few thread-safety issues when profiling or tracing all
threads via PyEval_SetProfileAllThreads or PyEval_SetTraceAllThreads:

* The loop over thread states could crash if a thread exits concurrently
  (in both the free threading and default build)
* The modification of `c_profilefunc` and `c_tracefunc` wasn't
  thread-safe on the free threading build.
This commit is contained in:
Sam Gross 2025-08-13 14:15:12 -04:00 committed by GitHub
parent 923d68655b
commit a10152f8fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 431 additions and 241 deletions

View file

@ -178,7 +178,15 @@ dummy_func(
}
tier1 op(_MAYBE_INSTRUMENT, (--)) {
if (tstate->tracing == 0) {
#ifdef Py_GIL_DISABLED
// For thread-safety, we need to check instrumentation version
// even when tracing. Otherwise, another thread may concurrently
// re-write the bytecode while we are executing this function.
int check_instrumentation = 1;
#else
int check_instrumentation = (tstate->tracing == 0);
#endif
if (check_instrumentation) {
uintptr_t global_version = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & ~_PY_EVAL_EVENTS_MASK;
uintptr_t code_version = FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version);
if (code_version != global_version) {