bpo-38070: Py_FatalError() logs runtime state (GH-16246) · python/cpython@1ce16fb (original) (raw)
`@@ -1975,13 +1975,14 @@ init_sys_streams(PyThreadState *tstate)
`
1975
1975
``
1976
1976
``
1977
1977
`static void
`
1978
``
`-
_Py_FatalError_DumpTracebacks(int fd)
`
``
1978
`+
_Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp,
`
``
1979
`+
PyThreadState *tstate)
`
1979
1980
`{
`
1980
1981
`fputc('\n', stderr);
`
1981
1982
`fflush(stderr);
`
1982
1983
``
1983
1984
`/* display the current Python stack */
`
1984
``
`-
_Py_DumpTracebackThreads(fd, NULL, NULL);
`
``
1985
`+
_Py_DumpTracebackThreads(fd, interp, tstate);
`
1985
1986
`}
`
1986
1987
``
1987
1988
`/* Print the current exception (if an exception is set) with its traceback,
`
`@@ -2079,10 +2080,39 @@ fatal_output_debug(const char *msg)
`
2079
2080
`}
`
2080
2081
`#endif
`
2081
2082
``
``
2083
+
``
2084
`+
static void
`
``
2085
`+
fatal_error_dump_runtime(FILE *stream, _PyRuntimeState *runtime)
`
``
2086
`+
{
`
``
2087
`+
fprintf(stream, "Python runtime state: ");
`
``
2088
`+
if (runtime->finalizing) {
`
``
2089
`+
fprintf(stream, "finalizing (tstate=%p)", runtime->finalizing);
`
``
2090
`+
}
`
``
2091
`+
else if (runtime->initialized) {
`
``
2092
`+
fprintf(stream, "initialized");
`
``
2093
`+
}
`
``
2094
`+
else if (runtime->core_initialized) {
`
``
2095
`+
fprintf(stream, "core initialized");
`
``
2096
`+
}
`
``
2097
`+
else if (runtime->preinitialized) {
`
``
2098
`+
fprintf(stream, "preinitialized");
`
``
2099
`+
}
`
``
2100
`+
else if (runtime->preinitializing) {
`
``
2101
`+
fprintf(stream, "preinitializing");
`
``
2102
`+
}
`
``
2103
`+
else {
`
``
2104
`+
fprintf(stream, "unknown");
`
``
2105
`+
}
`
``
2106
`+
fprintf(stream, "\n");
`
``
2107
`+
fflush(stream);
`
``
2108
`+
}
`
``
2109
+
``
2110
+
2082
2111
`static void _Py_NO_RETURN
`
2083
2112
`fatal_error(const char *prefix, const char *msg, int status)
`
2084
2113
`{
`
2085
``
`-
const int fd = fileno(stderr);
`
``
2114
`+
FILE *stream = stderr;
`
``
2115
`+
const int fd = fileno(stream);
`
2086
2116
`static int reentrant = 0;
`
2087
2117
``
2088
2118
`if (reentrant) {
`
`@@ -2092,45 +2122,48 @@ fatal_error(const char *prefix, const char *msg, int status)
`
2092
2122
` }
`
2093
2123
`reentrant = 1;
`
2094
2124
``
2095
``
`-
fprintf(stderr, "Fatal Python error: ");
`
``
2125
`+
fprintf(stream, "Fatal Python error: ");
`
2096
2126
`if (prefix) {
`
2097
``
`-
fputs(prefix, stderr);
`
2098
``
`-
fputs(": ", stderr);
`
``
2127
`+
fputs(prefix, stream);
`
``
2128
`+
fputs(": ", stream);
`
2099
2129
` }
`
2100
2130
`if (msg) {
`
2101
``
`-
fputs(msg, stderr);
`
``
2131
`+
fputs(msg, stream);
`
2102
2132
` }
`
2103
2133
`else {
`
2104
``
`-
fprintf(stderr, "");
`
``
2134
`+
fprintf(stream, "");
`
2105
2135
` }
`
2106
``
`-
fputs("\n", stderr);
`
2107
``
`-
fflush(stderr); /* it helps in Windows debug build */
`
``
2136
`+
fputs("\n", stream);
`
``
2137
`+
fflush(stream); /* it helps in Windows debug build */
`
2108
2138
``
2109
``
`-
/* Check if the current thread has a Python thread state
`
2110
``
`-
and holds the GIL */
`
2111
``
`-
PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
`
2112
``
`-
if (tss_tstate != NULL) {
`
2113
``
`-
PyThreadState *tstate = _PyThreadState_GET();
`
2114
``
`-
if (tss_tstate != tstate) {
`
2115
``
`-
/* The Python thread does not hold the GIL */
`
2116
``
`-
tss_tstate = NULL;
`
2117
``
`-
}
`
2118
``
`-
}
`
2119
``
`-
else {
`
2120
``
`-
/* Py_FatalError() has been called from a C thread
`
2121
``
`-
which has no Python thread state. */
`
``
2139
`+
_PyRuntimeState *runtime = &_PyRuntime;
`
``
2140
`+
fatal_error_dump_runtime(stream, runtime);
`
``
2141
+
``
2142
`+
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
`
``
2143
`+
PyInterpreterState *interp = NULL;
`
``
2144
`+
if (tstate != NULL) {
`
``
2145
`+
interp = tstate->interp;
`
2122
2146
` }
`
2123
``
`-
int has_tstate_and_gil = (tss_tstate != NULL);
`
2124
2147
``
``
2148
`+
/* Check if the current thread has a Python thread state
`
``
2149
`+
and holds the GIL.
`
``
2150
+
``
2151
`+
tss_tstate is NULL if Py_FatalError() is called from a C thread which
`
``
2152
`+
has no Python thread state.
`
``
2153
+
``
2154
`+
tss_tstate != tstate if the current Python thread does not hold the GIL.
`
``
2155
`+
*/
`
``
2156
`+
PyThreadState *tss_tstate = PyGILState_GetThisThreadState();
`
``
2157
`+
int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate);
`
2125
2158
`if (has_tstate_and_gil) {
`
2126
2159
`/* If an exception is set, print the exception with its traceback */
`
2127
2160
`if (!_Py_FatalError_PrintExc(fd)) {
`
2128
2161
`/* No exception is set, or an exception is set without traceback */
`
2129
``
`-
_Py_FatalError_DumpTracebacks(fd);
`
``
2162
`+
_Py_FatalError_DumpTracebacks(fd, interp, tss_tstate);
`
2130
2163
` }
`
2131
2164
` }
`
2132
2165
`else {
`
2133
``
`-
_Py_FatalError_DumpTracebacks(fd);
`
``
2166
`+
_Py_FatalError_DumpTracebacks(fd, interp, tss_tstate);
`
2134
2167
` }
`
2135
2168
``
2136
2169
`/* The main purpose of faulthandler is to display the traceback.
`