Index: Python/ceval.c =================================================================== --- Python/ceval.c (révision 67679) +++ Python/ceval.c (copie de travail) @@ -16,6 +16,7 @@ #include "eval.h" #include "opcode.h" #include "structmember.h" +#include "segfault.h" #include @@ -560,6 +561,7 @@ PyObject *retval = NULL; /* Return value */ PyThreadState *tstate = PyThreadState_GET(); PyCodeObject *co; + sigjmp_buf* env = NULL; /* when tracing we set things up so that @@ -803,6 +805,22 @@ x = Py_None; /* Not a reference, just anything non-NULL */ w = NULL; + env = segfault_enter(); + if (env) { + err = sigsetjmp(*env, 1); + if (err) { + segfault_python_handler(err); + err = 0; + why = WHY_EXCEPTION; + x = Py_None; + w = NULL; + goto on_error; + } + } else { + /* assign anything not-NULL */ + env = (sigjmp_buf*)1; + } + if (throwflag) { /* support for generator.throw() */ why = WHY_EXCEPTION; goto on_error; @@ -2719,6 +2737,8 @@ Py_LeaveRecursiveCall(); tstate->frame = f->f_back; + if (env) + segfault_exit(); return retval; } Index: Python/pythonrun.c =================================================================== --- Python/pythonrun.c (révision 67679) +++ Python/pythonrun.c (copie de travail) @@ -17,6 +17,7 @@ #include "ast.h" #include "eval.h" #include "marshal.h" +#include "segfault.h" #ifdef HAVE_SIGNAL_H #include @@ -400,6 +401,7 @@ interp = tstate->interp; /* Disable signal handling */ + PyOS_FiniSegfault(); PyOS_FiniInterrupts(); /* Clear type lookup cache */ @@ -1710,6 +1712,7 @@ PyOS_setsig(SIGXFSZ, SIG_IGN); #endif PyOS_InitInterrupts(); /* May imply initsignal() */ + PyOS_InitSegfault(); } Index: Python/segfault.c =================================================================== --- Python/segfault.c (révision 0) +++ Python/segfault.c (révision 0) @@ -0,0 +1,187 @@ +/** + * Python segmentation fault handler + */ + +/* + * Intel x86 on Ubuntu Gutsy: sigjmp_buf is 156 bytes + */ + +#include "Python.h" +#include "segfault.h" + +#define MAXDEPTH 3 + +typedef struct { + int init; + int in_error; + PyObject *segfault_text; + PyObject *fpe_text; + unsigned int index; + sigjmp_buf buffer[MAXDEPTH]; + struct sigaction old_sigfpe; + struct sigaction old_sigsegv; +#ifdef SEGFAULT_STACK + char stack[4096]; +#endif +} segfault_t; + +static segfault_t segfault; + +/** + * Function called in from Python function PyEval_EvalFrameEx() when a + * fault signal was received. Restore the GIL state and set a Python + * error. + */ +void +segfault_python_handler(int signum) +{ + (void)PyGILState_Ensure(); + + if (signum == SIGFPE) { + PyErr_SetObject(PyExc_ArithmeticError, segfault.fpe_text); + } else { + PyErr_SetObject(PyExc_MemoryError, segfault.segfault_text); + } + + segfault.in_error = 0; +} + +static int segfault_install(int signum); + +static void +segfault_signal_handler(int signum) +{ + sigjmp_buf* env; + + if (segfault.in_error || segfault.index == 0) { + /* Worst cases: error on handling an error (eg. segmentation + * fault in segfault_python_handler()) or a signal (eg. SIGFPE) + * is raised outside PyEval_EvalFrameEx() */ + kill(getpid(), signum); + return; + } + segfault.in_error = 1; + + /* reinstall our signal handler */ + (void)segfault_install(signum); + + /* long jump into PyEval_EvalFrameEx() */ + if (MAXDEPTH < segfault.index) + segfault.index = MAXDEPTH; + env = &segfault.buffer[segfault.index - 1]; + siglongjmp(*env, signum); +} + +/** + * Set our fault handler for the signal signum + */ +static int +segfault_install(int signum) +{ + struct sigaction context, *old_context; + context.sa_handler = segfault_signal_handler; + sigemptyset(&context.sa_mask); +#ifdef SEGFAULT_STACK + context.sa_flags = SA_RESETHAND | SA_RESTART | SA_ONSTACK; +#else + context.sa_flags = SA_RESETHAND | SA_RESTART; +#endif + if (signum == SIGFPE) + old_context = &segfault.old_sigfpe; + else + old_context = &segfault.old_sigsegv; + if (sigaction(signum, &context, old_context) == -1) + return 1; + else + return 0; +} + +/* Install signal handlers */ +static void +segfault_init(void) +{ + (void)segfault_install(SIGFPE); + (void)segfault_install(SIGSEGV); +} + +/* Restore the previous signal handlers */ +static void +segfault_deinit(void) +{ + (void)sigaction(SIGFPE, &segfault.old_sigfpe, NULL); + (void)sigaction(SIGSEGV, &segfault.old_sigsegv, NULL); +} + +/** + * Enter a Python frame in PyEval_EvalFrameEx(). + * Return a pointer to a jump buffer or NULL if they are too many frames. + * Use the jump buffer with sigsetjmp(). + */ +sigjmp_buf* +segfault_enter(void) +{ + sigjmp_buf* env; + if (segfault.index < MAXDEPTH) + env = &segfault.buffer[segfault.index]; + else + env = NULL; + segfault.index++; + if (segfault.index == 1) { + /* first call to segfault_enter(): install signal handlers */ + segfault_init(); + } + return env; +} + +/** + * Exit a Python frame in PyEval_EvalFrameEx(). + */ +void +segfault_exit(void) +{ + segfault.in_error = 0; + assert (0 < segfault.index); + segfault.index--; + if (segfault.index == 0) { + segfault_deinit(); + } +} + +/** + * Install the fault handlers et initialize variables + */ +void +PyOS_InitSegfault(void) +{ +#ifdef SEGFAULT_STACK + stack_t ss; +#endif + + segfault.index = 0; + segfault.in_error = 0; + +#ifdef SEGFAULT_STACK + ss.ss_sp = segfault.stack; + ss.ss_size = sizeof(segfault.stack); + ss.ss_flags = 0; + if( sigaltstack(&ss, NULL)) { + /* FIXME: catch this error */ + } +#endif + + /* FIXME: check errors! */ + segfault.fpe_text = PyString_FromString("SIGFPE"); + segfault.segfault_text = PyString_FromString("segmentation fault"); +} + +/** + * Uninstall the fault handlers + */ +void +PyOS_FiniSegfault(void) +{ + /* Free memory */ + Py_DECREF(segfault.fpe_text); + Py_DECREF(segfault.segfault_text); +} + Modification de propriétés sur Python/segfault.c ___________________________________________________________________ Nom : svn:eol-style + native Index: Include/segfault.h =================================================================== --- Include/segfault.h (révision 0) +++ Include/segfault.h (révision 0) @@ -0,0 +1,26 @@ + +/* Interface to execute compiled code */ + +#ifndef Py_SEGFAULT_H +#define Py_SEGFAULT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* Use a custom stack for signal handlers, especially the segfault handler */ +#define SEGFAULT_STACK + +sigjmp_buf* segfault_enter(void); +void segfault_exit(void); +void segfault_python_handler(int signum); + +void PyOS_InitSegfault(void); +void PyOS_FiniSegfault(void); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SEGFAULT_H */ Modification de propriétés sur Include/segfault.h ___________________________________________________________________ Nom : svn:eol-style + native Index: Makefile.pre.in =================================================================== --- Makefile.pre.in (révision 67679) +++ Makefile.pre.in (copie de travail) @@ -280,6 +280,7 @@ Python/pymath.o \ Python/pystate.o \ Python/pythonrun.o \ + Python/segfault.o \ Python/structmember.o \ Python/symtable.o \ Python/sysmodule.o \