Skip to content

Commit bcc7227

Browse files
[3.13] gh-125038: Fix crash after genexpr.gi_frame.f_locals manipulations (GH-125178) (#125846)
(cherry picked from commit 079875e) Co-authored-by: Mikhail Efimov <efimov.mikhail@gmail.com>
1 parent 5bb0538 commit bcc7227

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

‎Lib/test/test_dis.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,7 @@ def foo(x):
782782
POP_TOP
783783
L1: RESUME 0
784784
LOAD_FAST 0 (.0)
785+
GET_ITER
785786
L2: FOR_ITER 10 (to L3)
786787
STORE_FAST 1 (z)
787788
LOAD_DEREF 2 (x)

‎Lib/test/test_generators.py‎

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,79 @@ def loop():
246246
#This should not raise
247247
loop()
248248

249+
250+
classModifyUnderlyingIterableTest(unittest.TestCase):
251+
iterables= [
252+
range(0),
253+
range(20),
254+
[1, 2, 3],
255+
(2,),
256+
{13, 48, 211},
257+
frozenset((15, 8, 6)),
258+
{1: 2, 3: 4},
259+
]
260+
261+
non_iterables= [
262+
None,
263+
42,
264+
3.0,
265+
2j,
266+
]
267+
268+
defgenexpr(self):
269+
return (xforxinrange(10))
270+
271+
defgenfunc(self):
272+
defgen(it):
273+
forxinit:
274+
yieldx
275+
returngen(range(10))
276+
277+
defprocess_tests(self, get_generator):
278+
forobjinself.iterables:
279+
g_obj=get_generator(obj)
280+
withself.subTest(g_obj=g_obj, obj=obj):
281+
self.assertListEqual(list(g_obj), list(obj))
282+
283+
g_iter=get_generator(iter(obj))
284+
withself.subTest(g_iter=g_iter, obj=obj):
285+
self.assertListEqual(list(g_iter), list(obj))
286+
287+
err_regex="'.*' object is not iterable"
288+
forobjinself.non_iterables:
289+
g_obj=get_generator(obj)
290+
withself.subTest(g_obj=g_obj):
291+
self.assertRaisesRegex(TypeError, err_regex, list, g_obj)
292+
293+
deftest_modify_f_locals(self):
294+
defmodify_f_locals(g, local, obj):
295+
g.gi_frame.f_locals[local] =obj
296+
returng
297+
298+
defget_generator_genexpr(obj):
299+
returnmodify_f_locals(self.genexpr(), '.0', obj)
300+
301+
defget_generator_genfunc(obj):
302+
returnmodify_f_locals(self.genfunc(), 'it', obj)
303+
304+
self.process_tests(get_generator_genexpr)
305+
self.process_tests(get_generator_genfunc)
306+
307+
deftest_new_gen_from_gi_code(self):
308+
defnew_gen_from_gi_code(g, obj):
309+
generator_func=types.FunctionType(g.gi_code,{})
310+
returngenerator_func(obj)
311+
312+
defget_generator_genexpr(obj):
313+
returnnew_gen_from_gi_code(self.genexpr(), obj)
314+
315+
defget_generator_genfunc(obj):
316+
returnnew_gen_from_gi_code(self.genfunc(), obj)
317+
318+
self.process_tests(get_generator_genexpr)
319+
self.process_tests(get_generator_genfunc)
320+
321+
249322
classExceptionTest(unittest.TestCase):
250323
# Tests for the issue #23353: check that the currently handled exception
251324
# is correctly saved/restored in PyEval_EvalFrameEx().
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash when iterating over a generator expression after direct changes on ``gi_frame.f_locals``.
2+
Patch by Mikhail Efimov.

‎Python/compile.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5404,6 +5404,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
54045404

54055405
if (IS_LABEL(start)){
54065406
depth++;
5407+
ADDOP(c, LOC(gen->iter), GET_ITER);
54075408
USE_LABEL(c, start);
54085409
ADDOP_JUMP(c, LOC(gen->iter), FOR_ITER, anchor);
54095410
}

0 commit comments

Comments
(0)