@@ -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