[3.14] gh-144763: Fix race conditions in tracemalloc (#144779) (#144965)

gh-144763: Fix race conditions in tracemalloc (#144779)

Avoid PyUnstable_InterpreterFrame_GetLine() since it uses a critical
section which can lead to a deadlock.

_PyTraceMalloc_Stop() now also calls PyRefTracer_SetTracer() without
holding TABLES_LOCK() to prevent another deadlock.

(cherry picked from commit 83f4fffe3d)

Co-authored-by: Kumar Aditya <kumaraditya@python.org>
This commit is contained in:
Victor Stinner 2026-02-18 20:55:38 +01:00 committed by GitHub
parent 2ae7c2fadf
commit f67cf83a4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -224,13 +224,20 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
assert(PyStackRef_CodeCheck(pyframe->f_executable));
frame->filename = &_Py_STR(anon_unknown);
int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe);
int lineno = -1;
PyCodeObject *code = _PyFrame_GetCode(pyframe);
// PyUnstable_InterpreterFrame_GetLine() cannot but used, since it uses
// a critical section which can trigger a deadlock.
int lasti = _PyFrame_SafeGetLasti(pyframe);
if (lasti >= 0) {
lineno = _PyCode_SafeAddr2Line(code, lasti);
}
if (lineno < 0) {
lineno = 0;
}
frame->lineno = (unsigned int)lineno;
PyObject *filename = filename = _PyFrame_GetCode(pyframe)->co_filename;
PyObject *filename = code->co_filename;
if (filename == NULL) {
#ifdef TRACE_DEBUG
tracemalloc_error("failed to get the filename of the code object");
@ -853,7 +860,8 @@ _PyTraceMalloc_Stop(void)
TABLES_LOCK();
if (!tracemalloc_config.tracing) {
goto done;
TABLES_UNLOCK();
return;
}
/* stop tracing Python memory allocations */
@ -870,10 +878,12 @@ _PyTraceMalloc_Stop(void)
raw_free(tracemalloc_traceback);
tracemalloc_traceback = NULL;
(void)PyRefTracer_SetTracer(NULL, NULL);
done:
TABLES_UNLOCK();
// Call it after TABLES_UNLOCK() since it calls _PyEval_StopTheWorldAll()
// which would lead to a deadlock with TABLES_LOCK() which doesn't detach
// the thread state.
(void)PyRefTracer_SetTracer(NULL, NULL);
}