Skip to content

Commit 667e4ec

Browse files
authored
[3.11] gh-104615: don't make unsafe swaps in apply_static_swaps (GH-104620). (#104636)
(cherry picked from commit 0589c6a)
1 parent d78c3bc commit 667e4ec

File tree

3 files changed

+40
-0
lines changed

3 files changed

+40
-0
lines changed

Lib/test/test_compile.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,24 @@ def test_compare_positions(self):
10641064
with self.subTest(source):
10651065
self.assertEqual(actual_positions, expected_positions)
10661066

1067+
def test_apply_static_swaps(self):
1068+
def f(x, y):
1069+
a, a = x, y
1070+
return a
1071+
self.assertEqual(f("x", "y"), "y")
1072+
1073+
def test_apply_static_swaps_2(self):
1074+
def f(x, y, z):
1075+
a, b, a = x, y, z
1076+
return a
1077+
self.assertEqual(f("x", "y", "z"), "z")
1078+
1079+
def test_apply_static_swaps_3(self):
1080+
def f(x, y, z):
1081+
a, a, b = x, y, z
1082+
return a
1083+
self.assertEqual(f("x", "y", "z"), "y")
1084+
10671085

10681086
@requires_debug_ranges()
10691087
class TestSourcePositions(unittest.TestCase):
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.

Python/compile.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8690,6 +8690,9 @@ swaptimize(basicblock *block, int *ix)
86908690
#define SWAPPABLE(opcode) \
86918691
((opcode) == STORE_FAST || (opcode) == POP_TOP)
86928692

8693+
#define STORES_TO(instr) \
8694+
(((instr).i_opcode == STORE_FAST) ? (instr).i_oparg : -1)
8695+
86938696
static int
86948697
next_swappable_instruction(basicblock *block, int i, int lineno)
86958698
{
@@ -8741,6 +8744,23 @@ apply_static_swaps(basicblock *block, int i)
87418744
return;
87428745
}
87438746
}
8747+
// The reordering is not safe if the two instructions to be swapped
8748+
// store to the same location, or if any intervening instruction stores
8749+
// to the same location as either of them.
8750+
int store_j = STORES_TO(block->b_instr[j]);
8751+
int store_k = STORES_TO(block->b_instr[k]);
8752+
if (store_j >= 0 || store_k >= 0) {
8753+
if (store_j == store_k) {
8754+
return;
8755+
}
8756+
for (int idx = j + 1; idx < k; idx++) {
8757+
int store_idx = STORES_TO(block->b_instr[idx]);
8758+
if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) {
8759+
return;
8760+
}
8761+
}
8762+
}
8763+
87448764
// Success!
87458765
swap->i_opcode = NOP;
87468766
struct instr temp = block->b_instr[j];

0 commit comments

Comments
 (0)