diff --git a/Doc/data/python3.14.abi b/Doc/data/python3.14.abi index 372c35f3713..486c54565c4 100644 --- a/Doc/data/python3.14.abi +++ b/Doc/data/python3.14.abi @@ -1232,6 +1232,7 @@ + @@ -1450,6 +1451,7 @@ + @@ -1814,7 +1816,7 @@ - + @@ -1835,7 +1837,7 @@ - + @@ -1850,7 +1852,7 @@ - + @@ -1888,7 +1890,7 @@ - + @@ -1900,10 +1902,10 @@ - + - + @@ -1991,11 +1993,11 @@ - + - + @@ -2007,14 +2009,14 @@ - + - + @@ -2033,7 +2035,7 @@ - + @@ -2061,7 +2063,7 @@ - + @@ -2103,7 +2105,7 @@ - + @@ -2120,7 +2122,7 @@ - + @@ -2148,43 +2150,43 @@ - - + + - + - + - + - + - + - + - + - + - + - + @@ -2192,7 +2194,7 @@ - + @@ -2277,7 +2279,7 @@ - + @@ -2302,7 +2304,7 @@ - + @@ -2346,7 +2348,7 @@ - + @@ -2630,7 +2632,7 @@ - + @@ -3554,7 +3556,7 @@ - + @@ -3608,7 +3610,7 @@ - + @@ -3634,7 +3636,7 @@ - + @@ -3723,7 +3725,7 @@ - + @@ -3732,7 +3734,7 @@ - + @@ -3815,7 +3817,7 @@ - + @@ -3837,12 +3839,12 @@ - + - + @@ -3859,7 +3861,7 @@ - + @@ -3899,7 +3901,7 @@ - + @@ -3922,7 +3924,7 @@ - + @@ -3959,7 +3961,7 @@ - + @@ -4032,52 +4034,52 @@ - + - - + + - - + + - + - - + + - + - + - - + + - - - - + + + + - - - + + + - - + + - - + + @@ -4096,7 +4098,7 @@ - + @@ -4182,7 +4184,7 @@ - + @@ -4219,7 +4221,7 @@ - + @@ -4283,7 +4285,7 @@ - + @@ -4361,7 +4363,7 @@ - + @@ -5032,7 +5034,7 @@ - + @@ -5076,7 +5078,7 @@ - + @@ -5411,35 +5413,35 @@ - - + + - - - + + + - - + + - - + + - - - + + + - - - + + + - + @@ -5497,7 +5499,7 @@ - + @@ -5696,7 +5698,7 @@ - + @@ -5731,7 +5733,7 @@ - + @@ -5877,30 +5879,30 @@ - - - - + + + + - - - + + + - - - + + + - - + + - + @@ -5975,7 +5977,7 @@ - + @@ -5997,7 +5999,7 @@ - + @@ -6053,7 +6055,7 @@ - + @@ -6698,7 +6700,7 @@ - + @@ -6896,7 +6898,7 @@ - + @@ -7015,7 +7017,7 @@ - + @@ -7134,190 +7136,190 @@ - - + + - - - + + + - - - - + + + + - - - - - + + + + + - - - + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - + + - - - - - - + + + + + + @@ -7326,11 +7328,11 @@ - + - + @@ -7653,7 +7655,7 @@ - + @@ -7742,7 +7744,7 @@ - + @@ -7947,7 +7949,7 @@ - + @@ -8117,7 +8119,7 @@ - + @@ -8227,7 +8229,7 @@ - + @@ -8271,7 +8273,7 @@ - + @@ -8369,9 +8371,13 @@ - + + + + + @@ -8426,38 +8432,38 @@ - - + + - - + + - - - - + + + + - - + + - - + + - - - - + + + + - - - - + + + + @@ -8539,7 +8545,7 @@ - + @@ -8549,7 +8555,7 @@ - + @@ -8562,7 +8568,7 @@ - + @@ -8648,7 +8654,7 @@ - + @@ -8996,7 +9002,7 @@ - + @@ -9024,7 +9030,7 @@ - + @@ -9051,7 +9057,7 @@ - + @@ -9248,7 +9254,7 @@ - + @@ -9265,7 +9271,7 @@ - + @@ -9306,11 +9312,11 @@ - + - + @@ -9569,96 +9575,96 @@ - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + @@ -10445,7 +10451,7 @@ - + @@ -10509,7 +10515,7 @@ - + @@ -10524,7 +10530,7 @@ - + @@ -10559,7 +10565,7 @@ - + @@ -10614,35 +10620,35 @@ - - - + + + - - - + + + - - + + - - + + - - - + + + - - + + - + @@ -10664,7 +10670,7 @@ - + @@ -10735,7 +10741,7 @@ - + @@ -10747,13 +10753,13 @@ - - - + + + - + @@ -10773,7 +10779,7 @@ - + @@ -11084,51 +11090,57 @@ - + - - - + + + + + + + + + - - + + - - + + - - - + + + - - - + + + - + - - + + - - - - - + + + + + - + @@ -11137,7 +11149,7 @@ - + @@ -11159,7 +11171,7 @@ - + @@ -11306,7 +11318,7 @@ - + @@ -11860,7 +11872,7 @@ - + @@ -11874,7 +11886,7 @@ - + @@ -11934,7 +11946,7 @@ - + @@ -13065,7 +13077,7 @@ - + @@ -13144,7 +13156,7 @@ - + @@ -13219,7 +13231,7 @@ - + @@ -14414,7 +14426,7 @@ - + @@ -14453,7 +14465,7 @@ - + @@ -20846,18 +20858,18 @@ - + - + - - + + - - + + - + @@ -20879,446 +20891,455 @@ - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + - - - - + - - - - - - - - - - + - + + - + - + - - + + - + - - - - - - + - + - - - - + - + + - - - - - - - - - - - - - + - - - - + - + - - - - - - - - - - - - - - - - - - - + - + - - + + + + + - + - - - - + - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21330,385 +21351,385 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -22174,7 +22195,7 @@ - + @@ -22247,64 +22268,64 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -22449,10 +22470,10 @@ - + - + @@ -22461,75 +22482,75 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -24287,7 +24308,7 @@ - + @@ -24354,7 +24375,7 @@ - + @@ -24405,7 +24426,7 @@ - + @@ -24430,7 +24451,7 @@ - + @@ -24608,14 +24629,14 @@ - + - + @@ -24642,7 +24663,7 @@ - + @@ -24671,7 +24692,7 @@ - + @@ -24684,7 +24705,7 @@ - + @@ -24772,7 +24793,7 @@ - + @@ -24931,7 +24952,7 @@ - + @@ -24977,7 +24998,7 @@ - + @@ -25048,7 +25069,7 @@ - + @@ -25122,7 +25143,7 @@ - + @@ -25166,7 +25187,7 @@ - + @@ -25194,19 +25215,19 @@ - - + + - + - + - + - + @@ -25289,15 +25310,15 @@ - + - - - - - + + + + + @@ -25568,230 +25589,230 @@ - - + + - - - - + + + + - - + + - - - - + + + + - - - - - - + + + + + + - - + + - - - + + + - - - - + + + + - - - + + + - - - + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - + + + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + - + - - + + - - + + - - - - - - + + + + + + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - + + - - + + - - - - - + + + + + - - - + + + - - - - + + + + - - - + + + - + @@ -25931,7 +25952,7 @@ - + @@ -26030,7 +26051,7 @@ - + @@ -26646,7 +26667,7 @@ - + @@ -26849,7 +26870,7 @@ - + @@ -26927,13 +26948,13 @@ - - - + + + - + @@ -26993,7 +27014,7 @@ - + @@ -27525,7 +27546,7 @@ - + @@ -27651,7 +27672,7 @@ - + @@ -27762,7 +27783,7 @@ - + @@ -27786,7 +27807,7 @@ - + @@ -27906,7 +27927,7 @@ - + @@ -27933,7 +27954,7 @@ - + @@ -27966,7 +27987,7 @@ - + @@ -28023,7 +28044,7 @@ - + @@ -28081,7 +28102,7 @@ - + @@ -28089,7 +28110,7 @@ - + @@ -28163,21 +28184,21 @@ - + - + - + - + @@ -28186,7 +28207,7 @@ - + @@ -28230,7 +28251,7 @@ - + @@ -28322,7 +28343,7 @@ - + @@ -28376,16 +28397,16 @@ - + - + - + @@ -28409,111 +28430,111 @@ - + - - + + - - + + - - + + - - + + - - - - + + + + - - - + + + - - + + - - - + + + - - + + - - - + + + - + - + - - - + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - + + - - + + - - + + - - + + - - - + + + - + - + @@ -28551,24 +28572,24 @@ - + - + - + - + - + - + - + @@ -28717,7 +28738,7 @@ - + @@ -28743,7 +28764,7 @@ - + @@ -28870,123 +28891,123 @@ - - - - + + + + - - - - - + + + + + - - + + - + - + - - + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - + + - - + + - - - + + + - + - - - + + + - + - + @@ -29129,7 +29150,7 @@ - + @@ -29150,7 +29171,7 @@ - + @@ -29257,7 +29278,7 @@ - + @@ -29284,7 +29305,7 @@ - + @@ -29438,7 +29459,7 @@ - + @@ -29540,7 +29561,7 @@ - + @@ -29587,7 +29608,7 @@ - + @@ -29596,7 +29617,7 @@ - + @@ -29647,7 +29668,7 @@ - + @@ -29705,30 +29726,30 @@ - + - + - - + + - - + + - - + + - + @@ -29773,12 +29794,12 @@ - + - + @@ -29797,7 +29818,7 @@ - + @@ -29809,7 +29830,7 @@ - + @@ -29894,7 +29915,7 @@ - + @@ -29940,15 +29961,12 @@ - - - - + - + @@ -30099,21 +30117,21 @@ - + - + - + - + @@ -30275,7 +30293,7 @@ - + @@ -30404,10 +30422,13 @@ - + + + + - + @@ -30501,21 +30522,21 @@ - - - - + + + + - - + + - - + + - + @@ -30556,7 +30577,7 @@ - + @@ -30564,11 +30585,11 @@ - + - + @@ -30635,7 +30656,7 @@ - + @@ -30736,66 +30757,66 @@ - + - - + + - - + + - - - + + + - + - + - + - + - - + + - - - + + + - + - - - - + + + + - - - - - + + + + + - + @@ -30984,7 +31005,7 @@ - + @@ -31177,7 +31198,7 @@ - + @@ -31211,7 +31232,7 @@ - + @@ -31372,7 +31393,7 @@ - + @@ -31380,10 +31401,10 @@ - + - + @@ -31559,7 +31580,7 @@ - + @@ -31610,35 +31631,35 @@ - - - - + + + + - - + + - + - + - - - + + + - - - + + + diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 89504f6bfbb..4e197c2e29e 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -105,7 +105,6 @@ extern int _PyPerfTrampoline_SetCallbacks(_PyPerf_Callbacks *); extern void _PyPerfTrampoline_GetCallbacks(_PyPerf_Callbacks *); extern int _PyPerfTrampoline_Init(int activate); extern int _PyPerfTrampoline_Fini(void); -extern void _PyPerfTrampoline_FreeArenas(void); extern int _PyIsPerfTrampolineActive(void); extern PyStatus _PyPerfTrampoline_AfterFork_Child(void); #ifdef PY_HAVE_PERF_TRAMPOLINE diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index 15885b5f228..c3d9533e90f 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -87,6 +87,9 @@ struct _ceval_runtime_state { struct trampoline_api_st trampoline_api; FILE *map_file; Py_ssize_t persist_after_fork; + _PyFrameEvalFunction prev_eval_frame; + Py_ssize_t trampoline_refcount; + int code_watcher_id; #else int _not_used; #endif diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-23-57-43.gh-issue-143228.m3EF9E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-23-57-43.gh-issue-143228.m3EF9E.rst new file mode 100644 index 00000000000..893bc29543d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-27-23-57-43.gh-issue-143228.m3EF9E.rst @@ -0,0 +1,4 @@ +Fix use-after-free in perf trampoline when toggling profiling while +threads are running or during interpreter finalization with daemon threads +active. The fix uses reference counting to ensure trampolines are not freed +while any code object could still reference them. Pach by Pablo Galindo diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 4690e7b718f..8feb259a63a 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -204,6 +204,43 @@ enum perf_trampoline_type { #define perf_map_file _PyRuntime.ceval.perf.map_file #define persist_after_fork _PyRuntime.ceval.perf.persist_after_fork #define perf_trampoline_type _PyRuntime.ceval.perf.perf_trampoline_type +#define prev_eval_frame _PyRuntime.ceval.perf.prev_eval_frame +#define trampoline_refcount _PyRuntime.ceval.perf.trampoline_refcount +#define code_watcher_id _PyRuntime.ceval.perf.code_watcher_id + +static void free_code_arenas(void); + +static void +perf_trampoline_reset_state(void) +{ + free_code_arenas(); + if (code_watcher_id >= 0) { + PyCode_ClearWatcher(code_watcher_id); + code_watcher_id = -1; + } + extra_code_index = -1; +} + +static int +perf_trampoline_code_watcher(PyCodeEvent event, PyCodeObject *co) +{ + if (event != PY_CODE_EVENT_DESTROY) { + return 0; + } + if (extra_code_index == -1) { + return 0; + } + py_trampoline f = NULL; + int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f); + if (ret != 0 || f == NULL) { + return 0; + } + trampoline_refcount--; + if (trampoline_refcount == 0) { + perf_trampoline_reset_state(); + } + return 0; +} static void perf_map_write_entry(void *state, const void *code_addr, @@ -405,6 +442,7 @@ py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame, perf_code_arena->code_size, co); _PyCode_SetExtra((PyObject *)co, extra_code_index, (void *)new_trampoline); + trampoline_refcount++; f = new_trampoline; } assert(f != NULL); @@ -428,6 +466,7 @@ int PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *co) } trampoline_api.write_state(trampoline_api.state, new_trampoline, perf_code_arena->code_size, co); + trampoline_refcount++; return _PyCode_SetExtra((PyObject *)co, extra_code_index, (void *)new_trampoline); } @@ -482,6 +521,10 @@ _PyPerfTrampoline_Init(int activate) { #ifdef PY_HAVE_PERF_TRAMPOLINE PyThreadState *tstate = _PyThreadState_GET(); + if (code_watcher_id == 0) { + // Initialize to -1 since 0 is a valid watcher ID + code_watcher_id = -1; + } if (tstate->interp->eval_frame && tstate->interp->eval_frame != py_trampoline_evaluator) { PyErr_SetString(PyExc_RuntimeError, @@ -505,6 +548,13 @@ _PyPerfTrampoline_Init(int activate) if (new_code_arena() < 0) { return -1; } + code_watcher_id = PyCode_AddWatcher(perf_trampoline_code_watcher); + if (code_watcher_id < 0) { + PyErr_FormatUnraisable("Failed to register code watcher for perf trampoline"); + free_code_arenas(); + return -1; + } + trampoline_refcount = 1; // Base refcount held by the system perf_status = PERF_STATUS_OK; } #endif @@ -526,19 +576,21 @@ _PyPerfTrampoline_Fini(void) trampoline_api.free_state(trampoline_api.state); perf_trampoline_type = PERF_TRAMPOLINE_UNSET; } - extra_code_index = -1; + + // Prevent new trampolines from being created perf_status = PERF_STATUS_NO_INIT; + + // Decrement base refcount. If refcount reaches 0, all code objects are already + // dead so clean up now. Otherwise, watcher remains active to clean up when last + // code object dies; extra_code_index stays valid so watcher can identify them. + trampoline_refcount--; + if (trampoline_refcount == 0) { + perf_trampoline_reset_state(); + } #endif return 0; } -void _PyPerfTrampoline_FreeArenas(void) { -#ifdef PY_HAVE_PERF_TRAMPOLINE - free_code_arenas(); -#endif - return; -} - int PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable){ #ifdef PY_HAVE_PERF_TRAMPOLINE diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index fad69f82b60..9ae5e067023 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1923,7 +1923,6 @@ finalize_interp_clear(PyThreadState *tstate) _PyArg_Fini(); _Py_ClearFileSystemEncoding(); _PyPerfTrampoline_Fini(); - _PyPerfTrampoline_FreeArenas(); } finalize_interp_types(tstate->interp);