From 33ece1b595a18af452aad723d416f66e3eed3e55 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 17 Nov 2021 21:12:20 +0100 Subject: [PATCH] bpo-45831: _Py_DumpASCII() uses a single write() call if possible (GH-29596) If the string is ASCII only and doesn't need to escape characters, write the whole string with a single write() syscall. (cherry picked from commit b919d8105c4d77f00509b6d3ab2073f09db640de) Co-authored-by: Victor Stinner --- .../2021-11-17-19-25-37.bpo-45831.9-TojK.rst | 5 +++++ Python/traceback.c | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2021-11-17-19-25-37.bpo-45831.9-TojK.rst diff --git a/Misc/NEWS.d/next/Library/2021-11-17-19-25-37.bpo-45831.9-TojK.rst b/Misc/NEWS.d/next/Library/2021-11-17-19-25-37.bpo-45831.9-TojK.rst new file mode 100644 index 00000000000000..049449ff0a4a11 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-11-17-19-25-37.bpo-45831.9-TojK.rst @@ -0,0 +1,5 @@ +:mod:`faulthandler` can now write ASCII-only strings (like filenames and +function names) with a single write() syscall when dumping a traceback. It +reduces the risk of getting an unreadable dump when two threads or two +processes dump a traceback to the same file (like stderr) at the same time. +Patch by Victor Stinner. diff --git a/Python/traceback.c b/Python/traceback.c index 83f3074f43d050..23d0e38e7377cf 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -719,6 +719,26 @@ _Py_DumpASCII(int fd, PyObject *text) truncated = 0; } + // Is an ASCII string? + if (ascii->state.ascii) { + assert(kind == PyUnicode_1BYTE_KIND); + char *str = data; + + int need_escape = 0; + for (i=0; i < size; i++) { + ch = str[i]; + if (!(' ' <= ch && ch <= 126)) { + need_escape = 1; + break; + } + } + if (!need_escape) { + // The string can be written with a single write() syscall + _Py_write_noraise(fd, str, size); + goto done; + } + } + for (i=0; i < size; i++) { if (kind != PyUnicode_WCHAR_KIND) ch = PyUnicode_READ(kind, data, i); @@ -742,6 +762,8 @@ _Py_DumpASCII(int fd, PyObject *text) _Py_DumpHexadecimal(fd, ch, 8); } } + +done: if (truncated) { PUTS(fd, "..."); }