@@ -620,42 +620,6 @@ _PyFrame_GetState(PyFrameObject *frame)
620620 Py_UNREACHABLE ();
621621}
622622
623- static void
624- add_load_fast_null_checks (PyCodeObject * co )
625- {
626- int changed = 0 ;
627- _Py_CODEUNIT * instructions = _PyCode_CODE (co );
628- for (Py_ssize_t i = 0 ; i < Py_SIZE (co ); i ++ ) {
629- int opcode = _Py_OPCODE (instructions [i ]);
630- switch (opcode ) {
631- case LOAD_FAST :
632- case LOAD_FAST__LOAD_FAST :
633- case LOAD_FAST__LOAD_CONST :
634- changed = 1 ;
635- _Py_SET_OPCODE (instructions [i ], LOAD_FAST_CHECK );
636- break ;
637- case LOAD_CONST__LOAD_FAST :
638- changed = 1 ;
639- _Py_SET_OPCODE (instructions [i ], LOAD_CONST );
640- break ;
641- case STORE_FAST__LOAD_FAST :
642- changed = 1 ;
643- _Py_SET_OPCODE (instructions [i ], STORE_FAST );
644- break ;
645- }
646- i += _PyOpcode_Caches [_PyOpcode_Deopt [opcode ]];
647- }
648- if (changed && co -> _co_cached != NULL ) {
649- // invalidate cached co_code object
650- Py_CLEAR (co -> _co_cached -> _co_code );
651- Py_CLEAR (co -> _co_cached -> _co_cellvars );
652- Py_CLEAR (co -> _co_cached -> _co_freevars );
653- Py_CLEAR (co -> _co_cached -> _co_varnames );
654- PyMem_Free (co -> _co_cached );
655- co -> _co_cached = NULL ;
656- }
657- }
658-
659623/* Setter for f_lineno - you can set f_lineno from within a trace function in
660624 * order to jump to a given line of code, subject to some restrictions. Most
661625 * lines are OK to jump to because they don't make any assumptions about the
@@ -745,8 +709,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
745709 return -1 ;
746710 }
747711
748- add_load_fast_null_checks (f -> f_frame -> f_code );
749-
750712 /* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
751713 * should never overflow. */
752714 int len = (int )Py_SIZE (f -> f_frame -> f_code );
@@ -805,6 +767,31 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
805767 PyErr_SetString (PyExc_ValueError , msg );
806768 return -1 ;
807769 }
770+ // Populate any NULL locals that the compiler might have "proven" to exist
771+ // in the new location. Rather than crashing or changing co_code, just bind
772+ // None instead:
773+ int unbound = 0 ;
774+ for (int i = 0 ; i < f -> f_frame -> f_code -> co_nlocalsplus ; i ++ ) {
775+ // Counting every unbound local is overly-cautious, but a full flow
776+ // analysis (like we do in the compiler) is probably too expensive:
777+ unbound += f -> f_frame -> localsplus [i ] == NULL ;
778+ }
779+ if (unbound ) {
780+ const char * e = "assigning None to %d unbound local%s" ;
781+ const char * s = (unbound == 1 ) ? "" : "s" ;
782+ if (PyErr_WarnFormat (PyExc_RuntimeWarning , 0 , e , unbound , s )) {
783+ return -1 ;
784+ }
785+ // Do this in a second pass to avoid writing a bunch of Nones when
786+ // warnings are being treated as errors and the previous bit raises:
787+ for (int i = 0 ; i < f -> f_frame -> f_code -> co_nlocalsplus ; i ++ ) {
788+ if (f -> f_frame -> localsplus [i ] == NULL ) {
789+ f -> f_frame -> localsplus [i ] = Py_NewRef (Py_None );
790+ unbound -- ;
791+ }
792+ }
793+ assert (unbound == 0 );
794+ }
808795 if (state == FRAME_SUSPENDED ) {
809796 /* Account for value popped by yield */
810797 start_stack = pop_value (start_stack );
@@ -1269,7 +1256,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
12691256 }
12701257 fast = _PyFrame_GetLocalsArray (frame );
12711258 co = frame -> f_code ;
1272- bool added_null_checks = false;
12731259
12741260 PyErr_Fetch (& error_type , & error_value , & error_traceback );
12751261 for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
@@ -1289,10 +1275,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
12891275 }
12901276 }
12911277 PyObject * oldvalue = fast [i ];
1292- if (!added_null_checks && oldvalue != NULL && value == NULL ) {
1293- add_load_fast_null_checks (co );
1294- added_null_checks = true;
1295- }
12961278 PyObject * cell = NULL ;
12971279 if (kind == CO_FAST_FREE ) {
12981280 // The cell was set when the frame was created from
@@ -1319,7 +1301,17 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear)
13191301 }
13201302 }
13211303 else if (value != oldvalue ) {
1322- Py_XINCREF (value );
1304+ if (value == NULL ) {
1305+ // Probably can't delete this, since the compiler's flow
1306+ // analysis may have already "proven" that it exists here:
1307+ const char * e = "assigning None to unbound local %R" ;
1308+ if (PyErr_WarnFormat (PyExc_RuntimeWarning , 0 , e , name )) {
1309+ // It's okay if frame_obj is NULL, just try anyways:
1310+ PyErr_WriteUnraisable ((PyObject * )frame -> frame_obj );
1311+ }
1312+ value = Py_NewRef (Py_None );
1313+ }
1314+ Py_INCREF (value );
13231315 Py_XSETREF (fast [i ], value );
13241316 }
13251317 Py_XDECREF (value );
0 commit comments