Fix possible deadlock in backtrace (2nd attempt) YAZ-856
authorAdam Dickmeiss <adam@indexdata.dk>
Tue, 15 Sep 2015 08:05:10 +0000 (10:05 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 15 Sep 2015 08:05:10 +0000 (10:05 +0200)
An alarm is set up so that backtrace is terminated if it hangs.
Even if backtrace the handler also attempts to spawn gdb.

src/backtrace.c

index 2ed7385..1ad0d7e 100644 (file)
 
 static char static_progname[256];
 #if HAVE_EXECINFO_H
+static int yaz_panic_fd = -1;
 
-static void yaz_invoke_backtrace(char *buf, int buf_sz)
+static void yaz_invoke_gdb(void)
 {
-    FILE *file = yaz_log_file();
-    int fd = fileno(file);
+    int fd = yaz_panic_fd;
     pid_t pid;
     int fds[2];
-    void *backtrace_info[BACKTRACE_SZ];
-    int sz = BACKTRACE_SZ;
-
-    write(fd, buf, strlen(buf));
-    sz = backtrace(backtrace_info, sz);
-    backtrace_symbols_fd(backtrace_info, sz, fd);
-
     if (pipe(fds) == -1)
     {
         const char *cp = "backtrace: pipe failed\n";
@@ -128,11 +121,36 @@ static void yaz_invoke_backtrace(char *buf, int buf_sz)
     }
 }
 
+static void yaz_panic_alarm(int sig)
+{
+    const char *cp = "backtrace: backtrace hangs\n";
+
+    write(yaz_panic_fd, cp, strlen(cp));
+    yaz_invoke_gdb();
+    abort();
+}
+
+static void yaz_invoke_backtrace(void)
+{
+    int fd = yaz_panic_fd;
+    void *backtrace_info[BACKTRACE_SZ];
+    int sz = BACKTRACE_SZ;
+
+    signal(SIGALRM, yaz_panic_alarm);
+    alarm(1);
+    sz = backtrace(backtrace_info, sz);
+    backtrace_symbols_fd(backtrace_info, sz, fd);
+}
+
 static void yaz_panic_sig_handler(int sig)
 {
     char buf[512];
+    FILE *file;
 
     signal(SIGABRT, SIG_DFL);
+    signal(SIGSEGV, SIG_DFL);
+    signal(SIGFPE, SIG_DFL);
+    signal(SIGBUS, SIG_DFL);
     strcpy(buf, "\nYAZ panic received ");
     switch (sig)
     {
@@ -154,7 +172,14 @@ static void yaz_panic_sig_handler(int sig)
     }
     yaz_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
                  " PID=" NMEM_INT_PRINTF "\n", (nmem_int_t) getpid());
-    yaz_invoke_backtrace(buf, sizeof buf);
+
+    file = yaz_log_file();
+    /* static variable to be used in the following + handlers */
+    yaz_panic_fd = fileno(file);
+
+    write(yaz_panic_fd, buf, strlen(buf));
+    yaz_invoke_backtrace();
+    yaz_invoke_gdb();
     abort();
 }
 #endif
@@ -164,9 +189,6 @@ void yaz_enable_panic_backtrace(const char *progname)
     strncpy(static_progname, progname, sizeof(static_progname) - 1);
     static_progname[sizeof(static_progname) - 1] = '\0';
 #if HAVE_EXECINFO_H
-    void *bt[1];
-    backtrace(bt, 1);
-
     signal(SIGABRT, yaz_panic_sig_handler);
     signal(SIGSEGV, yaz_panic_sig_handler);
     signal(SIGFPE, yaz_panic_sig_handler);