mirror of
https://github.com/MariaDB/server.git
synced 2025-01-27 01:04:19 +01:00
314 lines
9.3 KiB
C++
314 lines
9.3 KiB
C++
/* Copyright (c) 2011, 2012, Oracle and/or its affiliates.
|
|
Copyright (c) 2011, 2021, MariaDB Corporation.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
#include "mariadb.h"
|
|
#include "my_dbug.h"
|
|
#include <signal.h>
|
|
|
|
//#include "sys_vars.h"
|
|
#include <keycache.h>
|
|
#include "mysqld.h"
|
|
#include "sql_class.h"
|
|
#include "my_stacktrace.h"
|
|
#include <source_revision.h>
|
|
|
|
#ifdef WITH_WSREP
|
|
#include "wsrep_server_state.h"
|
|
#endif /* WITH_WSREP */
|
|
|
|
#ifdef _WIN32
|
|
#include <crtdbg.h>
|
|
#include <direct.h>
|
|
#define SIGNAL_FMT "exception 0x%x"
|
|
#else
|
|
#define SIGNAL_FMT "signal %d"
|
|
#endif
|
|
|
|
|
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
|
#include <sys/sysctl.h>
|
|
#endif
|
|
|
|
#ifndef PATH_MAX
|
|
#define PATH_MAX 4096
|
|
#endif
|
|
|
|
/*
|
|
We are handling signals/exceptions in this file.
|
|
Any global variables we read should be 'volatile sig_atomic_t'
|
|
to guarantee that we read some consistent value.
|
|
*/
|
|
static volatile sig_atomic_t segfaulted= 0;
|
|
extern ulong max_used_connections;
|
|
extern volatile sig_atomic_t calling_initgroups;
|
|
|
|
extern const char *optimizer_switch_names[];
|
|
|
|
static inline void output_core_info()
|
|
{
|
|
/* proc is optional on some BSDs so it can't hurt to look */
|
|
#if defined(HAVE_READLINK) && !defined(__APPLE__) && !defined(__FreeBSD__)
|
|
char buff[PATH_MAX];
|
|
ssize_t len;
|
|
int fd;
|
|
if ((len= readlink("/proc/self/cwd", buff, sizeof(buff)-1)) >= 0)
|
|
{
|
|
buff[len]= 0;
|
|
my_safe_printf_stderr("Writing a core file...\nWorking directory at %.*s\n",
|
|
(int) len, buff);
|
|
}
|
|
#ifdef __FreeBSD__
|
|
if ((fd= open("/proc/curproc/rlimit", O_RDONLY)) >= 0)
|
|
#else
|
|
if ((fd= open("/proc/self/limits", O_RDONLY)) >= 0)
|
|
#endif
|
|
{
|
|
char *endline= buff;
|
|
ssize_t remain_len= len= read(fd, buff, sizeof(buff));
|
|
close(fd);
|
|
my_safe_printf_stderr("Resource Limits (excludes unlimited resources):\n");
|
|
/* first line, header */
|
|
endline= (char *) memchr(buff, '\n', remain_len);
|
|
if (endline)
|
|
{
|
|
endline++;
|
|
remain_len= buff + len - endline;
|
|
my_safe_printf_stderr("%.*s", (int) (endline - buff), buff);
|
|
|
|
while (remain_len > 27)
|
|
{
|
|
char *newendline= (char *) memchr(endline, '\n', remain_len);
|
|
if (!newendline)
|
|
break;
|
|
*newendline= '\0';
|
|
newendline++;
|
|
if (endline[26] != 'u') /* skip unlimited limits */
|
|
my_safe_printf_stderr("%s\n", endline);
|
|
|
|
remain_len-= newendline - endline;
|
|
endline= newendline;
|
|
}
|
|
}
|
|
}
|
|
#ifdef __linux__
|
|
if ((fd= open("/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0)
|
|
{
|
|
len= read(fd, (uchar*)buff, sizeof(buff));
|
|
my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);
|
|
close(fd);
|
|
}
|
|
if ((fd= open("/proc/version", O_RDONLY)) >= 0)
|
|
{
|
|
len= read(fd, (uchar*)buff, sizeof(buff));
|
|
my_safe_printf_stderr("Kernel version: %.*s\n", (int) len, buff);
|
|
close(fd);
|
|
}
|
|
#endif
|
|
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
|
char buff[PATH_MAX];
|
|
size_t len = sizeof(buff);
|
|
if (sysctlbyname("kern.corefile", buff, &len, NULL, 0) == 0)
|
|
{
|
|
my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff);
|
|
}
|
|
if (sysctlbyname("kern.version", buff, &len, NULL, 0) == 0)
|
|
{
|
|
my_safe_printf_stderr("Kernel version: %.*s\n", (int) len, buff);
|
|
}
|
|
#elif defined(HAVE_GETCWD)
|
|
char buff[80];
|
|
|
|
if (getcwd(buff, sizeof(buff)))
|
|
{
|
|
my_safe_printf_stderr("Writing a core file at %.*s\n", (int) sizeof(buff), buff);
|
|
fflush(stderr);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Handler for fatal signals on POSIX, exception handler on Windows.
|
|
*
|
|
* Fatal events (seg.fault, bus error etc.) will trigger
|
|
* this signal handler. The handler will try to dump relevant
|
|
* debugging information to stderr and dump a core image.
|
|
*
|
|
* POSIX : Signal handlers should, if possible, only use a set of 'safe' system
|
|
* calls and library functions. A list of safe calls in POSIX systems
|
|
* are available at:
|
|
* http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
|
|
*
|
|
* @param sig Signal number /Exception code
|
|
*/
|
|
extern "C" sig_handler handle_fatal_signal(int sig)
|
|
{
|
|
time_t curr_time;
|
|
struct tm tm;
|
|
#ifdef HAVE_STACKTRACE
|
|
THD *thd;
|
|
/*
|
|
This flag remembers if the query pointer was found invalid.
|
|
We will try and print the query at the end of the signal handler, in case
|
|
we're wrong.
|
|
*/
|
|
#endif
|
|
|
|
if (segfaulted)
|
|
{
|
|
my_safe_printf_stderr("Fatal " SIGNAL_FMT " while backtracing\n", sig);
|
|
goto end;
|
|
}
|
|
segfaulted = 1;
|
|
abort_loop= 1; // Disable now connections
|
|
DBUG_PRINT("error", ("handling fatal signal"));
|
|
|
|
curr_time= my_time(0);
|
|
localtime_r(&curr_time, &tm);
|
|
|
|
my_safe_printf_stderr("%02d%02d%02d %2d:%02d:%02d ",
|
|
tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
|
if (opt_expect_abort
|
|
#ifdef _WIN32
|
|
&& sig == (int)EXCEPTION_BREAKPOINT /* __debugbreak in my_sigabrt_hander() */
|
|
#else
|
|
&& sig == SIGABRT
|
|
#endif
|
|
)
|
|
{
|
|
fprintf(stderr,"[Note] mysqld did an expected abort\n");
|
|
goto end;
|
|
}
|
|
|
|
my_safe_printf_stderr("[ERROR] %s got " SIGNAL_FMT " ;\n", my_progname, sig);
|
|
|
|
my_safe_printf_stderr("%s",
|
|
"Sorry, we probably made a mistake, and this is a bug.\n\n"
|
|
"Your assistance in bug reporting will enable us to fix this for the next release.\n"
|
|
"To report this bug, see https://mariadb.com/kb/en/reporting-bugs about how to report\n"
|
|
"a bug on https://jira.mariadb.org/.\n\n"
|
|
"Please include the information from the server start above, to the end of the\n"
|
|
"information below.\n\n");
|
|
|
|
set_server_version(server_version, sizeof(server_version));
|
|
my_safe_printf_stderr("Server version: %s source revision: %s\n\n",
|
|
server_version, SOURCE_REVISION);
|
|
|
|
#ifdef WITH_WSREP
|
|
Wsrep_server_state::handle_fatal_signal();
|
|
#endif /* WITH_WSREP */
|
|
|
|
#ifdef HAVE_STACKTRACE
|
|
thd= current_thd;
|
|
|
|
if (opt_stack_trace)
|
|
{
|
|
my_safe_printf_stderr("%s",
|
|
"The information page at "
|
|
"https://mariadb.com/kb/en/how-to-produce-a-full-stack-trace-for-mariadbd/\n"
|
|
"contains instructions to obtain a better version of the backtrace below.\n"
|
|
"Following these instructions will help MariaDB developers provide a fix quicker.\n\n"
|
|
"Attempting backtrace. Include this in the bug report.\n"
|
|
"(note: Retrieving this information may fail)\n\n");
|
|
my_safe_printf_stderr("Thread pointer: %p\n", thd);
|
|
my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
|
|
(ulong)my_thread_stack_size, 0);
|
|
}
|
|
if (thd)
|
|
{
|
|
const char *kreason= "UNKNOWN";
|
|
switch (thd->killed) {
|
|
case NOT_KILLED:
|
|
case KILL_HARD_BIT:
|
|
kreason= "NOT_KILLED";
|
|
break;
|
|
case KILL_BAD_DATA:
|
|
case KILL_BAD_DATA_HARD:
|
|
kreason= "KILL_BAD_DATA";
|
|
break;
|
|
case KILL_CONNECTION:
|
|
case KILL_CONNECTION_HARD:
|
|
kreason= "KILL_CONNECTION";
|
|
break;
|
|
case KILL_QUERY:
|
|
case KILL_QUERY_HARD:
|
|
kreason= "KILL_QUERY";
|
|
break;
|
|
case KILL_TIMEOUT:
|
|
case KILL_TIMEOUT_HARD:
|
|
kreason= "KILL_TIMEOUT";
|
|
break;
|
|
case KILL_SYSTEM_THREAD:
|
|
case KILL_SYSTEM_THREAD_HARD:
|
|
kreason= "KILL_SYSTEM_THREAD";
|
|
break;
|
|
case KILL_SERVER:
|
|
case KILL_SERVER_HARD:
|
|
kreason= "KILL_SERVER";
|
|
break;
|
|
case ABORT_QUERY:
|
|
case ABORT_QUERY_HARD:
|
|
kreason= "ABORT_QUERY";
|
|
break;
|
|
case KILL_SLAVE_SAME_ID:
|
|
kreason= "KILL_SLAVE_SAME_ID";
|
|
break;
|
|
case KILL_WAIT_TIMEOUT:
|
|
case KILL_WAIT_TIMEOUT_HARD:
|
|
kreason= "KILL_WAIT_TIMEOUT";
|
|
break;
|
|
}
|
|
|
|
my_safe_printf_stderr("\nConnection ID (thread ID): %lu\n",
|
|
(ulong) thd->thread_id);
|
|
my_safe_printf_stderr("Status: %s\n", kreason);
|
|
my_safe_printf_stderr("Query (%p): ", thd->query());
|
|
my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length()));
|
|
my_safe_printf_stderr("%s", "Optimizer switch: ");
|
|
ulonglong optsw= thd->variables.optimizer_switch;
|
|
for (uint i= 0; optimizer_switch_names[i+1]; i++, optsw >>= 1)
|
|
{
|
|
if (i)
|
|
my_safe_printf_stderr("%s", ",");
|
|
my_safe_printf_stderr("%s=%s",
|
|
optimizer_switch_names[i], optsw & 1 ? "on" : "off");
|
|
}
|
|
my_safe_printf_stderr("%s", "\n\n");
|
|
}
|
|
|
|
#endif /* HAVE_STACKTRACE */
|
|
|
|
output_core_info();
|
|
#ifdef HAVE_WRITE_CORE
|
|
if (test_flags & TEST_CORE_ON_SIGNAL)
|
|
{
|
|
my_write_core(sig);
|
|
}
|
|
#endif
|
|
|
|
end:
|
|
#ifndef _WIN32
|
|
/*
|
|
Quit, without running destructors (etc.)
|
|
Use a signal, because the parent (systemd) can check that with WIFSIGNALED
|
|
On Windows, do not terminate, but pass control to exception filter.
|
|
*/
|
|
signal(sig, SIG_DFL);
|
|
kill(getpid(), sig);
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|