summaryrefslogtreecommitdiff
path: root/mysys/stacktrace.c
diff options
context:
space:
mode:
authorTor Didriksen <tor.didriksen@oracle.com>2011-12-02 14:16:48 +0100
committerTor Didriksen <tor.didriksen@oracle.com>2011-12-02 14:16:48 +0100
commitb522a6ce78bfe7bea3e52715c993c7d190159139 (patch)
tree9e4c9211a159f15e7bd8ab5ca489f53fd8b28a7c /mysys/stacktrace.c
parent8e6d41e278de3264d2a6e13cbc0ed328afca7f40 (diff)
downloadmariadb-git-b522a6ce78bfe7bea3e52715c993c7d190159139.tar.gz
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.
Diffstat (limited to 'mysys/stacktrace.c')
-rw-r--r--mysys/stacktrace.c334
1 files changed, 273 insertions, 61 deletions
diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c
index 5efe44a037d..175ee8a3025 100644
--- a/mysys/stacktrace.c
+++ b/mysys/stacktrace.c
@@ -52,10 +52,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;
}
}
@@ -119,10 +120,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);
@@ -144,13 +145,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)
@@ -162,14 +163,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)
@@ -207,9 +209,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]);
}
}
@@ -220,8 +222,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)))
{
@@ -314,8 +316,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;
}
@@ -323,24 +326,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)
@@ -354,8 +361,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__)
@@ -369,38 +377,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 */
@@ -618,7 +628,7 @@ void my_print_stacktrace(uchar* unused1, ulong unused2)
&(package.sym));
have_source= SymGetLineFromAddr64(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, '\\');
@@ -626,12 +636,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)
{
@@ -640,11 +651,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);
}
@@ -681,22 +692,22 @@ void my_write_core(int unused)
if(MiniDumpWriteDump(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);
}
@@ -704,11 +715,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;
+}