1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

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.
This commit is contained in:
Tor Didriksen
2011-11-30 15:39:29 +01:00
parent cfef24eb4f
commit 31aa2b6f3c
7 changed files with 620 additions and 242 deletions

View File

@ -1,5 +1,4 @@
/*
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
it under the terms of the GNU General Public License as published by
@ -12,8 +11,8 @@
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-1301 USA
*/
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
#define DONT_DEFINE_VOID 1
@ -57,10 +56,11 @@ void my_init_stacktrace()
static void print_buffer(char *buffer, size_t count)
{
const char s[]= " ";
for (; count && *buffer; --count)
{
int c= (int) *buffer++;
fputc(isprint(c) ? c : ' ', stderr);
my_write_stderr(isprint(*buffer) ? buffer : s, 1);
++buffer;
}
}
@ -124,10 +124,10 @@ static int safe_print_str(const char *addr, int max_len)
/* Output a new line if something was printed. */
if (total != (size_t) max_len)
fputc('\n', stderr);
my_safe_printf_stderr("%s", "\n");
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);
@ -149,13 +149,13 @@ void my_safe_print_str(const char* val, int max_len)
if (!PTR_SANE(val))
{
fprintf(stderr, "is an invalid pointer\n");
my_safe_printf_stderr("%s", "is an invalid pointer\n");
return;
}
for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr);
fputc('\n', stderr);
my_write_stderr((val++), 1);
my_safe_printf_stderr("%s", "\n");
}
#if defined(HAVE_PRINTSTACK)
@ -167,14 +167,15 @@ void my_print_stacktrace(uchar* stack_bottom __attribute__((unused)),
ulong thread_stack __attribute__((unused)))
{
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
fprintf(stderr,
"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"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
my_safe_printf_stderr("%s"
"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"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
}
#elif HAVE_BACKTRACE && (HAVE_BACKTRACE_SYMBOLS || HAVE_BACKTRACE_SYMBOLS_FD)
@ -212,9 +213,9 @@ static void my_demangle_symbols(char **addrs, int n)
}
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
fprintf(stderr, "%s\n", addrs[i]);
my_safe_printf_stderr("%s\n", addrs[i]);
}
}
@ -225,8 +226,8 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
void *addrs[128];
char **strings= NULL;
int n = backtrace(addrs, array_elements(addrs));
fprintf(stderr, "stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack);
my_safe_printf_stderr("stack_bottom = %p thread_stack 0x%lx\n",
stack_bottom, thread_stack);
#if BACKTRACE_DEMANGLE
if ((strings= backtrace_symbols(addrs, n)))
{
@ -319,8 +320,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
#endif
if (!fp)
{
fprintf(stderr, "frame pointer is NULL, did you compile with\n\
-fomit-frame-pointer? Aborting backtrace!\n");
my_safe_printf_stderr("%s",
"frame pointer is NULL, did you compile with\n"
"-fomit-frame-pointer? Aborting backtrace!\n");
return;
}
@ -328,24 +330,28 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
ulong tmp= min(0x10000,thread_stack);
/* Assume that the stack starts at the previous even 65K */
stack_bottom= (uchar*) (((ulong) &fp + tmp) &
~(ulong) 0xFFFF);
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
stack_bottom= (uchar*) (((ulong) &fp + tmp) & ~(ulong) 0xFFFF);
my_safe_printf_stderr("Cannot determine thread, fp=%p, "
"backtrace may not be correct.\n", fp);
}
if (fp > (uchar**) stack_bottom ||
fp < (uchar**) stack_bottom - thread_stack)
{
fprintf(stderr, "Bogus stack limit or frame pointer,\
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
fp, stack_bottom, thread_stack);
my_safe_printf_stderr("Bogus stack limit or frame pointer, "
"fp=%p, stack_bottom=%p, thread_stack=%ld, "
"aborting backtrace.\n",
fp, stack_bottom, thread_stack);
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__)
fprintf(stderr, "Warning: Alpha stacks are difficult -\
will be taking some wild guesses, stack trace may be incorrect or \
terminate abruptly\n");
my_safe_printf_stderr("%s",
"Warning: Alpha stacks are difficult -"
"will be taking some wild guesses, stack trace may be incorrect or "
"terminate abruptly\n");
/* On Alpha, we need to get pc */
__asm __volatile__ ("bsr %0, do_next; do_next: "
:"=r"(pc)
@ -359,8 +365,9 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
#if defined(__i386__) || defined(__x86_64__)
uchar** new_fp = (uchar**)*fp;
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
my_safe_printf_stderr("%p\n",
frame_count == sigreturn_frame_count ?
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
#endif /* defined(__386__) || defined(__x86_64__) */
#if defined(__alpha__) && defined(__GNUC__)
@ -374,38 +381,40 @@ void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
pc = find_prev_pc(pc, fp);
if (pc)
fprintf(stderr, "%p\n", pc);
my_safe_printf_stderr("%p\n", pc);
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;
}
}
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;
}
#endif /* defined(__alpha__) && defined(__GNUC__) */
if (new_fp <= fp )
{
fprintf(stderr, "New value of fp=%p failed sanity check,\
terminating stack trace!\n", new_fp);
my_safe_printf_stderr("New value of fp=%p failed sanity check, "
"terminating stack trace!\n", new_fp);
goto end;
}
fp = new_fp;
++frame_count;
}
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
my_safe_printf_stderr("%s",
"Stack trace seems successful - bottom reached\n");
end:
fprintf(stderr,
"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"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
my_safe_printf_stderr("%s",
"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"
"Resolved stack trace is much more helpful in diagnosing the\n"
"problem, so please do resolve it\n");
}
#endif /* TARGET_OS_LINUX */
#endif /* HAVE_STACKTRACE */
@ -670,7 +679,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
&(package.sym));
have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
fprintf(stderr, "%p ", addr);
my_safe_printf_stderr("%p ", addr);
if(have_module)
{
char *base_image_name= strrchr(module.ImageName, '\\');
@ -678,12 +687,13 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_image_name++;
else
base_image_name= module.ImageName;
fprintf(stderr, "%s!", base_image_name);
my_safe_printf_stderr("%s!", base_image_name);
}
if(have_symbol)
fprintf(stderr, "%s()", package.sym.Name);
my_safe_printf_stderr("%s()", package.sym.Name);
else if(have_module)
fprintf(stderr, "???");
my_safe_printf_stderr("%s", "???");
if(have_source)
{
@ -692,11 +702,11 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
base_file_name++;
else
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);
}
@ -733,22 +743,22 @@ void my_write_core(int unused)
if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpNormal, &info, 0, 0))
{
fprintf(stderr, "Minidump written to %s\n",
_fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
my_safe_printf_stderr("Minidump written to %s\n",
_fullpath(path, dump_fname, sizeof(path)) ?
path : dump_fname);
}
else
{
fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
GetLastError());
my_safe_printf_stderr("MiniDumpWriteDump() failed, last error %u\n",
(uint) GetLastError());
}
CloseHandle(hFile);
}
else
{
fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
GetLastError());
my_safe_printf_stderr("CreateFile(%s) failed, last error %u\n",
dump_fname, (uint) GetLastError());
}
fflush(stderr);
}
@ -756,11 +766,212 @@ void my_safe_print_str(const char *val, int len)
{
__try
{
fprintf(stderr,"=%.*s\n", len, val);
my_write_stderr(val, len);
}
__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__*/
#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;
}