summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/traceback.h18
-rw-r--r--Python/traceback.c109
2 files changed, 74 insertions, 53 deletions
diff --git a/Include/traceback.h b/Include/traceback.h
index 891000c..7c630e3 100644
--- a/Include/traceback.h
+++ b/Include/traceback.h
@@ -67,6 +67,24 @@ PyAPI_DATA(const char*) _Py_DumpTracebackThreads(
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
}
#endif
diff --git a/Python/traceback.c b/Python/traceback.c
index 941d1cb..a40dbd1 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -479,40 +479,26 @@ PyTraceBack_Print(PyObject *v, PyObject *f)
This function is signal safe. */
-static void
-reverse_string(char *text, const size_t len)
-{
- 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)
+void
+_Py_DumpDecimal(int fd, unsigned long value)
{
- char buffer[7];
- int len;
- if (value < 0 || 999999 < value)
- return;
- len = 0;
+ /* maximum number of characters required for output of %lld or %p.
+ We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
+ plus 1 for the null byte. 53/22 is an upper bound for log10(256). */
+ char buffer[1 + (sizeof(unsigned long)*53-1) / 22 + 1];
+ char *ptr, *end;
+
+ end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
+ ptr = end;
+ *ptr = '\0';
do {
- buffer[len] = '0' + (value % 10);
+ --ptr;
+ assert(ptr >= buffer);
+ *ptr = '0' + (value % 10);
value /= 10;
- len++;
} 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,
@@ -521,26 +507,29 @@ dump_decimal(int fd, int value)
This function is signal safe. */
static void
-dump_hexadecimal(int fd, unsigned long value, int width)
+dump_hexadecimal(int fd, unsigned long value, Py_ssize_t width)
{
- int len;
- char buffer[sizeof(unsigned long) * 2 + 1];
- len = 0;
+ Py_ssize_t size = sizeof(unsigned long) * 2;
+ char buffer[size + 1], *ptr, *end;
+
+ if (width > size)
+ width = size;
+
+ end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
+ ptr = end;
+ *ptr = '\0';
do {
- buffer[len] = Py_hexdigits[value & 15];
+ --ptr;
+ assert(ptr >= buffer);
+ *ptr = Py_hexdigits[value & 15];
value >>= 4;
- len++;
- } 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.
+ } while ((end - ptr) < width || value);
- This function is signal safe. */
+ _Py_write_noraise(fd, ptr, end - ptr);
+}
-static void
-dump_ascii(int fd, PyObject *text)
+void
+_Py_DumpASCII(int fd, PyObject *text)
{
PyASCIIObject *ascii = (PyASCIIObject *)text;
Py_ssize_t i, size;
@@ -550,6 +539,9 @@ dump_ascii(int fd, PyObject *text)
wchar_t *wstr = NULL;
Py_UCS4 ch;
+ if (!PyUnicode_Check(text))
+ return;
+
size = ascii->length;
kind = ascii->state.kind;
if (ascii->state.compact) {
@@ -574,8 +566,9 @@ dump_ascii(int fd, PyObject *text)
size = MAX_STRING_LENGTH;
truncated = 1;
}
- else
+ else {
truncated = 0;
+ }
for (i=0; i < size; i++) {
if (kind != PyUnicode_WCHAR_KIND)
@@ -600,8 +593,9 @@ dump_ascii(int fd, PyObject *text)
dump_hexadecimal(fd, ch, 8);
}
}
- if (truncated)
+ if (truncated) {
PUTS(fd, "...");
+ }
}
/* 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))
{
PUTS(fd, "\"");
- dump_ascii(fd, code->co_filename);
+ _Py_DumpASCII(fd, code->co_filename);
PUTS(fd, "\"");
} else {
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 */
lineno = PyCode_Addr2Line(code, frame->f_lasti);
PUTS(fd, ", line ");
- dump_decimal(fd, lineno);
+ if (lineno >= 0) {
+ _Py_DumpDecimal(fd, (unsigned long)lineno);
+ }
+ else {
+ PUTS(fd, "???");
+ }
PUTS(fd, " in ");
if (code != NULL && code->co_name != NULL
- && PyUnicode_Check(code->co_name))
- dump_ascii(fd, code->co_name);
- else
+ && PyUnicode_Check(code->co_name)) {
+ _Py_DumpASCII(fd, code->co_name);
+ }
+ else {
PUTS(fd, "???");
+ }
PUTS(fd, "\n");
}
@@ -692,7 +693,9 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
PUTS(fd, "Current thread 0x");
else
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");
}