@@ -81,23 +81,28 @@ static void
8181_clear_exec_local_writeback_for_frame (PyFrameObject * f )
8282{
8383 PyObject * frame_key ;
84+ PyObject * exc_type , * exc_value , * exc_tb ;
8485
8586 if (exec_local_writeback_map == NULL ) {
8687 return ;
8788 }
89+ PyErr_Fetch (& exc_type , & exc_value , & exc_tb );
8890 frame_key = PyLong_FromVoidPtr (f );
8991 if (frame_key == NULL ) {
9092 PyErr_Clear ();
93+ PyErr_Restore (exc_type , exc_value , exc_tb );
9194 return ;
9295 }
93- if (PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
96+ if (PyDict_GetItem (exec_local_writeback_map , frame_key ) != NULL &&
97+ PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
9498 PyErr_Clear ();
9599 }
96100 Py_DECREF (frame_key );
101+ PyErr_Restore (exc_type , exc_value , exc_tb );
97102}
98103
99104static int
100- _warn_exec_local_writeback (PyFrameObject * f , int oparg , int opcode )
105+ _warn_exec_local_writeback (PyFrameObject * f , int oparg )
101106{
102107 PyObject * frame_key = NULL ;
103108 PyObject * frame_dict = NULL ;
@@ -106,11 +111,7 @@ _warn_exec_local_writeback(PyFrameObject *f, int oparg, int opcode)
106111 PyObject * msg = NULL ;
107112 PyObject * name_obj = NULL ;
108113 const char * local_name = NULL ;
109- const char * func_name = NULL ;
110- int exec_lineno = 0 ;
111- int exec_offset = 0 ;
112114 int read_lineno = 0 ;
113- int read_offset = f -> f_lasti ;
114115 int warn_result ;
115116
116117 if (exec_local_writeback_map == NULL ) {
@@ -138,37 +139,18 @@ _warn_exec_local_writeback(PyFrameObject *f, int oparg, int opcode)
138139 Py_DECREF (frame_key );
139140 return 0 ;
140141 }
141- if (PyTuple_Check (entry ) && PyTuple_GET_SIZE (entry ) == 2 ) {
142- exec_lineno = (int )PyInt_AsLong (PyTuple_GET_ITEM (entry , 0 ));
143- exec_offset = (int )PyInt_AsLong (PyTuple_GET_ITEM (entry , 1 ));
144- }
145- if (exec_lineno < 0 ) {
146- exec_lineno = 0 ;
147- }
148142 read_lineno = PyCode_Addr2Line (f -> f_code , f -> f_lasti );
149143 name_obj = PyTuple_GetItem (f -> f_code -> co_varnames , oparg );
150144 if (name_obj != NULL ) {
151145 local_name = PyString_AsString (name_obj );
152146 }
153- if (local_name == NULL ) {
147+ else if (local_name == NULL ) {
154148 local_name = "<local>" ;
155149 }
156- if (f -> f_code -> co_name != NULL ) {
157- func_name = PyString_AsString (f -> f_code -> co_name );
158- }
159- if (func_name == NULL ) {
160- func_name = "<function>" ;
161- }
162150 msg = PyString_FromFormat (
163151 "exec() modified local '%s' which is read later in the enclosing function; "
164- "in 3.x exec() does not reliably write back to function locals without an explicit locals mapping"
165- "\nPYGRATE_META: {\"warning_type\":\"EXEC_LOCAL_WRITEBACK_WARNING\","
166- "\"scope_kind\":\"function\",\"has_explicit_globals\":false,"
167- "\"has_explicit_locals\":false,\"local_name\":\"%s\","
168- "\"exec_lineno\":%d,\"read_lineno\":%d,\"read_opcode\":%d,"
169- "\"exec_offset\":%d,\"read_offset\":%d,\"function_name\":\"%s\"}" ,
170- local_name , local_name , exec_lineno , read_lineno , opcode ,
171- exec_offset , read_offset , func_name );
152+ "in 3.x exec() does not reliably write back to function locals without an explicit locals mapping" ,
153+ local_name );
172154 if (msg == NULL ) {
173155 Py_DECREF (idx );
174156 Py_DECREF (frame_key );
@@ -197,10 +179,9 @@ _warn_exec_local_writeback(PyFrameObject *f, int oparg, int opcode)
197179 }
198180 Py_DECREF (idx );
199181
200- if (PyDict_Size (frame_dict ) <= 0 ) {
201- if (PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
202- PyErr_Clear ();
203- }
182+ if (PyDict_Size (frame_dict ) <= 0 &&
183+ PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
184+ PyErr_Clear ();
204185 }
205186 Py_DECREF (frame_key );
206187 return 0 ;
@@ -212,36 +193,42 @@ _clear_exec_local_writeback_for_local(PyFrameObject *f, int oparg)
212193 PyObject * frame_key = NULL ;
213194 PyObject * frame_dict = NULL ;
214195 PyObject * idx = NULL ;
196+ PyObject * exc_type , * exc_value , * exc_tb ;
215197
216198 if (exec_local_writeback_map == NULL ) {
217199 return ;
218200 }
201+ PyErr_Fetch (& exc_type , & exc_value , & exc_tb );
219202 frame_key = PyLong_FromVoidPtr (f );
220203 if (frame_key == NULL ) {
221204 PyErr_Clear ();
205+ PyErr_Restore (exc_type , exc_value , exc_tb );
222206 return ;
223207 }
224208 frame_dict = PyDict_GetItem (exec_local_writeback_map , frame_key );
225209 if (frame_dict == NULL ) {
226210 Py_DECREF (frame_key );
211+ PyErr_Restore (exc_type , exc_value , exc_tb );
227212 return ;
228213 }
229214 idx = PyInt_FromLong (oparg );
230215 if (idx == NULL ) {
231216 Py_DECREF (frame_key );
232217 PyErr_Clear ();
218+ PyErr_Restore (exc_type , exc_value , exc_tb );
233219 return ;
234220 }
235- if (PyDict_DelItem (frame_dict , idx ) < 0 ) {
221+ if (PyDict_GetItem (frame_dict , idx ) != NULL &&
222+ PyDict_DelItem (frame_dict , idx ) < 0 ) {
236223 PyErr_Clear ();
237224 }
238225 Py_DECREF (idx );
239- if (PyDict_Size (frame_dict ) <= 0 ) {
240- if (PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
241- PyErr_Clear ();
242- }
226+ if (PyDict_Size (frame_dict ) <= 0 &&
227+ PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
228+ PyErr_Clear ();
243229 }
244230 Py_DECREF (frame_key );
231+ PyErr_Restore (exc_type , exc_value , exc_tb );
245232}
246233
247234#ifndef WITH_TSC
@@ -1451,11 +1438,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
14511438 {
14521439 x = GETLOCAL (oparg );
14531440 if (x != NULL ) {
1454- if (Py_Py3kWarningFlag ) {
1455- if (_warn_exec_local_writeback (f , oparg , opcode ) < 0 ) {
1456- err = -1 ;
1457- break ;
1458- }
1441+ if (Py_Py3kWarningFlag &&
1442+ _warn_exec_local_writeback (f , oparg ) < 0 ) {
1443+ err = -1 ;
1444+ break ;
14591445 }
14601446 Py_INCREF (x );
14611447 PUSH (x );
@@ -5277,7 +5263,7 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
52775263 int n ;
52785264 PyObject * v ;
52795265 int plain = 0 ;
5280- int track_locals = 0 ;
5266+ int track_exec_writeback = 0 ;
52815267 int exec_lineno = 0 ;
52825268 int exec_offset = 0 ;
52835269 int nlocals = 0 ;
@@ -5329,6 +5315,8 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
53295315 if (PyDict_GetItemString (globals , "__builtins__" ) == NULL )
53305316 PyDict_SetItemString (globals , "__builtins__" , f -> f_builtins );
53315317
5318+ /* Snapshot fast locals for plain exec so later LOAD_FAST warns only
5319+ about bindings that exec actually wrote back. */
53325320 if (plain && Py_Py3kWarningFlag &&
53335321 (f -> f_code -> co_flags & CO_NEWLOCALS ) &&
53345322 f -> f_code -> co_nlocals > 0 &&
@@ -5340,7 +5328,7 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
53405328 before [i ] = f -> f_localsplus [i ];
53415329 Py_XINCREF (before [i ]);
53425330 }
5343- track_locals = 1 ;
5331+ track_exec_writeback = 1 ;
53445332 exec_offset = f -> f_lasti ;
53455333 exec_lineno = PyCode_Addr2Line (f -> f_code , exec_offset );
53465334 }
@@ -5392,7 +5380,7 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
53925380 }
53935381 if (plain )
53945382 PyFrame_LocalsToFast (f , 0 );
5395- if (track_locals && v != NULL ) {
5383+ if (track_exec_writeback && v != NULL ) {
53965384 PyObject * frame_key = NULL ;
53975385 PyObject * frame_dict = NULL ;
53985386 PyObject * map = NULL ;
@@ -5437,11 +5425,8 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
54375425 if (frame_dict != NULL ) {
54385426 PyObject * idx = PyInt_FromLong (i );
54395427 PyObject * val = Py_BuildValue ("ii" , exec_lineno , exec_offset );
5440- if (idx != NULL && val != NULL ) {
5441- if (PyDict_SetItem (frame_dict , idx , val ) < 0 ) {
5442- PyErr_Clear ();
5443- }
5444- } else {
5428+ if (idx == NULL || val == NULL ||
5429+ PyDict_SetItem (frame_dict , idx , val ) < 0 ) {
54455430 PyErr_Clear ();
54465431 }
54475432 Py_XDECREF (idx );
0 commit comments