@@ -300,17 +300,20 @@ first_line_not_before(int *lines, int len, int line)
300300static void
301301frame_stack_pop (PyFrameObject * f )
302302{
303- PyObject * v = (* -- f -> f_stacktop );
303+ assert (f -> f_stackdepth >= 0 );
304+ f -> f_stackdepth -- ;
305+ PyObject * v = f -> f_valuestack [f -> f_stackdepth ];
304306 Py_DECREF (v );
305307}
306308
307309static void
308310frame_block_unwind (PyFrameObject * f )
309311{
312+ assert (f -> f_stackdepth >= 0 );
310313 assert (f -> f_iblock > 0 );
311314 f -> f_iblock -- ;
312315 PyTryBlock * b = & f -> f_blockstack [f -> f_iblock ];
313- intptr_t delta = ( f -> f_stacktop - f -> f_valuestack ) - b -> b_level ;
316+ intptr_t delta = f -> f_stackdepth - b -> b_level ;
314317 while (delta > 0 ) {
315318 frame_stack_pop (f );
316319 delta -- ;
@@ -352,33 +355,36 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
352355 return -1 ;
353356 }
354357
355- /* Upon the 'call' trace event of a new frame, f->f_lasti is -1 and
356- * f->f_trace is NULL, check first on the first condition.
357- * Forbidding jumps from the 'call' event of a new frame is a side effect
358- * of allowing to set f_lineno only from trace functions. */
359- if (f -> f_lasti == -1 ) {
360- PyErr_Format (PyExc_ValueError ,
358+ /*
359+ * This code preserves the historical restrictions on
360+ * setting the line number of a frame.
361+ * Jumps are forbidden on a 'return' trace event (except after a yield).
362+ * Jumps from 'call' trace events are also forbidden.
363+ * In addition, jumps are forbidden when not tracing,
364+ * as this is a debugging feature.
365+ */
366+ switch (f -> f_state ) {
367+ case FRAME_CREATED :
368+ PyErr_Format (PyExc_ValueError ,
361369 "can't jump from the 'call' trace event of a new frame" );
362- return -1 ;
363- }
364-
365- /* You can only do this from within a trace function, not via
366- * _getframe or similar hackery. */
367- if (!f -> f_trace ) {
368- PyErr_Format (PyExc_ValueError ,
369- "f_lineno can only be set by a trace function" );
370- return -1 ;
371- }
372-
373- /* Forbid jumps upon a 'return' trace event (except after executing a
374- * YIELD_VALUE or YIELD_FROM opcode, f_stacktop is not NULL in that case)
375- * and upon an 'exception' trace event.
376- * Jumps from 'call' trace events have already been forbidden above for new
377- * frames, so this check does not change anything for 'call' events. */
378- if (f -> f_stacktop == NULL ) {
379- PyErr_SetString (PyExc_ValueError ,
370+ return -1 ;
371+ case FRAME_RETURNED :
372+ case FRAME_UNWINDING :
373+ case FRAME_RAISED :
374+ case FRAME_CLEARED :
375+ PyErr_SetString (PyExc_ValueError ,
380376 "can only jump from a 'line' trace event" );
381- return -1 ;
377+ return -1 ;
378+ case FRAME_EXECUTING :
379+ case FRAME_SUSPENDED :
380+ /* You can only do this from within a trace function, not via
381+ * _getframe or similar hackery. */
382+ if (!f -> f_trace ) {
383+ PyErr_Format (PyExc_ValueError ,
384+ "f_lineno can only be set by a trace function" );
385+ return -1 ;
386+ }
387+ break ;
382388 }
383389
384390 int new_lineno ;
@@ -585,11 +591,10 @@ frame_dealloc(PyFrameObject *f)
585591 }
586592
587593 /* Free stack */
588- if (f -> f_stacktop != NULL ) {
589- for (PyObject * * p = valuestack ; p < f -> f_stacktop ; p ++ ) {
590- Py_XDECREF (* p );
591- }
594+ for (int i = 0 ; i < f -> f_stackdepth ; i ++ ) {
595+ Py_XDECREF (f -> f_valuestack [i ]);
592596 }
597+ f -> f_stackdepth = 0 ;
593598
594599 Py_XDECREF (f -> f_back );
595600 Py_DECREF (f -> f_builtins );
@@ -647,10 +652,8 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
647652 }
648653
649654 /* stack */
650- if (f -> f_stacktop != NULL ) {
651- for (PyObject * * p = f -> f_valuestack ; p < f -> f_stacktop ; p ++ ) {
652- Py_VISIT (* p );
653- }
655+ for (int i = 0 ; i < f -> f_stackdepth ; i ++ ) {
656+ Py_VISIT (f -> f_valuestack [i ]);
654657 }
655658 return 0 ;
656659}
@@ -663,9 +666,7 @@ frame_tp_clear(PyFrameObject *f)
663666 * frame may also point to this frame, believe itself to still be
664667 * active, and try cleaning up this frame again.
665668 */
666- PyObject * * oldtop = f -> f_stacktop ;
667- f -> f_stacktop = NULL ;
668- f -> f_executing = 0 ;
669+ f -> f_state = FRAME_CLEARED ;
669670
670671 Py_CLEAR (f -> f_trace );
671672
@@ -676,18 +677,17 @@ frame_tp_clear(PyFrameObject *f)
676677 }
677678
678679 /* stack */
679- if (oldtop != NULL ) {
680- for (PyObject * * p = f -> f_valuestack ; p < oldtop ; p ++ ) {
681- Py_CLEAR (* p );
682- }
680+ for (int i = 0 ; i < f -> f_stackdepth ; i ++ ) {
681+ Py_CLEAR (f -> f_valuestack [i ]);
683682 }
683+ f -> f_stackdepth = 0 ;
684684 return 0 ;
685685}
686686
687687static PyObject *
688688frame_clear (PyFrameObject * f , PyObject * Py_UNUSED (ignored ))
689689{
690- if (f -> f_executing ) {
690+ if (_PyFrame_IsExecuting ( f ) ) {
691691 PyErr_SetString (PyExc_RuntimeError ,
692692 "cannot clear an executing frame" );
693693 return NULL ;
@@ -898,7 +898,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
898898 return NULL ;
899899 }
900900
901- f -> f_stacktop = f -> f_valuestack ;
901+ f -> f_stackdepth = 0 ;
902902 f -> f_builtins = builtins ;
903903 Py_XINCREF (back );
904904 f -> f_back = back ;
@@ -927,7 +927,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
927927 f -> f_lasti = -1 ;
928928 f -> f_lineno = code -> co_firstlineno ;
929929 f -> f_iblock = 0 ;
930- f -> f_executing = 0 ;
930+ f -> f_state = FRAME_CREATED ;
931931 f -> f_gen = NULL ;
932932 f -> f_trace_opcodes = 0 ;
933933 f -> f_trace_lines = 1 ;
0 commit comments