Home | History | Annotate | Download | only in wtf
      1 /*
      2  * Copyright (C) 2003, 2006, 2007 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2007-2009 Torch Mobile, Inc.
      4  * Copyright (C) 2011 University of Szeged. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 // The vprintf_stderr_common function triggers this error in the Mac build.
     29 // Feel free to remove this pragma if this file builds on Mac.
     30 // According to http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
     31 // we need to place this directive before any data or functions are defined.
     32 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
     33 
     34 #include "config.h"
     35 #include "Assertions.h"
     36 
     37 #include "Compiler.h"
     38 #include "OwnArrayPtr.h"
     39 
     40 #include <stdio.h>
     41 #include <stdarg.h>
     42 #include <string.h>
     43 
     44 #if HAVE(SIGNAL_H)
     45 #include <signal.h>
     46 #endif
     47 
     48 #if USE(CF)
     49 #include <AvailabilityMacros.h>
     50 #include <CoreFoundation/CFString.h>
     51 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
     52 #define WTF_USE_APPLE_SYSTEM_LOG 1
     53 #include <asl.h>
     54 #endif
     55 #endif // USE(CF)
     56 
     57 #if COMPILER(MSVC)
     58 #include <crtdbg.h>
     59 #endif
     60 
     61 #if OS(WINDOWS)
     62 #include <windows.h>
     63 #endif
     64 
     65 #if (OS(DARWIN) || (OS(LINUX) && !defined(__UCLIBC__))) && !OS(ANDROID)
     66 #include <cxxabi.h>
     67 #include <dlfcn.h>
     68 #include <execinfo.h>
     69 #endif
     70 
     71 #if OS(ANDROID)
     72 #include "android/log.h"
     73 #endif
     74 
     75 extern "C" {
     76 
     77 WTF_ATTRIBUTE_PRINTF(1, 0)
     78 static void vprintf_stderr_common(const char* format, va_list args)
     79 {
     80 #if USE(CF) && !OS(WINDOWS)
     81     if (strstr(format, "%@")) {
     82         CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
     83 
     84 #if COMPILER(CLANG)
     85 #pragma clang diagnostic push
     86 #pragma clang diagnostic ignored "-Wformat-nonliteral"
     87 #endif
     88         CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
     89 #if COMPILER(CLANG)
     90 #pragma clang diagnostic pop
     91 #endif
     92         CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
     93         char* buffer = (char*)malloc(length + 1);
     94 
     95         CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);
     96 
     97 #if USE(APPLE_SYSTEM_LOG)
     98         asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer);
     99 #endif
    100         fputs(buffer, stderr);
    101 
    102         free(buffer);
    103         CFRelease(str);
    104         CFRelease(cfFormat);
    105         return;
    106     }
    107 
    108 #if USE(APPLE_SYSTEM_LOG)
    109     va_list copyOfArgs;
    110     va_copy(copyOfArgs, args);
    111     asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
    112     va_end(copyOfArgs);
    113 #endif
    114 
    115     // Fall through to write to stderr in the same manner as other platforms.
    116 
    117 #elif OS(ANDROID)
    118     __android_log_vprint(ANDROID_LOG_WARN, "WebKit", format, args);
    119 #elif HAVE(ISDEBUGGERPRESENT)
    120     if (IsDebuggerPresent()) {
    121         size_t size = 1024;
    122 
    123         do {
    124             char* buffer = (char*)malloc(size);
    125 
    126             if (buffer == NULL)
    127                 break;
    128 
    129             if (_vsnprintf(buffer, size, format, args) != -1) {
    130                 OutputDebugStringA(buffer);
    131                 free(buffer);
    132                 break;
    133             }
    134 
    135             free(buffer);
    136             size *= 2;
    137         } while (size > 1024);
    138     }
    139 #endif
    140     vfprintf(stderr, format, args);
    141 }
    142 
    143 #if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
    144 #pragma GCC diagnostic push
    145 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
    146 #endif
    147 
    148 static void vprintf_stderr_with_prefix(const char* prefix, const char* format, va_list args)
    149 {
    150     size_t prefixLength = strlen(prefix);
    151     size_t formatLength = strlen(format);
    152     OwnArrayPtr<char> formatWithPrefix = adoptArrayPtr(new char[prefixLength + formatLength + 1]);
    153     memcpy(formatWithPrefix.get(), prefix, prefixLength);
    154     memcpy(formatWithPrefix.get() + prefixLength, format, formatLength);
    155     formatWithPrefix[prefixLength + formatLength] = 0;
    156 
    157     vprintf_stderr_common(formatWithPrefix.get(), args);
    158 }
    159 
    160 static void vprintf_stderr_with_trailing_newline(const char* format, va_list args)
    161 {
    162     size_t formatLength = strlen(format);
    163     if (formatLength && format[formatLength - 1] == '\n') {
    164         vprintf_stderr_common(format, args);
    165         return;
    166     }
    167 
    168     OwnArrayPtr<char> formatWithNewline = adoptArrayPtr(new char[formatLength + 2]);
    169     memcpy(formatWithNewline.get(), format, formatLength);
    170     formatWithNewline[formatLength] = '\n';
    171     formatWithNewline[formatLength + 1] = 0;
    172 
    173     vprintf_stderr_common(formatWithNewline.get(), args);
    174 }
    175 
    176 #if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
    177 #pragma GCC diagnostic pop
    178 #endif
    179 
    180 WTF_ATTRIBUTE_PRINTF(1, 2)
    181 static void printf_stderr_common(const char* format, ...)
    182 {
    183     va_list args;
    184     va_start(args, format);
    185     vprintf_stderr_common(format, args);
    186     va_end(args);
    187 }
    188 
    189 static void printCallSite(const char* file, int line, const char* function)
    190 {
    191 #if OS(WINDOWS) && defined(_DEBUG)
    192     _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function);
    193 #else
    194     // By using this format, which matches the format used by MSVC for compiler errors, developers
    195     // using Visual Studio can double-click the file/line number in the Output Window to have the
    196     // editor navigate to that line of code. It seems fine for other developers, too.
    197     printf_stderr_common("%s(%d) : %s\n", file, line, function);
    198 #endif
    199 }
    200 
    201 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion)
    202 {
    203     if (assertion)
    204         printf_stderr_common("ASSERTION FAILED: %s\n", assertion);
    205     else
    206         printf_stderr_common("SHOULD NEVER BE REACHED\n");
    207     printCallSite(file, line, function);
    208 }
    209 
    210 void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...)
    211 {
    212     va_list args;
    213     va_start(args, format);
    214     vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args);
    215     va_end(args);
    216     printf_stderr_common("\n%s\n", assertion);
    217     printCallSite(file, line, function);
    218 }
    219 
    220 void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion)
    221 {
    222     printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion);
    223     printCallSite(file, line, function);
    224 }
    225 
    226 void WTFGetBacktrace(void** stack, int* size)
    227 {
    228 #if (OS(DARWIN) || (OS(LINUX) && !defined(__UCLIBC__))) && !OS(ANDROID)
    229     *size = backtrace(stack, *size);
    230 #elif OS(WINDOWS)
    231     // The CaptureStackBackTrace function is available in XP, but it is not defined
    232     // in the Windows Server 2003 R2 Platform SDK. So, we'll grab the function
    233     // through GetProcAddress.
    234     typedef WORD (NTAPI* RtlCaptureStackBackTraceFunc)(DWORD, DWORD, PVOID*, PDWORD);
    235     HMODULE kernel32 = ::GetModuleHandleW(L"Kernel32.dll");
    236     if (!kernel32) {
    237         *size = 0;
    238         return;
    239     }
    240     RtlCaptureStackBackTraceFunc captureStackBackTraceFunc = reinterpret_cast<RtlCaptureStackBackTraceFunc>(
    241         ::GetProcAddress(kernel32, "RtlCaptureStackBackTrace"));
    242     if (captureStackBackTraceFunc)
    243         *size = captureStackBackTraceFunc(0, *size, stack, 0);
    244     else
    245         *size = 0;
    246 #else
    247     *size = 0;
    248 #endif
    249 }
    250 
    251 void WTFReportBacktrace()
    252 {
    253     static const int framesToShow = 31;
    254     static const int framesToSkip = 2;
    255     void* samples[framesToShow + framesToSkip];
    256     int frames = framesToShow + framesToSkip;
    257 
    258     WTFGetBacktrace(samples, &frames);
    259     WTFPrintBacktrace(samples + framesToSkip, frames - framesToSkip);
    260 }
    261 
    262 void WTFPrintBacktrace(void** stack, int size)
    263 {
    264     for (int i = 0; i < size; ++i) {
    265         const char* mangledName = 0;
    266         char* cxaDemangled = 0;
    267 #if OS(DARWIN) || (OS(LINUX) && !OS(ANDROID))
    268         Dl_info info;
    269         if (dladdr(stack[i], &info) && info.dli_sname)
    270             mangledName = info.dli_sname;
    271         if (mangledName)
    272             cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
    273 #endif
    274         const int frameNumber = i + 1;
    275         if (mangledName || cxaDemangled)
    276             printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName);
    277         else
    278             printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
    279         free(cxaDemangled);
    280     }
    281 }
    282 
    283 static WTFCrashHookFunction globalHook = 0;
    284 
    285 void WTFSetCrashHook(WTFCrashHookFunction function)
    286 {
    287     globalHook = function;
    288 }
    289 
    290 void WTFInvokeCrashHook()
    291 {
    292     if (globalHook)
    293         globalHook();
    294 }
    295 
    296 #if HAVE(SIGNAL_H)
    297 static NO_RETURN void dumpBacktraceSignalHandler(int sig)
    298 {
    299     WTFReportBacktrace();
    300     exit(128 + sig);
    301 }
    302 
    303 static void installSignalHandlersForFatalErrors(void (*handler)(int))
    304 {
    305     signal(SIGILL, handler); //    4: illegal instruction (not reset when caught).
    306     signal(SIGTRAP, handler); //   5: trace trap (not reset when caught).
    307     signal(SIGFPE, handler); //    8: floating point exception.
    308     signal(SIGBUS, handler); //   10: bus error.
    309     signal(SIGSEGV, handler); //  11: segmentation violation.
    310     signal(SIGSYS, handler); //   12: bad argument to system call.
    311     signal(SIGPIPE, handler); //  13: write on a pipe with no reader.
    312     signal(SIGXCPU, handler); //  24: exceeded CPU time limit.
    313     signal(SIGXFSZ, handler); //  25: exceeded file size limit.
    314 }
    315 
    316 static void resetSignalHandlersForFatalErrors()
    317 {
    318     installSignalHandlersForFatalErrors(SIG_DFL);
    319 }
    320 #endif
    321 
    322 void WTFInstallReportBacktraceOnCrashHook()
    323 {
    324 #if HAVE(SIGNAL_H)
    325     // Needed otherwise we are going to dump the stack trace twice
    326     // in case we hit an assertion.
    327     WTFSetCrashHook(&resetSignalHandlersForFatalErrors);
    328     installSignalHandlersForFatalErrors(&dumpBacktraceSignalHandler);
    329 #endif
    330 }
    331 
    332 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
    333 {
    334     va_list args;
    335     va_start(args, format);
    336     vprintf_stderr_with_prefix("FATAL ERROR: ", format, args);
    337     va_end(args);
    338     printf_stderr_common("\n");
    339     printCallSite(file, line, function);
    340 }
    341 
    342 void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
    343 {
    344     va_list args;
    345     va_start(args, format);
    346     vprintf_stderr_with_prefix("ERROR: ", format, args);
    347     va_end(args);
    348     printf_stderr_common("\n");
    349     printCallSite(file, line, function);
    350 }
    351 
    352 void WTFLog(WTFLogChannel* channel, const char* format, ...)
    353 {
    354     if (channel->state != WTFLogChannelOn)
    355         return;
    356 
    357     va_list args;
    358     va_start(args, format);
    359     vprintf_stderr_with_trailing_newline(format, args);
    360     va_end(args);
    361 }
    362 
    363 void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
    364 {
    365     if (channel->state != WTFLogChannelOn)
    366         return;
    367 
    368     va_list args;
    369     va_start(args, format);
    370     vprintf_stderr_with_trailing_newline(format, args);
    371     va_end(args);
    372 
    373     printCallSite(file, line, function);
    374 }
    375 
    376 void WTFLogAlways(const char* format, ...)
    377 {
    378     va_list args;
    379     va_start(args, format);
    380     vprintf_stderr_with_trailing_newline(format, args);
    381     va_end(args);
    382 }
    383 
    384 } // extern "C"
    385