Skip to content

Commit

Permalink
Move the function that calls backtrace() to within the core.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeroIntensity committed Dec 25, 2024
1 parent 8198997 commit 0f670f0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 65 deletions.
4 changes: 4 additions & 0 deletions Include/internal/pycore_traceback.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ extern int _PyTraceBack_Print(
extern int _Py_WriteIndentedMargin(int, const char*, PyObject *);
extern int _Py_WriteIndent(int, PyObject *);

// Export for the faulthandler module
PyAPI_FUNC(void)
_Py_DumpStack(int fd);

#ifdef __cplusplus
}
#endif
Expand Down
67 changes: 2 additions & 65 deletions Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h> // _exit()
#endif
#ifdef HAVE_EXECINFO_H
# include <execinfo.h> // backtrace(), backtrace_symbols()
#endif

#include <signal.h> // sigaction()
#include <stdlib.h> // abort()
Expand Down Expand Up @@ -216,66 +213,6 @@ faulthandler_dump_traceback(int fd, int all_threads,
reentrant = 0;
}

#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
static void
faulthandler_stack_dump_impl(int fd)
{
#define BACKTRACE_SIZE 32
#define TRACEBACK_ENTRY_MAX_SIZE 256
void *callstack[BACKTRACE_SIZE];
int frames = backtrace(callstack, BACKTRACE_SIZE);
if (frames == 0) {
// Some systems won't return anything for the stack trace
PUTS(fd, " <system returned no stack trace>\n");
return;
}

char **strings = backtrace_symbols(callstack, BACKTRACE_SIZE);
if (strings == NULL) {
PUTS(fd, " <not enough memory to get stack trace>\n");
return;
}
for (int i = 0; i < frames; ++i) {
char entry_str[TRACEBACK_ENTRY_MAX_SIZE];
snprintf(entry_str, TRACEBACK_ENTRY_MAX_SIZE, " %s\n", strings[i]);
size_t length = strlen(entry_str) + 1;
if (length == TRACEBACK_ENTRY_MAX_SIZE) {
/* We exceeded the size, make it look prettier */
// Add ellipsis to last 3 characters
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 5] = '.';
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 4] = '.';
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 3] = '.';
// Ensure trailing newline
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 2] = '\n';
// Ensure that it's null-terminated
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 1] = '\0';
}
_Py_write_noraise(fd, entry_str, length);
}

if (frames == BACKTRACE_SIZE) {
PUTS(fd, " <truncated rest of calls>\n");
}

free(strings);
#undef BACKTRACE_SIZE
#undef TRACEBACK_ENTRY_MAX_SIZE
}
#else
static void
faulthandler_stack_dump_impl(int fd)
{
PUTS(fd, " <cannot get C stack on this system>\n");
}
#endif

static void
faulthandler_dump_c_stack_nocheck(int fd)
{
PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
faulthandler_stack_dump_impl(fd);
}

static void
faulthandler_dump_c_stack(int fd)
{
Expand All @@ -288,7 +225,7 @@ faulthandler_dump_c_stack(int fd)

if (fatal_error.c_stack) {
PUTS(fd, "\n");
faulthandler_dump_c_stack_nocheck(fd);
_Py_DumpStack(fd);
}

reentrant = 0;
Expand Down Expand Up @@ -352,7 +289,7 @@ faulthandler_dump_c_stack_py(PyObject *self,
return NULL;
}

faulthandler_dump_c_stack_nocheck(fd);
_Py_DumpStack(fd);

if (PyErr_CheckSignals()) {
return NULL;
Expand Down
59 changes: 59 additions & 0 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h> // lseek()
#endif
#ifdef HAVE_EXECINFO_H
# include <execinfo.h> // backtrace(), backtrace_symbols()
#endif


#define OFF(x) offsetof(PyTracebackObject, x)
Expand Down Expand Up @@ -1101,3 +1104,59 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
return NULL;
}

/* This is for faulthandler.
* Apparently, backtrace() doesn't play well across DLL boundaries on macOS */
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
void
_Py_DumpStack(int fd)
{
#define BACKTRACE_SIZE 32
#define TRACEBACK_ENTRY_MAX_SIZE 256
PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
void *callstack[BACKTRACE_SIZE];
int frames = backtrace(callstack, BACKTRACE_SIZE);
if (frames == 0) {
// Some systems won't return anything for the stack trace
PUTS(fd, " <system returned no stack trace>\n");
return;
}

char **strings = backtrace_symbols(callstack, BACKTRACE_SIZE);
if (strings == NULL) {
PUTS(fd, " <not enough memory to get stack trace>\n");
return;
}
for (int i = 0; i < frames; ++i) {
char entry_str[TRACEBACK_ENTRY_MAX_SIZE];
snprintf(entry_str, TRACEBACK_ENTRY_MAX_SIZE, " %s\n", strings[i]);
size_t length = strlen(entry_str) + 1;
if (length == TRACEBACK_ENTRY_MAX_SIZE) {
/* We exceeded the size, make it look prettier */
// Add ellipsis to last 3 characters
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 5] = '.';
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 4] = '.';
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 3] = '.';
// Ensure trailing newline
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 2] = '\n';
// Ensure that it's null-terminated
entry_str[TRACEBACK_ENTRY_MAX_SIZE - 1] = '\0';
}
_Py_write_noraise(fd, entry_str, length);
}

if (frames == BACKTRACE_SIZE) {
PUTS(fd, " <truncated rest of calls>\n");
}

free(strings);
#undef BACKTRACE_SIZE
#undef TRACEBACK_ENTRY_MAX_SIZE
}
#else
void
_Py_DumpStack(int fd)
{
PUTS(fd, "Current thread's C stack trace (most recent call first):\n");
PUTS(fd, " <cannot get C stack on this system>\n");
}
#endif

0 comments on commit 0f670f0

Please sign in to comment.