Remove even more Mountain Lion support
[WebKit.git] / Source / WTF / wtf / Assertions.cpp
1 /*
2  * Copyright (C) 2003, 2006, 2007, 2013 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 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 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 <wtf/StdLibExtras.h>
39 #include <wtf/StringExtras.h>
40 #include <wtf/text/CString.h>
41 #include <wtf/text/WTFString.h>
42
43 #include <stdio.h>
44 #include <string.h>
45
46 #if HAVE(SIGNAL_H)
47 #include <signal.h>
48 #endif
49
50 #if USE(CF)
51 #include <CoreFoundation/CFString.h>
52 #if PLATFORM(COCOA)
53 #define WTF_USE_APPLE_SYSTEM_LOG 1
54 #include <asl.h>
55 #endif
56 #endif // USE(CF)
57
58 #if COMPILER(MSVC)
59 #include <crtdbg.h>
60 #endif
61
62 #if OS(WINDOWS)
63 #include <windows.h>
64 #endif
65
66 #if OS(DARWIN)
67 #include <sys/sysctl.h>
68 #include <unistd.h>
69 #endif
70
71 #if OS(DARWIN) || (OS(LINUX) && !defined(__UCLIBC__))
72 #include <cxxabi.h>
73 #include <dlfcn.h>
74 #include <execinfo.h>
75 #endif
76
77 extern "C" {
78
79 WTF_ATTRIBUTE_PRINTF(1, 0)
80 static void vprintf_stderr_common(const char* format, va_list args)
81 {
82 #if USE(CF) && !OS(WINDOWS)
83     if (strstr(format, "%@")) {
84         CFStringRef cfFormat = CFStringCreateWithCString(NULL, format, kCFStringEncodingUTF8);
85
86 #if COMPILER(CLANG)
87 #pragma clang diagnostic push
88 #pragma clang diagnostic ignored "-Wformat-nonliteral"
89 #endif
90         CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, cfFormat, args);
91 #if COMPILER(CLANG)
92 #pragma clang diagnostic pop
93 #endif
94         CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8);
95         char* buffer = (char*)malloc(length + 1);
96
97         CFStringGetCString(str, buffer, length, kCFStringEncodingUTF8);
98
99 #if USE(APPLE_SYSTEM_LOG)
100         asl_log(0, 0, ASL_LEVEL_NOTICE, "%s", buffer);
101 #endif
102         fputs(buffer, stderr);
103
104         free(buffer);
105         CFRelease(str);
106         CFRelease(cfFormat);
107         return;
108     }
109
110 #if USE(APPLE_SYSTEM_LOG)
111     va_list copyOfArgs;
112     va_copy(copyOfArgs, args);
113     asl_vlog(0, 0, ASL_LEVEL_NOTICE, format, copyOfArgs);
114     va_end(copyOfArgs);
115 #endif
116
117     // Fall through to write to stderr in the same manner as other platforms.
118
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)
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     auto formatWithPrefix = std::make_unique<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     auto formatWithNewline = std::make_unique<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)
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__))
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 #if OS(DARWIN) || OS(LINUX)
263 #  if PLATFORM(GTK)
264 #    if defined(__GLIBC__) && !defined(__UCLIBC__)
265 #      define WTF_USE_BACKTRACE_SYMBOLS 1
266 #    endif
267 #  else
268 #    define WTF_USE_DLADDR 1
269 #  endif
270 #endif
271
272 void WTFPrintBacktrace(void** stack, int size)
273 {
274 #if USE(BACKTRACE_SYMBOLS)
275     char** symbols = backtrace_symbols(stack, size);
276     if (!symbols)
277         return;
278 #endif
279
280     for (int i = 0; i < size; ++i) {
281         const char* mangledName = 0;
282         char* cxaDemangled = 0;
283 #if USE(BACKTRACE_SYMBOLS)
284         mangledName = symbols[i];
285 #elif USE(DLADDR)
286         Dl_info info;
287         if (dladdr(stack[i], &info) && info.dli_sname)
288             mangledName = info.dli_sname;
289         if (mangledName)
290             cxaDemangled = abi::__cxa_demangle(mangledName, 0, 0, 0);
291 #endif
292         const int frameNumber = i + 1;
293         if (mangledName || cxaDemangled)
294             printf_stderr_common("%-3d %p %s\n", frameNumber, stack[i], cxaDemangled ? cxaDemangled : mangledName);
295         else
296             printf_stderr_common("%-3d %p\n", frameNumber, stack[i]);
297         free(cxaDemangled);
298     }
299
300 #if USE(BACKTRACE_SYMBOLS)
301     free(symbols);
302 #endif
303 }
304
305 #undef WTF_USE_BACKTRACE_SYMBOLS
306 #undef WTF_USE_DLADDR
307
308 static WTFCrashHookFunction globalHook = 0;
309
310 void WTFSetCrashHook(WTFCrashHookFunction function)
311 {
312     globalHook = function;
313 }
314
315 void WTFCrash()
316 {
317     if (globalHook)
318         globalHook();
319
320     WTFReportBacktrace();
321     *(int *)(uintptr_t)0xbbadbeef = 0;
322     // More reliable, but doesn't say BBADBEEF.
323 #if COMPILER(CLANG)
324     __builtin_trap();
325 #else
326     ((void(*)())0)();
327 #endif
328 }
329     
330 void WTFCrashWithSecurityImplication()
331 {
332     if (globalHook)
333         globalHook();
334     WTFReportBacktrace();
335     *(int *)(uintptr_t)0xfbadbeef = 0;
336     // More reliable, but doesn't say fbadbeef.
337 #if COMPILER(CLANG)
338     __builtin_trap();
339 #else
340     ((void(*)())0)();
341 #endif
342 }
343
344 #if HAVE(SIGNAL_H)
345 static NO_RETURN void dumpBacktraceSignalHandler(int sig)
346 {
347     WTFReportBacktrace();
348     exit(128 + sig);
349 }
350
351 static void installSignalHandlersForFatalErrors(void (*handler)(int))
352 {
353     signal(SIGILL, handler); //    4: illegal instruction (not reset when caught).
354     signal(SIGTRAP, handler); //   5: trace trap (not reset when caught).
355     signal(SIGFPE, handler); //    8: floating point exception.
356     signal(SIGBUS, handler); //   10: bus error.
357     signal(SIGSEGV, handler); //  11: segmentation violation.
358     signal(SIGSYS, handler); //   12: bad argument to system call.
359     signal(SIGPIPE, handler); //  13: write on a pipe with no reader.
360     signal(SIGXCPU, handler); //  24: exceeded CPU time limit.
361     signal(SIGXFSZ, handler); //  25: exceeded file size limit.
362 }
363
364 static void resetSignalHandlersForFatalErrors()
365 {
366     installSignalHandlersForFatalErrors(SIG_DFL);
367 }
368 #endif
369
370 void WTFInstallReportBacktraceOnCrashHook()
371 {
372 #if HAVE(SIGNAL_H)
373     // Needed otherwise we are going to dump the stack trace twice
374     // in case we hit an assertion.
375     WTFSetCrashHook(&resetSignalHandlersForFatalErrors);
376     installSignalHandlersForFatalErrors(&dumpBacktraceSignalHandler);
377 #endif
378 }
379
380 bool WTFIsDebuggerAttached()
381 {
382 #if OS(DARWIN)
383     struct kinfo_proc info;
384     int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
385     size_t size = sizeof(info);
386     if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &info, &size, nullptr, 0) == -1)
387         return false;
388     return info.kp_proc.p_flag & P_TRACED;
389 #else
390     return false;
391 #endif
392 }
393
394 void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...)
395 {
396     va_list args;
397     va_start(args, format);
398     vprintf_stderr_with_prefix("FATAL ERROR: ", format, args);
399     va_end(args);
400     printf_stderr_common("\n");
401     printCallSite(file, line, function);
402 }
403
404 void WTFReportError(const char* file, int line, const char* function, const char* format, ...)
405 {
406     va_list args;
407     va_start(args, format);
408     vprintf_stderr_with_prefix("ERROR: ", format, args);
409     va_end(args);
410     printf_stderr_common("\n");
411     printCallSite(file, line, function);
412 }
413
414 void WTFLog(WTFLogChannel* channel, const char* format, ...)
415 {
416     if (channel->state != WTFLogChannelOn)
417         return;
418
419     va_list args;
420     va_start(args, format);
421     vprintf_stderr_with_trailing_newline(format, args);
422     va_end(args);
423 }
424
425 void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...)
426 {
427     if (channel->state != WTFLogChannelOn)
428         return;
429
430     va_list args;
431     va_start(args, format);
432     vprintf_stderr_with_trailing_newline(format, args);
433     va_end(args);
434
435     printCallSite(file, line, function);
436 }
437
438 void WTFLogAlwaysV(const char* format, va_list args)
439 {
440     vprintf_stderr_with_trailing_newline(format, args);
441 }
442
443 void WTFLogAlways(const char* format, ...)
444 {
445     va_list args;
446     va_start(args, format);
447     WTFLogAlwaysV(format, args);
448     va_end(args);
449 }
450
451 void WTFLogAlwaysAndCrash(const char* format, ...)
452 {
453     va_list args;
454     va_start(args, format);
455     WTFLogAlwaysV(format, args);
456     va_end(args);
457     WTFCrash();
458 }
459
460 WTFLogChannel* WTFLogChannelByName(WTFLogChannel* channels[], size_t count, const char* name)
461 {
462     for (size_t i = 0; i < count; ++i) {
463         WTFLogChannel* channel = channels[i];
464         if (!strcasecmp(name, channel->name))
465             return channel;
466     }
467
468     return 0;
469 }
470
471 static void setStateOfAllChannels(WTFLogChannel* channels[], size_t channelCount, WTFLogChannelState state)
472 {
473     for (size_t i = 0; i < channelCount; ++i)
474         channels[i]->state = state;
475 }
476
477 void WTFInitializeLogChannelStatesFromString(WTFLogChannel* channels[], size_t count, const char* logLevel)
478 {
479     String logLevelString = logLevel;
480     Vector<String> components;
481     logLevelString.split(',', components);
482
483     for (size_t i = 0; i < components.size(); ++i) {
484         String component = components[i];
485
486         WTFLogChannelState logChannelState = WTFLogChannelOn;
487         if (component.startsWith('-')) {
488             logChannelState = WTFLogChannelOff;
489             component = component.substring(1);
490         }
491
492         if (equalIgnoringCase(component, "all")) {
493             setStateOfAllChannels(channels, count, logChannelState);
494             continue;
495         }
496
497         if (WTFLogChannel* channel = WTFLogChannelByName(channels, count, component.utf8().data()))
498             channel->state = logChannelState;
499         else
500             WTFLogAlways("Unknown logging channel: %s", component.utf8().data());
501     }
502 }
503
504 } // extern "C"