]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-107758: Improvements to lltrace feature (#107757)
authorGuido van Rossum <guido@python.org>
Tue, 8 Aug 2023 04:36:25 +0000 (21:36 -0700)
committerGitHub <noreply@github.com>
Tue, 8 Aug 2023 04:36:25 +0000 (21:36 -0700)
- The `dump_stack()` method could call a `__repr__` method implemented in Python,
  causing (infinite) recursion.
  I rewrote it to only print out the values for some fundamental types (`int`, `str`, etc.);
  for everything else it just prints `<type_name @ 0xdeadbeef>`.

- The lltrace-like feature for uops wrote to `stderr`, while the one in `ceval.c` writes to `stdout`;
  I changed the uops to write to stdout as well.

Misc/NEWS.d/next/Core and Builtins/2023-08-08-02-46-46.gh-issue-107758.R5kyBI.rst [new file with mode: 0644]
Python/ceval.c
Python/executor.c
Python/optimizer.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-08-08-02-46-46.gh-issue-107758.R5kyBI.rst b/Misc/NEWS.d/next/Core and Builtins/2023-08-08-02-46-46.gh-issue-107758.R5kyBI.rst
new file mode 100644 (file)
index 0000000..192f1df
--- /dev/null
@@ -0,0 +1 @@
+Make the ``dump_stack()`` routine used by the ``lltrace`` feature (low-level interpreter debugging) robust against recursion by ensuring that it never calls a ``__repr__`` method implemented in Python. Also make the similar output for Tier-2 uops appear on ``stdout`` (instead of ``stderr``), to match the ``lltrace`` code in ceval.c.
index 30f722e45e476b8880860c7ea0a3d5d7580c4ad1..1dc4fd80224bbdf18dcc60fcdd6720e837e6b73f 100644 (file)
@@ -109,11 +109,24 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
         if (ptr != stack_base) {
             printf(", ");
         }
-        if (PyObject_Print(*ptr, stdout, 0) != 0) {
+        if (*ptr == NULL) {
+            printf("<nil>");
+            continue;
+        }
+        if (
+            *ptr == Py_None
+            || PyBool_Check(*ptr)
+            || PyLong_CheckExact(*ptr)
+            || PyFloat_CheckExact(*ptr)
+            || PyUnicode_CheckExact(*ptr)
+        ) {
+            if (PyObject_Print(*ptr, stdout, 0) == 0) {
+                continue;
+            }
             PyErr_Clear();
-            printf("<%s object at %p>",
-                   Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
         }
+        // Don't call __repr__(), it might recurse into the interpreter.
+        printf("<%s at %p>", Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
     }
     printf("]\n");
     fflush(stdout);
@@ -128,9 +141,6 @@ lltrace_instruction(_PyInterpreterFrame *frame,
     if (frame->owner == FRAME_OWNED_BY_CSTACK) {
         return;
     }
-    /* This dump_stack() operation is risky, since the repr() of some
-       objects enters the interpreter recursively. It is also slow.
-       So you might want to comment it out. */
     dump_stack(frame, stack_pointer);
     int oparg = next_instr->op.arg;
     int opcode = next_instr->op.code;
@@ -729,6 +739,13 @@ resume_frame:
                 goto exit_unwind;
             }
             lltrace = r;
+            if (!lltrace) {
+                // When tracing executed uops, also trace bytecode
+                char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG");
+                if (uop_debug != NULL && *uop_debug >= '0') {
+                    lltrace = (*uop_debug - '0') >= 4;  // TODO: Parse an int and all that
+                }
+            }
         }
         if (lltrace) {
             lltrace_resume_frame(frame);
@@ -896,6 +913,11 @@ exception_unwind:
                 goto exception_unwind;
             }
             /* Resume normal execution */
+#ifdef LLTRACE
+            if (lltrace) {
+                lltrace_resume_frame(frame);
+            }
+#endif
             DISPATCH();
         }
     }
index 57525df202d861a73a4a6c6322928af5129ac916..4a18618c0c6c0c07aeea1da52431ae547994f1f8 100644 (file)
@@ -41,7 +41,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
         lltrace = *uop_debug - '0';  // TODO: Parse an int and all that
     }
     #define DPRINTF(level, ...) \
-        if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); }
+        if (lltrace >= (level)) { printf(__VA_ARGS__); }
 #else
     #define DPRINTF(level, ...)
 #endif
index d2ed8dfcd2cff20a3f73672059b0dda30be2d2db..6c730aa14b9a47ceada35196b808c0a2e4fa0cf7 100644 (file)
@@ -391,7 +391,7 @@ translate_bytecode_to_trace(
 
 #ifdef Py_DEBUG
 #define DPRINTF(level, ...) \
-    if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); }
+    if (lltrace >= (level)) { printf(__VA_ARGS__); }
 #else
 #define DPRINTF(level, ...)
 #endif