[PATCH 2/2] Fix the SIGSEGV handler

David Shea dshea at redhat.com
Fri Sep 12 20:03:25 UTC 2014


Due to the way that python handles signals and threads, synchronous
signals--i.e., those that are delivered synchronously due to an attempt
to execute an instruction, such as SIGSEGV and SIGFPE--cannot be handled
in a multi-threaded program with signal handlers installed from python.
Move the signal handler deeper into a depths of isys.c and replace the
handleSegv handler with a method that installs the C signal handlers.

Also remove the part where the signal handler resets itself because
it's unlikely that this does anything we want. Use sigaction to install
the handlers to ensure that we don't somehow encounter the weird old
unix rules that would deliver a signal without blocking the signal in
the handler.
---
 anaconda                    |  6 +++++-
 pyanaconda/isys/__init__.py |  2 +-
 pyanaconda/isys/isys.c      | 34 ++++++++++++++++++++++++++++------
 3 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/anaconda b/anaconda
index 4518fb1..594c106 100755
--- a/anaconda
+++ b/anaconda
@@ -1002,9 +1002,13 @@ if __name__ == "__main__":
 
     # reset python's default SIGINT handler
     signal.signal(signal.SIGINT, signal.SIG_IGN)
-    signal.signal(signal.SIGSEGV, isys.handleSegv)
     signal.signal(signal.SIGTERM, lambda num, frame: sys.exit(1))
 
+    # synchronously-delivered signals such as SIGSEGV and SIGILL cannot be
+    # handled property from python, so install signal handlers from the C
+    # function in isys.
+    isys.installSyncSignalHandlers()
+
     setupEnvironment()
     # make sure we have /var/log soon, some programs fail to start without it
     iutil.mkdirChain("/var/log")
diff --git a/pyanaconda/isys/__init__.py b/pyanaconda/isys/__init__.py
index f29f08b..f5448dd 100644
--- a/pyanaconda/isys/__init__.py
+++ b/pyanaconda/isys/__init__.py
@@ -171,4 +171,4 @@ def total_memory():
         log.error("MemTotal: line not found in /proc/meminfo")
         raise RuntimeError("MemTotal: line not found in /proc/meminfo")
 
-handleSegv = _isys.handleSegv
+installSyncSignalHandlers = _isys.installSyncSignalHandlers
diff --git a/pyanaconda/isys/isys.c b/pyanaconda/isys/isys.c
index 10a43e6..a0f5183 100644
--- a/pyanaconda/isys/isys.c
+++ b/pyanaconda/isys/isys.c
@@ -28,14 +28,15 @@
 #include <signal.h>
 #include <execinfo.h>
 #include <stdlib.h>
+#include <string.h>
 
 static PyObject * doSync(PyObject * s, PyObject * args);
-static PyObject * doSegvHandler(PyObject *s, PyObject *args);
+static PyObject * doSignalHandlers(PyObject *s, PyObject *args);
 static PyObject * doSetSystemTime(PyObject *s, PyObject *args);
 
 static PyMethodDef isysModuleMethods[] = {
     { "sync", (PyCFunction) doSync, METH_NOARGS, NULL},
-    { "handleSegv", (PyCFunction) doSegvHandler, METH_NOARGS, NULL },
+    { "installSyncSignalHandlers", (PyCFunction) doSignalHandlers, METH_NOARGS, NULL},
     { "set_system_time", (PyCFunction) doSetSystemTime, METH_VARARGS, NULL},
     { NULL, NULL, 0, NULL }
 } ;
@@ -52,18 +53,16 @@ static PyObject * doSync(PyObject * s, PyObject * args) {
     return Py_None;
 }
 
-static PyObject * doSegvHandler(PyObject *s, PyObject *args) {
+static void sync_signal_handler(int signum) {
     void *array[20];
     size_t size;
     char **strings;
     size_t i;
 
-    signal(SIGSEGV, SIG_DFL); /* back to default */
-    
     size = backtrace (array, 20);
     strings = backtrace_symbols (array, size);
     
-    printf ("Anaconda received SIGSEGV!.  Backtrace:\n");
+    printf ("Anaconda received signal %d!.  Backtrace:\n", signum);
     for (i = 0; i < size; i++)
         printf ("%s\n", strings[i]);
      
@@ -71,6 +70,29 @@ static PyObject * doSegvHandler(PyObject *s, PyObject *args) {
     exit(1);
 }
 
+static PyObject * doSignalHandlers(PyObject *s, PyObject *args) {
+    /* Install a signal handler for all synchronous signals */
+    struct sigaction sa;
+
+    memset(&sa, 0, sizeof(struct sigaction));
+    sa.sa_handler = sync_signal_handler;
+
+    if (sigaction(SIGILL, &sa, NULL) != 0) {
+        return PyErr_SetFromErrno(PyExc_SystemError);
+    }
+
+    if (sigaction(SIGFPE, &sa, NULL) != 0) {
+        return PyErr_SetFromErrno(PyExc_SystemError);
+    }
+
+    if (sigaction(SIGSEGV, &sa, NULL) != 0) {
+        return PyErr_SetFromErrno(PyExc_SystemError);
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static PyObject * doSetSystemTime(PyObject *s, PyObject  *args) {
     struct timeval tv;
     tv.tv_usec = 0;
-- 
2.1.0



More information about the anaconda-patches mailing list