Skip to content

Commit 328d925

Browse files
authored
gh-107758: Improvements to lltrace feature (#107757)
- 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.
1 parent 2df58dc commit 328d925

File tree

4 files changed

+31
-8
lines changed

4 files changed

+31
-8
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

Python/ceval.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,24 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
109109
if (ptr != stack_base) {
110110
printf(", ");
111111
}
112-
if (PyObject_Print(*ptr, stdout, 0) != 0) {
112+
if (*ptr == NULL) {
113+
printf("<nil>");
114+
continue;
115+
}
116+
if (
117+
*ptr == Py_None
118+
|| PyBool_Check(*ptr)
119+
|| PyLong_CheckExact(*ptr)
120+
|| PyFloat_CheckExact(*ptr)
121+
|| PyUnicode_CheckExact(*ptr)
122+
) {
123+
if (PyObject_Print(*ptr, stdout, 0) == 0) {
124+
continue;
125+
}
113126
PyErr_Clear();
114-
printf("<%s object at %p>",
115-
Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
116127
}
128+
// Don't call __repr__(), it might recurse into the interpreter.
129+
printf("<%s at %p>", Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
117130
}
118131
printf("]\n");
119132
fflush(stdout);
@@ -128,9 +141,6 @@ lltrace_instruction(_PyInterpreterFrame *frame,
128141
if (frame->owner == FRAME_OWNED_BY_CSTACK) {
129142
return;
130143
}
131-
/* This dump_stack() operation is risky, since the repr() of some
132-
objects enters the interpreter recursively. It is also slow.
133-
So you might want to comment it out. */
134144
dump_stack(frame, stack_pointer);
135145
int oparg = next_instr->op.arg;
136146
int opcode = next_instr->op.code;
@@ -729,6 +739,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
729739
goto exit_unwind;
730740
}
731741
lltrace = r;
742+
if (!lltrace) {
743+
// When tracing executed uops, also trace bytecode
744+
char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG");
745+
if (uop_debug != NULL && *uop_debug >= '0') {
746+
lltrace = (*uop_debug - '0') >= 4; // TODO: Parse an int and all that
747+
}
748+
}
732749
}
733750
if (lltrace) {
734751
lltrace_resume_frame(frame);
@@ -896,6 +913,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
896913
goto exception_unwind;
897914
}
898915
/* Resume normal execution */
916+
#ifdef LLTRACE
917+
if (lltrace) {
918+
lltrace_resume_frame(frame);
919+
}
920+
#endif
899921
DISPATCH();
900922
}
901923
}

Python/executor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
4141
lltrace = *uop_debug - '0'; // TODO: Parse an int and all that
4242
}
4343
#define DPRINTF(level, ...) \
44-
if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); }
44+
if (lltrace >= (level)) { printf(__VA_ARGS__); }
4545
#else
4646
#define DPRINTF(level, ...)
4747
#endif

Python/optimizer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ translate_bytecode_to_trace(
391391

392392
#ifdef Py_DEBUG
393393
#define DPRINTF(level, ...) \
394-
if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); }
394+
if (lltrace >= (level)) { printf(__VA_ARGS__); }
395395
#else
396396
#define DPRINTF(level, ...)
397397
#endif

0 commit comments

Comments
 (0)