[Python-checkins] [3.11] gh-104615: don't make unsafe swaps in apply_static_swaps (GH-104620). (#104636)

carljm webhook-mailer at python.org
Fri May 19 14:04:11 EDT 2023


https://github.com/python/cpython/commit/667e4ece9873146a99fc7c017b8a2be76765a715
commit: 667e4ece9873146a99fc7c017b8a2be76765a715
branch: 3.11
author: Carl Meyer <carl at oddbird.net>
committer: carljm <carl at oddbird.net>
date: 2023-05-19T12:04:04-06:00
summary:

[3.11] gh-104615: don't make unsafe swaps in apply_static_swaps (GH-104620). (#104636)

(cherry picked from commit 0589c6a4d3d822cace42050198cb9a5e99c879ad)

files:
A Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst
M Lib/test/test_compile.py
M Python/compile.c

diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index c96ae4375df8..c756d43a3cf3 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1064,6 +1064,24 @@ def test_compare_positions(self):
                 with self.subTest(source):
                     self.assertEqual(actual_positions, expected_positions)
 
+    def test_apply_static_swaps(self):
+        def f(x, y):
+            a, a = x, y
+            return a
+        self.assertEqual(f("x", "y"), "y")
+
+    def test_apply_static_swaps_2(self):
+        def f(x, y, z):
+            a, b, a = x, y, z
+            return a
+        self.assertEqual(f("x", "y", "z"), "z")
+
+    def test_apply_static_swaps_3(self):
+        def f(x, y, z):
+            a, a, b = x, y, z
+            return a
+        self.assertEqual(f("x", "y", "z"), "y")
+
 
 @requires_debug_ranges()
 class TestSourcePositions(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst
new file mode 100644
index 000000000000..447291a619dd
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst	
@@ -0,0 +1,2 @@
+Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed by
+Carl Meyer.
diff --git a/Python/compile.c b/Python/compile.c
index f87a423acd1f..1c712fba3157 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -8690,6 +8690,9 @@ swaptimize(basicblock *block, int *ix)
 #define SWAPPABLE(opcode) \
     ((opcode) == STORE_FAST || (opcode) == POP_TOP)
 
+#define STORES_TO(instr) \
+    (((instr).i_opcode == STORE_FAST) ? (instr).i_oparg : -1)
+
 static int
 next_swappable_instruction(basicblock *block, int i, int lineno)
 {
@@ -8741,6 +8744,23 @@ apply_static_swaps(basicblock *block, int i)
                 return;
             }
         }
+        // The reordering is not safe if the two instructions to be swapped
+        // store to the same location, or if any intervening instruction stores
+        // to the same location as either of them.
+        int store_j = STORES_TO(block->b_instr[j]);
+        int store_k = STORES_TO(block->b_instr[k]);
+        if (store_j >= 0 || store_k >= 0) {
+            if (store_j == store_k) {
+                return;
+            }
+            for (int idx = j + 1; idx < k; idx++) {
+                int store_idx = STORES_TO(block->b_instr[idx]);
+                if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) {
+                    return;
+                }
+            }
+        }
+
         // Success!
         swap->i_opcode = NOP;
         struct instr temp = block->b_instr[j];



More information about the Python-checkins mailing list