1// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
2// Licensed under the MIT License:
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22#ifndef _GNU_SOURCE
23#define _GNU_SOURCE
24#endif
25
26#include "exception.h"
27#include "string.h"
28#include "debug.h"
29#include "threadlocal.h"
30#include "miniposix.h"
31#include "function.h"
32#include <stdlib.h>
33#include <exception>
34#include <new>
35#include <signal.h>
36#include <stdint.h>
37#ifndef _WIN32
38#include <sys/mman.h>
39#endif
40#include "io.h"
41
42#if !KJ_NO_RTTI
43#include <typeinfo>
44#endif
45#if __GNUC__
46#include <cxxabi.h>
47#endif
48
49#if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__
50#define KJ_HAS_BACKTRACE 1
51#include <execinfo.h>
52#endif
53
54#if _WIN32
55#define WIN32_LEAN_AND_MEAN
56#include <windows.h>
57#include "windows-sanity.h"
58#include <dbghelp.h>
59#endif
60
61#if (__linux__ || __APPLE__)
62#include <stdio.h>
63#include <pthread.h>
64#endif
65
66#if KJ_HAS_LIBDL
67#include "dlfcn.h"
68#endif
69
70namespace kj {
71
72StringPtr KJ_STRINGIFY(LogSeverity severity) {
73 static const char* SEVERITY_STRINGS[] = {
74 "info",
75 "warning",
76 "error",
77 "fatal",
78 "debug"
79 };
80
81 return SEVERITY_STRINGS[static_cast<uint>(severity)];
82}
83
84#if _WIN32 && _M_X64
85// Currently the Win32 stack-trace code only supports x86_64. We could easily extend it to support
86// i386 as well but it requires some code changes around how we read the context to start the
87// trace.
88
89namespace {
90
91struct Dbghelp {
92 // Load dbghelp.dll dynamically since we don't really need it, it's just for debugging.
93
94 HINSTANCE lib;
95
96 BOOL (WINAPI *symInitialize)(HANDLE hProcess,PCSTR UserSearchPath,BOOL fInvadeProcess);
97 BOOL (WINAPI *stackWalk64)(
98 DWORD MachineType,HANDLE hProcess,HANDLE hThread,
99 LPSTACKFRAME64 StackFrame,PVOID ContextRecord,
100 PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
101 PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
102 PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
103 PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
104 PVOID (WINAPI *symFunctionTableAccess64)(HANDLE hProcess,DWORD64 AddrBase);
105 DWORD64 (WINAPI *symGetModuleBase64)(HANDLE hProcess,DWORD64 qwAddr);
106 BOOL (WINAPI *symGetLineFromAddr64)(
107 HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE64 Line64);
108
109 Dbghelp()
110 : lib(LoadLibraryA("dbghelp.dll")),
111 symInitialize(lib == nullptr ? nullptr :
112 reinterpret_cast<decltype(symInitialize)>(
113 GetProcAddress(lib, "SymInitialize"))),
114 stackWalk64(symInitialize == nullptr ? nullptr :
115 reinterpret_cast<decltype(stackWalk64)>(
116 GetProcAddress(lib, "StackWalk64"))),
117 symFunctionTableAccess64(symInitialize == nullptr ? nullptr :
118 reinterpret_cast<decltype(symFunctionTableAccess64)>(
119 GetProcAddress(lib, "SymFunctionTableAccess64"))),
120 symGetModuleBase64(symInitialize == nullptr ? nullptr :
121 reinterpret_cast<decltype(symGetModuleBase64)>(
122 GetProcAddress(lib, "SymGetModuleBase64"))),
123 symGetLineFromAddr64(symInitialize == nullptr ? nullptr :
124 reinterpret_cast<decltype(symGetLineFromAddr64)>(
125 GetProcAddress(lib, "SymGetLineFromAddr64"))) {
126 if (symInitialize != nullptr) {
127 symInitialize(GetCurrentProcess(), NULL, TRUE);
128 }
129 }
130};
131
132const Dbghelp& getDbghelp() {
133 static Dbghelp dbghelp;
134 return dbghelp;
135}
136
137ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount,
138 HANDLE thread, CONTEXT& context) {
139 const Dbghelp& dbghelp = getDbghelp();
140 if (dbghelp.stackWalk64 == nullptr ||
141 dbghelp.symFunctionTableAccess64 == nullptr ||
142 dbghelp.symGetModuleBase64 == nullptr) {
143 return nullptr;
144 }
145
146 STACKFRAME64 frame;
147 memset(&frame, 0, sizeof(frame));
148
149 frame.AddrPC.Offset = context.Rip;
150 frame.AddrPC.Mode = AddrModeFlat;
151 frame.AddrStack.Offset = context.Rsp;
152 frame.AddrStack.Mode = AddrModeFlat;
153 frame.AddrFrame.Offset = context.Rbp;
154 frame.AddrFrame.Mode = AddrModeFlat;
155
156 HANDLE process = GetCurrentProcess();
157
158 uint count = 0;
159 for (; count < space.size(); count++) {
160 if (!dbghelp.stackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread,
161 &frame, &context, NULL, dbghelp.symFunctionTableAccess64,
162 dbghelp.symGetModuleBase64, NULL)){
163 break;
164 }
165
166 // Subtract 1 from each address so that we identify the calling instructions, rather than the
167 // return addresses (which are typically the instruction after the call).
168 space[count] = reinterpret_cast<void*>(frame.AddrPC.Offset - 1);
169 }
170
171 return space.slice(kj::min(ignoreCount, count), count);
172}
173
174} // namespace
175#endif
176
177ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
178 if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) {
179 return nullptr;
180 }
181
182#if _WIN32 && _M_X64
183 CONTEXT context;
184 RtlCaptureContext(&context);
185 return getStackTrace(space, ignoreCount, GetCurrentThread(), context);
186#elif KJ_HAS_BACKTRACE
187 size_t size = backtrace(space.begin(), space.size());
188 for (auto& addr: space.slice(0, size)) {
189 // The addresses produced by backtrace() are return addresses, which means they point to the
190 // instruction immediately after the call. Invoking addr2line on these can be confusing because
191 // it often points to the next line. If the next instruction is inlined from another function,
192 // the trace can be extra-confusing, since now it claims to be in a function that was not
193 // actually on the call stack. If we subtract 1 from each address, though, we get a much more
194 // reasonable trace. This may cause the addresses to be invalid instruction pointers if the
195 // instructions were multi-byte, but it appears addr2line is able to cope with this.
196 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - 1);
197 }
198 return space.slice(kj::min(ignoreCount + 1, size), size);
199#else
200 return nullptr;
201#endif
202}
203
204String stringifyStackTrace(ArrayPtr<void* const> trace) {
205 if (trace.size() == 0) return nullptr;
206 if (getExceptionCallback().stackTraceMode() != ExceptionCallback::StackTraceMode::FULL) {
207 return nullptr;
208 }
209
210#if _WIN32 && _M_X64 && _MSC_VER
211
212 // Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since
213 // this requires MSVC debug info.
214 //
215 // TODO(someday): We could perhaps shell out to addr2line on MinGW.
216
217 const Dbghelp& dbghelp = getDbghelp();
218 if (dbghelp.symGetLineFromAddr64 == nullptr) return nullptr;
219
220 HANDLE process = GetCurrentProcess();
221
222 KJ_STACK_ARRAY(String, lines, trace.size(), 32, 32);
223
224 for (auto i: kj::indices(trace)) {
225 IMAGEHLP_LINE64 lineInfo;
226 memset(&lineInfo, 0, sizeof(lineInfo));
227 lineInfo.SizeOfStruct = sizeof(lineInfo);
228 if (dbghelp.symGetLineFromAddr64(process, reinterpret_cast<DWORD64>(trace[i]), NULL, &lineInfo)) {
229 lines[i] = kj::str('\n', lineInfo.FileName, ':', lineInfo.LineNumber);
230 }
231 }
232
233 return strArray(lines, "");
234
235#elif (__linux__ || __APPLE__) && !__ANDROID__
236 // We want to generate a human-readable stack trace.
237
238 // TODO(someday): It would be really great if we could avoid farming out to another process
239 // and do this all in-process, but that may involve onerous requirements like large library
240 // dependencies or using -rdynamic.
241
242 // The environment manipulation is not thread-safe, so lock a mutex. This could still be
243 // problematic if another thread is manipulating the environment in unrelated code, but there's
244 // not much we can do about that. This is debug-only anyway and only an issue when LD_PRELOAD
245 // is in use.
246 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
247 pthread_mutex_lock(&mutex);
248 KJ_DEFER(pthread_mutex_unlock(&mutex));
249
250 // Don't heapcheck / intercept syscalls.
251 const char* preload = getenv("LD_PRELOAD");
252 String oldPreload;
253 if (preload != nullptr) {
254 oldPreload = heapString(preload);
255 unsetenv("LD_PRELOAD");
256 }
257 KJ_DEFER(if (oldPreload != nullptr) { setenv("LD_PRELOAD", oldPreload.cStr(), true); });
258
259 String lines[32];
260 FILE* p = nullptr;
261 auto strTrace = strArray(trace, " ");
262
263#if __linux__
264 if (access("/proc/self/exe", R_OK) < 0) {
265 // Apparently /proc is not available?
266 return nullptr;
267 }
268
269 // Obtain symbolic stack trace using addr2line.
270 // TODO(cleanup): Use fork() and exec() or maybe our own Subprocess API (once it exists), to
271 // avoid depending on a shell.
272 p = popen(str("addr2line -e /proc/", getpid(), "/exe ", strTrace).cStr(), "r");
273#elif __APPLE__
274 // The Mac OS X equivalent of addr2line is atos.
275 // (Internally, it uses the private CoreSymbolication.framework library.)
276 p = popen(str("xcrun atos -p ", getpid(), ' ', strTrace).cStr(), "r");
277#endif
278
279 if (p == nullptr) {
280 return nullptr;
281 }
282
283 char line[512];
284 size_t i = 0;
285 while (i < kj::size(lines) && fgets(line, sizeof(line), p) != nullptr) {
286 // Don't include exception-handling infrastructure or promise infrastructure in stack trace.
287 // addr2line output matches file names; atos output matches symbol names.
288 if (strstr(line, "kj/common.c++") != nullptr ||
289 strstr(line, "kj/exception.") != nullptr ||
290 strstr(line, "kj/debug.") != nullptr ||
291 strstr(line, "kj/async.") != nullptr ||
292 strstr(line, "kj/async-prelude.h") != nullptr ||
293 strstr(line, "kj/async-inl.h") != nullptr ||
294 strstr(line, "kj::Exception") != nullptr ||
295 strstr(line, "kj::_::Debug") != nullptr) {
296 continue;
297 }
298
299 size_t len = strlen(line);
300 if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';
301 lines[i++] = str("\n ", trimSourceFilename(line), ": returning here");
302 }
303
304 // Skip remaining input.
305 while (fgets(line, sizeof(line), p) != nullptr) {}
306
307 pclose(p);
308
309 return strArray(arrayPtr(lines, i), "");
310
311#else
312 return nullptr;
313#endif
314}
315
316String stringifyStackTraceAddresses(ArrayPtr<void* const> trace) {
317#if KJ_HAS_LIBDL
318 return strArray(KJ_MAP(addr, trace) {
319 Dl_info info;
320 // Shared libraries are mapped near the end of the address space while the executable is mapped
321 // near the beginning. We want to print addresses in the executable as raw addresses, not
322 // offsets, since that's what addr2line expects for executables. For shared libraries it
323 // expects offsets. In any case, most frames are likely to be in the main executable so it
324 // makes the output cleaner if we don't repeatedly write its name.
325 if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
326 uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
327 reinterpret_cast<uintptr_t>(info.dli_fbase);
328 return kj::str(info.dli_fname, '@', reinterpret_cast<void*>(offset));
329 } else {
330 return kj::str(addr);
331 }
332 }, " ");
333#else
334 // TODO(someday): Support other platforms.
335 return kj::strArray(trace, " ");
336#endif
337}
338
339StringPtr stringifyStackTraceAddresses(ArrayPtr<void* const> trace, ArrayPtr<char> scratch) {
340 // Version which writes into a pre-allocated buffer. This is safe for signal handlers to the
341 // extent that dladdr() is safe.
342 //
343 // TODO(cleanup): We should improve the KJ stringification framework so that there's a way to
344 // write this string directly into a larger message buffer with strPreallocated().
345
346#if KJ_HAS_LIBDL
347 char* ptr = scratch.begin();
348 char* limit = scratch.end() - 1;
349
350 for (auto addr: trace) {
351 Dl_info info;
352 // Shared libraries are mapped near the end of the address space while the executable is mapped
353 // near the beginning. We want to print addresses in the executable as raw addresses, not
354 // offsets, since that's what addr2line expects for executables. For shared libraries it
355 // expects offsets. In any case, most frames are likely to be in the main executable so it
356 // makes the output cleaner if we don't repeatedly write its name.
357 if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
358 uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
359 reinterpret_cast<uintptr_t>(info.dli_fbase);
360 ptr = _::fillLimited(ptr, limit, kj::StringPtr(info.dli_fname), "@0x"_kj, hex(offset));
361 } else {
362 ptr = _::fillLimited(ptr, limit, toCharSequence(addr));
363 }
364
365 ptr = _::fillLimited(ptr, limit, " "_kj);
366 }
367 *ptr = '\0';
368 return StringPtr(scratch.begin(), ptr);
369#else
370 // TODO(someday): Support other platforms.
371 return kj::strPreallocated(scratch, kj::delimited(trace, " "));
372#endif
373}
374
375String getStackTrace() {
376 void* space[32];
377 auto trace = getStackTrace(space, 2);
378 return kj::str(stringifyStackTraceAddresses(trace), stringifyStackTrace(trace));
379}
380
381#if _WIN32 && _M_X64
382namespace {
383
384DWORD mainThreadId = 0;
385
386BOOL WINAPI breakHandler(DWORD type) {
387 switch (type) {
388 case CTRL_C_EVENT:
389 case CTRL_BREAK_EVENT: {
390 HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThreadId);
391 if (thread != NULL) {
392 if (SuspendThread(thread) != (DWORD)-1) {
393 CONTEXT context;
394 memset(&context, 0, sizeof(context));
395 context.ContextFlags = CONTEXT_FULL;
396 if (GetThreadContext(thread, &context)) {
397 void* traceSpace[32];
398 auto trace = getStackTrace(traceSpace, 0, thread, context);
399 ResumeThread(thread);
400 auto message = kj::str("*** Received CTRL+C. stack: ",
401 stringifyStackTraceAddresses(trace),
402 stringifyStackTrace(trace), '\n');
403 FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
404 } else {
405 ResumeThread(thread);
406 }
407 }
408 CloseHandle(thread);
409 }
410 break;
411 }
412 default:
413 break;
414 }
415
416 return FALSE; // still crash
417}
418
419kj::StringPtr exceptionDescription(DWORD code) {
420 switch (code) {
421 case EXCEPTION_ACCESS_VIOLATION: return "access violation";
422 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "array bounds exceeded";
423 case EXCEPTION_BREAKPOINT: return "breakpoint";
424 case EXCEPTION_DATATYPE_MISALIGNMENT: return "datatype misalignment";
425 case EXCEPTION_FLT_DENORMAL_OPERAND: return "denormal floating point operand";
426 case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "floating point division by zero";
427 case EXCEPTION_FLT_INEXACT_RESULT: return "inexact floating point result";
428 case EXCEPTION_FLT_INVALID_OPERATION: return "invalid floating point operation";
429 case EXCEPTION_FLT_OVERFLOW: return "floating point overflow";
430 case EXCEPTION_FLT_STACK_CHECK: return "floating point stack overflow";
431 case EXCEPTION_FLT_UNDERFLOW: return "floating point underflow";
432 case EXCEPTION_ILLEGAL_INSTRUCTION: return "illegal instruction";
433 case EXCEPTION_IN_PAGE_ERROR: return "page error";
434 case EXCEPTION_INT_DIVIDE_BY_ZERO: return "integer divided by zero";
435 case EXCEPTION_INT_OVERFLOW: return "integer overflow";
436 case EXCEPTION_INVALID_DISPOSITION: return "invalid disposition";
437 case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "noncontinuable exception";
438 case EXCEPTION_PRIV_INSTRUCTION: return "privileged instruction";
439 case EXCEPTION_SINGLE_STEP: return "single step";
440 case EXCEPTION_STACK_OVERFLOW: return "stack overflow";
441 default: return "(unknown exception code)";
442 }
443}
444
445LONG WINAPI sehHandler(EXCEPTION_POINTERS* info) {
446 void* traceSpace[32];
447 auto trace = getStackTrace(traceSpace, 0, GetCurrentThread(), *info->ContextRecord);
448 auto message = kj::str("*** Received structured exception #0x",
449 hex(info->ExceptionRecord->ExceptionCode), ": ",
450 exceptionDescription(info->ExceptionRecord->ExceptionCode),
451 "; stack: ",
452 stringifyStackTraceAddresses(trace),
453 stringifyStackTrace(trace), '\n');
454 FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
455 return EXCEPTION_EXECUTE_HANDLER; // still crash
456}
457
458} // namespace
459
460void printStackTraceOnCrash() {
461 mainThreadId = GetCurrentThreadId();
462 KJ_WIN32(SetConsoleCtrlHandler(breakHandler, TRUE));
463 SetUnhandledExceptionFilter(&sehHandler);
464}
465
466#elif KJ_HAS_BACKTRACE
467namespace {
468
469void crashHandler(int signo, siginfo_t* info, void* context) {
470 void* traceSpace[32];
471
472 // ignoreCount = 2 to ignore crashHandler() and signal trampoline.
473 auto trace = getStackTrace(traceSpace, 2);
474
475 auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
476 "\nstack: ", stringifyStackTraceAddresses(trace),
477 stringifyStackTrace(trace), '\n');
478
479 FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
480 _exit(1);
481}
482
483} // namespace
484
485void printStackTraceOnCrash() {
486 // Set up alternate signal stack so that stack overflows can be handled.
487 stack_t stack;
488 memset(&stack, 0, sizeof(stack));
489
490#ifndef MAP_ANONYMOUS
491#define MAP_ANONYMOUS MAP_ANON
492#endif
493#ifndef MAP_GROWSDOWN
494#define MAP_GROWSDOWN 0
495#endif
496
497 stack.ss_size = 65536;
498 // Note: ss_sp is char* on FreeBSD, void* on Linux and OSX.
499 stack.ss_sp = reinterpret_cast<char*>(mmap(
500 nullptr, stack.ss_size, PROT_READ | PROT_WRITE,
501 MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0));
502 KJ_SYSCALL(sigaltstack(&stack, nullptr));
503
504 // Catch all relevant signals.
505 struct sigaction action;
506 memset(&action, 0, sizeof(action));
507
508 action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
509 action.sa_sigaction = &crashHandler;
510
511 // Dump stack on common "crash" signals.
512 KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr));
513 KJ_SYSCALL(sigaction(SIGBUS, &action, nullptr));
514 KJ_SYSCALL(sigaction(SIGFPE, &action, nullptr));
515 KJ_SYSCALL(sigaction(SIGABRT, &action, nullptr));
516 KJ_SYSCALL(sigaction(SIGILL, &action, nullptr));
517
518 // Dump stack on unimplemented syscalls -- useful in seccomp sandboxes.
519 KJ_SYSCALL(sigaction(SIGSYS, &action, nullptr));
520
521#ifdef KJ_DEBUG
522 // Dump stack on keyboard interrupt -- useful for infinite loops. Only in debug mode, though,
523 // because stack traces on ctrl+c can be obnoxious for, say, command-line tools.
524 KJ_SYSCALL(sigaction(SIGINT, &action, nullptr));
525#endif
526}
527#else
528void printStackTraceOnCrash() {
529}
530#endif
531
532kj::StringPtr trimSourceFilename(kj::StringPtr filename) {
533 // Removes noisy prefixes from source code file name.
534 //
535 // The goal here is to produce the "canonical" filename given the filename returned by e.g.
536 // addr2line. addr2line gives us the full path of the file as passed on the compiler
537 // command-line, which in turn is affected by build system and by whether and where we're
538 // performing an out-of-tree build.
539 //
540 // To deal with all this, we look for directory names in the path which we recognize to be
541 // locations that represent roots of the source tree. We strip said root and everything before
542 // it.
543 //
544 // On Windows, we often get filenames containing backslashes. Since we aren't allowed to allocate
545 // a new string here, we can't do much about this, so our returned "canonical" name will
546 // unfortunately end up with backslashes.
547
548 static constexpr const char* ROOTS[] = {
549 "ekam-provider/canonical/", // Ekam source file.
550 "ekam-provider/c++header/", // Ekam include file.
551 "src/", // Non-Ekam source root.
552 "tmp/", // Non-Ekam generated code.
553#if _WIN32
554 "src\\", // Win32 source root.
555 "tmp\\", // Win32 generated code.
556#endif
557 };
558
559retry:
560 for (size_t i: kj::indices(filename)) {
561 if (i == 0 || filename[i-1] == '/'
562#if _WIN32
563 || filename[i-1] == '\\'
564#endif
565 ) {
566 // We're at the start of a directory name. Check for valid prefixes.
567 for (kj::StringPtr root: ROOTS) {
568 if (filename.slice(i).startsWith(root)) {
569 filename = filename.slice(i + root.size());
570
571 // We should keep searching to find the last instance of a root name. `i` is no longer
572 // a valid index for `filename` so start the loop over.
573 goto retry;
574 }
575 }
576 }
577 }
578
579 return filename;
580}
581
582StringPtr KJ_STRINGIFY(Exception::Type type) {
583 static const char* TYPE_STRINGS[] = {
584 "failed",
585 "overloaded",
586 "disconnected",
587 "unimplemented"
588 };
589
590 return TYPE_STRINGS[static_cast<uint>(type)];
591}
592
593String KJ_STRINGIFY(const Exception& e) {
594 uint contextDepth = 0;
595
596 Maybe<const Exception::Context&> contextPtr = e.getContext();
597 for (;;) {
598 KJ_IF_MAYBE(c, contextPtr) {
599 ++contextDepth;
600 contextPtr = c->next;
601 } else {
602 break;
603 }
604 }
605
606 Array<String> contextText = heapArray<String>(contextDepth);
607
608 contextDepth = 0;
609 contextPtr = e.getContext();
610 for (;;) {
611 KJ_IF_MAYBE(c, contextPtr) {
612 contextText[contextDepth++] =
613 str(c->file, ":", c->line, ": context: ", c->description, "\n");
614 contextPtr = c->next;
615 } else {
616 break;
617 }
618 }
619
620 return str(strArray(contextText, ""),
621 e.getFile(), ":", e.getLine(), ": ", e.getType(),
622 e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
623 e.getStackTrace().size() > 0 ? "\nstack: " : "",
624 stringifyStackTraceAddresses(e.getStackTrace()),
625 stringifyStackTrace(e.getStackTrace()));
626}
627
628Exception::Exception(Type type, const char* file, int line, String description) noexcept
629 : file(trimSourceFilename(file).cStr()), line(line), type(type), description(mv(description)),
630 traceCount(0) {}
631
632Exception::Exception(Type type, String file, int line, String description) noexcept
633 : ownFile(kj::mv(file)), file(trimSourceFilename(ownFile).cStr()), line(line), type(type),
634 description(mv(description)), traceCount(0) {}
635
636Exception::Exception(const Exception& other) noexcept
637 : file(other.file), line(other.line), type(other.type),
638 description(heapString(other.description)), traceCount(other.traceCount) {
639 if (file == other.ownFile.cStr()) {
640 ownFile = heapString(other.ownFile);
641 file = ownFile.cStr();
642 }
643
644 memcpy(trace, other.trace, sizeof(trace[0]) * traceCount);
645
646 KJ_IF_MAYBE(c, other.context) {
647 context = heap(**c);
648 }
649}
650
651Exception::~Exception() noexcept {}
652
653Exception::Context::Context(const Context& other) noexcept
654 : file(other.file), line(other.line), description(str(other.description)) {
655 KJ_IF_MAYBE(n, other.next) {
656 next = heap(**n);
657 }
658}
659
660void Exception::wrapContext(const char* file, int line, String&& description) {
661 context = heap<Context>(file, line, mv(description), mv(context));
662}
663
664void Exception::extendTrace(uint ignoreCount) {
665 KJ_STACK_ARRAY(void*, newTraceSpace, kj::size(trace) + ignoreCount + 1,
666 sizeof(trace)/sizeof(trace[0]) + 8, 128);
667
668 auto newTrace = kj::getStackTrace(newTraceSpace, ignoreCount + 1);
669 if (newTrace.size() > ignoreCount + 2) {
670 // Remove suffix that won't fit into our static-sized trace.
671 newTrace = newTrace.slice(0, kj::min(kj::size(trace) - traceCount, newTrace.size()));
672
673 // Copy the rest into our trace.
674 memcpy(trace + traceCount, newTrace.begin(), newTrace.asBytes().size());
675 traceCount += newTrace.size();
676 }
677}
678
679void Exception::truncateCommonTrace() {
680 if (traceCount > 0) {
681 // Create a "reference" stack trace that is a little bit deeper than the one in the exception.
682 void* refTraceSpace[sizeof(this->trace) / sizeof(this->trace[0]) + 4];
683 auto refTrace = kj::getStackTrace(refTraceSpace, 0);
684
685 // We expect that the deepest frame in the exception's stack trace should be somewhere in our
686 // own trace, since our own trace has a deeper limit. Search for it.
687 for (uint i = refTrace.size(); i > 0; i--) {
688 if (refTrace[i-1] == trace[traceCount-1]) {
689 // See how many frames match.
690 for (uint j = 0; j < i; j++) {
691 if (j >= traceCount) {
692 // We matched the whole trace, apparently?
693 traceCount = 0;
694 return;
695 } else if (refTrace[i-j-1] != trace[traceCount-j-1]) {
696 // Found mismatching entry.
697
698 // If we matched more than half of the reference trace, guess that this is in fact
699 // the prefix we're looking for.
700 if (j > refTrace.size() / 2) {
701 // Delete the matching suffix. Also delete one non-matched entry on the assumption
702 // that both traces contain that stack frame but are simply at different points in
703 // the function.
704 traceCount -= j + 1;
705 return;
706 }
707 }
708 }
709 }
710 }
711
712 // No match. Ignore.
713 }
714}
715
716void Exception::addTrace(void* ptr) {
717 if (traceCount < kj::size(trace)) {
718 trace[traceCount++] = ptr;
719 }
720}
721
722class ExceptionImpl: public Exception, public std::exception {
723public:
724 inline ExceptionImpl(Exception&& other): Exception(mv(other)) {}
725 ExceptionImpl(const ExceptionImpl& other): Exception(other) {
726 // No need to copy whatBuffer since it's just to hold the return value of what().
727 }
728
729 const char* what() const noexcept override;
730
731private:
732 mutable String whatBuffer;
733};
734
735const char* ExceptionImpl::what() const noexcept {
736 whatBuffer = str(*this);
737 return whatBuffer.begin();
738}
739
740// =======================================================================================
741
742namespace {
743
744KJ_THREADLOCAL_PTR(ExceptionCallback) threadLocalCallback = nullptr;
745
746} // namespace
747
748ExceptionCallback::ExceptionCallback(): next(getExceptionCallback()) {
749 char stackVar;
750 ptrdiff_t offset = reinterpret_cast<char*>(this) - &stackVar;
751 KJ_ASSERT(offset < 65536 && offset > -65536,
752 "ExceptionCallback must be allocated on the stack.");
753
754 threadLocalCallback = this;
755}
756
757ExceptionCallback::ExceptionCallback(ExceptionCallback& next): next(next) {}
758
759ExceptionCallback::~ExceptionCallback() noexcept(false) {
760 if (&next != this) {
761 threadLocalCallback = &next;
762 }
763}
764
765void ExceptionCallback::onRecoverableException(Exception&& exception) {
766 next.onRecoverableException(mv(exception));
767}
768
769void ExceptionCallback::onFatalException(Exception&& exception) {
770 next.onFatalException(mv(exception));
771}
772
773void ExceptionCallback::logMessage(
774 LogSeverity severity, const char* file, int line, int contextDepth, String&& text) {
775 next.logMessage(severity, file, line, contextDepth, mv(text));
776}
777
778ExceptionCallback::StackTraceMode ExceptionCallback::stackTraceMode() {
779 return next.stackTraceMode();
780}
781
782Function<void(Function<void()>)> ExceptionCallback::getThreadInitializer() {
783 return next.getThreadInitializer();
784}
785
786class ExceptionCallback::RootExceptionCallback: public ExceptionCallback {
787public:
788 RootExceptionCallback(): ExceptionCallback(*this) {}
789
790 void onRecoverableException(Exception&& exception) override {
791#if KJ_NO_EXCEPTIONS
792 logException(LogSeverity::ERROR, mv(exception));
793#else
794 if (std::uncaught_exception()) {
795 // Bad time to throw an exception. Just log instead.
796 //
797 // TODO(someday): We should really compare uncaughtExceptionCount() against the count at
798 // the innermost runCatchingExceptions() frame in this thread to tell if exceptions are
799 // being caught correctly.
800 logException(LogSeverity::ERROR, mv(exception));
801 } else {
802 throw ExceptionImpl(mv(exception));
803 }
804#endif
805 }
806
807 void onFatalException(Exception&& exception) override {
808#if KJ_NO_EXCEPTIONS
809 logException(LogSeverity::FATAL, mv(exception));
810#else
811 throw ExceptionImpl(mv(exception));
812#endif
813 }
814
815 void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
816 String&& text) override {
817 text = str(kj::repeat('_', contextDepth), file, ":", line, ": ", severity, ": ",
818 mv(text), '\n');
819
820 StringPtr textPtr = text;
821
822 while (textPtr != nullptr) {
823 miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size());
824 if (n <= 0) {
825 // stderr is broken. Give up.
826 return;
827 }
828 textPtr = textPtr.slice(n);
829 }
830 }
831
832 StackTraceMode stackTraceMode() override {
833#ifdef KJ_DEBUG
834 return StackTraceMode::FULL;
835#else
836 return StackTraceMode::ADDRESS_ONLY;
837#endif
838 }
839
840 Function<void(Function<void()>)> getThreadInitializer() override {
841 return [](Function<void()> func) {
842 // No initialization needed since RootExceptionCallback is automatically the root callback
843 // for new threads.
844 func();
845 };
846 }
847
848private:
849 void logException(LogSeverity severity, Exception&& e) {
850 // We intentionally go back to the top exception callback on the stack because we don't want to
851 // bypass whatever log processing is in effect.
852 //
853 // We intentionally don't log the context since it should get re-added by the exception callback
854 // anyway.
855 getExceptionCallback().logMessage(severity, e.getFile(), e.getLine(), 0, str(
856 e.getType(), e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
857 e.getStackTrace().size() > 0 ? "\nstack: " : "",
858 stringifyStackTraceAddresses(e.getStackTrace()),
859 stringifyStackTrace(e.getStackTrace()), "\n"));
860 }
861};
862
863ExceptionCallback& getExceptionCallback() {
864 static ExceptionCallback::RootExceptionCallback defaultCallback;
865 ExceptionCallback* scoped = threadLocalCallback;
866 return scoped != nullptr ? *scoped : defaultCallback;
867}
868
869void throwFatalException(kj::Exception&& exception, uint ignoreCount) {
870 exception.extendTrace(ignoreCount + 1);
871 getExceptionCallback().onFatalException(kj::mv(exception));
872 abort();
873}
874
875void throwRecoverableException(kj::Exception&& exception, uint ignoreCount) {
876 exception.extendTrace(ignoreCount + 1);
877 getExceptionCallback().onRecoverableException(kj::mv(exception));
878}
879
880// =======================================================================================
881
882namespace _ { // private
883
884#if __cplusplus >= 201703L
885
886uint uncaughtExceptionCount() {
887 return std::uncaught_exceptions();
888}
889
890#elif __GNUC__
891
892// Horrible -- but working -- hack: We can dig into __cxa_get_globals() in order to extract the
893// count of uncaught exceptions. This function is part of the C++ ABI implementation used on Linux,
894// OSX, and probably other platforms that use GCC. Unfortunately, __cxa_get_globals() is only
895// actually defined in cxxabi.h on some platforms (e.g. Linux, but not OSX), and even where it is
896// defined, it returns an incomplete type. Here we use the same hack used by Evgeny Panasyuk:
897// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
898//
899// Notice that a similar hack is possible on MSVC -- if its C++11 support ever gets to the point of
900// supporting KJ in the first place.
901//
902// It appears likely that a future version of the C++ standard may include an
903// uncaught_exception_count() function in the standard library, or an equivalent language feature.
904// Some discussion:
905// https://groups.google.com/a/isocpp.org/d/msg/std-proposals/HglEslyZFYs/kKdu5jJw5AgJ
906
907struct FakeEhGlobals {
908 // Fake
909
910 void* caughtExceptions;
911 uint uncaughtExceptions;
912};
913
914// LLVM's libstdc++ doesn't declare __cxa_get_globals in its cxxabi.h. GNU does. Because it is
915// extern "C", the compiler wills get upset if we re-declare it even in a different namespace.
916#if _LIBCPPABI_VERSION
917extern "C" void* __cxa_get_globals();
918#else
919using abi::__cxa_get_globals;
920#endif
921
922uint uncaughtExceptionCount() {
923 return reinterpret_cast<FakeEhGlobals*>(__cxa_get_globals())->uncaughtExceptions;
924}
925
926#elif _MSC_VER
927
928#if _MSC_VER >= 1900
929// MSVC14 has a refactored CRT which now provides a direct accessor for this value.
930// See https://svn.boost.org/trac/boost/ticket/10158 for a brief discussion.
931extern "C" int *__cdecl __processing_throw();
932
933uint uncaughtExceptionCount() {
934 return static_cast<uint>(*__processing_throw());
935}
936
937#elif _MSC_VER >= 1400
938// The below was copied from:
939// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
940
941extern "C" char *__cdecl _getptd();
942
943uint uncaughtExceptionCount() {
944 return *reinterpret_cast<uint*>(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90));
945}
946#else
947uint uncaughtExceptionCount() {
948 // Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect
949 // results in very obscure cases that Cap'n Proto doesn't really rely on anyway.
950 return std::uncaught_exception();
951}
952#endif
953
954#else
955#error "This needs to be ported to your compiler / C++ ABI."
956#endif
957
958} // namespace _ (private)
959
960UnwindDetector::UnwindDetector(): uncaughtCount(_::uncaughtExceptionCount()) {}
961
962bool UnwindDetector::isUnwinding() const {
963 return _::uncaughtExceptionCount() > uncaughtCount;
964}
965
966void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const {
967 // TODO(someday): Attach the secondary exception to whatever primary exception is causing
968 // the unwind. For now we just drop it on the floor as this is probably fine most of the
969 // time.
970 runCatchingExceptions(runnable);
971}
972
973#if __GNUC__ && !KJ_NO_RTTI
974static kj::String demangleTypeName(const char* name) {
975 if (name == nullptr) return kj::heapString("(nil)");
976
977 int status;
978 char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status);
979 kj::String result = kj::heapString(buf == nullptr ? name : buf);
980 free(buf);
981 return kj::mv(result);
982}
983
984kj::String getCaughtExceptionType() {
985 return demangleTypeName(abi::__cxa_current_exception_type()->name());
986}
987#else
988kj::String getCaughtExceptionType() {
989 return kj::heapString("(unknown)");
990}
991#endif
992
993namespace _ { // private
994
995class RecoverableExceptionCatcher: public ExceptionCallback {
996 // Catches a recoverable exception without using try/catch. Used when compiled with
997 // -fno-exceptions.
998
999public:
1000 virtual ~RecoverableExceptionCatcher() noexcept(false) {}
1001
1002 void onRecoverableException(Exception&& exception) override {
1003 if (caught == nullptr) {
1004 caught = mv(exception);
1005 } else {
1006 // TODO(someday): Consider it a secondary fault?
1007 }
1008 }
1009
1010 Maybe<Exception> caught;
1011};
1012
1013Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
1014#if KJ_NO_EXCEPTIONS
1015 RecoverableExceptionCatcher catcher;
1016 runnable.run();
1017 KJ_IF_MAYBE(e, catcher.caught) {
1018 e->truncateCommonTrace();
1019 }
1020 return mv(catcher.caught);
1021#else
1022 try {
1023 runnable.run();
1024 return nullptr;
1025 } catch (Exception& e) {
1026 e.truncateCommonTrace();
1027 return kj::mv(e);
1028 } catch (std::bad_alloc& e) {
1029 return Exception(Exception::Type::OVERLOADED,
1030 "(unknown)", -1, str("std::bad_alloc: ", e.what()));
1031 } catch (std::exception& e) {
1032 return Exception(Exception::Type::FAILED,
1033 "(unknown)", -1, str("std::exception: ", e.what()));
1034 } catch (...) {
1035#if __GNUC__ && !KJ_NO_RTTI
1036 return Exception(Exception::Type::FAILED, "(unknown)", -1, str(
1037 "unknown non-KJ exception of type: ", getCaughtExceptionType()));
1038#else
1039 return Exception(Exception::Type::FAILED, "(unknown)", -1, str("unknown non-KJ exception"));
1040#endif
1041 }
1042#endif
1043}
1044
1045} // namespace _ (private)
1046
1047} // namespace kj
1048