Skip to content

Commit cedb1f3

Browse files
committed
Returning const char* from PyUnstable_DumpTraceback, write errors to fd
1 parent 5594e75 commit cedb1f3

File tree

5 files changed

+28
-13
lines changed

5 files changed

+28
-13
lines changed

Doc/c-api/exceptions.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1347,7 +1347,7 @@ Tracebacks
13471347
This function returns ``0`` on success, and returns ``-1`` with an
13481348
exception set on failure.
13491349
1350-
.. c:function:: void PyUnstable_DumpTraceback(int fd, PyThreadState *tstate)
1350+
.. c:function:: const char* PyUnstable_DumpTraceback(int fd, PyThreadState *tstate)
13511351
13521352
Write a trace of the Python stack in *tstate* into the file *fd*. The format
13531353
looks like::
@@ -1363,6 +1363,9 @@ Tracebacks
13631363
backslashreplace and truncated to 500 characters. It writes only the first
13641364
100 frames; further frames are truncated with the line ``...``.
13651365
1366+
This function will return ``NULL`` on success, or an error message on error.
1367+
It will also write this error message to *fd*.
1368+
13661369
This function is safe to use from signal handlers.
13671370
13681371
The caller does not need to hold an :term:`attached thread state`, nor does
@@ -1384,6 +1387,7 @@ Tracebacks
13841387
error if the function is unable to get the current Python thread state.
13851388
13861389
This function will return ``NULL`` on success, or an error message on error.
1390+
It will also write this error message to *fd*.
13871391
13881392
This function is meant to debug debug situations such as segfaults, fatal
13891393
errors, and similar. It calls :c:func:`PyUnstable_DumpTraceback` for each

Include/cpython/traceback.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct _traceback {
1212
int tb_lineno;
1313
};
1414

15-
PyAPI_FUNC(void) PyUnstable_DumpTraceback(int fd, PyThreadState *tstate);
15+
PyAPI_FUNC(const char*) PyUnstable_DumpTraceback(int fd, PyThreadState *tstate);
1616

1717
PyAPI_FUNC(const char*) PyUnstable_DumpTracebackThreads(
1818
int fd,

Include/traceback.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
1313
PyAPI_DATA(PyTypeObject) PyTraceBack_Type;
1414
#define PyTraceBack_Check(v) Py_IS_TYPE((v), &PyTraceBack_Type)
1515

16+
1617
#ifndef Py_LIMITED_API
1718
# define Py_CPYTHON_TRACEBACK_H
1819
# include "cpython/traceback.h"

Modules/faulthandler.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,15 +276,16 @@ faulthandler_dump_traceback_py_impl(PyObject *module, PyObject *file,
276276
_PyEval_StopTheWorld(interp);
277277
errmsg = PyUnstable_DumpTracebackThreads(fd, NULL, tstate);
278278
_PyEval_StartTheWorld(interp);
279-
if (errmsg != NULL) {
280-
PyErr_SetString(PyExc_RuntimeError, errmsg);
281-
Py_XDECREF(file);
282-
return NULL;
283-
}
284279
}
285280
else {
286-
PyUnstable_DumpTraceback(fd, tstate);
281+
errmsg = PyUnstable_DumpTraceback(fd, tstate);
287282
}
283+
if (errmsg != NULL) {
284+
PyErr_SetString(PyExc_RuntimeError, errmsg);
285+
Py_XDECREF(file);
286+
return NULL;
287+
}
288+
288289
Py_XDECREF(file);
289290

290291
if (PyErr_CheckSignals())

Python/traceback.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,10 +1167,11 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
11671167
11681168
The caller is responsible to call PyErr_CheckSignals() to call Python signal
11691169
handlers if signals were received. */
1170-
void
1170+
const char*
11711171
PyUnstable_DumpTraceback(int fd, PyThreadState *tstate)
11721172
{
11731173
dump_traceback(fd, tstate, 1);
1174+
return NULL;
11741175
}
11751176

11761177
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
@@ -1257,6 +1258,14 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
12571258
PUTS(fd, " (most recent call first):\n");
12581259
}
12591260

1261+
/* Write an error string and also return it at the same time. */
1262+
static const char*
1263+
dump_error(int fd, const char *msg)
1264+
{
1265+
PUTS(fd, msg);
1266+
return msg;
1267+
}
1268+
12601269
/* Dump the traceback of all Python threads into fd. Use write() to write the
12611270
traceback and retry if write() is interrupted by a signal (failed with
12621271
EINTR), but don't call the Python signal handler.
@@ -1283,15 +1292,15 @@ PyUnstable_DumpTracebackThreads(int fd, PyInterpreterState *interp,
12831292
}
12841293

12851294
if (current_tstate != NULL && tstate_is_freed(current_tstate)) {
1286-
return "tstate is freed";
1295+
return dump_error(fd, "tstate is freed");
12871296
}
12881297

12891298
if (interp == NULL) {
12901299
if (current_tstate == NULL) {
12911300
interp = _PyGILState_GetInterpreterStateUnsafe();
12921301
if (interp == NULL) {
12931302
/* We need the interpreter state to get Python threads */
1294-
return "unable to get the interpreter state";
1303+
return dump_error(fd, "unable to get the interpreter state");
12951304
}
12961305
}
12971306
else {
@@ -1301,13 +1310,13 @@ PyUnstable_DumpTracebackThreads(int fd, PyInterpreterState *interp,
13011310
assert(interp != NULL);
13021311

13031312
if (interp_is_freed(interp)) {
1304-
return "interp is freed";
1313+
return dump_error(fd, "interp is freed");
13051314
}
13061315

13071316
/* Get the current interpreter from the current thread */
13081317
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
13091318
if (tstate == NULL)
1310-
return "unable to get the thread head state";
1319+
return dump_error(fd, "unable to get the thread head state");
13111320

13121321
/* Dump the traceback of each thread */
13131322
unsigned int nthreads = 0;

0 commit comments

Comments
 (0)