https://github.com/python/cpython/commit/f67cf83a4e3c6a28522b53d985928a46aae22b77 commit: f67cf83a4e3c6a28522b53d985928a46aae22b77 branch: 3.14 author: Victor Stinner <[email protected]> committer: vstinner <[email protected]> date: 2026-02-18T20:55:38+01:00 summary:
[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 83f4fffe3d78ba368c0d4864c42c7c9c9223f7d1) Co-authored-by: Kumar Aditya <[email protected]> files: M Python/tracemalloc.c diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index 8ae12e545761ef..4795068d0a0618 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -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); } _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
