mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Enhance and rewrite traceback dump C functions
Issue #26564: * Expose _Py_DumpASCII() and _Py_DumpDecimal() in traceback.h * Change the type of the second _Py_DumpASCII() parameter from int to unsigned long * Rewrite _Py_DumpDecimal() and dump_hexadecimal() to write directly characters in the expected order, avoid the need of reversing the string. * dump_hexadecimal() limits width to the size of the buffer * _Py_DumpASCII() does nothing if the object is not a Unicode string * dump_frame() wrtites "???" as the line number if the line number is negative
This commit is contained in:
parent
b380010782
commit
89e7cdcb9c
2 changed files with 73 additions and 52 deletions
|
@ -67,6 +67,24 @@ PyAPI_DATA(const char*) _Py_DumpTracebackThreads(
|
||||||
PyThreadState *current_thread);
|
PyThreadState *current_thread);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Py_LIMITED_API
|
||||||
|
|
||||||
|
/* Write a Unicode object into the file descriptor fd. Encode the string to
|
||||||
|
ASCII using the backslashreplace error handler.
|
||||||
|
|
||||||
|
Do nothing if text is not a Unicode object. The function accepts Unicode
|
||||||
|
string which is not ready (PyUnicode_WCHAR_KIND).
|
||||||
|
|
||||||
|
This function is signal safe. */
|
||||||
|
PyAPI_FUNC(void) _Py_DumpASCII(int fd, PyObject *text);
|
||||||
|
|
||||||
|
/* Format an integer as decimal into the file descriptor fd.
|
||||||
|
|
||||||
|
This function is signal safe. */
|
||||||
|
PyAPI_FUNC(void) _Py_DumpDecimal(int fd, unsigned long value);
|
||||||
|
|
||||||
|
#endif /* !Py_LIMITED_API */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -479,40 +479,26 @@ PyTraceBack_Print(PyObject *v, PyObject *f)
|
||||||
|
|
||||||
This function is signal safe. */
|
This function is signal safe. */
|
||||||
|
|
||||||
static void
|
void
|
||||||
reverse_string(char *text, const size_t len)
|
_Py_DumpDecimal(int fd, unsigned long value)
|
||||||
{
|
{
|
||||||
char tmp;
|
/* maximum number of characters required for output of %lld or %p.
|
||||||
size_t i, j;
|
We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
|
||||||
if (len == 0)
|
plus 1 for the null byte. 53/22 is an upper bound for log10(256). */
|
||||||
return;
|
char buffer[1 + (sizeof(unsigned long)*53-1) / 22 + 1];
|
||||||
for (i=0, j=len-1; i < j; i++, j--) {
|
char *ptr, *end;
|
||||||
tmp = text[i];
|
|
||||||
text[i] = text[j];
|
|
||||||
text[j] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Format an integer in range [0; 999999] to decimal,
|
end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
|
||||||
and write it into the file fd.
|
ptr = end;
|
||||||
|
*ptr = '\0';
|
||||||
This function is signal safe. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
dump_decimal(int fd, int value)
|
|
||||||
{
|
|
||||||
char buffer[7];
|
|
||||||
int len;
|
|
||||||
if (value < 0 || 999999 < value)
|
|
||||||
return;
|
|
||||||
len = 0;
|
|
||||||
do {
|
do {
|
||||||
buffer[len] = '0' + (value % 10);
|
--ptr;
|
||||||
|
assert(ptr >= buffer);
|
||||||
|
*ptr = '0' + (value % 10);
|
||||||
value /= 10;
|
value /= 10;
|
||||||
len++;
|
|
||||||
} while (value);
|
} while (value);
|
||||||
reverse_string(buffer, len);
|
|
||||||
_Py_write_noraise(fd, buffer, len);
|
_Py_write_noraise(fd, ptr, end - ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Format an integer in range [0; 0xffffffff] to hexadecimal of 'width' digits,
|
/* Format an integer in range [0; 0xffffffff] to hexadecimal of 'width' digits,
|
||||||
|
@ -521,26 +507,29 @@ dump_decimal(int fd, int value)
|
||||||
This function is signal safe. */
|
This function is signal safe. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_hexadecimal(int fd, unsigned long value, int width)
|
dump_hexadecimal(int fd, unsigned long value, Py_ssize_t width)
|
||||||
{
|
{
|
||||||
int len;
|
Py_ssize_t size = sizeof(unsigned long) * 2;
|
||||||
char buffer[sizeof(unsigned long) * 2 + 1];
|
char buffer[size + 1], *ptr, *end;
|
||||||
len = 0;
|
|
||||||
|
if (width > size)
|
||||||
|
width = size;
|
||||||
|
|
||||||
|
end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
|
||||||
|
ptr = end;
|
||||||
|
*ptr = '\0';
|
||||||
do {
|
do {
|
||||||
buffer[len] = Py_hexdigits[value & 15];
|
--ptr;
|
||||||
|
assert(ptr >= buffer);
|
||||||
|
*ptr = Py_hexdigits[value & 15];
|
||||||
value >>= 4;
|
value >>= 4;
|
||||||
len++;
|
} while ((end - ptr) < width || value);
|
||||||
} while (len < width || value);
|
|
||||||
reverse_string(buffer, len);
|
_Py_write_noraise(fd, ptr, end - ptr);
|
||||||
_Py_write_noraise(fd, buffer, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write an unicode object into the file fd using ascii+backslashreplace.
|
void
|
||||||
|
_Py_DumpASCII(int fd, PyObject *text)
|
||||||
This function is signal safe. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
dump_ascii(int fd, PyObject *text)
|
|
||||||
{
|
{
|
||||||
PyASCIIObject *ascii = (PyASCIIObject *)text;
|
PyASCIIObject *ascii = (PyASCIIObject *)text;
|
||||||
Py_ssize_t i, size;
|
Py_ssize_t i, size;
|
||||||
|
@ -550,6 +539,9 @@ dump_ascii(int fd, PyObject *text)
|
||||||
wchar_t *wstr = NULL;
|
wchar_t *wstr = NULL;
|
||||||
Py_UCS4 ch;
|
Py_UCS4 ch;
|
||||||
|
|
||||||
|
if (!PyUnicode_Check(text))
|
||||||
|
return;
|
||||||
|
|
||||||
size = ascii->length;
|
size = ascii->length;
|
||||||
kind = ascii->state.kind;
|
kind = ascii->state.kind;
|
||||||
if (ascii->state.compact) {
|
if (ascii->state.compact) {
|
||||||
|
@ -574,8 +566,9 @@ dump_ascii(int fd, PyObject *text)
|
||||||
size = MAX_STRING_LENGTH;
|
size = MAX_STRING_LENGTH;
|
||||||
truncated = 1;
|
truncated = 1;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
truncated = 0;
|
truncated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (i=0; i < size; i++) {
|
for (i=0; i < size; i++) {
|
||||||
if (kind != PyUnicode_WCHAR_KIND)
|
if (kind != PyUnicode_WCHAR_KIND)
|
||||||
|
@ -600,9 +593,10 @@ dump_ascii(int fd, PyObject *text)
|
||||||
dump_hexadecimal(fd, ch, 8);
|
dump_hexadecimal(fd, ch, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (truncated)
|
if (truncated) {
|
||||||
PUTS(fd, "...");
|
PUTS(fd, "...");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
|
/* Write a frame into the file fd: "File "xxx", line xxx in xxx".
|
||||||
|
|
||||||
|
@ -620,7 +614,7 @@ dump_frame(int fd, PyFrameObject *frame)
|
||||||
&& PyUnicode_Check(code->co_filename))
|
&& PyUnicode_Check(code->co_filename))
|
||||||
{
|
{
|
||||||
PUTS(fd, "\"");
|
PUTS(fd, "\"");
|
||||||
dump_ascii(fd, code->co_filename);
|
_Py_DumpASCII(fd, code->co_filename);
|
||||||
PUTS(fd, "\"");
|
PUTS(fd, "\"");
|
||||||
} else {
|
} else {
|
||||||
PUTS(fd, "???");
|
PUTS(fd, "???");
|
||||||
|
@ -629,14 +623,21 @@ dump_frame(int fd, PyFrameObject *frame)
|
||||||
/* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
|
/* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */
|
||||||
lineno = PyCode_Addr2Line(code, frame->f_lasti);
|
lineno = PyCode_Addr2Line(code, frame->f_lasti);
|
||||||
PUTS(fd, ", line ");
|
PUTS(fd, ", line ");
|
||||||
dump_decimal(fd, lineno);
|
if (lineno >= 0) {
|
||||||
|
_Py_DumpDecimal(fd, (unsigned long)lineno);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PUTS(fd, "???");
|
||||||
|
}
|
||||||
PUTS(fd, " in ");
|
PUTS(fd, " in ");
|
||||||
|
|
||||||
if (code != NULL && code->co_name != NULL
|
if (code != NULL && code->co_name != NULL
|
||||||
&& PyUnicode_Check(code->co_name))
|
&& PyUnicode_Check(code->co_name)) {
|
||||||
dump_ascii(fd, code->co_name);
|
_Py_DumpASCII(fd, code->co_name);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
PUTS(fd, "???");
|
PUTS(fd, "???");
|
||||||
|
}
|
||||||
|
|
||||||
PUTS(fd, "\n");
|
PUTS(fd, "\n");
|
||||||
}
|
}
|
||||||
|
@ -692,7 +693,9 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
||||||
PUTS(fd, "Current thread 0x");
|
PUTS(fd, "Current thread 0x");
|
||||||
else
|
else
|
||||||
PUTS(fd, "Thread 0x");
|
PUTS(fd, "Thread 0x");
|
||||||
dump_hexadecimal(fd, (unsigned long)tstate->thread_id, sizeof(unsigned long)*2);
|
dump_hexadecimal(fd,
|
||||||
|
(unsigned long)tstate->thread_id,
|
||||||
|
sizeof(unsigned long) * 2);
|
||||||
PUTS(fd, " (most recent call first):\n");
|
PUTS(fd, " (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue