Skip to content

Commit 64d7be6

Browse files
committed
gh-138122: Don't sample partial frame chains with suspended generators
1 parent 64ccb1a commit 64d7be6

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

Modules/_remote_debugging_module.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,15 +2254,22 @@ is_frame_valid(
22542254
}
22552255

22562256
void* frame = (void*)frame_addr;
2257+
char owner = GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner);
22572258

2258-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_INTERPRETER) {
2259+
if (owner == FRAME_OWNED_BY_INTERPRETER) {
22592260
return 0; // C frame
22602261
}
22612262

2262-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR
2263-
&& GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_THREAD) {
2264-
PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n",
2265-
GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner));
2263+
// Reject generator frames with NULL previous pointer - can't unwind past them
2264+
if (owner == FRAME_OWNED_BY_GENERATOR) {
2265+
uintptr_t previous = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
2266+
if (previous == 0) {
2267+
return 0; // Generator frame with no caller - skip it
2268+
}
2269+
}
2270+
2271+
if (owner != FRAME_OWNED_BY_GENERATOR && owner != FRAME_OWNED_BY_THREAD) {
2272+
PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n", owner);
22662273
set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame");
22672274
return -1;
22682275
}

0 commit comments

Comments
 (0)