Skip to content

Commit 8d5a3aa

Browse files
authored
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.
1 parent bf477a9 commit 8d5a3aa

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

Python/pylifecycle.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,16 +1825,46 @@ _Py_FatalError_PrintExc(int fd)
18251825

18261826
/* Print fatal error message and abort */
18271827

1828+
#ifdef MS_WINDOWS
1829+
static void
1830+
fatal_output_debug(const char *msg)
1831+
{
1832+
/* buffer of 256 bytes allocated on the stack */
1833+
WCHAR buffer[256 / sizeof(WCHAR)];
1834+
size_t buflen = Py_ARRAY_LENGTH(buffer) - 1;
1835+
size_t msglen;
1836+
1837+
OutputDebugStringW(L"Fatal Python error: ");
1838+
1839+
msglen = strlen(msg);
1840+
while (msglen) {
1841+
size_t i;
1842+
1843+
if (buflen > msglen) {
1844+
buflen = msglen;
1845+
}
1846+
1847+
/* Convert the message to wchar_t. This uses a simple one-to-one
1848+
conversion, assuming that the this error message actually uses
1849+
ASCII only. If this ceases to be true, we will have to convert. */
1850+
for (i=0; i < buflen; ++i) {
1851+
buffer[i] = msg[i];
1852+
}
1853+
buffer[i] = L'\0';
1854+
OutputDebugStringW(buffer);
1855+
1856+
msg += buflen;
1857+
msglen -= buflen;
1858+
}
1859+
OutputDebugStringW(L"\n");
1860+
}
1861+
#endif
1862+
18281863
void
18291864
Py_FatalError(const char *msg)
18301865
{
18311866
const int fd = fileno(stderr);
18321867
static int reentrant = 0;
1833-
#ifdef MS_WINDOWS
1834-
size_t len;
1835-
WCHAR* buffer;
1836-
size_t i;
1837-
#endif
18381868

18391869
if (reentrant) {
18401870
/* Py_FatalError() caused a second fatal error.
@@ -1848,12 +1878,14 @@ Py_FatalError(const char *msg)
18481878

18491879
/* Print the exception (if an exception is set) with its traceback,
18501880
* or display the current Python stack. */
1851-
if (!_Py_FatalError_PrintExc(fd))
1881+
if (!_Py_FatalError_PrintExc(fd)) {
18521882
_Py_FatalError_DumpTracebacks(fd);
1883+
}
18531884

1854-
/* The main purpose of faulthandler is to display the traceback. We already
1855-
* did our best to display it. So faulthandler can now be disabled.
1856-
* (Don't trigger it on abort().) */
1885+
/* The main purpose of faulthandler is to display the traceback.
1886+
This function already did its best to display a traceback.
1887+
Disable faulthandler to prevent writing a second traceback
1888+
on abort(). */
18571889
_PyFaulthandler_Fini();
18581890

18591891
/* Check if the current Python thread hold the GIL */
@@ -1863,17 +1895,7 @@ Py_FatalError(const char *msg)
18631895
}
18641896

18651897
#ifdef MS_WINDOWS
1866-
len = strlen(msg);
1867-
1868-
/* Convert the message to wchar_t. This uses a simple one-to-one
1869-
conversion, assuming that the this error message actually uses ASCII
1870-
only. If this ceases to be true, we will have to convert. */
1871-
buffer = alloca( (len+1) * (sizeof *buffer));
1872-
for( i=0; i<=len; ++i)
1873-
buffer[i] = msg[i];
1874-
OutputDebugStringW(L"Fatal Python error: ");
1875-
OutputDebugStringW(buffer);
1876-
OutputDebugStringW(L"\n");
1898+
fatal_output_debug(msg);
18771899
#endif /* MS_WINDOWS */
18781900

18791901
exit:

0 commit comments

Comments
 (0)