[Python-checkins] [3.10] gh-91924: Fix __ltrace__ for non-UTF-8 stdout encoding (#93214)

vstinner webhook-mailer at python.org
Wed May 25 18:16:41 EDT 2022


https://github.com/python/cpython/commit/9369942054fe3fe389f4f4ff808d33c5d7945052
commit: 9369942054fe3fe389f4f4ff808d33c5d7945052
branch: 3.10
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022-05-26T00:16:32+02:00
summary:

[3.10] gh-91924: Fix __ltrace__ for non-UTF-8 stdout encoding (#93214)

Fix __ltrace__ debug feature if the stdout encoding is not UTF-8.

If the stdout encoding is not UTF-8, the first call to
lltrace_resume_frame() indirectly sets lltrace to 0 when calling
unicode_check_encoding_errors() which calls
encodings.search_function().

Add test_lltrace.test_lltrace() test.

files:
A Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst
M Lib/test/test_lltrace.py
M Python/ceval.c

diff --git a/Lib/test/test_lltrace.py b/Lib/test/test_lltrace.py
index 06e33f4c4c2f3..b5b0c10d404be 100644
--- a/Lib/test/test_lltrace.py
+++ b/Lib/test/test_lltrace.py
@@ -1,11 +1,16 @@
-import os
+import opcode
+import re
+import sys
 import textwrap
 import unittest
 
-from test.support import os_helper
+from test.support import os_helper, verbose
 from test.support.script_helper import assert_python_ok
 
 
+Py_DEBUG = hasattr(sys, 'gettotalrefcount')
+
+ at unittest.skipUnless(Py_DEBUG, "lltrace requires Py_DEBUG")
 class TestLLTrace(unittest.TestCase):
 
     def test_lltrace_does_not_crash_on_subscript_operator(self):
@@ -27,5 +32,67 @@ def test_lltrace_does_not_crash_on_subscript_operator(self):
 
             assert_python_ok(os_helper.TESTFN)
 
+    def run_code(self, code):
+        code = textwrap.dedent(code).strip()
+        with open(os_helper.TESTFN, 'w', encoding='utf-8') as fd:
+            self.addCleanup(os_helper.unlink, os_helper.TESTFN)
+            fd.write(code)
+        status, stdout, stderr = assert_python_ok(os_helper.TESTFN)
+        self.assertEqual(stderr, b"")
+        self.assertEqual(status, 0)
+        result = stdout.decode('utf-8')
+        if verbose:
+            print("\n\n--- code ---")
+            print(code)
+            print("\n--- stdout ---")
+            print(result)
+            print()
+        return result
+
+    def check_op(self, op, stdout, present):
+        op = opcode.opmap[op]
+        regex = re.compile(f': {op}($|, )', re.MULTILINE)
+        if present:
+            self.assertTrue(regex.search(stdout),
+                            f'": {op}" not found in: {stdout}')
+        else:
+            self.assertFalse(regex.search(stdout),
+                             f'": {op}" found in: {stdout}')
+
+    def check_op_in(self, op, stdout):
+        self.check_op(op, stdout, True)
+
+    def check_op_not_in(self, op, stdout):
+        self.check_op(op, stdout, False)
+
+    def test_lltrace(self):
+        stdout = self.run_code("""
+            def dont_trace_1():
+                a = "a"
+                a = 10 * a
+            def trace_me():
+                for i in range(3):
+                    +i
+            def dont_trace_2():
+                x = 42
+                y = -x
+            dont_trace_1()
+            __ltrace__ = 1
+            trace_me()
+            del __ltrace__
+            dont_trace_2()
+        """)
+        self.check_op_in("GET_ITER", stdout)
+        self.check_op_in("FOR_ITER", stdout)
+        self.check_op_in("UNARY_POSITIVE", stdout)
+        self.check_op_in("POP_TOP", stdout)
+
+        # before: dont_trace_1() is not traced
+        self.check_op_not_in("BINARY_MULTIPLY", stdout)
+
+        # after: dont_trace_2() is not traced
+        self.check_op_not_in("UNARY_NEGATIVE", stdout)
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst
new file mode 100644
index 0000000000000..3986ad8aa8d95
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-25-04-07-22.gh-issue-91924.-UyO4q.rst	
@@ -0,0 +1,2 @@
+Fix ``__ltrace__`` debug feature if the stdout encoding is not UTF-8. Patch
+by Victor Stinner.
diff --git a/Python/ceval.c b/Python/ceval.c
index 21674e0be1324..9a193c994d12e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -5377,6 +5377,8 @@ prtrace(PyThreadState *tstate, PyObject *v, const char *str)
     }
     printf("\n");
     PyErr_Restore(type, value, traceback);
+    // gh-91924: PyObject_Print() can indirectly set lltrace to 0
+    lltrace = 1;
     return 1;
 }
 #endif



More information about the Python-checkins mailing list