1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
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_global.h"
24 #include <signal.h>
25 
26 #include "sys_vars.h"
27 #include "my_stacktrace.h"
28 #include "connection_handler_manager.h"  // Connection_handler_manager
29 #include "mysqld_thd_manager.h"          // Global_THD_manager
30 #include "sql_class.h"
31 
32 #ifdef _WIN32
33 #include <crtdbg.h>
34 #define SIGNAL_FMT "exception 0x%x"
35 #else
36 #define SIGNAL_FMT "signal %d"
37 #endif
38 
39 /*
40   We are handling signals in this file.
41   Any global variables we read should be 'volatile sig_atomic_t'
42   to guarantee that we read some consistent value.
43  */
44 static volatile sig_atomic_t segfaulted= 0;
45 extern volatile sig_atomic_t calling_initgroups;
46 
47 /**
48  * Handler for fatal signals
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  * Signal handlers can only use a set of 'safe' system calls
55  * 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  * For MS Windows, guidelines are available at:
59  *  http://msdn.microsoft.com/en-us/library/xdkz3x12(v=vs.71).aspx
60  *
61  * @param sig Signal number
62 */
handle_fatal_signal(int sig)63 extern "C" void handle_fatal_signal(int sig)
64 {
65   if (segfaulted)
66   {
67     my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
68     _exit(MYSQLD_FAILURE_EXIT); /* Quit without running destructors */
69   }
70 
71   segfaulted = 1;
72 
73 #ifdef _WIN32
74   SYSTEMTIME utc_time;
75   GetSystemTime(&utc_time);
76   const long hrs=  utc_time.wHour;
77   const long mins= utc_time.wMinute;
78   const long secs= utc_time.wSecond;
79 #else
80   /* Using time() instead of my_time() to avoid looping */
81   const time_t curr_time= time(NULL);
82   /* Calculate time of day */
83   const long tmins = curr_time / 60;
84   const long thrs  = tmins / 60;
85   const long hrs   = thrs  % 24;
86   const long mins  = tmins % 60;
87   const long secs  = curr_time % 60;
88 #endif
89 
90   char hrs_buf[3]= "00";
91   char mins_buf[3]= "00";
92   char secs_buf[3]= "00";
93   my_safe_itoa(10, hrs, &hrs_buf[2]);
94   my_safe_itoa(10, mins, &mins_buf[2]);
95   my_safe_itoa(10, secs, &secs_buf[2]);
96 
97   my_safe_printf_stderr("%s:%s:%s UTC - mysqld got " SIGNAL_FMT " ;\n",
98                         hrs_buf, mins_buf, secs_buf, sig);
99 
100   my_safe_printf_stderr("%s",
101     "This could be because you hit a bug. It is also possible that this binary\n"
102     "or one of the libraries it was linked against is corrupt, improperly built,\n"
103     "or misconfigured. This error can also be caused by malfunctioning hardware.\n");
104 
105   my_safe_printf_stderr("%s",
106     "Attempting to collect some information that could help diagnose the problem.\n"
107     "As this is a crash and something is definitely wrong, the information\n"
108     "collection process might fail.\n"
109     "Please help us make Percona Server better by reporting any\n"
110     "bugs at https://bugs.percona.com/\n\n");
111 
112   my_safe_printf_stderr("key_buffer_size=%lu\n",
113                         (ulong) dflt_key_cache->key_cache_mem_size);
114 
115   my_safe_printf_stderr("read_buffer_size=%ld\n",
116                         (long) global_system_variables.read_buff_size);
117 
118   my_safe_printf_stderr("max_used_connections=%lu\n",
119                         Connection_handler_manager::max_used_connections);
120 
121   uint max_threads= 1;
122 #ifndef EMBEDDED_LIBRARY
123   max_threads= Connection_handler_manager::max_threads;
124 #endif
125   my_safe_printf_stderr("max_threads=%u\n", max_threads +
126                         (uint) extra_max_connections);
127 
128   my_safe_printf_stderr("thread_count=%u\n", Global_THD_manager::global_thd_count);
129 
130   my_safe_printf_stderr("connection_count=%u\n",
131                         Connection_handler_manager::connection_count);
132 
133   my_safe_printf_stderr("It is possible that mysqld could use up to \n"
134                         "key_buffer_size + "
135                         "(read_buffer_size + sort_buffer_size)*max_threads = "
136                         "%lu K  bytes of memory\n",
137                         (ulong)(dflt_key_cache->key_cache_mem_size +
138                          (global_system_variables.read_buff_size +
139                          global_system_variables.sortbuff_size) *
140                           max_threads +
141                          (max_connections + extra_max_connections) * sizeof(THD)) / 1024);
142 
143   my_safe_printf_stderr("%s",
144     "Hope that's ok; if not, decrease some variables in the equation.\n\n");
145 
146   my_safe_printf_stderr("\n");
147 #ifdef __linux__
148   my_print_buildID();
149 #endif
150   my_safe_printf_stderr("Server Version: %s %s\n\n", server_version,
151                         MYSQL_COMPILATION_COMMENT);
152 
153 #ifdef HAVE_STACKTRACE
154   THD *thd= my_thread_get_THR_THD();
155 
156   if (!(test_flags & TEST_NO_STACKTRACE))
157   {
158     my_safe_printf_stderr("Thread pointer: 0x%p\n", thd);
159     my_safe_printf_stderr("%s",
160       "Attempting backtrace. You can use the following "
161       "information to find out\n"
162       "where mysqld died. If you see no messages after this, something went\n"
163       "terribly wrong...\n");
164     my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
165                         my_thread_stack_size);
166   }
167   if (thd)
168   {
169     const char *kreason= "UNKNOWN";
170     switch (thd->killed) {
171     case THD::NOT_KILLED:
172       kreason= "NOT_KILLED";
173       break;
174     case THD::KILL_BAD_DATA:
175       kreason= "KILL_BAD_DATA";
176       break;
177     case THD::KILL_CONNECTION:
178       kreason= "KILL_CONNECTION";
179       break;
180     case THD::KILL_QUERY:
181       kreason= "KILL_QUERY";
182       break;
183     case THD::KILL_TIMEOUT:
184       kreason= "KILL_TIMEOUT";
185       break;
186     case THD::KILLED_NO_VALUE:
187       kreason= "KILLED_NO_VALUE";
188       break;
189     }
190     my_safe_printf_stderr("%s", "\n"
191       "Trying to get some variables.\n"
192       "Some pointers may be invalid and cause the dump to abort.\n");
193 
194     my_safe_printf_stderr("Query (%p): ", thd->query().str);
195     my_safe_puts_stderr(thd->query().str, MY_MIN(1024U, thd->query().length));
196     my_safe_printf_stderr("Connection ID (thread ID): %u\n",
197                           thd->thread_id());
198     my_safe_printf_stderr("Status: %s\n\n", kreason);
199   }
200   my_safe_printf_stderr("%s",
201     "You may download the Percona Server operations manual by visiting\n"
202     "http://www.percona.com/software/percona-server/. You may find information\n"
203     "in the manual which will help you identify the cause of the crash.\n");
204 
205 #endif /* HAVE_STACKTRACE */
206 
207 #ifdef HAVE_INITGROUPS
208   if (calling_initgroups)
209   {
210     my_safe_printf_stderr("%s", "\n"
211       "This crash occured while the server was calling initgroups(). This is\n"
212       "often due to the use of a mysqld that is statically linked against \n"
213       "glibc and configured to use LDAP in /etc/nsswitch.conf.\n"
214       "You will need to either upgrade to a version of glibc that does not\n"
215       "have this problem (2.3.4 or later when used with nscd),\n"
216       "disable LDAP in your nsswitch.conf, or use a "
217       "mysqld that is not statically linked.\n");
218   }
219 #endif
220 
221   if (locked_in_memory)
222   {
223     my_safe_printf_stderr("%s", "\n"
224       "The \"--memlock\" argument, which was enabled, "
225       "uses system calls that are\n"
226       "unreliable and unstable on some operating systems and "
227       "operating-system versions (notably, some versions of Linux).\n"
228       "This crash could be due to use of those buggy OS calls.\n"
229       "You should consider whether you really need the "
230       "\"--memlock\" parameter and/or consult the OS distributer about "
231       "\"mlockall\" bugs.\n");
232   }
233 
234   if (test_flags & TEST_CORE_ON_SIGNAL)
235   {
236 #if HAVE_LIBCOREDUMPER
237     if (opt_libcoredumper)
238     {
239       if (opt_libcoredumper_path != NULL)
240       {
241         if (!validate_libcoredumper_path(opt_libcoredumper_path))
242         {
243           my_safe_printf_stderr("%s", "Changing path to datadir\n");
244           opt_libcoredumper_path= NULL;
245         }
246       }
247       my_safe_printf_stderr("%s",
248                             "Writing a core file using lib coredumper\n");
249       my_write_libcoredumper(sig, opt_libcoredumper_path, curr_time);
250     }
251     else
252     {
253 #endif
254     my_safe_printf_stderr("%s", "Writing a core file\n");
255     my_write_core(sig);
256 #if HAVE_LIBCOREDUMPER
257     }
258 #endif
259   }
260 
261 #ifndef _WIN32
262   /*
263      Quit, without running destructors (etc.)
264      On Windows, do not terminate, but pass control to exception filter.
265   */
266   _exit(MYSQLD_FAILURE_EXIT);  // Using _exit(), since exit() is not async signal safe
267 #endif
268 }
269