From 8d5a3aad2f805dc0ea40829b751f58aa6c75305d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Oct 2017 09:50:12 -0700 Subject: [PATCH] bpo-31683: Py_FatalError() now supports long error messages (#3878) On Windows, Py_FatalError() now limits the size to 256 bytes of the buffer used to call OutputDebugStringW(). Previously, the size depended on the length of the error message. --- Python/pylifecycle.c | 62 ++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7adbc29406e..4b0383b4292 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1825,16 +1825,46 @@ _Py_FatalError_PrintExc(int fd) /* Print fatal error message and abort */ +#ifdef MS_WINDOWS +static void +fatal_output_debug(const char *msg) +{ + /* buffer of 256 bytes allocated on the stack */ + WCHAR buffer[256 / sizeof(WCHAR)]; + size_t buflen = Py_ARRAY_LENGTH(buffer) - 1; + size_t msglen; + + OutputDebugStringW(L"Fatal Python error: "); + + msglen = strlen(msg); + while (msglen) { + size_t i; + + if (buflen > msglen) { + buflen = msglen; + } + + /* Convert the message to wchar_t. This uses a simple one-to-one + conversion, assuming that the this error message actually uses + ASCII only. If this ceases to be true, we will have to convert. */ + for (i=0; i < buflen; ++i) { + buffer[i] = msg[i]; + } + buffer[i] = L'\0'; + OutputDebugStringW(buffer); + + msg += buflen; + msglen -= buflen; + } + OutputDebugStringW(L"\n"); +} +#endif + void Py_FatalError(const char *msg) { const int fd = fileno(stderr); static int reentrant = 0; -#ifdef MS_WINDOWS - size_t len; - WCHAR* buffer; - size_t i; -#endif if (reentrant) { /* Py_FatalError() caused a second fatal error. @@ -1848,12 +1878,14 @@ Py_FatalError(const char *msg) /* Print the exception (if an exception is set) with its traceback, * or display the current Python stack. */ - if (!_Py_FatalError_PrintExc(fd)) + if (!_Py_FatalError_PrintExc(fd)) { _Py_FatalError_DumpTracebacks(fd); + } - /* The main purpose of faulthandler is to display the traceback. We already - * did our best to display it. So faulthandler can now be disabled. - * (Don't trigger it on abort().) */ + /* The main purpose of faulthandler is to display the traceback. + This function already did its best to display a traceback. + Disable faulthandler to prevent writing a second traceback + on abort(). */ _PyFaulthandler_Fini(); /* Check if the current Python thread hold the GIL */ @@ -1863,17 +1895,7 @@ Py_FatalError(const char *msg) } #ifdef MS_WINDOWS - len = strlen(msg); - - /* Convert the message to wchar_t. This uses a simple one-to-one - conversion, assuming that the this error message actually uses ASCII - only. If this ceases to be true, we will have to convert. */ - buffer = alloca( (len+1) * (sizeof *buffer)); - for( i=0; i<=len; ++i) - buffer[i] = msg[i]; - OutputDebugStringW(L"Fatal Python error: "); - OutputDebugStringW(buffer); - OutputDebugStringW(L"\n"); + fatal_output_debug(msg); #endif /* MS_WINDOWS */ exit: