From 07a26bde9fb2832722c52f965741cb1ed9d54f78 Mon Sep 17 00:00:00 2001 From: "Gabriele N. Tornetta" Date: Tue, 2 Dec 2025 10:12:23 +0000 Subject: [PATCH 1/2] Make PY_UNWIND available as a local event We make the PY_UNWIND monitoring event available as a code-local event to allow trapping on function exit events when an exception bubbles up. This complements the PY_RETURN event by allowing to catch any function exit event. --- Include/cpython/monitoring.h | 11 +++++++---- Include/internal/pycore_instruments.h | 2 +- Python/ceval.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Include/cpython/monitoring.h b/Include/cpython/monitoring.h index 5094c8c23ae32b..2dbf47e8a4bb8c 100644 --- a/Include/cpython/monitoring.h +++ b/Include/cpython/monitoring.h @@ -9,7 +9,7 @@ extern "C" { /* Local events. - * These require bytecode instrumentation */ + * Some of these require bytecode instrumentation */ #define PY_MONITORING_EVENT_PY_START 0 #define PY_MONITORING_EVENT_PY_RESUME 1 @@ -22,15 +22,18 @@ extern "C" { #define PY_MONITORING_EVENT_BRANCH_LEFT 8 #define PY_MONITORING_EVENT_BRANCH_RIGHT 9 #define PY_MONITORING_EVENT_STOP_ITERATION 10 +#define PY_MONITORING_EVENT_PY_UNWIND 11 +// TODO: PY_UNWIND requires no instrumentation so this definition is not +// entirely correct. #define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ - ((ev) < _PY_MONITORING_LOCAL_EVENTS) +((ev) <= _PY_MONITORING_LOCAL_EVENTS) + /* Other events, mainly exceptions */ -#define PY_MONITORING_EVENT_RAISE 11 #define PY_MONITORING_EVENT_EXCEPTION_HANDLED 12 -#define PY_MONITORING_EVENT_PY_UNWIND 13 +#define PY_MONITORING_EVENT_RAISE 13 #define PY_MONITORING_EVENT_PY_THROW 14 #define PY_MONITORING_EVENT_RERAISE 15 diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 3775b074ecf54c..f2cefcc9943569 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -74,7 +74,7 @@ PyAPI_DATA(PyObject) _PyInstrumentation_DISABLE; /* Total tool ids available */ #define PY_MONITORING_TOOL_IDS 8 /* Count of all local monitoring events */ -#define _PY_MONITORING_LOCAL_EVENTS 11 +#define _PY_MONITORING_LOCAL_EVENTS 12 /* Count of all "real" monitoring events (not derived from other events) */ #define _PY_MONITORING_UNGROUPED_EVENTS 16 /* Count of all monitoring events */ diff --git a/Python/ceval.h b/Python/ceval.h index bb5f7ddb857246..323bda22152c63 100644 --- a/Python/ceval.h +++ b/Python/ceval.h @@ -431,7 +431,7 @@ monitor_unwind(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) { - if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND)) { + if (no_tools_for_local_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) { return; } do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND); From 1a3e8285f51ea8b5de671666030395f3b6108ee5 Mon Sep 17 00:00:00 2001 From: "Gabriele N. Tornetta" Date: Tue, 2 Dec 2025 11:39:50 +0000 Subject: [PATCH 2/2] break local == instrumented assumption --- Include/cpython/monitoring.h | 10 ++++++---- Python/instrumentation.c | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Include/cpython/monitoring.h b/Include/cpython/monitoring.h index 2dbf47e8a4bb8c..513b18ad041882 100644 --- a/Include/cpython/monitoring.h +++ b/Include/cpython/monitoring.h @@ -22,12 +22,14 @@ extern "C" { #define PY_MONITORING_EVENT_BRANCH_LEFT 8 #define PY_MONITORING_EVENT_BRANCH_RIGHT 9 #define PY_MONITORING_EVENT_STOP_ITERATION 10 -#define PY_MONITORING_EVENT_PY_UNWIND 11 -// TODO: PY_UNWIND requires no instrumentation so this definition is not -// entirely correct. #define PY_MONITORING_IS_INSTRUMENTED_EVENT(ev) \ -((ev) <= _PY_MONITORING_LOCAL_EVENTS) +((ev) <= PY_MONITORING_EVENT_STOP_ITERATION) + +#define PY_MONITORING_EVENT_PY_UNWIND 11 + +#define PY_MONITORING_IS_LOCAL_EVENT(ev) \ +((ev) < _PY_MONITORING_LOCAL_EVENTS) /* Other events, mainly exceptions */ diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 1aed6769d217fe..bbcbd37f355885 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1102,7 +1102,7 @@ get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i, event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } - if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) { + if (PY_MONITORING_IS_LOCAL_EVENT(event)) { CHECK(debug_check_sanity(interp, code)); if (code->_co_monitoring->tools) { tools = code->_co_monitoring->tools[i];