Skip to content

Commit 2dbcf91

Browse files
committed
gh-158539: Fix exception mode missing handlers in generators/coroutines
The sampling profiler's exception mode decided whether a thread was handling an exception by reading the embedded PyThreadState.exc_state. Generators, coroutines and async generators repoint tstate->exc_info at their own _PyErr_StackItem while they run, so an except block running in one of them (or in a function they call) stored the exception in that item instead, and was never sampled. Follow tstate->exc_info and its previous_item chain, mirroring _PyErr_GetTopmostException(), and export the two debug offsets needed to walk the chain from remote memory. The common case where exc_info points at the embedded exc_state keeps the existing zero-extra-read fast path.
1 parent a4f28a5 commit 2dbcf91

5 files changed

Lines changed: 466 additions & 10 deletions

File tree

‎Include/internal/pycore_debug_offsets.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,13 @@ typedef struct _Py_DebugOffsets {
113113
uint64_t gil_requested;
114114
uint64_t current_exception;
115115
uint64_t exc_state;
116+
uint64_t exc_info;
116117
} thread_state;
117118

118119
// Exception stack item offset
119120
struct {
120121
uint64_t exc_value;
122+
uint64_t previous_item;
121123
} err_stackitem;
122124

123125
// InterpreterFrame offset;
@@ -304,9 +306,11 @@ typedef struct _Py_DebugOffsets {
304306
.gil_requested = offsetof(PyThreadState, gil_requested), \
305307
.current_exception = offsetof(PyThreadState, current_exception), \
306308
.exc_state = offsetof(PyThreadState, exc_state), \
309+
.exc_info = offsetof(PyThreadState, exc_info), \
307310
}, \
308311
.err_stackitem = { \
309312
.exc_value = offsetof(_PyErr_StackItem, exc_value), \
313+
.previous_item = offsetof(_PyErr_StackItem, previous_item), \
310314
}, \
311315
.interpreter_frame = { \
312316
.size = sizeof(_PyInterpreterFrame), \

0 commit comments

Comments
 (0)