Issue #23571: Fix reentrant call to Py_FatalError()

Flushing sys.stdout and sys.stderr in Py_FatalError() can call again
Py_FatalError(). Add a reentrant flag to detect this case and just abort at the
second call.
This commit is contained in:
Victor Stinner 2015-03-25 01:54:46 +01:00
parent b0749ca933
commit 84092ac370

View file

@ -2663,6 +2663,19 @@ void
Py_FatalError(const char *msg) Py_FatalError(const char *msg)
{ {
const int fd = fileno(stderr); 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.
Example: flush_std_files() raises a recursion error. */
goto exit;
}
reentrant = 1;
fprintf(stderr, "Fatal Python error: %s\n", msg); fprintf(stderr, "Fatal Python error: %s\n", msg);
fflush(stderr); /* it helps in Windows debug build */ fflush(stderr); /* it helps in Windows debug build */
@ -2680,25 +2693,23 @@ Py_FatalError(const char *msg)
_PyFaulthandler_Fini(); _PyFaulthandler_Fini();
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
{ len = strlen(msg);
size_t len = strlen(msg);
WCHAR* buffer;
size_t i;
/* Convert the message to wchar_t. This uses a simple one-to-one /* Convert the message to wchar_t. This uses a simple one-to-one
conversion, assuming that the this error message actually uses ASCII conversion, assuming that the this error message actually uses ASCII
only. If this ceases to be true, we will have to convert. */ only. If this ceases to be true, we will have to convert. */
buffer = alloca( (len+1) * (sizeof *buffer)); buffer = alloca( (len+1) * (sizeof *buffer));
for( i=0; i<=len; ++i) for( i=0; i<=len; ++i)
buffer[i] = msg[i]; buffer[i] = msg[i];
OutputDebugStringW(L"Fatal Python error: "); OutputDebugStringW(L"Fatal Python error: ");
OutputDebugStringW(buffer); OutputDebugStringW(buffer);
OutputDebugStringW(L"\n"); OutputDebugStringW(L"\n");
} #endif /* MS_WINDOWS */
#ifdef _DEBUG
exit:
#if defined(MS_WINDOWS) && defined(_DEBUG)
DebugBreak(); DebugBreak();
#endif #endif
#endif /* MS_WINDOWS */
abort(); abort();
} }