diff options
Diffstat (limited to 'Python/traceback.c')
-rw-r--r-- | Python/traceback.c | 183 |
1 files changed, 67 insertions, 116 deletions
diff --git a/Python/traceback.c b/Python/traceback.c index 62a6b1e1a2..941d1cbbbb 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -479,26 +479,40 @@ PyTraceBack_Print(PyObject *v, PyObject *f) This function is signal safe. */ -void -_Py_DumpDecimal(int fd, unsigned long value) +static void +reverse_string(char *text, const size_t len) { - /* 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'; + 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]; + int len; + if (value < 0 || 999999 < value) + return; + len = 0; do { - --ptr; - assert(ptr >= buffer); - *ptr = '0' + (value % 10); + buffer[len] = '0' + (value % 10); value /= 10; + len++; } while (value); - - _Py_write_noraise(fd, ptr, end - ptr); + reverse_string(buffer, len); + _Py_write_noraise(fd, buffer, len); } /* Format an integer in range [0; 0xffffffff] to hexadecimal of 'width' digits, @@ -506,31 +520,27 @@ _Py_DumpDecimal(int fd, unsigned long value) This function is signal safe. */ -void -_Py_DumpHexadecimal(int fd, unsigned long value, Py_ssize_t width) +static void +dump_hexadecimal(int fd, unsigned long value, int width) { - char buffer[sizeof(unsigned long) * 2 + 1], *ptr, *end; - const Py_ssize_t size = Py_ARRAY_LENGTH(buffer) - 1; - - if (width > size) - width = size; - /* it's ok if width is negative */ - - end = &buffer[size]; - ptr = end; - *ptr = '\0'; + int len; + char buffer[sizeof(unsigned long) * 2 + 1]; + len = 0; do { - --ptr; - assert(ptr >= buffer); - *ptr = Py_hexdigits[value & 15]; + buffer[len] = Py_hexdigits[value & 15]; value >>= 4; - } while ((end - ptr) < width || value); - - _Py_write_noraise(fd, ptr, end - ptr); + len++; + } while (len < width || value); + reverse_string(buffer, len); + _Py_write_noraise(fd, buffer, len); } -void -_Py_DumpASCII(int fd, PyObject *text) +/* Write an unicode object into the file fd using ascii+backslashreplace. + + This function is signal safe. */ + +static void +dump_ascii(int fd, PyObject *text) { PyASCIIObject *ascii = (PyASCIIObject *)text; Py_ssize_t i, size; @@ -540,36 +550,32 @@ _Py_DumpASCII(int fd, PyObject *text) wchar_t *wstr = NULL; Py_UCS4 ch; - if (!PyUnicode_Check(text)) - return; - size = ascii->length; kind = ascii->state.kind; - if (kind == PyUnicode_WCHAR_KIND) { - wstr = ((PyASCIIObject *)text)->wstr; - if (wstr == NULL) - return; - size = ((PyCompactUnicodeObject *)text)->wstr_length; - } - else if (ascii->state.compact) { + if (ascii->state.compact) { if (ascii->state.ascii) data = ((PyASCIIObject*)text) + 1; else data = ((PyCompactUnicodeObject*)text) + 1; } - else { + else if (kind != PyUnicode_WCHAR_KIND) { data = ((PyUnicodeObject *)text)->data.any; if (data == NULL) return; } + else { + wstr = ((PyASCIIObject *)text)->wstr; + if (wstr == NULL) + return; + size = ((PyCompactUnicodeObject *)text)->wstr_length; + } if (MAX_STRING_LENGTH < size) { size = MAX_STRING_LENGTH; truncated = 1; } - else { + else truncated = 0; - } for (i=0; i < size; i++) { if (kind != PyUnicode_WCHAR_KIND) @@ -583,20 +589,19 @@ _Py_DumpASCII(int fd, PyObject *text) } else if (ch <= 0xff) { PUTS(fd, "\\x"); - _Py_DumpHexadecimal(fd, ch, 2); + dump_hexadecimal(fd, ch, 2); } else if (ch <= 0xffff) { PUTS(fd, "\\u"); - _Py_DumpHexadecimal(fd, ch, 4); + dump_hexadecimal(fd, ch, 4); } else { PUTS(fd, "\\U"); - _Py_DumpHexadecimal(fd, ch, 8); + dump_hexadecimal(fd, ch, 8); } } - if (truncated) { + if (truncated) PUTS(fd, "..."); - } } /* Write a frame into the file fd: "File "xxx", line xxx in xxx". @@ -615,7 +620,7 @@ dump_frame(int fd, PyFrameObject *frame) && PyUnicode_Check(code->co_filename)) { PUTS(fd, "\""); - _Py_DumpASCII(fd, code->co_filename); + dump_ascii(fd, code->co_filename); PUTS(fd, "\""); } else { PUTS(fd, "???"); @@ -624,21 +629,14 @@ 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 "); - if (lineno >= 0) { - _Py_DumpDecimal(fd, (unsigned long)lineno); - } - else { - PUTS(fd, "???"); - } + dump_decimal(fd, lineno); PUTS(fd, " in "); if (code != NULL && code->co_name != NULL - && PyUnicode_Check(code->co_name)) { - _Py_DumpASCII(fd, code->co_name); - } - else { + && PyUnicode_Check(code->co_name)) + dump_ascii(fd, code->co_name); + else PUTS(fd, "???"); - } PUTS(fd, "\n"); } @@ -694,9 +692,7 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current) PUTS(fd, "Current thread 0x"); else PUTS(fd, "Thread 0x"); - _Py_DumpHexadecimal(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"); } @@ -708,56 +704,11 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current) handlers if signals were received. */ const char* _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, - PyThreadState *current_tstate) + PyThreadState *current_thread) { PyThreadState *tstate; unsigned int nthreads; -#ifdef WITH_THREAD - if (current_tstate == NULL) { - /* _Py_DumpTracebackThreads() is called from signal handlers by - faulthandler. - - SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals - and are thus delivered to the thread that caused the fault. Get the - Python thread state of the current thread. - - PyThreadState_Get() doesn't give the state of the thread that caused - the fault if the thread released the GIL, and so this function - cannot be used. Read the thread local storage (TLS) instead: call - PyGILState_GetThisThreadState(). */ - current_tstate = PyGILState_GetThisThreadState(); - } - - if (interp == NULL) { - if (current_tstate == NULL) { - interp = _PyGILState_GetInterpreterStateUnsafe(); - if (interp == NULL) { - /* We need the interpreter state to get Python threads */ - return "unable to get the interpreter state"; - } - } - else { - interp = current_tstate->interp; - } - } -#else - if (current_tstate == NULL) { - /* Call _PyThreadState_UncheckedGet() instead of PyThreadState_Get() - to not fail with a fatal error if the thread state is NULL. */ - current_thread = _PyThreadState_UncheckedGet(); - } - - if (interp == NULL) { - if (current_tstate == NULL) { - /* We need the interpreter state to get Python threads */ - return "unable to get the interpreter state"; - } - interp = current_tstate->interp; - } -#endif - assert(interp != NULL); - /* Get the current interpreter from the current thread */ tstate = PyInterpreterState_ThreadHead(interp); if (tstate == NULL) @@ -775,7 +726,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, PUTS(fd, "...\n"); break; } - write_thread_id(fd, tstate, tstate == current_tstate); + write_thread_id(fd, tstate, tstate == current_thread); dump_traceback(fd, tstate, 0); tstate = PyThreadState_Next(tstate); nthreads++; |