Add check for integer overflow in odr_write YAZ-816
[yaz-moved-to-github.git] / src / backtrace.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file
8  * \brief get information for abnormal terminated, crashes, etc
9  */
10
11
12 #if HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <signal.h>
17 #include <string.h>
18 #include <errno.h>
19 #if HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #include <stdlib.h>
23 #if HAVE_SYS_WAIT_H
24 #include <sys/wait.h>
25 #endif
26 #include <yaz/log.h>
27 #include <yaz/snprintf.h>
28 #include <yaz/backtrace.h>
29 #include <yaz/nmem.h>
30
31 #if HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34
35 #if HAVE_EXECINFO_H
36 #include <execinfo.h>
37 #endif
38
39 #define BACKTRACE_SZ 100
40
41 static char static_progname[256];
42 #if HAVE_EXECINFO_H
43
44 static void yaz_invoke_backtrace(char *buf, int buf_sz)
45 {
46     FILE *file = yaz_log_file();
47     int fd = fileno(file);
48     pid_t pid;
49     int fds[2];
50     void *backtrace_info[BACKTRACE_SZ];
51     int sz = BACKTRACE_SZ;
52
53     write(fd, buf, strlen(buf));
54     sz = backtrace(backtrace_info, sz);
55     backtrace_symbols_fd(backtrace_info, sz, fd);
56
57     if (pipe(fds) == -1)
58     {
59         const char *cp = "backtrace: pipe failed\n";
60         write(fd, cp, strlen(cp));
61         return;
62     }
63     pid = fork();
64     if (pid == (pid_t) (-1))
65     {   /* error */
66         const char *cp = "backtrace: fork failure\n";
67         write(fd, cp, strlen(cp));
68     }
69     else if (pid == 0)
70     {   /* child */
71         char *arg[20];
72         int arg_no = 0;
73         char pidstr[40];
74         const char *cp = "backtrace: could not exec gdb";
75
76         close(fds[1]);
77         close(0);
78         dup(fds[0]);
79         if (fd != 1)
80         {
81             close(1);
82             dup(fd);
83         }
84         if (fd != 2)
85         {
86             close(2);
87             dup(fd);
88         }
89         arg[arg_no++] = "/usr/bin/gdb";
90         arg[arg_no++] = "-n";
91         arg[arg_no++] = "-batch";
92         arg[arg_no++] = "-ex";
93         arg[arg_no++] = "info threads";
94         arg[arg_no++] = "-ex";
95         arg[arg_no++] = "thread apply all bt";
96         arg[arg_no++] = static_progname;
97         sprintf(pidstr, NMEM_INT_PRINTF, (nmem_int_t) getppid());
98         arg[arg_no++] = pidstr;
99         arg[arg_no] = 0;
100         execv(arg[0], arg);
101         write(2, cp, strlen(cp)); /* exec failure if we make it this far */
102         _exit(1);
103     }
104     else
105     {  /* parent */
106         int sec = 0;
107
108         close(fds[0]);
109         write(fds[1], "quit\n", 5);
110         while (1)
111         {
112             int status;
113             pid_t s = waitpid(pid, &status, WNOHANG);
114             if (s != 0)
115                 break;
116             if (sec == 9)
117                 kill(pid, SIGTERM);
118             if (sec == 10)
119                 kill(pid, SIGKILL);
120             if (sec == 11)
121                 break;
122             if (sec > 3)
123                 write(fds[1], "quit\n", 5);
124             sleep(1);
125             sec++;
126         }
127         close(fds[1]);
128     }
129 }
130
131 static void yaz_panic_sig_handler(int sig)
132 {
133     char buf[512];
134
135     signal(SIGABRT, SIG_DFL);
136     strcpy(buf, "\nYAZ panic received ");
137     switch (sig)
138     {
139     case SIGSEGV:
140         strcat(buf, "SIGSEGV");
141         break;
142     case SIGABRT:
143         strcat(buf, "SIGABRT");
144         break;
145     case SIGFPE:
146         strcat(buf, "SIGFPE");
147         break;
148     case SIGBUS:
149         strcat(buf, "SIGBUS");
150         break;
151     default:
152         yaz_snprintf(buf + strlen(buf), sizeof buf, "signo=%d", sig);
153         break;
154     }
155     yaz_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
156                  " PID=" NMEM_INT_PRINTF "\n", (nmem_int_t) getpid());
157     yaz_invoke_backtrace(buf, sizeof buf);
158     abort();
159 }
160 #endif
161
162 void yaz_enable_panic_backtrace(const char *progname)
163 {
164     strncpy(static_progname, progname, sizeof(static_progname) - 1);
165     static_progname[sizeof(static_progname) - 1] = '\0';
166 #if HAVE_EXECINFO_H
167     signal(SIGABRT, yaz_panic_sig_handler);
168     signal(SIGSEGV, yaz_panic_sig_handler);
169     signal(SIGFPE, yaz_panic_sig_handler);
170     signal(SIGBUS, yaz_panic_sig_handler);
171 #endif
172 }
173
174 /*
175  * Local variables:
176  * c-basic-offset: 4
177  * c-file-style: "Stroustrup"
178  * indent-tabs-mode: nil
179  * End:
180  * vim: shiftwidth=4 tabstop=8 expandtab
181  */
182