[Python-checkins] cpython: Enhance and rewrite traceback dump C functions

victor.stinner python-checkins at python.org
Tue Mar 15 16:58:07 EDT 2016


https://hg.python.org/cpython/rev/18a19e62bac5
changeset:   100548:18a19e62bac5
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Tue Mar 15 21:49:37 2016 +0100
summary:
  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

files:
  Include/traceback.h |   18 +++++
  Python/traceback.c  |  111 ++++++++++++++++---------------
  2 files changed, 75 insertions(+), 54 deletions(-)


diff --git a/Include/traceback.h b/Include/traceback.h
--- a/Include/traceback.h
+++ b/Include/traceback.h
@@ -67,6 +67,24 @@
     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
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -479,40 +479,26 @@
 
    This function is signal safe. */
 
-static void
-reverse_string(char *text, const size_t len)
+void
+_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;
-    }
-}
+    /* 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;
 
-/* Format an integer in range [0; 999999] to decimal,
-   and write it into the file fd.
+    end = &buffer[Py_ARRAY_LENGTH(buffer) - 1];
+    ptr = end;
+    *ptr = '\0';
+    do {
+        --ptr;
+        assert(ptr >= buffer);
+        *ptr = '0' + (value % 10);
+        value /= 10;
+    } while (value);
 
-   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);
-    _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 @@
    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);
+    } while ((end - ptr) < width || value);
+
+    _Py_write_noraise(fd, ptr, end - ptr);
 }
 
-/* Write an unicode object into the file fd using ascii+backslashreplace.
-
-   This function is signal safe. */
-
-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 @@
     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 @@
         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_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 @@
         && 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 @@
     /* 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 @@
         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");
 }
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list