bpo-42923: Py_FatalError() avoids fprintf() (GH-24242)

* Replace buffered fprintf() with unbuffered _Py_write_noraise()
  in Py_FatalError().
* _Py_DumpHexadecimal() now accepts uintptr_t.
This commit is contained in:
Victor Stinner 2021-01-18 18:34:56 +01:00 committed by GitHub
parent e232025025
commit 314b8787e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 50 deletions

View file

@ -38,6 +38,9 @@
#endif
#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
_Py_IDENTIFIER(flush);
_Py_IDENTIFIER(name);
_Py_IDENTIFIER(stdin);
@ -2348,8 +2351,7 @@ static void
_Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,
PyThreadState *tstate)
{
fputc('\n', stderr);
fflush(stderr);
PUTS(fd, "\n");
/* display the current Python stack */
_Py_DumpTracebackThreads(fd, interp, tstate);
@ -2451,30 +2453,31 @@ fatal_output_debug(const char *msg)
static void
fatal_error_dump_runtime(FILE *stream, _PyRuntimeState *runtime)
fatal_error_dump_runtime(int fd, _PyRuntimeState *runtime)
{
fprintf(stream, "Python runtime state: ");
PUTS(fd, "Python runtime state: ");
PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime);
if (finalizing) {
fprintf(stream, "finalizing (tstate=%p)", finalizing);
PUTS(fd, "finalizing (tstate=0x");
_Py_DumpHexadecimal(fd, (uintptr_t)finalizing, sizeof(finalizing) * 2);
PUTS(fd, ")");
}
else if (runtime->initialized) {
fprintf(stream, "initialized");
PUTS(fd, "initialized");
}
else if (runtime->core_initialized) {
fprintf(stream, "core initialized");
PUTS(fd, "core initialized");
}
else if (runtime->preinitialized) {
fprintf(stream, "preinitialized");
PUTS(fd, "preinitialized");
}
else if (runtime->preinitializing) {
fprintf(stream, "preinitializing");
PUTS(fd, "preinitializing");
}
else {
fprintf(stream, "unknown");
PUTS(fd, "unknown");
}
fprintf(stream, "\n");
fflush(stream);
PUTS(fd, "\n");
}
@ -2494,10 +2497,9 @@ fatal_error_exit(int status)
static void _Py_NO_RETURN
fatal_error(FILE *stream, int header, const char *prefix, const char *msg,
fatal_error(int fd, int header, const char *prefix, const char *msg,
int status)
{
const int fd = fileno(stream);
static int reentrant = 0;
if (reentrant) {
@ -2508,29 +2510,22 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg,
reentrant = 1;
if (header) {
fprintf(stream, "Fatal Python error: ");
PUTS(fd, "Fatal Python error: ");
if (prefix) {
fputs(prefix, stream);
fputs(": ", stream);
PUTS(fd, prefix);
PUTS(fd, ": ");
}
if (msg) {
fputs(msg, stream);
PUTS(fd, msg);
}
else {
fprintf(stream, "<message not set>");
PUTS(fd, "<message not set>");
}
fputs("\n", stream);
fflush(stream);
PUTS(fd, "\n");
}
_PyRuntimeState *runtime = &_PyRuntime;
fatal_error_dump_runtime(stream, runtime);
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
PyInterpreterState *interp = NULL;
if (tstate != NULL) {
interp = tstate->interp;
}
fatal_error_dump_runtime(fd, runtime);
/* Check if the current thread has a Python thread state
and holds the GIL.
@ -2540,8 +2535,17 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg,
tss_tstate != tstate if the current Python thread does not hold the GIL.
*/
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
PyInterpreterState *interp = NULL;
PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
if (tstate != NULL) {
interp = tstate->interp;
}
else if (tss_tstate != NULL) {
interp = tss_tstate->interp;
}
int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate);
if (has_tstate_and_gil) {
/* If an exception is set, print the exception with its traceback */
if (!_Py_FatalError_PrintExc(tss_tstate)) {
@ -2578,14 +2582,14 @@ fatal_error(FILE *stream, int header, const char *prefix, const char *msg,
void _Py_NO_RETURN
Py_FatalError(const char *msg)
{
fatal_error(stderr, 1, NULL, msg, -1);
fatal_error(fileno(stderr), 1, NULL, msg, -1);
}
void _Py_NO_RETURN
_Py_FatalErrorFunc(const char *func, const char *msg)
{
fatal_error(stderr, 1, func, msg, -1);
fatal_error(fileno(stderr), 1, func, msg, -1);
}
@ -2600,12 +2604,12 @@ _Py_FatalErrorFormat(const char *func, const char *format, ...)
reentrant = 1;
FILE *stream = stderr;
fprintf(stream, "Fatal Python error: ");
const int fd = fileno(stream);
PUTS(fd, "Fatal Python error: ");
if (func) {
fputs(func, stream);
fputs(": ", stream);
PUTS(fd, func);
PUTS(fd, ": ");
}
fflush(stream);
va_list vargs;
#ifdef HAVE_STDARG_PROTOTYPES
@ -2619,7 +2623,7 @@ _Py_FatalErrorFormat(const char *func, const char *format, ...)
fputs("\n", stream);
fflush(stream);
fatal_error(stream, 0, NULL, NULL, -1);
fatal_error(fd, 0, NULL, NULL, -1);
}
@ -2630,7 +2634,7 @@ Py_ExitStatusException(PyStatus status)
exit(status.exitcode);
}
else if (_PyStatus_IS_ERROR(status)) {
fatal_error(stderr, 1, status.func, status.err_msg, 1);
fatal_error(fileno(stderr), 1, status.func, status.err_msg, 1);
}
else {
Py_FatalError("Py_ExitStatusException() must not be called on success");