From d3c216b4c8eb33b04cff0f81e2233fb2d662df64 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 31 Mar 2011 01:31:06 +0200 Subject: Issue #11393: Add the new faulthandler module --- Python/traceback.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 59bb3f0d15..37673d93e0 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -13,6 +13,11 @@ #define OFF(x) offsetof(PyTracebackObject, x) +#define PUTS(fd, str) write(fd, str, strlen(str)) +#define MAX_STRING_LENGTH 100 +#define MAX_FRAME_DEPTH 100 +#define MAX_NTHREADS 100 + /* Method from Parser/tokenizer.c */ extern char * PyTokenizer_FindEncoding(int); @@ -402,3 +407,233 @@ PyTraceBack_Print(PyObject *v, PyObject *f) err = tb_printinternal((PyTracebackObject *)v, f, limit); return err; } + +/* Reverse a string. For example, "abcd" becomes "dcba". + + 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) +{ + char buffer[7]; + int len; + if (value < 0 || 999999 < value) + return; + len = 0; + do { + buffer[len] = '0' + (value % 10); + value /= 10; + len++; + } while (value); + reverse_string(buffer, len); + write(fd, buffer, len); +} + +/* Format an integer in range [0; 0xffffffff] to hexdecimal of 'width' digits, + and write it into the file fd. + + This function is signal safe. */ + +static void +dump_hexadecimal(int width, unsigned long value, int fd) +{ + const char *hexdigits = "0123456789abcdef"; + int len; + char buffer[sizeof(unsigned long) * 2 + 1]; + len = 0; + do { + buffer[len] = hexdigits[value & 15]; + value >>= 4; + len++; + } while (len < width || value); + reverse_string(buffer, len); + write(fd, buffer, len); +} + +/* Write an unicode object into the file fd using ascii+backslashreplace. + + This function is signal safe. */ + +static void +dump_ascii(int fd, PyObject *text) +{ + Py_ssize_t i, size; + int truncated; + Py_UNICODE *u; + char c; + + size = PyUnicode_GET_SIZE(text); + u = PyUnicode_AS_UNICODE(text); + + if (MAX_STRING_LENGTH < size) { + size = MAX_STRING_LENGTH; + truncated = 1; + } + else + truncated = 0; + + for (i=0; i < size; i++, u++) { + if (*u < 128) { + c = (char)*u; + write(fd, &c, 1); + } + else if (*u < 256) { + PUTS(fd, "\\x"); + dump_hexadecimal(2, *u, fd); + } + else +#ifdef Py_UNICODE_WIDE + if (*u < 65536) +#endif + { + PUTS(fd, "\\u"); + dump_hexadecimal(4, *u, fd); +#ifdef Py_UNICODE_WIDE + } + else { + PUTS(fd, "\\U"); + dump_hexadecimal(8, *u, fd); +#endif + } + } + if (truncated) + PUTS(fd, "..."); +} + +/* Write a frame into the file fd: "File "xxx", line xxx in xxx". + + This function is signal safe. */ + +static void +dump_frame(int fd, PyFrameObject *frame) +{ + PyCodeObject *code; + int lineno; + + code = frame->f_code; + PUTS(fd, " File "); + if (code != NULL && code->co_filename != NULL + && PyUnicode_Check(code->co_filename)) + { + write(fd, "\"", 1); + dump_ascii(fd, code->co_filename); + write(fd, "\"", 1); + } else { + PUTS(fd, "???"); + } + + /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */ + lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti); + PUTS(fd, ", line "); + dump_decimal(fd, lineno); + PUTS(fd, " in "); + + if (code != NULL && code->co_name != NULL + && PyUnicode_Check(code->co_name)) + dump_ascii(fd, code->co_name); + else + PUTS(fd, "???"); + + write(fd, "\n", 1); +} + +static int +dump_traceback(int fd, PyThreadState *tstate, int write_header) +{ + PyFrameObject *frame; + unsigned int depth; + + frame = _PyThreadState_GetFrame(tstate); + if (frame == NULL) + return -1; + + if (write_header) + PUTS(fd, "Traceback (most recent call first):\n"); + depth = 0; + while (frame != NULL) { + if (MAX_FRAME_DEPTH <= depth) { + PUTS(fd, " ...\n"); + break; + } + if (!PyFrame_Check(frame)) + break; + dump_frame(fd, frame); + frame = frame->f_back; + depth++; + } + return 0; +} + +int +_Py_DumpTraceback(int fd, PyThreadState *tstate) +{ + return dump_traceback(fd, tstate, 1); +} + +/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if + is_current is true, "Thread 0xHHHH:\n" otherwise. + + This function is signal safe. */ + +static void +write_thread_id(int fd, PyThreadState *tstate, int is_current) +{ + if (is_current) + PUTS(fd, "Current thread 0x"); + else + PUTS(fd, "Thread 0x"); + dump_hexadecimal(sizeof(long)*2, (unsigned long)tstate->thread_id, fd); + PUTS(fd, ":\n"); +} + +const char* +_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, + PyThreadState *current_thread) +{ + PyThreadState *tstate; + unsigned int nthreads; + + /* Get the current interpreter from the current thread */ + tstate = PyInterpreterState_ThreadHead(interp); + if (tstate == NULL) + return "unable to get the thread head state"; + + /* Dump the traceback of each thread */ + tstate = PyInterpreterState_ThreadHead(interp); + nthreads = 0; + do + { + if (nthreads != 0) + write(fd, "\n", 1); + if (nthreads >= MAX_NTHREADS) { + PUTS(fd, "...\n"); + break; + } + write_thread_id(fd, tstate, tstate == current_thread); + dump_traceback(fd, tstate, 0); + tstate = PyThreadState_Next(tstate); + nthreads++; + } while (tstate != NULL); + + return NULL; +} + -- cgit v1.2.1 From 28169f0c91398cc93c3c5d114f055ab1e3ecbd59 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Apr 2011 15:34:01 +0200 Subject: Issue #11393: _Py_DumpTraceback() writes the header even if there is no frame --- Python/traceback.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 37673d93e0..f0142da792 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -556,18 +556,19 @@ dump_frame(int fd, PyFrameObject *frame) write(fd, "\n", 1); } -static int +static void dump_traceback(int fd, PyThreadState *tstate, int write_header) { PyFrameObject *frame; unsigned int depth; + if (write_header) + PUTS(fd, "Traceback (most recent call first):\n"); + frame = _PyThreadState_GetFrame(tstate); if (frame == NULL) - return -1; + return; - if (write_header) - PUTS(fd, "Traceback (most recent call first):\n"); depth = 0; while (frame != NULL) { if (MAX_FRAME_DEPTH <= depth) { @@ -580,13 +581,12 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header) frame = frame->f_back; depth++; } - return 0; } -int +void _Py_DumpTraceback(int fd, PyThreadState *tstate) { - return dump_traceback(fd, tstate, 1); + dump_traceback(fd, tstate, 1); } /* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if -- cgit v1.2.1 From f41c2fdbb05ad29ad7c2a6a65dfac2e9d919f022 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 5 Apr 2011 01:48:03 +0200 Subject: Issue #9319: Include the filename in "Non-UTF8 code ..." syntax error. --- Python/traceback.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index f0142da792..e74a1474df 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -18,8 +18,8 @@ #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 -/* Method from Parser/tokenizer.c */ -extern char * PyTokenizer_FindEncoding(int); +/* Function from Parser/tokenizer.c */ +extern char * PyTokenizer_FindEncodingFilename(int, PyObject *); static PyObject * tb_dir(PyTracebackObject *self) @@ -251,7 +251,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) /* use the right encoding to decode the file as unicode */ fd = PyObject_AsFileDescriptor(binary); - found_encoding = PyTokenizer_FindEncoding(fd); + found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; lseek(fd, 0, 0); /* Reset position */ fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding); -- cgit v1.2.1 From d1d013c01c268d869597b35cbcd8b5d7c5baf2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Wed, 28 Sep 2011 07:41:54 +0200 Subject: Implement PEP 393. --- Python/traceback.c | 61 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index e74a1474df..9a11bf2df7 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -229,8 +229,8 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) PyObject *lineobj = NULL; PyObject *res; char buf[MAXPATHLEN+1]; - Py_UNICODE *u, *p; - Py_ssize_t len; + int kind; + void *data; /* open the file */ if (filename == NULL) @@ -285,13 +285,16 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) } /* remove the indentation of the line */ - u = PyUnicode_AS_UNICODE(lineobj); - len = PyUnicode_GET_SIZE(lineobj); - for (p=u; *p == ' ' || *p == '\t' || *p == '\014'; p++) - len--; - if (u != p) { + kind = PyUnicode_KIND(lineobj); + data = PyUnicode_DATA(lineobj); + for (i=0; i < PyUnicode_GET_LENGTH(lineobj); i++) { + Py_UCS4 ch = PyUnicode_READ(kind, data, i); + if (ch != ' ' && ch != '\t' && ch != '\014') + break; + } + if (i) { PyObject *truncated; - truncated = PyUnicode_FromUnicode(p, len); + truncated = PyUnicode_Substring(lineobj, i, PyUnicode_GET_LENGTH(lineobj)); if (truncated) { Py_DECREF(lineobj); lineobj = truncated; @@ -476,13 +479,26 @@ dump_hexadecimal(int width, unsigned long value, int fd) static void dump_ascii(int fd, PyObject *text) { + PyASCIIObject *ascii = (PyASCIIObject *)text; Py_ssize_t i, size; int truncated; - Py_UNICODE *u; - char c; - - size = PyUnicode_GET_SIZE(text); - u = PyUnicode_AS_UNICODE(text); + int kind; + void *data; + Py_UCS4 ch; + + size = ascii->length; + kind = ascii->state.kind; + if (ascii->state.compact) { + if (ascii->state.ascii) + data = ((PyASCIIObject*)text) + 1; + else + data = ((PyCompactUnicodeObject*)text) + 1; + } + else { + data = ((PyUnicodeObject *)text)->data.any; + if (data == NULL) + return; + } if (MAX_STRING_LENGTH < size) { size = MAX_STRING_LENGTH; @@ -491,27 +507,28 @@ dump_ascii(int fd, PyObject *text) else truncated = 0; - for (i=0; i < size; i++, u++) { - if (*u < 128) { - c = (char)*u; + for (i=0; i < size; i++) { + ch = PyUnicode_READ(kind, data, i); + if (ch < 128) { + char c = (char)ch; write(fd, &c, 1); } - else if (*u < 256) { + else if (ch < 256) { PUTS(fd, "\\x"); - dump_hexadecimal(2, *u, fd); + dump_hexadecimal(2, ch, fd); } else #ifdef Py_UNICODE_WIDE - if (*u < 65536) + if (ch < 65536) #endif { PUTS(fd, "\\u"); - dump_hexadecimal(4, *u, fd); + dump_hexadecimal(4, ch, fd); #ifdef Py_UNICODE_WIDE } else { PUTS(fd, "\\U"); - dump_hexadecimal(8, *u, fd); + dump_hexadecimal(8, ch, fd); #endif } } @@ -542,7 +559,7 @@ dump_frame(int fd, PyFrameObject *frame) } /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */ - lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti); + lineno = PyCode_Addr2Line(code, frame->f_lasti); PUTS(fd, ", line "); dump_decimal(fd, lineno); PUTS(fd, " in "); -- cgit v1.2.1 From dc2d990c5a49d8a3c852444d37e59a1408ac326c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 5 Oct 2011 22:44:12 +0200 Subject: traceback: fix dump_ascii() for string with kind=PyUnicode_WCHAR_KIND --- Python/traceback.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 9a11bf2df7..b66c96cda6 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -483,7 +483,8 @@ dump_ascii(int fd, PyObject *text) Py_ssize_t i, size; int truncated; int kind; - void *data; + void *data = NULL; + wchar_t *wstr = NULL; Py_UCS4 ch; size = ascii->length; @@ -494,11 +495,17 @@ dump_ascii(int fd, PyObject *text) 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; @@ -508,7 +515,10 @@ dump_ascii(int fd, PyObject *text) truncated = 0; for (i=0; i < size; i++) { - ch = PyUnicode_READ(kind, data, i); + if (kind != PyUnicode_WCHAR_KIND) + ch = PyUnicode_READ(kind, data, i); + else + ch = wstr[i]; if (ch < 128) { char c = (char)ch; write(fd, &c, 1); -- cgit v1.2.1 From dcacb24f386ae1b107462181af42b6826ec15fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Sun, 9 Oct 2011 10:38:36 +0200 Subject: =?UTF-8?q?Add=20API=20for=20static=20strings,=20primarily=20good?= =?UTF-8?q?=20for=20identifiers.=20Thanks=20to=20Konrad=20Sch=C3=B6bel=20a?= =?UTF-8?q?nd=20Jasper=20Schulz=20for=20helping=20with=20the=20mass-editin?= =?UTF-8?q?g.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Python/traceback.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index b66c96cda6..551f9d6228 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -152,6 +152,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * const char* filepath; Py_ssize_t len; PyObject* result; + _Py_identifier(open); filebytes = PyUnicode_EncodeFSDefault(filename); if (filebytes == NULL) { @@ -199,7 +200,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * namebuf[len++] = SEP; strcpy(namebuf+len, tail); - binary = PyObject_CallMethod(io, "open", "ss", namebuf, "rb"); + binary = _PyObject_CallMethodId(io, &PyId_open, "ss", namebuf, "rb"); if (binary != NULL) { result = binary; goto finally; @@ -231,6 +232,9 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) char buf[MAXPATHLEN+1]; int kind; void *data; + _Py_identifier(close); + _Py_identifier(open); + _Py_identifier(TextIOWrapper); /* open the file */ if (filename == NULL) @@ -239,7 +243,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) io = PyImport_ImportModuleNoBlock("io"); if (io == NULL) return -1; - binary = PyObject_CallMethod(io, "open", "Os", filename, "rb"); + binary = _PyObject_CallMethodId(io, &PyId_open, "Os", filename, "rb"); if (binary == NULL) { binary = _Py_FindSourceFile(filename, buf, sizeof(buf), io); @@ -254,7 +258,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) found_encoding = PyTokenizer_FindEncodingFilename(fd, filename); encoding = (found_encoding != NULL) ? found_encoding : "utf-8"; lseek(fd, 0, 0); /* Reset position */ - fob = PyObject_CallMethod(io, "TextIOWrapper", "Os", binary, encoding); + fob = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "Os", binary, encoding); Py_DECREF(io); Py_DECREF(binary); PyMem_FREE(found_encoding); @@ -273,7 +277,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) break; } } - res = PyObject_CallMethod(fob, "close", ""); + res = _PyObject_CallMethodId(fob, &PyId_close, ""); if (res) Py_DECREF(res); else -- cgit v1.2.1 From da328a42858356139f9e6de860b802408ed76f5d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 14 Oct 2011 02:13:11 +0200 Subject: Issue #13088: Add shared Py_hexdigits constant to format a number into base 16 --- Python/traceback.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 551f9d6228..44358ed78d 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -463,12 +463,11 @@ dump_decimal(int fd, int value) static void dump_hexadecimal(int width, unsigned long value, int fd) { - const char *hexdigits = "0123456789abcdef"; int len; char buffer[sizeof(unsigned long) * 2 + 1]; len = 0; do { - buffer[len] = hexdigits[value & 15]; + buffer[len] = Py_hexdigits[value & 15]; value >>= 4; len++; } while (len < width || value); -- cgit v1.2.1 From f5ad3b280b43227eb0e3fa63d89490a58ba9c28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Fri, 14 Oct 2011 10:20:37 +0200 Subject: Rename _Py_identifier to _Py_IDENTIFIER. --- Python/traceback.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 44358ed78d..2f4653bce6 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -152,7 +152,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * const char* filepath; Py_ssize_t len; PyObject* result; - _Py_identifier(open); + _Py_IDENTIFIER(open); filebytes = PyUnicode_EncodeFSDefault(filename); if (filebytes == NULL) { @@ -232,9 +232,9 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent) char buf[MAXPATHLEN+1]; int kind; void *data; - _Py_identifier(close); - _Py_identifier(open); - _Py_identifier(TextIOWrapper); + _Py_IDENTIFIER(close); + _Py_IDENTIFIER(open); + _Py_IDENTIFIER(TextIOWrapper); /* open the file */ if (filename == NULL) -- cgit v1.2.1 From 806c2672ae49f639fd7a8a14a9a8ce67a14e94a6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 22 Nov 2011 03:31:20 +0100 Subject: Remove "#ifdef Py_UNICODE_WIDE": Python is now always wide --- Python/traceback.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'Python/traceback.c') diff --git a/Python/traceback.c b/Python/traceback.c index 2f4653bce6..c8b3ee1b63 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -526,23 +526,17 @@ dump_ascii(int fd, PyObject *text) char c = (char)ch; write(fd, &c, 1); } - else if (ch < 256) { + else if (ch < 0xff) { PUTS(fd, "\\x"); dump_hexadecimal(2, ch, fd); } - else -#ifdef Py_UNICODE_WIDE - if (ch < 65536) -#endif - { + else if (ch < 0xffff) { PUTS(fd, "\\u"); dump_hexadecimal(4, ch, fd); -#ifdef Py_UNICODE_WIDE } else { PUTS(fd, "\\U"); dump_hexadecimal(8, ch, fd); -#endif } } if (truncated) -- cgit v1.2.1