@@ -66,6 +66,184 @@ _Py3kWarn_NextOpcode(void)
6666 return -1 ;
6767}
6868
69+ static PyObject * exec_local_writeback_map = NULL ;
70+
71+ static PyObject *
72+ _get_exec_local_writeback_map (void )
73+ {
74+ if (exec_local_writeback_map == NULL ) {
75+ exec_local_writeback_map = PyDict_New ();
76+ }
77+ return exec_local_writeback_map ;
78+ }
79+
80+ static void
81+ _clear_exec_local_writeback_for_frame (PyFrameObject * f )
82+ {
83+ PyObject * frame_key ;
84+
85+ if (exec_local_writeback_map == NULL ) {
86+ return ;
87+ }
88+ frame_key = PyLong_FromVoidPtr (f );
89+ if (frame_key == NULL ) {
90+ PyErr_Clear ();
91+ return ;
92+ }
93+ if (PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
94+ PyErr_Clear ();
95+ }
96+ Py_DECREF (frame_key );
97+ }
98+
99+ static int
100+ _warn_exec_local_writeback (PyFrameObject * f , int oparg , int opcode )
101+ {
102+ PyObject * frame_key = NULL ;
103+ PyObject * frame_dict = NULL ;
104+ PyObject * entry = NULL ;
105+ PyObject * idx = NULL ;
106+ PyObject * msg = NULL ;
107+ PyObject * name_obj = NULL ;
108+ const char * local_name = NULL ;
109+ const char * func_name = NULL ;
110+ int exec_lineno = 0 ;
111+ int exec_offset = 0 ;
112+ int read_lineno = 0 ;
113+ int read_offset = f -> f_lasti ;
114+ int warn_result ;
115+
116+ if (exec_local_writeback_map == NULL ) {
117+ return 0 ;
118+ }
119+ frame_key = PyLong_FromVoidPtr (f );
120+ if (frame_key == NULL ) {
121+ PyErr_Clear ();
122+ return 0 ;
123+ }
124+ frame_dict = PyDict_GetItem (exec_local_writeback_map , frame_key );
125+ if (frame_dict == NULL ) {
126+ Py_DECREF (frame_key );
127+ return 0 ;
128+ }
129+ idx = PyInt_FromLong (oparg );
130+ if (idx == NULL ) {
131+ Py_DECREF (frame_key );
132+ PyErr_Clear ();
133+ return 0 ;
134+ }
135+ entry = PyDict_GetItem (frame_dict , idx );
136+ if (entry == NULL ) {
137+ Py_DECREF (idx );
138+ Py_DECREF (frame_key );
139+ return 0 ;
140+ }
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+ }
148+ read_lineno = PyCode_Addr2Line (f -> f_code , f -> f_lasti );
149+ name_obj = PyTuple_GetItem (f -> f_code -> co_varnames , oparg );
150+ if (name_obj != NULL ) {
151+ local_name = PyString_AsString (name_obj );
152+ }
153+ if (local_name == NULL ) {
154+ local_name = "<local>" ;
155+ }
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+ }
162+ msg = PyString_FromFormat (
163+ "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 );
172+ if (msg == NULL ) {
173+ Py_DECREF (idx );
174+ Py_DECREF (frame_key );
175+ PyErr_Clear ();
176+ return 0 ;
177+ }
178+
179+ warn_result = PyErr_WarnExplicit_WithFix (
180+ PyExc_Py3xWarning ,
181+ PyString_AsString (msg ),
182+ "use exec(code, globals, locals) with an explicit locals mapping" ,
183+ PyString_AsString (f -> f_code -> co_filename ),
184+ read_lineno ,
185+ NULL ,
186+ NULL );
187+
188+ Py_DECREF (msg );
189+ if (warn_result < 0 ) {
190+ Py_DECREF (idx );
191+ Py_DECREF (frame_key );
192+ return -1 ;
193+ }
194+
195+ if (PyDict_DelItem (frame_dict , idx ) < 0 ) {
196+ PyErr_Clear ();
197+ }
198+ Py_DECREF (idx );
199+
200+ if (PyDict_Size (frame_dict ) <= 0 ) {
201+ if (PyDict_DelItem (exec_local_writeback_map , frame_key ) < 0 ) {
202+ PyErr_Clear ();
203+ }
204+ }
205+ Py_DECREF (frame_key );
206+ return 0 ;
207+ }
208+
209+ static void
210+ _clear_exec_local_writeback_for_local (PyFrameObject * f , int oparg )
211+ {
212+ PyObject * frame_key = NULL ;
213+ PyObject * frame_dict = NULL ;
214+ PyObject * idx = NULL ;
215+
216+ if (exec_local_writeback_map == NULL ) {
217+ return ;
218+ }
219+ frame_key = PyLong_FromVoidPtr (f );
220+ if (frame_key == NULL ) {
221+ PyErr_Clear ();
222+ return ;
223+ }
224+ frame_dict = PyDict_GetItem (exec_local_writeback_map , frame_key );
225+ if (frame_dict == NULL ) {
226+ Py_DECREF (frame_key );
227+ return ;
228+ }
229+ idx = PyInt_FromLong (oparg );
230+ if (idx == NULL ) {
231+ Py_DECREF (frame_key );
232+ PyErr_Clear ();
233+ return ;
234+ }
235+ if (PyDict_DelItem (frame_dict , idx ) < 0 ) {
236+ PyErr_Clear ();
237+ }
238+ 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+ }
243+ }
244+ Py_DECREF (frame_key );
245+ }
246+
69247#ifndef WITH_TSC
70248
71249#define READ_TIMESTAMP (var )
@@ -1273,6 +1451,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
12731451 {
12741452 x = GETLOCAL (oparg );
12751453 if (x != NULL ) {
1454+ if (Py_Py3kWarningFlag ) {
1455+ if (_warn_exec_local_writeback (f , oparg , opcode ) < 0 ) {
1456+ err = -1 ;
1457+ break ;
1458+ }
1459+ }
12761460 Py_INCREF (x );
12771461 PUSH (x );
12781462 FAST_DISPATCH ();
@@ -1296,6 +1480,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
12961480 {
12971481 v = POP ();
12981482 SETLOCAL (oparg , v );
1483+ if (Py_Py3kWarningFlag ) {
1484+ _clear_exec_local_writeback_for_local (f , oparg );
1485+ }
12991486 FAST_DISPATCH ();
13001487 }
13011488
@@ -2454,6 +2641,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
24542641 x = GETLOCAL (oparg );
24552642 if (x != NULL ) {
24562643 SETLOCAL (oparg , NULL );
2644+ if (Py_Py3kWarningFlag ) {
2645+ _clear_exec_local_writeback_for_local (f , oparg );
2646+ }
24572647 DISPATCH ();
24582648 }
24592649 format_exc_check_arg (
@@ -3404,6 +3594,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
34043594
34053595 /* pop frame */
34063596exit_eval_frame :
3597+ _clear_exec_local_writeback_for_frame (f );
34073598 Py_LeaveRecursiveCall ();
34083599 tstate -> frame = f -> f_back ;
34093600
@@ -5086,6 +5277,12 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
50865277 int n ;
50875278 PyObject * v ;
50885279 int plain = 0 ;
5280+ int track_locals = 0 ;
5281+ int exec_lineno = 0 ;
5282+ int exec_offset = 0 ;
5283+ int nlocals = 0 ;
5284+ PyObject * * before = NULL ;
5285+ int i ;
50895286
50905287 if (PyTuple_Check (prog ) && globals == Py_None && locals == Py_None &&
50915288 ((n = PyTuple_Size (prog )) == 2 || n == 3 )) {
@@ -5131,6 +5328,23 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
51315328 }
51325329 if (PyDict_GetItemString (globals , "__builtins__" ) == NULL )
51335330 PyDict_SetItemString (globals , "__builtins__" , f -> f_builtins );
5331+
5332+ if (plain && Py_Py3kWarningFlag &&
5333+ (f -> f_code -> co_flags & CO_NEWLOCALS ) &&
5334+ f -> f_code -> co_nlocals > 0 &&
5335+ f -> f_localsplus != NULL ) {
5336+ nlocals = f -> f_code -> co_nlocals ;
5337+ before = PyMem_New (PyObject * , nlocals );
5338+ if (before != NULL ) {
5339+ for (i = 0 ; i < nlocals ; i ++ ) {
5340+ before [i ] = f -> f_localsplus [i ];
5341+ Py_XINCREF (before [i ]);
5342+ }
5343+ track_locals = 1 ;
5344+ exec_offset = f -> f_lasti ;
5345+ exec_lineno = PyCode_Addr2Line (f -> f_code , exec_offset );
5346+ }
5347+ }
51345348 if (PyCode_Check (prog )) {
51355349 if (PyCode_GetNumFree ((PyCodeObject * )prog ) > 0 ) {
51365350 PyErr_SetString (PyExc_TypeError ,
@@ -5178,6 +5392,70 @@ exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals,
51785392 }
51795393 if (plain )
51805394 PyFrame_LocalsToFast (f , 0 );
5395+ if (track_locals && v != NULL ) {
5396+ PyObject * frame_key = NULL ;
5397+ PyObject * frame_dict = NULL ;
5398+ PyObject * map = NULL ;
5399+ for (i = 0 ; i < nlocals ; i ++ ) {
5400+ PyObject * before_obj = before [i ];
5401+ PyObject * after_obj = f -> f_localsplus [i ];
5402+ if (before_obj == after_obj ) {
5403+ continue ;
5404+ }
5405+ if (frame_key == NULL ) {
5406+ frame_key = PyLong_FromVoidPtr (f );
5407+ if (frame_key == NULL ) {
5408+ PyErr_Clear ();
5409+ break ;
5410+ }
5411+ }
5412+ if (map == NULL ) {
5413+ map = _get_exec_local_writeback_map ();
5414+ if (map == NULL ) {
5415+ PyErr_Clear ();
5416+ break ;
5417+ }
5418+ }
5419+ if (frame_dict == NULL ) {
5420+ frame_dict = PyDict_GetItem (map , frame_key );
5421+ if (frame_dict == NULL ) {
5422+ frame_dict = PyDict_New ();
5423+ if (frame_dict == NULL ) {
5424+ PyErr_Clear ();
5425+ break ;
5426+ }
5427+ if (PyDict_SetItem (map , frame_key , frame_dict ) < 0 ) {
5428+ PyErr_Clear ();
5429+ Py_DECREF (frame_dict );
5430+ frame_dict = NULL ;
5431+ break ;
5432+ }
5433+ Py_DECREF (frame_dict );
5434+ frame_dict = PyDict_GetItem (map , frame_key );
5435+ }
5436+ }
5437+ if (frame_dict != NULL ) {
5438+ PyObject * idx = PyInt_FromLong (i );
5439+ 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 {
5445+ PyErr_Clear ();
5446+ }
5447+ Py_XDECREF (idx );
5448+ Py_XDECREF (val );
5449+ }
5450+ }
5451+ Py_XDECREF (frame_key );
5452+ }
5453+ if (before != NULL ) {
5454+ for (i = 0 ; i < nlocals ; i ++ ) {
5455+ Py_XDECREF (before [i ]);
5456+ }
5457+ PyMem_Free (before );
5458+ }
51815459 if (v == NULL )
51825460 return -1 ;
51835461 Py_DECREF (v );
0 commit comments