Kaydet (Commit) 89e7cdcb authored tarafından Victor Stinner's avatar Victor Stinner

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
üst b3800107
...@@ -67,6 +67,24 @@ PyAPI_DATA(const char*) _Py_DumpTracebackThreads( ...@@ -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) ...@@ -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;
size_t i, j;
if (len == 0)
return;
for (i=0, j=len-1; i < j; i++, j--) {
tmp = text[i];
text[i] = text[j];
text[j] = tmp;
}
}
/* Format an integer in range [0; 999999] to decimal,
and write it into the file fd.
This function is signal safe. */
static void
dump_decimal(int fd, int value)
{ {
char buffer[7]; /* maximum number of characters required for output of %lld or %p.
int len; We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
if (value < 0 || 999999 < value) 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];
len = 0; char *ptr, *end;
end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
ptr = end;
*ptr = '\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) ...@@ -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, buffer, len);
}
/* Write an unicode object into the file fd using ascii+backslashreplace.
This function is signal safe. */ _Py_write_noraise(fd, ptr, end - ptr);
}
static void void
dump_ascii(int fd, PyObject *text) _Py_DumpASCII(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) ...@@ -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) ...@@ -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,8 +593,9 @@ dump_ascii(int fd, PyObject *text) ...@@ -600,8 +593,9 @@ 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) ...@@ -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) ...@@ -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) ...@@ -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");
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment