1/* Copyright (c) 2011, 2012, Oracle and/or its affiliates.
2 Copyright (c) 2011, 2014, SkySQL Ab.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#include "mariadb.h"
18#include <signal.h>
19
20//#include "sys_vars.h"
21#include <keycache.h>
22#include "mysqld.h"
23#include "sql_class.h"
24#include "my_stacktrace.h"
25
26#ifdef __WIN__
27#include <crtdbg.h>
28#define SIGNAL_FMT "exception 0x%x"
29#else
30#define SIGNAL_FMT "signal %d"
31#endif
32
33/*
34 We are handling signals/exceptions in this file.
35 Any global variables we read should be 'volatile sig_atomic_t'
36 to guarantee that we read some consistent value.
37 */
38static volatile sig_atomic_t segfaulted= 0;
39extern ulong max_used_connections;
40extern volatile sig_atomic_t calling_initgroups;
41#ifdef HAVE_NPTL
42extern volatile sig_atomic_t ld_assume_kernel_is_set;
43#endif
44
45extern const char *optimizer_switch_names[];
46
47/**
48 * Handler for fatal signals on POSIX, exception handler on Windows.
49 *
50 * Fatal events (seg.fault, bus error etc.) will trigger
51 * this signal handler. The handler will try to dump relevant
52 * debugging information to stderr and dump a core image.
53 *
54 * POSIX : Signal handlers should, if possible, only use a set of 'safe' system
55 * calls and library functions. A list of safe calls in POSIX systems
56 * are available at:
57 * http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
58 *
59 * @param sig Signal number /Exception code
60*/
61extern "C" sig_handler handle_fatal_signal(int sig)
62{
63 time_t curr_time;
64 struct tm tm;
65#ifdef HAVE_STACKTRACE
66 THD *thd;
67 /*
68 This flag remembers if the query pointer was found invalid.
69 We will try and print the query at the end of the signal handler, in case
70 we're wrong.
71 */
72 bool print_invalid_query_pointer= false;
73#endif
74
75 if (segfaulted)
76 {
77 my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
78 goto end;
79 }
80
81 segfaulted = 1;
82
83 curr_time= my_time(0);
84 localtime_r(&curr_time, &tm);
85
86 my_safe_printf_stderr("%02d%02d%02d %2d:%02d:%02d ",
87 tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
88 tm.tm_hour, tm.tm_min, tm.tm_sec);
89 if (opt_expect_abort
90#ifdef _WIN32
91 && sig == (int)EXCEPTION_BREAKPOINT /* __debugbreak in my_sigabrt_hander() */
92#else
93 && sig == SIGABRT
94#endif
95 )
96 {
97 fprintf(stderr,"[Note] mysqld did an expected abort\n");
98 goto end;
99 }
100
101 my_safe_printf_stderr("[ERROR] mysqld got " SIGNAL_FMT " ;\n",sig);
102
103 my_safe_printf_stderr("%s",
104 "This could be because you hit a bug. It is also possible that this binary\n"
105 "or one of the libraries it was linked against is corrupt, improperly built,\n"
106 "or misconfigured. This error can also be caused by malfunctioning hardware.\n\n");
107
108 my_safe_printf_stderr("%s",
109 "To report this bug, see https://mariadb.com/kb/en/reporting-bugs\n\n");
110
111 my_safe_printf_stderr("%s",
112 "We will try our best to scrape up some info that will hopefully help\n"
113 "diagnose the problem, but since we have already crashed, \n"
114 "something is definitely wrong and this may fail.\n\n");
115
116 set_server_version(server_version, sizeof(server_version));
117 my_safe_printf_stderr("Server version: %s\n", server_version);
118
119 if (dflt_key_cache)
120 my_safe_printf_stderr("key_buffer_size=%lu\n",
121 (ulong) dflt_key_cache->key_cache_mem_size);
122
123 my_safe_printf_stderr("read_buffer_size=%ld\n",
124 (long) global_system_variables.read_buff_size);
125
126 my_safe_printf_stderr("max_used_connections=%lu\n",
127 (ulong) max_used_connections);
128
129 if (thread_scheduler)
130 my_safe_printf_stderr("max_threads=%u\n",
131 (uint) thread_scheduler->max_threads +
132 (uint) extra_max_connections);
133
134 my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count);
135
136 if (dflt_key_cache && thread_scheduler)
137 {
138 my_safe_printf_stderr("It is possible that mysqld could use up to \n"
139 "key_buffer_size + "
140 "(read_buffer_size + sort_buffer_size)*max_threads = "
141 "%lu K bytes of memory\n",
142 (ulong)
143 (dflt_key_cache->key_cache_mem_size +
144 (global_system_variables.read_buff_size +
145 global_system_variables.sortbuff_size) *
146 (thread_scheduler->max_threads + extra_max_connections) +
147 (max_connections + extra_max_connections) *
148 sizeof(THD)) / 1024);
149 my_safe_printf_stderr("%s",
150 "Hope that's ok; if not, decrease some variables in "
151 "the equation.\n\n");
152 }
153
154#ifdef HAVE_STACKTRACE
155 thd= current_thd;
156
157 if (opt_stack_trace)
158 {
159 my_safe_printf_stderr("Thread pointer: %p\n", thd);
160 my_safe_printf_stderr("%s",
161 "Attempting backtrace. You can use the following "
162 "information to find out\n"
163 "where mysqld died. If you see no messages after this, something went\n"
164 "terribly wrong...\n");
165 my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
166 (ulong)my_thread_stack_size, 0);
167 }
168 if (thd)
169 {
170 const char *kreason= "UNKNOWN";
171 switch (thd->killed) {
172 case NOT_KILLED:
173 case KILL_HARD_BIT:
174 kreason= "NOT_KILLED";
175 break;
176 case KILL_BAD_DATA:
177 case KILL_BAD_DATA_HARD:
178 kreason= "KILL_BAD_DATA";
179 break;
180 case KILL_CONNECTION:
181 case KILL_CONNECTION_HARD:
182 kreason= "KILL_CONNECTION";
183 break;
184 case KILL_QUERY:
185 case KILL_QUERY_HARD:
186 kreason= "KILL_QUERY";
187 break;
188 case KILL_TIMEOUT:
189 case KILL_TIMEOUT_HARD:
190 kreason= "KILL_TIMEOUT";
191 break;
192 case KILL_SYSTEM_THREAD:
193 case KILL_SYSTEM_THREAD_HARD:
194 kreason= "KILL_SYSTEM_THREAD";
195 break;
196 case KILL_SERVER:
197 case KILL_SERVER_HARD:
198 kreason= "KILL_SERVER";
199 break;
200 case ABORT_QUERY:
201 case ABORT_QUERY_HARD:
202 kreason= "ABORT_QUERY";
203 break;
204 case KILL_SLAVE_SAME_ID:
205 kreason= "KILL_SLAVE_SAME_ID";
206 break;
207 case KILL_WAIT_TIMEOUT:
208 case KILL_WAIT_TIMEOUT_HARD:
209 kreason= "KILL_WAIT_TIMEOUT";
210 break;
211 }
212 my_safe_printf_stderr("%s", "\n"
213 "Trying to get some variables.\n"
214 "Some pointers may be invalid and cause the dump to abort.\n");
215
216 my_safe_printf_stderr("Query (%p): ", thd->query());
217 if (my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length())))
218 {
219 // Query was found invalid. We will try to print it at the end.
220 print_invalid_query_pointer= true;
221 }
222
223 my_safe_printf_stderr("\nConnection ID (thread ID): %lu\n",
224 (ulong) thd->thread_id);
225 my_safe_printf_stderr("Status: %s\n\n", kreason);
226 my_safe_printf_stderr("%s", "Optimizer switch: ");
227 ulonglong optsw= thd->variables.optimizer_switch;
228 for (uint i= 0; optimizer_switch_names[i+1]; i++, optsw >>= 1)
229 {
230 if (i)
231 my_safe_printf_stderr("%s", ",");
232 my_safe_printf_stderr("%s=%s",
233 optimizer_switch_names[i], optsw & 1 ? "on" : "off");
234 }
235 my_safe_printf_stderr("%s", "\n\n");
236 }
237 my_safe_printf_stderr("%s",
238 "The manual page at "
239 "http://dev.mysql.com/doc/mysql/en/crashing.html contains\n"
240 "information that should help you find out what is causing the crash.\n");
241
242#endif /* HAVE_STACKTRACE */
243
244#ifdef HAVE_INITGROUPS
245 if (calling_initgroups)
246 {
247 my_safe_printf_stderr("%s", "\n"
248 "This crash occurred while the server was calling initgroups(). This is\n"
249 "often due to the use of a mysqld that is statically linked against \n"
250 "glibc and configured to use LDAP in /etc/nsswitch.conf.\n"
251 "You will need to either upgrade to a version of glibc that does not\n"
252 "have this problem (2.3.4 or later when used with nscd),\n"
253 "disable LDAP in your nsswitch.conf, or use a "
254 "mysqld that is not statically linked.\n");
255 }
256#endif
257
258#ifdef HAVE_NPTL
259 if (thd_lib_detected == THD_LIB_LT && !ld_assume_kernel_is_set)
260 {
261 my_safe_printf_stderr("%s",
262 "You are running a statically-linked LinuxThreads binary on an NPTL\n"
263 "system. This can result in crashes on some distributions due to "
264 "LT/NPTL conflicts.\n"
265 "You should either build a dynamically-linked binary, "
266 "or force LinuxThreads\n"
267 "to be used with the LD_ASSUME_KERNEL environment variable.\n"
268 "Please consult the documentation for your distribution "
269 "on how to do that.\n");
270 }
271#endif
272
273 if (locked_in_memory)
274 {
275 my_safe_printf_stderr("%s", "\n"
276 "The \"--memlock\" argument, which was enabled, "
277 "uses system calls that are\n"
278 "unreliable and unstable on some operating systems and "
279 "operating-system versions (notably, some versions of Linux).\n"
280 "This crash could be due to use of those buggy OS calls.\n"
281 "You should consider whether you really need the "
282 "\"--memlock\" parameter and/or consult the OS distributer about "
283 "\"mlockall\" bugs.\n");
284 }
285
286#ifdef HAVE_STACKTRACE
287 if (print_invalid_query_pointer)
288 {
289 my_safe_printf_stderr(
290 "\nWe think the query pointer is invalid, but we will try "
291 "to print it anyway. \n"
292 "Query: ");
293 my_write_stderr(thd->query(), MY_MIN(65536U, thd->query_length()));
294 my_safe_printf_stderr("\n\n");
295 }
296#endif
297
298#ifdef HAVE_WRITE_CORE
299 if (test_flags & TEST_CORE_ON_SIGNAL)
300 {
301 char buff[80];
302 my_getwd(buff, sizeof(buff), 0);
303 my_safe_printf_stderr("Writing a core file at %s\n", buff);
304 fflush(stderr);
305 my_write_core(sig);
306 }
307#endif
308
309end:
310#ifndef __WIN__
311 /*
312 Quit, without running destructors (etc.)
313 Use a signal, because the parent (systemd) can check that with WIFSIGNALED
314 On Windows, do not terminate, but pass control to exception filter.
315 */
316 signal(sig, SIG_DFL);
317 kill(getpid(), sig);
318#else
319 return;
320#endif
321}
322