Commit b522a6ce authored by Tor Didriksen's avatar Tor Didriksen

Bug#11761576 54082: HANDLE_SEGFAULT MAKES USE OF UNSAFE FUNCTIONS

handle_segfault is the signal handler code of mysqld.  however, it makes
calls to potentially unsafe functions localtime_r, fprintf, fflush.



include/my_stacktrace.h:
  Add safe versions of itoa() write() and snprintf().
libmysqld/CMakeLists.txt:
  Move signal handler to separate file.
mysys/stacktrace.c:
  Remove unsafe function calls.
sql/CMakeLists.txt:
  Move signal handler to separate file.
sql/mysqld.cc:
  Move signal handler to separate file.
sql/set_var.h:
  Add missing #include dependency.
sql/sys_vars.cc:
  Cleanup .h and .cc files.
sql/sys_vars.h:
  Cleanup .h and .cc files.
parent 8e6d41e2
/* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -59,6 +59,69 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep); ...@@ -59,6 +59,69 @@ void my_set_exception_pointers(EXCEPTION_POINTERS *ep);
void my_write_core(int sig); void my_write_core(int sig);
#endif #endif
/**
Async-signal-safe utility functions used by signal handler routines.
Declared here in order to unit-test them.
These are not general-purpose, but tailored to the signal handling routines.
*/
/**
Converts a longlong value to string.
@param base 10 for decimal, 16 for hex values (0..9a..f)
@param val The value to convert
@param buf Assumed to point to the *end* of the buffer.
@returns Pointer to the first character of the converted string.
Negative values:
for base-10 the return string will be prepended with '-'
for base-16 the return string will contain 16 characters
Implemented with simplicity, and async-signal-safety in mind.
*/
char *my_safe_itoa(int base, longlong val, char *buf);
/**
Converts a ulonglong value to string.
@param base 10 for decimal, 16 for hex values (0..9a..f)
@param val The value to convert
@param buf Assumed to point to the *end* of the buffer.
@returns Pointer to the first character of the converted string.
Implemented with simplicity, and async-signal-safety in mind.
*/
char *my_safe_utoa(int base, ulonglong val, char *buf);
/**
A (very) limited version of snprintf.
@param to Destination buffer.
@param n Size of destination buffer.
@param fmt printf() style format string.
@returns Number of bytes written, including terminating '\0'
Supports 'd' 'i' 'u' 'x' 'p' 's' conversion.
Supports 'l' and 'll' modifiers for integral types.
Does not support any width/precision.
Implemented with simplicity, and async-signal-safety in mind.
*/
size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...)
ATTRIBUTE_FORMAT(printf, 3, 4);
/**
A (very) limited version of snprintf, which writes the result to STDERR.
@sa my_safe_snprintf
Implemented with simplicity, and async-signal-safety in mind.
@note Has an internal buffer capacity of 512 bytes,
which should suffice for our signal handling routines.
*/
size_t my_safe_printf_stderr(const char* fmt, ...)
ATTRIBUTE_FORMAT(printf, 1, 2);
/**
Writes up to count bytes from buffer to STDERR.
Implemented with simplicity, and async-signal-safety in mind.
@param buf Buffer containing data to be written.
@param count Number of bytes to write.
@returns Number of bytes written.
*/
size_t my_write_stderr(const void *buf, size_t count);
C_MODE_END C_MODE_END
#endif /* _my_stacktrace_h_ */ #endif /* _my_stacktrace_h_ */
...@@ -45,6 +45,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ...@@ -45,6 +45,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/password.c ../sql/discover.cc ../sql/derror.cc ../sql/password.c ../sql/discover.cc ../sql/derror.cc
../sql/field.cc ../sql/field_conv.cc ../sql/field.cc ../sql/field_conv.cc
../sql/filesort.cc ../sql/gstream.cc ../sql/filesort.cc ../sql/gstream.cc
../sql/signal_handler.cc
../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc ../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc
../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc ../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc
../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc ../sql/item.cc ../sql/item_create.cc ../sql/item_func.cc
......
...@@ -52,10 +52,11 @@ void my_init_stacktrace() ...@@ -52,10 +52,11 @@ void my_init_stacktrace()
static void print_buffer(char *buffer, size_t count) static void print_buffer(char *buffer, size_t count)
{ {
const char s[]= " ";
for (; count && *buffer; --count) for (; count && *buffer; --count)
{ {
int c= (int) *buffer++; my_write_stderr(isprint(*buffer) ? buffer : s, 1);
fputc(isprint(c) ? c : ' ', stderr); ++buffer;
} }
} }
...@@ -119,10 +120,10 @@ static int safe_print_str(const char *addr, int max_len) ...@@ -119,10 +120,10 @@ static int safe_print_str(const char *addr, int max_len)
/* Output a new line if something was printed. */ /* Output a new line if something was printed. */
if (total != (size_t) max_len) if (total != (size_t) max_len)
fputc('\n', stderr); my_safe_printf_stderr("%s", "\n");
if (nbytes == -1) if (nbytes == -1)
fprintf(stderr, "Can't read from address %p: %m.\n", addr); my_safe_printf_stderr("Can't read from address %p\n", addr);
close(fd); close(fd);
...@@ -144,13 +145,13 @@ void my_safe_print_str(const char* val, int max_len) ...@@ -144,13 +145,13 @@ void my_safe_print_str(const char* val, int max_len)
if (!PTR_SANE(val)) if (!PTR_SANE(val))
{ {
fprintf(stderr, "is an invalid pointer\n"); my_safe_printf_stderr("%s", "is an invalid pointer\n");
return; return;
} }
for (; max_len && PTR_SANE(val) && *val; --max_len) for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr); my_write_stderr((val++), 1);
fputc('\n', stderr); my_safe_printf_stderr("%s", "\n");
} }
#if defined(HAVE_PRINTSTACK) #if defined(HAVE_PRINTSTACK)
...@@ -162,9 +163,10 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)), ...@@ -162,9 +163,10 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
ulong thread_stack __attribute__((unused))) ulong thread_stack __attribute__((unused)))
{ {
if (printstack(fileno(stderr)) == -1) if (printstack(fileno(stderr)) == -1)
fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n"); my_safe_printf_stderr("%s",
"Error when traversing the stack, stack appears corrupt.\n");
else else
fprintf(stderr, my_safe_printf_stderr("%s"
"Please read " "Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" "http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n" "and follow instructions on how to resolve the stack trace.\n"
...@@ -207,9 +209,9 @@ static void my_demangle_symbols(char **addrs, int n) ...@@ -207,9 +209,9 @@ static void my_demangle_symbols(char **addrs, int n)
} }
if (demangled) if (demangled)
fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); my_safe_printf_stderr("%s(%s+%s\n", addrs[i], demangled, end);
else else
fprintf(stderr, "%s\n", addrs[i]); my_safe_printf_stderr("%s\n", addrs[i]);
} }
} }
...@@ -220,7 +222,7 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) ...@@ -220,7 +222,7 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
void *addrs[128]; void *addrs[128];
char **strings= NULL; char **strings= NULL;
int n = backtrace(addrs, array_elements(addrs)); int n = backtrace(addrs, array_elements(addrs));
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n", my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack); stack_bottom, thread_stack);
#if BACKTRACE_DEMANGLE #if BACKTRACE_DEMANGLE
if ((strings= backtrace_symbols(addrs, n))) if ((strings= backtrace_symbols(addrs, n)))
...@@ -314,8 +316,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) ...@@ -314,8 +316,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
#endif #endif
if (!fp) if (!fp)
{ {
fprintf(stderr, "frame pointer is NULL, did you compile with\n\ my_safe_printf_stderr("%s",
-fomit-frame-pointer? Aborting backtrace!\n"); "frame pointer is NULL, did you compile with\n"
"-fomit-frame-pointer? Aborting backtrace!\n");
return; return;
} }
...@@ -323,24 +326,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) ...@@ -323,24 +326,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{ {
ulong tmp= min(0x10000,thread_stack); ulong tmp= min(0x10000,thread_stack);
/* Assume that the stack starts at the previous even 65K */ /* Assume that the stack starts at the previous even 65K */
stack_bottom= (uchar*) (((ulong) &fp + tmp) & stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF);
~(ulong) 0xFFFF); my_safe_printf_stderr("Cannot determine thread, fp=%p, "
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); "backtrace may not be correct.\n", fp);
} }
if (fp > (uchar**) stack_bottom || if (fp > (uchar**) stack_bottom ||
fp < (uchar**) stack_bottom - thread_stack) fp < (uchar**) stack_bottom - thread_stack)
{ {
fprintf(stderr, "Bogus stack limit or frame pointer,\ my_safe_printf_stderr("Bogus stack limit or frame pointer, "
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", "fp=%p, stack_bottom=%p, thread_stack=%ld, "
"aborting backtrace.\n",
fp, stack_bottom, thread_stack); fp, stack_bottom, thread_stack);
return; return;
} }
fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); my_safe_printf_stderr("%s",
"Stack range sanity check OK, backtrace follows:\n");
#if defined(__alpha__) && defined(__GNUC__) #if defined(__alpha__) && defined(__GNUC__)
fprintf(stderr, "Warning: Alpha stacks are difficult -\ my_safe_printf_stderr("%s",
will be taking some wild guesses, stack trace may be incorrect or \ "Warning: Alpha stacks are difficult -"
terminate abruptly\n"); "will be taking some wild guesses, stack trace may be incorrect or "
"terminate abruptly\n");
/* On Alpha, we need to get pc */ /* On Alpha, we need to get pc */
__asm __volatile__ ("bsr %0, do_next; do_next: " __asm __volatile__ ("bsr %0, do_next; do_next: "
:"=r"(pc) :"=r"(pc)
...@@ -354,7 +361,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) ...@@ -354,7 +361,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{ {
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
uchar** new_fp = (uchar**)*fp; uchar** new_fp = (uchar**)*fp;
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ? my_safe_printf_stderr("%p\n",
frame_count == sigreturn_frame_count ?
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1)); *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
#endif /* defined(__386__) || defined(__x86_64__) */ #endif /* defined(__386__) || defined(__x86_64__) */
...@@ -369,35 +377,37 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) ...@@ -369,35 +377,37 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{ {
pc = find_prev_pc(pc, fp); pc = find_prev_pc(pc, fp);
if (pc) if (pc)
fprintf(stderr, "%p\n", pc); my_safe_printf_stderr("%p\n", pc);
else else
{ {
fprintf(stderr, "Not smart enough to deal with the rest\ my_safe_printf_stderr("%s",
of this stack\n"); "Not smart enough to deal with the rest of this stack\n");
goto end; goto end;
} }
} }
else else
{ {
fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); my_safe_printf_stderr("%s",
"Not smart enough to deal with the rest of this stack\n");
goto end; goto end;
} }
#endif /* defined(__alpha__) && defined(__GNUC__) */ #endif /* defined(__alpha__) && defined(__GNUC__) */
if (new_fp <= fp ) if (new_fp <= fp )
{ {
fprintf(stderr, "New value of fp=%p failed sanity check,\ my_safe_printf_stderr("New value of fp=%p failed sanity check, "
terminating stack trace!\n", new_fp); "terminating stack trace!\n", new_fp);
goto end; goto end;
} }
fp = new_fp; fp = new_fp;
++frame_count; ++frame_count;
} }
my_safe_printf_stderr("%s",
fprintf(stderr, "Stack trace seems successful - bottom reached\n"); "Stack trace seems successful - bottom reached\n");
end: end:
fprintf(stderr, my_safe_printf_stderr("%s",
"Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n" "Please read "
"http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
"and follow instructions on how to resolve the stack trace.\n" "and follow instructions on how to resolve the stack trace.\n"
"Resolved stack trace is much more helpful in diagnosing the\n" "Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n"); "problem, so please do resolve it\n");
...@@ -618,7 +628,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) ...@@ -618,7 +628,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
&(package.sym)); &(package.sym));
have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line); have_source= SymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
fprintf(stderr, "%p ", addr); my_safe_printf_stderr("%p ", addr);
if(have_module) if(have_module)
{ {
char *base_image_name= strrchr(module.ImageName, '\\'); char *base_image_name= strrchr(module.ImageName, '\\');
...@@ -626,12 +636,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) ...@@ -626,12 +636,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_image_name++; base_image_name++;
else else
base_image_name= module.ImageName; base_image_name= module.ImageName;
fprintf(stderr, "%s!", base_image_name); my_safe_printf_stderr("%s!", base_image_name);
} }
if(have_symbol) if(have_symbol)
fprintf(stderr, "%s()", package.sym.Name); my_safe_printf_stderr("%s()", package.sym.Name);
else if(have_module) else if(have_module)
fprintf(stderr, "???"); my_safe_printf_stderr("%s", "???");
if(have_source) if(have_source)
{ {
...@@ -640,11 +651,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2) ...@@ -640,11 +651,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_file_name++; base_file_name++;
else else
base_file_name= line.FileName; base_file_name= line.FileName;
fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); my_safe_printf_stderr("[%s:%u]",
base_file_name, line.LineNumber);
} }
fprintf(stderr, "\n"); my_safe_printf_stderr("%s", "\n");
} }
fflush(stderr);
} }
...@@ -681,22 +692,22 @@ void my_write_core(int unused) ...@@ -681,22 +692,22 @@ void my_write_core(int unused)
if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), if(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpNormal, &info, 0, 0)) hFile, MiniDumpNormal, &info, 0, 0))
{ {
fprintf(stderr, "Minidump written to %s\n", my_safe_printf_stderr("Minidump written to %s\n",
_fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); _fullpath(path, dump_fname, sizeof(path)) ?
path : dump_fname);
} }
else else
{ {
fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n",
GetLastError()); (uint) GetLastError());
} }
CloseHandle(hFile); CloseHandle(hFile);
} }
else else
{ {
fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n",
GetLastError()); dump_fname, (uint) GetLastError());
} }
fflush(stderr);
} }
...@@ -704,11 +715,212 @@ void my_safe_print_str(const char *val, int len) ...@@ -704,11 +715,212 @@ void my_safe_print_str(const char *val, int len)
{ {
__try __try
{ {
fprintf(stderr, "%.*s\n", len, val); my_write_stderr(val, len);
} }
__except(EXCEPTION_EXECUTE_HANDLER) __except(EXCEPTION_EXECUTE_HANDLER)
{ {
fprintf(stderr, "is an invalid string pointer\n"); my_safe_printf_stderr("%s", "is an invalid string pointer\n");
} }
} }
#endif /*__WIN__*/ #endif /*__WIN__*/
#ifdef __WIN__
size_t my_write_stderr(const void *buf, size_t count)
{
DWORD bytes_written;
SetFilePointer(GetStdHandle(STD_ERROR_HANDLE), 0, NULL, FILE_END);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, count, &bytes_written, NULL);
return bytes_written;
}
#else
size_t my_write_stderr(const void *buf, size_t count)
{
return (size_t) write(STDERR_FILENO, buf, count);
}
#endif
static const char digits[]= "0123456789abcdef";
char *my_safe_utoa(int base, ulonglong val, char *buf)
{
*buf--= 0;
do {
*buf--= digits[val % base];
} while ((val /= base) != 0);
return buf + 1;
}
char *my_safe_itoa(int base, longlong val, char *buf)
{
char *orig_buf= buf;
const my_bool is_neg= (val < 0);
*buf--= 0;
if (is_neg)
val= -val;
if (is_neg && base == 16)
{
int ix;
val-= 1;
for (ix= 0; ix < 16; ++ix)
buf[-ix]= '0';
}
do {
*buf--= digits[val % base];
} while ((val /= base) != 0);
if (is_neg && base == 10)
*buf--= '-';
if (is_neg && base == 16)
{
int ix;
buf= orig_buf - 1;
for (ix= 0; ix < 16; ++ix, --buf)
{
switch (*buf)
{
case '0': *buf= 'f'; break;
case '1': *buf= 'e'; break;
case '2': *buf= 'd'; break;
case '3': *buf= 'c'; break;
case '4': *buf= 'b'; break;
case '5': *buf= 'a'; break;
case '6': *buf= '9'; break;
case '7': *buf= '8'; break;
case '8': *buf= '7'; break;
case '9': *buf= '6'; break;
case 'a': *buf= '5'; break;
case 'b': *buf= '4'; break;
case 'c': *buf= '3'; break;
case 'd': *buf= '2'; break;
case 'e': *buf= '1'; break;
case 'f': *buf= '0'; break;
}
}
}
return buf+1;
}
static const char *check_longlong(const char *fmt, my_bool *have_longlong)
{
*have_longlong= FALSE;
if (*fmt == 'l')
{
fmt++;
if (*fmt != 'l')
*have_longlong= (sizeof(long) == sizeof(longlong));
else
{
fmt++;
*have_longlong= TRUE;
}
}
return fmt;
}
static size_t my_safe_vsnprintf(char *to, size_t size,
const char* format, va_list ap)
{
char *start= to;
char *end= start + size - 1;
for (; *format; ++format)
{
my_bool have_longlong = FALSE;
if (*format != '%')
{
if (to == end) /* end of buffer */
break;
*to++= *format; /* copy ordinary char */
continue;
}
++format; /* skip '%' */
format= check_longlong(format, &have_longlong);
switch (*format)
{
case 'd':
case 'i':
case 'u':
case 'x':
case 'p':
{
longlong ival= 0;
ulonglong uval = 0;
if (*format == 'p')
have_longlong= (sizeof(void *) == sizeof(longlong));
if (have_longlong)
{
if (*format == 'u')
uval= va_arg(ap, ulonglong);
else
ival= va_arg(ap, longlong);
}
else
{
if (*format == 'u')
uval= va_arg(ap, unsigned int);
else
ival= va_arg(ap, int);
}
{
char buff[22];
const int base= (*format == 'x' || *format == 'p') ? 16 : 10;
char *val_as_str= (*format == 'u') ?
my_safe_utoa(base, uval, &buff[sizeof(buff)-1]) :
my_safe_itoa(base, ival, &buff[sizeof(buff)-1]);
/* Strip off "ffffffff" if we have 'x' format without 'll' */
if (*format == 'x' && !have_longlong && ival < 0)
val_as_str+= 8;
while (*val_as_str && to < end)
*to++= *val_as_str++;
continue;
}
}
case 's':
{
const char *val= va_arg(ap, char*);
if (!val)
val= "(null)";
while (*val && to < end)
*to++= *val++;
continue;
}
}
}
*to= 0;
return to - start;
}
size_t my_safe_snprintf(char* to, size_t n, const char* fmt, ...)
{
size_t result;
va_list args;
va_start(args,fmt);
result= my_safe_vsnprintf(to, n, fmt, args);
va_end(args);
return result;
}
size_t my_safe_printf_stderr(const char* fmt, ...)
{
char to[512];
size_t result;
va_list args;
va_start(args,fmt);
result= my_safe_vsnprintf(to, sizeof(to), fmt, args);
va_end(args);
my_write_stderr(to, result);
return result;
}
...@@ -41,6 +41,7 @@ SET (SQL_SOURCE ...@@ -41,6 +41,7 @@ SET (SQL_SOURCE
../sql-common/client.c derror.cc des_key_file.cc ../sql-common/client.c derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
filesort.cc gstream.cc sha2.cc filesort.cc gstream.cc sha2.cc
signal_handler.cc
handler.cc hash_filo.h sql_plugin_services.h handler.cc hash_filo.h sql_plugin_services.h
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
item_create.cc item_func.cc item_geofunc.cc item_row.cc item_create.cc item_func.cc item_geofunc.cc item_row.cc
......
...@@ -144,9 +144,6 @@ extern "C" { // Because of SCO 3.2V4.2 ...@@ -144,9 +144,6 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef __WIN__ #ifdef __WIN__
#include <crtdbg.h> #include <crtdbg.h>
#define SIGNAL_FMT "exception 0x%x"
#else
#define SIGNAL_FMT "signal %d"
#endif #endif
#ifdef HAVE_SOLARIS_LARGE_PAGES #ifdef HAVE_SOLARIS_LARGE_PAGES
...@@ -256,7 +253,7 @@ inline void setup_fpu() ...@@ -256,7 +253,7 @@ inline void setup_fpu()
extern "C" int gethostname(char *name, int namelen); extern "C" int gethostname(char *name, int namelen);
#endif #endif
extern "C" sig_handler handle_segfault(int sig); extern "C" sig_handler handle_fatal_signal(int sig);
#if defined(__linux__) #if defined(__linux__)
#define ENABLE_TEMP_POOL 1 #define ENABLE_TEMP_POOL 1
...@@ -323,6 +320,10 @@ static PSI_rwlock_key key_rwlock_openssl; ...@@ -323,6 +320,10 @@ static PSI_rwlock_key key_rwlock_openssl;
#endif #endif
#endif /* HAVE_PSI_INTERFACE */ #endif /* HAVE_PSI_INTERFACE */
#ifdef HAVE_NPTL
volatile sig_atomic_t ld_assume_kernel_is_set= 0;
#endif
/* the default log output is log tables */ /* the default log output is log tables */
static bool lower_case_table_names_used= 0; static bool lower_case_table_names_used= 0;
static bool max_long_data_size_used= false; static bool max_long_data_size_used= false;
...@@ -333,7 +334,7 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; ...@@ -333,7 +334,7 @@ static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0; static my_bool opt_short_log_format= 0;
static uint kill_cached_threads, wake_thread; static uint kill_cached_threads, wake_thread;
static ulong killed_threads; static ulong killed_threads;
static ulong max_used_connections; ulong max_used_connections;
static volatile ulong cached_thread_count= 0; static volatile ulong cached_thread_count= 0;
static char *mysqld_user, *mysqld_chroot; static char *mysqld_user, *mysqld_chroot;
static char *default_character_set_name; static char *default_character_set_name;
...@@ -442,7 +443,7 @@ my_bool sp_automatic_privileges= 1; ...@@ -442,7 +443,7 @@ my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size; ulong opt_binlog_rows_event_max_size;
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS}; const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
#ifdef HAVE_INITGROUPS #ifdef HAVE_INITGROUPS
static bool calling_initgroups= FALSE; /**< Used in SIGSEGV handler. */ volatile sig_atomic_t calling_initgroups= 0; /**< Used in SIGSEGV handler. */
#endif #endif
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint mysqld_port_timeout; uint mysqld_port_timeout;
...@@ -656,7 +657,9 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname; ...@@ -656,7 +657,9 @@ char *opt_logname, *opt_slow_logname, *opt_bin_logname;
/* Static variables */ /* Static variables */
static bool kill_in_progress, segfaulted; static volatile sig_atomic_t kill_in_progress;
static my_bool opt_bootstrap, opt_myisam_log; static my_bool opt_bootstrap, opt_myisam_log;
static int cleanup_done; static int cleanup_done;
static ulong opt_specialflag; static ulong opt_specialflag;
...@@ -1703,9 +1706,9 @@ static void set_user(const char *user, struct passwd *user_info_arg) ...@@ -1703,9 +1706,9 @@ static void set_user(const char *user, struct passwd *user_info_arg)
calling_initgroups as a flag to the SIGSEGV handler that is then used to calling_initgroups as a flag to the SIGSEGV handler that is then used to
output a specific message to help the user resolve this problem. output a specific message to help the user resolve this problem.
*/ */
calling_initgroups= TRUE; calling_initgroups= 1;
initgroups((char*) user, user_info_arg->pw_gid); initgroups((char*) user, user_info_arg->pw_gid);
calling_initgroups= FALSE; calling_initgroups= 0;
#endif #endif
if (setgid(user_info_arg->pw_gid) == -1) if (setgid(user_info_arg->pw_gid) == -1)
{ {
...@@ -2335,7 +2338,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) ...@@ -2335,7 +2338,7 @@ LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
__try __try
{ {
my_set_exception_pointers(ex_pointers); my_set_exception_pointers(ex_pointers);
handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); handle_fatal_signal(ex_pointers->ExceptionRecord->ExceptionCode);
} }
__except(EXCEPTION_EXECUTE_HANDLER) __except(EXCEPTION_EXECUTE_HANDLER)
{ {
...@@ -2409,161 +2412,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status) ...@@ -2409,161 +2412,6 @@ extern "C" char *my_demangle(const char *mangled_name, int *status)
#endif #endif
extern "C" sig_handler handle_segfault(int sig)
{
time_t curr_time;
struct tm tm;
/*
Strictly speaking, one needs a mutex here
but since we have got SIGSEGV already, things are a mess
so not having the mutex is not as bad as possibly using a buggy
mutex - so we keep things simple
*/
if (segfaulted)
{
fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
exit(1);
}
segfaulted = 1;
curr_time= my_time(0);
localtime_r(&curr_time, &tm);
fprintf(stderr,"\
%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
tm.tm_year % 100, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
sig);
fprintf(stderr, "\
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
fprintf(stderr, "key_buffer_size=%lu\n",
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
fprintf(stderr, "max_threads=%u\n", thread_scheduler->max_threads);
fprintf(stderr, "thread_count=%u\n", thread_count);
fprintf(stderr, "connection_count=%u\n", connection_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
thread_scheduler->max_threads +
max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
fprintf(stderr, "\
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
thread_count);
}
#endif /* HAVE_LINUXTHREADS */
#ifdef HAVE_STACKTRACE
THD *thd=current_thd;
if (!(test_flags & TEST_NO_STACKTRACE))
{
fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd);
fprintf(stderr, "Attempting backtrace. You can use the following "
"information to find out\nwhere mysqld died. If "
"you see no messages after this, something went\n"
"terribly wrong...\n");
my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL,
my_thread_stack_size);
}
if (thd)
{
const char *kreason= "UNKNOWN";
switch (thd->killed) {
case THD::NOT_KILLED:
kreason= "NOT_KILLED";
break;
case THD::KILL_BAD_DATA:
kreason= "KILL_BAD_DATA";
break;
case THD::KILL_CONNECTION:
kreason= "KILL_CONNECTION";
break;
case THD::KILL_QUERY:
kreason= "KILL_QUERY";
break;
case THD::KILLED_NO_VALUE:
kreason= "KILLED_NO_VALUE";
break;
}
fprintf(stderr, "\nTrying to get some variables.\n"
"Some pointers may be invalid and cause the dump to abort.\n");
fprintf(stderr, "Query (%p): ", thd->query());
my_safe_print_str(thd->query(), min(1024, thd->query_length()));
fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id);
fprintf(stderr, "Status: %s\n", kreason);
fputc('\n', stderr);
}
fprintf(stderr, "\
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
fflush(stderr);
#endif /* HAVE_STACKTRACE */
#ifdef HAVE_INITGROUPS
if (calling_initgroups)
fprintf(stderr, "\n\
This crash occured while the server was calling initgroups(). This is\n\
often due to the use of a mysqld that is statically linked against glibc\n\
and configured to use LDAP in /etc/nsswitch.conf. You will need to either\n\
upgrade to a version of glibc that does not have this problem (2.3.4 or\n\
later when used with nscd), disable LDAP in your nsswitch.conf, or use a\n\
mysqld that is not statically linked.\n");
#endif
#ifdef HAVE_NPTL
if (thd_lib_detected == THD_LIB_LT && !getenv("LD_ASSUME_KERNEL"))
fprintf(stderr,"\n\
You are running a statically-linked LinuxThreads binary on an NPTL system.\n\
This can result in crashes on some distributions due to LT/NPTL conflicts.\n\
You should either build a dynamically-linked binary, or force LinuxThreads\n\
to be used with the LD_ASSUME_KERNEL environment variable. Please consult\n\
the documentation for your distribution on how to do that.\n");
#endif
if (locked_in_memory)
{
fprintf(stderr, "\n\
The \"--memlock\" argument, which was enabled, uses system calls that are\n\
unreliable and unstable on some operating systems and operating-system\n\
versions (notably, some versions of Linux). This crash could be due to use\n\
of those buggy OS calls. You should consider whether you really need the\n\
\"--memlock\" parameter and/or consult the OS distributer about \"mlockall\"\n\
bugs.\n");
}
#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
fprintf(stderr, "Writing a core file\n");
fflush(stderr);
my_write_core(sig);
}
#endif
#ifndef __WIN__
/* On Windows, do not terminate, but pass control to exception filter */
exit(1);
#endif
}
#if !defined(__WIN__) #if !defined(__WIN__)
#ifndef SA_RESETHAND #ifndef SA_RESETHAND
...@@ -2593,9 +2441,9 @@ static void init_signals(void) ...@@ -2593,9 +2441,9 @@ static void init_signals(void)
my_init_stacktrace(); my_init_stacktrace();
#endif #endif
#if defined(__amiga__) #if defined(__amiga__)
sa.sa_handler=(void(*)())handle_segfault; sa.sa_handler=(void(*)())handle_fatal_signal;
#else #else
sa.sa_handler=handle_segfault; sa.sa_handler=handle_fatal_signal;
#endif #endif
sigaction(SIGSEGV, &sa, NULL); sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGABRT, &sa, NULL); sigaction(SIGABRT, &sa, NULL);
...@@ -4282,6 +4130,9 @@ int mysqld_main(int argc, char **argv) ...@@ -4282,6 +4130,9 @@ int mysqld_main(int argc, char **argv)
to be able to read defaults files and parse options. to be able to read defaults files and parse options.
*/ */
my_progname= argv[0]; my_progname= argv[0];
#ifdef HAVE_NPTL
ld_assume_kernel_is_set= (getenv("LD_ASSUME_KERNEL") != 0);
#endif
#ifndef _WIN32 #ifndef _WIN32
// For windows, my_init() is called from the win specific mysqld_main // For windows, my_init() is called from the win specific mysqld_main
if (my_init()) // init my_sys library & pthreads if (my_init()) // init my_sys library & pthreads
...@@ -6778,7 +6629,7 @@ static int mysql_init_variables(void) ...@@ -6778,7 +6629,7 @@ static int mysql_init_variables(void)
opt_secure_auth= 0; opt_secure_auth= 0;
opt_bootstrap= opt_myisam_log= 0; opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0; mqh_used= 0;
segfaulted= kill_in_progress= 0; kill_in_progress= 0;
cleanup_done= 0; cleanup_done= 0;
server_id_supplied= 0; server_id_supplied= 0;
test_flags= select_errors= dropping_tables= ha_open_options=0; test_flags= select_errors= dropping_tables= ha_open_options=0;
......
...@@ -34,6 +34,7 @@ class Item_func_set_user_var; ...@@ -34,6 +34,7 @@ class Item_func_set_user_var;
// This include needs to be here since item.h requires enum_var_type :-P // This include needs to be here since item.h requires enum_var_type :-P
#include "item.h" /* Item */ #include "item.h" /* Item */
#include "sql_class.h" /* THD */
extern TYPELIB bool_typelib; extern TYPELIB bool_typelib;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "my_global.h" #include "my_global.h"
#include <signal.h> #include <signal.h>
#include "mysql_priv.h" #include "sys_vars.h"
#include "my_stacktrace.h" #include "my_stacktrace.h"
#ifdef __WIN__ #ifdef __WIN__
...@@ -111,7 +111,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) ...@@ -111,7 +111,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
(ulong) max_used_connections); (ulong) max_used_connections);
my_safe_printf_stderr("max_threads=%u\n", my_safe_printf_stderr("max_threads=%u\n",
(uint) thread_scheduler.max_threads); (uint) thread_scheduler->max_threads);
my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count); my_safe_printf_stderr("thread_count=%u\n", (uint) thread_count);
...@@ -124,7 +124,7 @@ extern "C" sig_handler handle_fatal_signal(int sig) ...@@ -124,7 +124,7 @@ extern "C" sig_handler handle_fatal_signal(int sig)
((ulong) dflt_key_cache->key_cache_mem_size + ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size + (global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) * global_system_variables.sortbuff_size) *
thread_scheduler.max_threads + thread_scheduler->max_threads +
max_connections * sizeof(THD)) / 1024); max_connections * sizeof(THD)) / 1024);
my_safe_printf_stderr("%s", my_safe_printf_stderr("%s",
......
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#include "../storage/perfschema/pfs_server.h" #include "../storage/perfschema/pfs_server.h"
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */
TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
/* /*
This forward declaration is needed because including sql_base.h This forward declaration is needed because including sql_base.h
causes further includes. [TODO] Eliminate this forward declaration causes further includes. [TODO] Eliminate this forward declaration
...@@ -56,6 +58,77 @@ ...@@ -56,6 +58,77 @@
*/ */
extern void close_thread_tables(THD *thd); extern void close_thread_tables(THD *thd);
static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache,
ptrdiff_t offset, ulonglong new_value)
{
bool error= false;
DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size));
if (new_value == 0)
{
if (key_cache == dflt_key_cache)
{
my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
return true;
}
if (key_cache->key_cache_inited) // If initied
{
/*
Move tables using this key cache to the default key cache
and clear the old key cache.
*/
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
key_cache->param_buff_size= 0;
ha_resize_key_cache(key_cache);
ha_change_key_cache(key_cache, dflt_key_cache);
/*
We don't delete the key cache as some running threads my still be in
the key cache code with a pointer to the deleted (empty) key cache
*/
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
}
return error;
}
key_cache->param_buff_size= new_value;
/* If key cache didn't exist initialize it, else resize it */
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
if (!key_cache->key_cache_inited)
error= ha_init_key_cache(0, key_cache);
else
error= ha_resize_key_cache(key_cache);
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
return error;
}
static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache,
ptrdiff_t offset, ulonglong new_value)
{
bool error= false;
DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size));
keycache_var(key_cache, offset)= new_value;
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
error= ha_resize_key_cache(key_cache);
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
return error;
}
/* /*
The rule for this file: everything should be 'static'. When a sys_var The rule for this file: everything should be 'static'. When a sys_var
variable or a function from this file is - in very rare cases - needed variable or a function from this file is - in very rare cases - needed
......
...@@ -72,7 +72,6 @@ ...@@ -72,7 +72,6 @@
enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET}; enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
static const char *bool_values[3]= {"OFF", "ON", 0}; static const char *bool_values[3]= {"OFF", "ON", 0};
TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
/** /**
A small wrapper class to pass getopt arguments as a pair A small wrapper class to pass getopt arguments as a pair
...@@ -710,76 +709,6 @@ class Sys_var_keycache: public Sys_var_ulonglong ...@@ -710,76 +709,6 @@ class Sys_var_keycache: public Sys_var_ulonglong
} }
}; };
static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache,
ptrdiff_t offset, ulonglong new_value)
{
bool error= false;
DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size));
if (new_value == 0)
{
if (key_cache == dflt_key_cache)
{
my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
return true;
}
if (key_cache->key_cache_inited) // If initied
{
/*
Move tables using this key cache to the default key cache
and clear the old key cache.
*/
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
key_cache->param_buff_size= 0;
ha_resize_key_cache(key_cache);
ha_change_key_cache(key_cache, dflt_key_cache);
/*
We don't delete the key cache as some running threads my still be in
the key cache code with a pointer to the deleted (empty) key cache
*/
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
}
return error;
}
key_cache->param_buff_size= new_value;
/* If key cache didn't exist initialize it, else resize it */
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
if (!key_cache->key_cache_inited)
error= ha_init_key_cache(0, key_cache);
else
error= ha_resize_key_cache(key_cache);
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
return error;
}
static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache,
ptrdiff_t offset, ulonglong new_value)
{
bool error= false;
DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size));
keycache_var(key_cache, offset)= new_value;
key_cache->in_init= 1;
mysql_mutex_unlock(&LOCK_global_system_variables);
error= ha_resize_key_cache(key_cache);
mysql_mutex_lock(&LOCK_global_system_variables);
key_cache->in_init= 0;
return error;
}
/** /**
The class for floating point variables The class for floating point variables
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment