]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-109052: Use the base opcode when comparing code objects (gh-109107)
authorTian Gao <gaogaotiantian@hotmail.com>
Sat, 9 Sep 2023 01:24:49 +0000 (18:24 -0700)
committerGitHub <noreply@github.com>
Sat, 9 Sep 2023 01:24:49 +0000 (10:24 +0900)
Lib/test/test_code.py
Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-49-01.gh-issue-109052.TBU4nC.rst [new file with mode: 0644]
Objects/codeobject.c

index 812c0682569207645726d8f7f9b25dbfd6c3e44b..a961ddbe17a3d3207e875243541fe246e1cb8c85 100644 (file)
@@ -505,6 +505,25 @@ class CodeTest(unittest.TestCase):
         self.assertNotEqual(c, c1)
         self.assertNotEqual(hash(c), hash(c1))
 
+    @cpython_only
+    def test_code_equal_with_instrumentation(self):
+        """ GH-109052
+
+        Make sure the instrumentation doesn't affect the code equality
+        The validity of this test relies on the fact that "x is x" and
+        "x in x" have only one different instruction and the instructions
+        have the same argument.
+
+        """
+        code1 = compile("x is x", "example.py", "eval")
+        code2 = compile("x in x", "example.py", "eval")
+        sys._getframe().f_trace_opcodes = True
+        sys.settrace(lambda *args: None)
+        exec(code1, {'x': []})
+        exec(code2, {'x': []})
+        self.assertNotEqual(code1, code2)
+        sys.settrace(None)
+
 
 def isinterned(s):
     return s is sys.intern(('_' + s + '_')[1:-1])
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-49-01.gh-issue-109052.TBU4nC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-07-18-49-01.gh-issue-109052.TBU4nC.rst
new file mode 100644 (file)
index 0000000..175046c
--- /dev/null
@@ -0,0 +1 @@
+Use the base opcode when comparing code objects to avoid interference from instrumentation
index d00bd0422f004dfff02e87f681292ab0a9c760eb..20e5dedb22826f03b5ec9e9ad58b3896d00871f3 100644 (file)
@@ -1798,28 +1798,26 @@ code_richcompare(PyObject *self, PyObject *other, int op)
     for (int i = 0; i < Py_SIZE(co); i++) {
         _Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
         _Py_CODEUNIT cp_instr = _PyCode_CODE(cp)[i];
-        uint8_t co_code = co_instr.op.code;
+        uint8_t co_code = _Py_GetBaseOpcode(co, i);
         uint8_t co_arg = co_instr.op.arg;
-        uint8_t cp_code = cp_instr.op.code;
+        uint8_t cp_code = _Py_GetBaseOpcode(cp, i);
         uint8_t cp_arg = cp_instr.op.arg;
 
         if (co_code == ENTER_EXECUTOR) {
             const int exec_index = co_arg;
             _PyExecutorObject *exec = co->co_executors->executors[exec_index];
-            co_code = exec->vm_data.opcode;
+            co_code = _PyOpcode_Deopt[exec->vm_data.opcode];
             co_arg = exec->vm_data.oparg;
         }
         assert(co_code != ENTER_EXECUTOR);
-        co_code = _PyOpcode_Deopt[co_code];
 
         if (cp_code == ENTER_EXECUTOR) {
             const int exec_index = cp_arg;
             _PyExecutorObject *exec = cp->co_executors->executors[exec_index];
-            cp_code = exec->vm_data.opcode;
+            cp_code = _PyOpcode_Deopt[exec->vm_data.opcode];
             cp_arg = exec->vm_data.oparg;
         }
         assert(cp_code != ENTER_EXECUTOR);
-        cp_code = _PyOpcode_Deopt[cp_code];
 
         if (co_code != cp_code || co_arg != cp_arg) {
             goto unequal;