Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (révision 85385) +++ Python/pythonrun.c (copie de travail) @@ -80,6 +80,9 @@ extern void _PyGILState_Fini(void); #endif /* WITH_THREAD */ +extern void _Py_InitSegfault(void); +extern void _Py_FiniSegfault(void); + int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ @@ -397,6 +400,7 @@ interp = tstate->interp; /* Disable signal handling */ + _Py_FiniSegfault(); PyOS_FiniInterrupts(); /* Clear type lookup cache */ @@ -2467,6 +2471,7 @@ PyOS_setsig(SIGXFSZ, SIG_IGN); #endif PyOS_InitInterrupts(); /* May imply initsignal() */ + _Py_InitSegfault(); } Index: Python/segfault.c =================================================================== --- Python/segfault.c (révision 0) +++ Python/segfault.c (révision 0) @@ -0,0 +1,179 @@ +/* + * Python SIGSEGV and SIGFPE signal handlers: display the Python backtrace and + * abort. Allocate an alternative stack for this handler, if sigaltstack() is + * available, to be able to display the backtrace on stack overflow. + */ + +#include "Python.h" +#include "frameobject.h" +#include "code.h" +#include +#include +#include + +#ifdef MS_WINDOWS +# include "windows.h" +#endif + +#ifdef HAVE_SIGALTSTACK +static stack_t stack; +#endif +static int sigsegv_enable = 0, sigfpe_enable = 0; +#ifdef HAVE_SIGACTION +static struct sigaction old_sigsegv_handler, old_sigfpe_handler; +#else +static PyOS_sighandler_t old_sigsegv_handler, old_sigfpe_handler; +#endif + +/* Write an unicode object into the file f using ascii+backslashreplace */ + +static void +dump_ascii(PyUnicodeObject *unicode, FILE *f) +{ + Py_ssize_t i, size; + Py_UNICODE *u; + size = PyUnicode_GET_SIZE(unicode); + u = PyUnicode_AS_UNICODE(unicode); + for (i=0; i < size; i++, u++) { + if (*u < 128) + fputc(*u, f); + else if (*u < 256) + fprintf(f, "\\x%02x", *u); + else +#ifdef Py_UNICODE_WIDE + if (*u < 65535) +#endif + fprintf(f, "\\u%04x", *u); +#ifdef Py_UNICODE_WIDE + else + fprintf(f, "\\U%08x", *u); +#endif + } +} + +/* Dump one frame to stderr */ + +static void +dump_frame(PyFrameObject *f) +{ + PyCodeObject *code; + int lineno; + + code = f->f_code; + fputs(" File ", stderr); + if (code != NULL && code->co_filename != NULL + && PyUnicode_Check(code->co_filename)) + { + fputc('"', stderr); + dump_ascii((PyUnicodeObject*)code->co_filename, stderr); + fputc('"', stderr); + } else + fputs("???", stderr); + + lineno = PyFrame_GetLineNumber(f); + fprintf(stderr, ", line %u in ", lineno); + + if (code != NULL && code->co_name != NULL + && PyUnicode_Check(code->co_name)) + dump_ascii((PyUnicodeObject*)code->co_name, stderr); + else + fputs("???", stderr); + + fputc('\n', stderr); + fflush(stderr); +} + +static void +segfault_handler(int signum) +{ + PyThreadState *tstate; + PyFrameObject *frame; + const char *msg; + + if (signum == SIGFPE) + msg = "Fatal Python error: floating point exception\n\n"; + else + msg = "Fatal Python error: segmentation fault\n\n"; + fputs(msg, stderr); + fflush(stderr); + tstate = ((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)); + if (tstate == NULL) + goto exit; + + fputs("Traceback (most recent call first):\n", stderr); + fflush(stderr); + frame = tstate->frame; + while (frame != NULL) { + dump_frame(frame); + frame = frame->f_back; + } + if (signum == SIGFPE) + msg = "Floating point exception\n"; + else + msg = "Segmentation fault\n"; + fputs(msg, stderr); + fflush(stderr); + +exit: +#if defined(MS_WINDOWS) && defined(_DEBUG) + DebugBreak(); +#endif + abort(); +} + +void _Py_InitSegfault(void) +{ +#ifdef HAVE_SIGACTION + struct sigaction action; +#endif + +#ifdef HAVE_SIGALTSTACK + stack.ss_size = SIGSTKSZ; + stack.ss_sp = PyMem_Malloc(stack.ss_size); + stack.ss_flags = SS_ONSTACK; + if (stack.ss_sp == NULL) + return; + if (sigaltstack(&stack, NULL) != 0) + return; +#else +# error "nope" +#endif + +#ifdef HAVE_SIGACTION + action.sa_handler = segfault_handler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_ONSTACK; + if (sigaction(SIGSEGV, &action, &old_sigsegv_handler) == 0) + sigsegv_enable = 1; + if (sigaction(SIGFPE, &action, &old_sigfpe_handler) == 0) + sigfpe_enable = 1; +#else + old_sigsegv_handler = signal(SIGSEGV, segfault_handler); + if (old_sigsegv_handler != SIG_ERR) + sigsegv_enable = 1; + old_sigfpe_handler = signal(SIGFPE, segfault_handler); + if (old_sigfpe_handler != SIG_ERR) + sigfpe_enable = 1; +#endif +} + +void _Py_FiniSegfault(void) +{ +#ifdef HAVE_SIGACTION + if (sigsegv_enable) + (void)sigaction(SIGSEGV, &old_sigsegv_handler, NULL); + if (sigfpe_enable) + (void)sigaction(SIGFPE, &old_sigfpe_handler, NULL); +#else + if (sigsegv_enable) + (void)signal(SIGSEGV, old_sigsegv_handler); + if (sigfpe_enable) + (void)signal(SIGFPE, old_sigfpe_handler); +#endif + +#ifdef HAVE_SIGALTSTACK + if (stack.ss_sp != NULL) + PyMem_Free(stack.ss_sp); +#endif +} + Index: configure =================================================================== --- configure (révision 85385) +++ configure (copie de travail) @@ -9312,7 +9312,7 @@ select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ setgid \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setuid setvbuf \ - sigaction siginterrupt sigrelse snprintf strftime strlcpy \ + sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname unsetenv utimes waitpid wait3 wait4 \ wcscoll wcsftime wcsxfrm _getpty Index: configure.in =================================================================== --- configure.in (révision 85385) +++ configure.in (copie de travail) @@ -2560,7 +2560,7 @@ select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ setgid \ setlocale setregid setreuid setresuid setresgid setsid setpgid setpgrp setuid setvbuf \ - sigaction siginterrupt sigrelse snprintf strftime strlcpy \ + sigaction sigaltstack siginterrupt sigrelse snprintf strftime strlcpy \ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname unsetenv utimes waitpid wait3 wait4 \ wcscoll wcsftime wcsxfrm _getpty) Index: Misc/NEWS =================================================================== --- Misc/NEWS (révision 85389) +++ Misc/NEWS (copie de travail) @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #8863: Create SIGSEGV and SIGFPE signal handler displaying the Python + backtrace. + Library ------- Index: Makefile.pre.in =================================================================== --- Makefile.pre.in (révision 85385) +++ Makefile.pre.in (copie de travail) @@ -326,6 +326,7 @@ Python/dtoa.o \ Python/formatter_unicode.o \ Python/fileutils.o \ + Python/segfault.o \ Python/$(DYNLOADFILE) \ $(LIBOBJS) \ $(MACHDEP_OBJS) \ Index: pyconfig.h.in =================================================================== --- pyconfig.h.in (révision 85385) +++ pyconfig.h.in (copie de travail) @@ -620,6 +620,9 @@ /* Define to 1 if you have the `sigaction' function. */ #undef HAVE_SIGACTION +/* Define to 1 if you have the `sigaltstack' function. */ +#undef HAVE_SIGALTSTACK + /* Define to 1 if you have the `siginterrupt' function. */ #undef HAVE_SIGINTERRUPT