@@ -792,6 +792,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
792792 return NULL ;
793793 }
794794
795+ /* Local "register" variables.
796+ * These are cached values from the frame and code object. */
797+ _Py_CODEUNIT * next_instr ;
798+ _PyStackRef * stack_pointer ;
799+
795800#if defined(Py_DEBUG ) && !defined(Py_STACKREF_DEBUG )
796801 /* Set these to invalid but identifiable values for debugging. */
797802 entry_frame .f_funcobj = (_PyStackRef ){.bits = 0xaaa0 };
@@ -819,67 +824,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
819824 /* support for generator.throw() */
820825 if (throwflag ) {
821826 if (_Py_EnterRecursivePy (tstate )) {
822- goto exit_unwind ;
827+ goto early_exit ;
823828 }
824- /* Because this avoids the RESUME,
825- * we need to update instrumentation */
826829#ifdef Py_GIL_DISABLED
827830 /* Load thread-local bytecode */
828831 if (frame -> tlbc_index != ((_PyThreadStateImpl * )tstate )-> tlbc_index ) {
829832 _Py_CODEUNIT * bytecode =
830833 _PyEval_GetExecutableCode (tstate , _PyFrame_GetCode (frame ));
831834 if (bytecode == NULL ) {
832- goto exit_unwind ;
835+ goto early_exit ;
833836 }
834837 ptrdiff_t off = frame -> instr_ptr - _PyFrame_GetBytecode (frame );
835838 frame -> tlbc_index = ((_PyThreadStateImpl * )tstate )-> tlbc_index ;
836839 frame -> instr_ptr = bytecode + off ;
837840 }
838841#endif
842+ /* Because this avoids the RESUME, we need to update instrumentation */
839843 _Py_Instrument (_PyFrame_GetCode (frame ), tstate -> interp );
840- monitor_throw (tstate , frame , frame -> instr_ptr );
841- /* TO DO -- Monitor throw entry. */
842- goto resume_with_error ;
844+ next_instr = frame -> instr_ptr ;
845+ stack_pointer = _PyFrame_GetStackPointer (frame );
846+ monitor_throw (tstate , frame , next_instr );
847+ goto error ;
843848 }
844849
845- /* Local "register" variables.
846- * These are cached values from the frame and code object. */
847- _Py_CODEUNIT * next_instr ;
848- _PyStackRef * stack_pointer ;
849-
850850#if defined(_Py_TIER2 ) && !defined(_Py_JIT )
851851 /* Tier 2 interpreter state */
852852 _PyExecutorObject * current_executor = NULL ;
853853 const _PyUOpInstruction * next_uop = NULL ;
854854#endif
855855
856- start_frame :
857- if (_Py_EnterRecursivePy (tstate )) {
858- goto exit_unwind ;
859- }
860-
861- next_instr = frame -> instr_ptr ;
862- resume_frame :
863- stack_pointer = _PyFrame_GetStackPointer (frame );
864-
865- #ifdef LLTRACE
866- {
867- int lltrace = maybe_lltrace_resume_frame (frame , GLOBALS ());
868- frame -> lltrace = lltrace ;
869- if (lltrace < 0 ) {
870- goto exit_unwind ;
871- }
872- }
873- #endif
874-
875- #ifdef Py_DEBUG
876- /* _PyEval_EvalFrameDefault() must not be called with an exception set,
877- because it can clear it (directly or indirectly) and so the
878- caller loses its exception */
879- assert (!_PyErr_Occurred (tstate ));
880- #endif
881-
882- DISPATCH ();
856+ goto start_frame ;
883857
884858#include "generated_cases.c.h"
885859
@@ -983,10 +957,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
983957 OPT_HIST (trace_uop_execution_counter , trace_run_length_hist );
984958 assert (next_uop [-1 ].format == UOP_FORMAT_TARGET );
985959 frame -> return_offset = 0 ; // Don't leave this random
986- _PyFrame_SetStackPointer (frame , stack_pointer );
987960 Py_DECREF (current_executor );
988961 tstate -> previous_executor = NULL ;
989- goto resume_with_error ;
962+ next_instr = frame -> instr_ptr ;
963+ goto error ;
990964
991965jump_to_jump_target :
992966 assert (next_uop [-1 ].format == UOP_FORMAT_JUMP );
@@ -1018,6 +992,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
1018992
1019993#endif // _Py_TIER2
1020994
995+ early_exit :
996+ assert (_PyErr_Occurred (tstate ));
997+ _Py_LeaveRecursiveCallPy (tstate );
998+ assert (frame -> owner != FRAME_OWNED_BY_INTERPRETER );
999+ // GH-99729: We need to unlink the frame *before* clearing it:
1000+ _PyInterpreterFrame * dying = frame ;
1001+ frame = tstate -> current_frame = dying -> previous ;
1002+ _PyEval_FrameClearAndPop (tstate , dying );
1003+ frame -> return_offset = 0 ;
1004+ assert (frame -> owner == FRAME_OWNED_BY_INTERPRETER );
1005+ /* Restore previous frame and exit */
1006+ tstate -> current_frame = frame -> previous ;
1007+ tstate -> c_recursion_remaining += PY_EVAL_C_STACK_UNITS ;
1008+ return NULL ;
10211009}
10221010
10231011#if defined(__GNUC__ )
0 commit comments