Bug report
There's a race on tstate->c_profilefunc if profiling is disable concurrently via sys._setprofileallthreads or threading.setprofile_all_threads or PyEval_SetProfileAllThreads.
|
static PyObject * |
|
call_profile_func(_PyLegacyEventHandler *self, PyObject *arg) |
|
{ |
|
PyThreadState *tstate = _PyThreadState_GET(); |
|
if (tstate->c_profilefunc == NULL) { |
|
Py_RETURN_NONE; |
|
} |
|
PyFrameObject *frame = PyEval_GetFrame(); |
|
if (frame == NULL) { |
|
PyErr_SetString(PyExc_SystemError, |
|
"Missing frame when calling profile function."); |
|
return NULL; |
|
} |
|
Py_INCREF(frame); |
|
int err = tstate->c_profilefunc(tstate->c_profileobj, frame, self->event, arg); |
|
Py_DECREF(frame); |
|
if (err) { |
|
return NULL; |
|
} |
|
Py_RETURN_NONE; |
|
} |
Repro
import sys
import threading
done = threading.Event()
def foo():
pass
def my_profile(frame, event, arg):
return None
def bg_thread():
while not done.is_set():
foo()
foo()
foo()
foo()
foo()
foo()
foo()
foo()
foo()
foo()
def main():
bg_threads = []
for i in range(10):
t = threading.Thread(target=bg_thread)
t.start()
bg_threads.append(t)
for i in range(100):
print(f"Iteration {i}")
sys._setprofileallthreads(my_profile)
sys._setprofileallthreads(None)
done.set()
for t in bg_threads:
t.join()
if __name__ == "__main__":
main()
Linked PRs
Bug report
There's a race on
tstate->c_profilefuncif profiling is disable concurrently viasys._setprofileallthreadsorthreading.setprofile_all_threadsorPyEval_SetProfileAllThreads.cpython/Python/legacy_tracing.c
Lines 37 to 57 in 001461a
Repro
Linked PRs