mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
2df58dcd50
commit
328d925244
|
@ -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.
|
|
@ -109,11 +109,24 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
|
|||
if (ptr != stack_base) {
|
||||
printf(", ");
|
||||
}
|
||||
if (PyObject_Print(*ptr, stdout, 0) != 0) {
|
||||
PyErr_Clear();
|
||||
printf("<%s object at %p>",
|
||||
Py_TYPE(*ptr)->tp_name, (void *)(*ptr));
|
||||
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();
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue