summaryrefslogtreecommitdiff
path: root/Python/traceback.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/traceback.c')
-rw-r--r--Python/traceback.c183
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++;