gh-112367: Only free perf trampoline arenas at shutdown (#112368)

Signed-off-by: Pablo Galindo <pablogsal@gmail.com>
This commit is contained in:
Pablo Galindo Salgado 2023-12-01 13:20:51 +00:00 committed by GitHub
parent bfb576ee23
commit a73aa48e6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 6 deletions

View File

@ -101,6 +101,7 @@ extern int _PyPerfTrampoline_SetCallbacks(_PyPerf_Callbacks *);
extern void _PyPerfTrampoline_GetCallbacks(_PyPerf_Callbacks *); extern void _PyPerfTrampoline_GetCallbacks(_PyPerf_Callbacks *);
extern int _PyPerfTrampoline_Init(int activate); extern int _PyPerfTrampoline_Init(int activate);
extern int _PyPerfTrampoline_Fini(void); extern int _PyPerfTrampoline_Fini(void);
extern void _PyPerfTrampoline_FreeArenas(void);
extern int _PyIsPerfTrampolineActive(void); extern int _PyIsPerfTrampolineActive(void);
extern PyStatus _PyPerfTrampoline_AfterFork_Child(void); extern PyStatus _PyPerfTrampoline_AfterFork_Child(void);
#ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef PY_HAVE_PERF_TRAMPOLINE

View File

@ -0,0 +1,2 @@
Avoid undefined behaviour when using the perf trampolines by not freeing the
code arenas until shutdown. Patch by Pablo Galindo

View File

@ -216,10 +216,24 @@ perf_map_write_entry(void *state, const void *code_addr,
PyMem_RawFree(perf_map_entry); PyMem_RawFree(perf_map_entry);
} }
static void*
perf_map_init_state(void)
{
PyUnstable_PerfMapState_Init();
return NULL;
}
static int
perf_map_free_state(void *state)
{
PyUnstable_PerfMapState_Fini();
return 0;
}
_PyPerf_Callbacks _Py_perfmap_callbacks = { _PyPerf_Callbacks _Py_perfmap_callbacks = {
NULL, &perf_map_init_state,
&perf_map_write_entry, &perf_map_write_entry,
NULL, &perf_map_free_state,
}; };
static int static int
@ -415,7 +429,6 @@ _PyPerfTrampoline_SetCallbacks(_PyPerf_Callbacks *callbacks)
trampoline_api.write_state = callbacks->write_state; trampoline_api.write_state = callbacks->write_state;
trampoline_api.free_state = callbacks->free_state; trampoline_api.free_state = callbacks->free_state;
trampoline_api.state = NULL; trampoline_api.state = NULL;
perf_status = PERF_STATUS_OK;
#endif #endif
return 0; return 0;
} }
@ -434,6 +447,7 @@ _PyPerfTrampoline_Init(int activate)
} }
if (!activate) { if (!activate) {
tstate->interp->eval_frame = NULL; tstate->interp->eval_frame = NULL;
perf_status = PERF_STATUS_NO_INIT;
} }
else { else {
tstate->interp->eval_frame = py_trampoline_evaluator; tstate->interp->eval_frame = py_trampoline_evaluator;
@ -444,6 +458,9 @@ _PyPerfTrampoline_Init(int activate)
if (extra_code_index == -1) { if (extra_code_index == -1) {
return -1; return -1;
} }
if (trampoline_api.state == NULL && trampoline_api.init_state != NULL) {
trampoline_api.state = trampoline_api.init_state();
}
perf_status = PERF_STATUS_OK; perf_status = PERF_STATUS_OK;
} }
#endif #endif
@ -454,16 +471,29 @@ int
_PyPerfTrampoline_Fini(void) _PyPerfTrampoline_Fini(void)
{ {
#ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef PY_HAVE_PERF_TRAMPOLINE
if (perf_status != PERF_STATUS_OK) {
return 0;
}
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
if (tstate->interp->eval_frame == py_trampoline_evaluator) { if (tstate->interp->eval_frame == py_trampoline_evaluator) {
tstate->interp->eval_frame = NULL; tstate->interp->eval_frame = NULL;
} }
free_code_arenas(); if (perf_status == PERF_STATUS_OK) {
trampoline_api.free_state(trampoline_api.state);
}
extra_code_index = -1; extra_code_index = -1;
perf_status = PERF_STATUS_NO_INIT;
#endif #endif
return 0; return 0;
} }
void _PyPerfTrampoline_FreeArenas(void) {
#ifdef PY_HAVE_PERF_TRAMPOLINE
free_code_arenas();
#endif
return;
}
int int
PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable){ PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable){
#ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef PY_HAVE_PERF_TRAMPOLINE
@ -477,8 +507,8 @@ PyStatus
_PyPerfTrampoline_AfterFork_Child(void) _PyPerfTrampoline_AfterFork_Child(void)
{ {
#ifdef PY_HAVE_PERF_TRAMPOLINE #ifdef PY_HAVE_PERF_TRAMPOLINE
PyUnstable_PerfMapState_Fini();
if (persist_after_fork) { if (persist_after_fork) {
_PyPerfTrampoline_Fini();
char filename[256]; char filename[256];
pid_t parent_pid = getppid(); pid_t parent_pid = getppid();
snprintf(filename, sizeof(filename), "/tmp/perf-%d.map", parent_pid); snprintf(filename, sizeof(filename), "/tmp/perf-%d.map", parent_pid);

View File

@ -1797,6 +1797,7 @@ finalize_interp_clear(PyThreadState *tstate)
_PyArg_Fini(); _PyArg_Fini();
_Py_ClearFileSystemEncoding(); _Py_ClearFileSystemEncoding();
_PyPerfTrampoline_Fini(); _PyPerfTrampoline_Fini();
_PyPerfTrampoline_FreeArenas();
} }
finalize_interp_types(tstate->interp); finalize_interp_types(tstate->interp);
@ -1854,7 +1855,6 @@ Py_FinalizeEx(void)
*/ */
_PyAtExit_Call(tstate->interp); _PyAtExit_Call(tstate->interp);
PyUnstable_PerfMapState_Fini();
/* Copy the core config, PyInterpreterState_Delete() free /* Copy the core config, PyInterpreterState_Delete() free
the core config memory */ the core config memory */