1 /* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "my_config.h"
24 
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <algorithm>
29 #include <atomic>
30 
31 #include "lex_string.h"
32 #include "my_inttypes.h"
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 
37 #include "my_macros.h"
38 #include "my_stacktrace.h"
39 #include "my_sys.h"
40 #include "sql/mysqld.h"
41 #include "sql/sql_class.h"
42 #include "sql/sql_const.h"
43 
44 #ifdef _WIN32
45 #include <crtdbg.h>
46 
47 #define SIGNAL_FMT "exception 0x%x"
48 #else
49 #define SIGNAL_FMT "signal %d"
50 #endif
51 
52 /*
53   We are handling signals in this file.
54   Any global variables we read should be 'volatile sig_atomic_t'
55   to guarantee that we read some consistent value.
56  */
57 static volatile sig_atomic_t segfaulted = 0;
58 
59 /**
60  * Handler for fatal signals
61  *
62  * Fatal events (seg.fault, bus error etc.) will trigger
63  * this signal handler.  The handler will try to dump relevant
64  * debugging information to stderr and dump a core image.
65  *
66  * Signal handlers can only use a set of 'safe' system calls
67  * and library functions.  A list of safe calls in POSIX systems
68  * are available at:
69  *  http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
70  * For MS Windows, guidelines are available at:
71  *  http://msdn.microsoft.com/en-us/library/xdkz3x12(v=vs.71).aspx
72  *
73  * @param sig Signal number
74  */
handle_fatal_signal(int sig)75 extern "C" void handle_fatal_signal(int sig) {
76   if (segfaulted) {
77     my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
78     _exit(MYSQLD_FAILURE_EXIT); /* Quit without running destructors */
79   }
80 
81   segfaulted = 1;
82 
83 #ifdef _WIN32
84   SYSTEMTIME utc_time;
85   GetSystemTime(&utc_time);
86   const long hrs = utc_time.wHour;
87   const long mins = utc_time.wMinute;
88   const long secs = utc_time.wSecond;
89 #else
90   /* Using time() instead of my_time() to avoid looping */
91   const time_t curr_time = time(nullptr);
92   /* Calculate time of day */
93   const long tmins = curr_time / 60;
94   const long thrs = tmins / 60;
95   const long hrs = thrs % 24;
96   const long mins = tmins % 60;
97   const long secs = curr_time % 60;
98 #endif
99 
100   char hrs_buf[3] = "00";
101   char mins_buf[3] = "00";
102   char secs_buf[3] = "00";
103   my_safe_itoa(10, hrs, &hrs_buf[2]);
104   my_safe_itoa(10, mins, &mins_buf[2]);
105   my_safe_itoa(10, secs, &secs_buf[2]);
106 
107   my_safe_printf_stderr("%s:%s:%s UTC - mysqld got " SIGNAL_FMT " ;\n", hrs_buf,
108                         mins_buf, secs_buf, sig);
109 
110   my_safe_printf_stderr(
111       "%s",
112       "Most likely, you have hit a bug, but this error can also "
113       "be caused by malfunctioning hardware.\n");
114 
115 #ifdef HAVE_STACKTRACE
116   THD *thd = current_thd;
117 
118   if (!(test_flags & TEST_NO_STACKTRACE)) {
119     my_safe_printf_stderr("Thread pointer: 0x%p\n", thd);
120     my_safe_printf_stderr(
121         "%s",
122         "Attempting backtrace. You can use the following "
123         "information to find out\n"
124         "where mysqld died. If you see no messages after this, something went\n"
125         "terribly wrong...\n");
126     my_print_stacktrace(
127         thd ? pointer_cast<const uchar *>(thd->thread_stack) : nullptr,
128         my_thread_stack_size);
129   }
130   if (thd) {
131     const char *kreason = "UNKNOWN";
132     switch (thd->killed.load()) {
133       case THD::NOT_KILLED:
134         kreason = "NOT_KILLED";
135         break;
136       case THD::KILL_CONNECTION:
137         kreason = "KILL_CONNECTION";
138         break;
139       case THD::KILL_QUERY:
140         kreason = "KILL_QUERY";
141         break;
142       case THD::KILL_TIMEOUT:
143         kreason = "KILL_TIMEOUT";
144         break;
145       case THD::KILLED_NO_VALUE:
146         kreason = "KILLED_NO_VALUE";
147         break;
148     }
149     my_safe_printf_stderr(
150         "%s",
151         "\n"
152         "Trying to get some variables.\n"
153         "Some pointers may be invalid and cause the dump to abort.\n");
154 
155     my_safe_printf_stderr("Query (%p): ", thd->query().str);
156     my_safe_puts_stderr(thd->query().str,
157                         std::min(size_t{1024}, thd->query().length));
158     my_safe_printf_stderr("Connection ID (thread ID): %u\n", thd->thread_id());
159     my_safe_printf_stderr("Status: %s\n\n", kreason);
160   }
161   my_safe_printf_stderr(
162       "%s",
163       "\n"
164       "Please report a bug at https://jira.percona.com/projects/PXB\n");
165 
166 #endif /* HAVE_STACKTRACE */
167 
168   if (test_flags & TEST_CORE_ON_SIGNAL) {
169     my_safe_printf_stderr("%s", "Writing a core file\n");
170     my_write_core(sig);
171   }
172 
173 #ifndef _WIN32
174   /*
175      Quit, without running destructors (etc.)
176      On Windows, do not terminate, but pass control to exception filter.
177   */
178   _exit(MYSQLD_FAILURE_EXIT);  // Using _exit(), since exit() is not async
179                                // signal safe
180 #endif
181 }
182