Skip to content

Commit 0589c6a

Browse files
authored
gh-104615: don't make unsafe swaps in apply_static_swaps (#104620)
1 parent dcdc90d commit 0589c6a

14 files changed

+95
-20
lines changed

‎Include/internal/pycore_compile.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen(
105105

106106
PyAPI_FUNC(PyObject*) _PyCompile_OptimizeCfg(
107107
PyObject *instructions,
108-
PyObject *consts);
108+
PyObject *consts,
109+
int nlocals);
109110

110111
PyAPI_FUNC(PyCodeObject*)
111112
_PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,

‎Include/internal/pycore_global_objects_fini_generated.h‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/internal/pycore_global_strings.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ struct _Py_global_strings {
559559
STRUCT_FOR_ID(newline)
560560
STRUCT_FOR_ID(newlines)
561561
STRUCT_FOR_ID(next)
562+
STRUCT_FOR_ID(nlocals)
562563
STRUCT_FOR_ID(node_depth)
563564
STRUCT_FOR_ID(node_offset)
564565
STRUCT_FOR_ID(ns)

‎Include/internal/pycore_runtime_init_generated.h‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/internal/pycore_unicodeobject_generated.h‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Lib/test/support/bytecode_helper.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ def generate_code(self, ast):
130130

131131
class CfgOptimizationTestCase(CompilationStepTestCase):
132132

133-
def get_optimized(self, insts, consts):
133+
def get_optimized(self, insts, consts, nlocals=0):
134134
insts = self.normalize_insts(insts)
135135
insts = self.complete_insts_info(insts)
136-
insts = optimize_cfg(insts, consts)
136+
insts = optimize_cfg(insts, consts, nlocals)
137137
return insts, consts
138138

139139
class AssemblerTestCase(CompilationStepTestCase):

‎Lib/test/test_compile.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,24 @@ def foo(param, lambda_exp):
11681168
""")
11691169
compile(code, "<test>", "exec")
11701170

1171+
def test_apply_static_swaps(self):
1172+
def f(x, y):
1173+
a, a = x, y
1174+
return a
1175+
self.assertEqual(f("x", "y"), "y")
1176+
1177+
def test_apply_static_swaps_2(self):
1178+
def f(x, y, z):
1179+
a, b, a = x, y, z
1180+
return a
1181+
self.assertEqual(f("x", "y", "z"), "z")
1182+
1183+
def test_apply_static_swaps_3(self):
1184+
def f(x, y, z):
1185+
a, a, b = x, y, z
1186+
return a
1187+
self.assertEqual(f("x", "y", "z"), "y")
1188+
11711189

11721190
@requires_debug_ranges()
11731191
class TestSourcePositions(unittest.TestCase):

‎Lib/test/test_listcomps.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,12 @@ def test_nested_listcomp_in_lambda(self):
484484
"""
485485
self._check_in_scopes(code, {"z": 1, "out": [(3, 2, 1)]})
486486

487+
def test_assign_to_comp_iter_var_in_outer_function(self):
488+
code = """
489+
a = [1 for a in [0]]
490+
"""
491+
self._check_in_scopes(code, {"a": [1]}, scopes=["function"])
492+
487493

488494
__test__ = {'doctests' : doctests}
489495

‎Lib/test/test_peepholer.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -971,13 +971,14 @@ def trace(frame, event, arg):
971971
self.assertNotInBytecode(f, "LOAD_FAST_CHECK")
972972

973973

974-
class DirectiCfgOptimizerTests(CfgOptimizationTestCase):
974+
class DirectCfgOptimizerTests(CfgOptimizationTestCase):
975975

976976
def cfg_optimization_test(self, insts, expected_insts,
977-
consts=None, expected_consts=None):
977+
consts=None, expected_consts=None,
978+
nlocals=0):
978979
if expected_consts is None:
979980
expected_consts = consts
980-
opt_insts, opt_consts = self.get_optimized(insts, consts)
981+
opt_insts, opt_consts = self.get_optimized(insts, consts, nlocals)
981982
expected_insts = self.normalize_insts(expected_insts)
982983
self.assertInstructionsMatch(opt_insts, expected_insts)
983984
self.assertEqual(opt_consts, expected_consts)
@@ -1058,6 +1059,19 @@ def test_conditional_jump_backward_const_condition(self):
10581059
]
10591060
self.cfg_optimization_test(insts, expected_insts, consts=list(range(5)))
10601061

1062+
def test_no_unsafe_static_swap(self):
1063+
# We can't change order of two stores to the same location
1064+
insts = [
1065+
('LOAD_CONST', 0, 1),
1066+
('LOAD_CONST', 1, 2),
1067+
('LOAD_CONST', 2, 3),
1068+
('SWAP', 3, 4),
1069+
('STORE_FAST', 1, 4),
1070+
('STORE_FAST', 1, 4),
1071+
('POP_TOP', 0, 4),
1072+
('RETURN_VALUE', 5)
1073+
]
1074+
self.cfg_optimization_test(insts, insts, consts=list(range(3)), nlocals=1)
10611075

10621076
if __name__ == "__main__":
10631077
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed by
2+
Carl Meyer.

0 commit comments

Comments
 (0)