capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

exception.c++ (47407B)


      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 #if _WIN32 || __CYGWIN__
     27 #include "win32-api-version.h"
     28 #endif
     29 
     30 #if (_WIN32 && _M_X64) || (__CYGWIN__ && __x86_64__)
     31 // Currently the Win32 stack-trace code only supports x86_64. We could easily extend it to support
     32 // i386 as well but it requires some code changes around how we read the context to start the
     33 // trace.
     34 #define KJ_USE_WIN32_DBGHELP 1
     35 #endif
     36 
     37 #include "exception.h"
     38 #include "string.h"
     39 #include "debug.h"
     40 #include "threadlocal.h"
     41 #include "miniposix.h"
     42 #include "function.h"
     43 #include "main.h"
     44 #include <stdlib.h>
     45 #include <exception>
     46 #include <new>
     47 #include <signal.h>
     48 #include <stdint.h>
     49 #ifndef _WIN32
     50 #include <sys/mman.h>
     51 #endif
     52 #include "io.h"
     53 
     54 #if !KJ_NO_RTTI
     55 #include <typeinfo>
     56 #endif
     57 #if __GNUC__
     58 #include <cxxabi.h>
     59 #endif
     60 
     61 #if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__
     62 #define KJ_HAS_BACKTRACE 1
     63 #include <execinfo.h>
     64 #endif
     65 
     66 #if _WIN32 || __CYGWIN__
     67 #include <windows.h>
     68 #include "windows-sanity.h"
     69 #include <dbghelp.h>
     70 #endif
     71 
     72 #if (__linux__ || __APPLE__ || __CYGWIN__)
     73 #include <stdio.h>
     74 #include <pthread.h>
     75 #endif
     76 
     77 #if __CYGWIN__
     78 #include <sys/cygwin.h>
     79 #include <ucontext.h>
     80 #endif
     81 
     82 #if KJ_HAS_LIBDL
     83 #include "dlfcn.h"
     84 #endif
     85 
     86 #if _MSC_VER
     87 #include <intrin.h>
     88 #endif
     89 
     90 #if KJ_HAS_COMPILER_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
     91 #include <sanitizer/lsan_interface.h>
     92 #else
     93 static void __lsan_ignore_object(const void* p) {}
     94 #endif
     95 // TODO(cleanup): Remove the LSAN stuff per https://github.com/capnproto/capnproto/pull/1255
     96 // feedback.
     97 
     98 namespace {
     99 template <typename T>
    100 inline T* lsanIgnoreObjectAndReturn(T* ptr) {
    101   // Defensively lsan_ignore_object since the documentation doesn't explicitly specify what happens
    102   // if you call this multiple times on the same object.
    103   // TODO(cleanup): Remove this per https://github.com/capnproto/capnproto/pull/1255.
    104   __lsan_ignore_object(ptr);
    105   return ptr;
    106 }
    107 }
    108 
    109 namespace kj {
    110 
    111 StringPtr KJ_STRINGIFY(LogSeverity severity) {
    112   static const char* SEVERITY_STRINGS[] = {
    113     "info",
    114     "warning",
    115     "error",
    116     "fatal",
    117     "debug"
    118   };
    119 
    120   return SEVERITY_STRINGS[static_cast<uint>(severity)];
    121 }
    122 
    123 #if KJ_USE_WIN32_DBGHELP
    124 
    125 namespace {
    126 
    127 struct Dbghelp {
    128   // Load dbghelp.dll dynamically since we don't really need it, it's just for debugging.
    129 
    130   HINSTANCE lib;
    131 
    132   BOOL (WINAPI *symInitialize)(HANDLE hProcess,PCSTR UserSearchPath,BOOL fInvadeProcess);
    133   BOOL (WINAPI *stackWalk64)(
    134       DWORD MachineType,HANDLE hProcess,HANDLE hThread,
    135       LPSTACKFRAME64 StackFrame,PVOID ContextRecord,
    136       PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
    137       PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
    138       PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
    139       PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
    140   PVOID (WINAPI *symFunctionTableAccess64)(HANDLE hProcess,DWORD64 AddrBase);
    141   DWORD64 (WINAPI *symGetModuleBase64)(HANDLE hProcess,DWORD64 qwAddr);
    142   BOOL (WINAPI *symGetLineFromAddr64)(
    143       HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE64 Line64);
    144 
    145 #if __GNUC__ && !__clang__ && __GNUC__ >= 8
    146 // GCC 8 warns that our reinterpret_casts of function pointers below are casting between
    147 // incompatible types. Yes, GCC, we know that. This is the nature of GetProcAddress(); it returns
    148 // everything as `long long int (*)()` and we have to cast to the actual type.
    149 #pragma GCC diagnostic push
    150 #pragma GCC diagnostic ignored "-Wcast-function-type"
    151 #endif
    152   Dbghelp()
    153       : lib(LoadLibraryA("dbghelp.dll")),
    154         symInitialize(lib == nullptr ? nullptr :
    155             reinterpret_cast<decltype(symInitialize)>(
    156                 GetProcAddress(lib, "SymInitialize"))),
    157         stackWalk64(symInitialize == nullptr ? nullptr :
    158             reinterpret_cast<decltype(stackWalk64)>(
    159                 GetProcAddress(lib, "StackWalk64"))),
    160         symFunctionTableAccess64(symInitialize == nullptr ? nullptr :
    161             reinterpret_cast<decltype(symFunctionTableAccess64)>(
    162                 GetProcAddress(lib, "SymFunctionTableAccess64"))),
    163         symGetModuleBase64(symInitialize == nullptr ? nullptr :
    164             reinterpret_cast<decltype(symGetModuleBase64)>(
    165                 GetProcAddress(lib, "SymGetModuleBase64"))),
    166         symGetLineFromAddr64(symInitialize == nullptr ? nullptr :
    167             reinterpret_cast<decltype(symGetLineFromAddr64)>(
    168                 GetProcAddress(lib, "SymGetLineFromAddr64"))) {
    169     if (symInitialize != nullptr) {
    170       symInitialize(GetCurrentProcess(), NULL, TRUE);
    171     }
    172   }
    173 #if __GNUC__ && !__clang__ && __GNUC__ >= 9
    174 #pragma GCC diagnostic pop
    175 #endif
    176 };
    177 
    178 const Dbghelp& getDbghelp() {
    179   static Dbghelp dbghelp;
    180   return dbghelp;
    181 }
    182 
    183 ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount,
    184                                     HANDLE thread, CONTEXT& context) {
    185   // NOTE: Apparently there is a function CaptureStackBackTrace() that is equivalent to glibc's
    186   //   backtrace(). Somehow I missed that when I originally wrote this. However,
    187   //   CaptureStackBackTrace() does not accept a CONTEXT parameter; it can only trace the caller.
    188   //   That's more problematic on Windows where breakHandler(), sehHandler(), and Cygwin signal
    189   //   handlers all depend on the ability to pass a CONTEXT. So we'll keep this code, which works
    190   //   after all.
    191 
    192   const Dbghelp& dbghelp = getDbghelp();
    193   if (dbghelp.stackWalk64 == nullptr ||
    194       dbghelp.symFunctionTableAccess64 == nullptr ||
    195       dbghelp.symGetModuleBase64 == nullptr) {
    196     return nullptr;
    197   }
    198 
    199   STACKFRAME64 frame;
    200   memset(&frame, 0, sizeof(frame));
    201 
    202   frame.AddrPC.Offset = context.Rip;
    203   frame.AddrPC.Mode = AddrModeFlat;
    204   frame.AddrStack.Offset = context.Rsp;
    205   frame.AddrStack.Mode = AddrModeFlat;
    206   frame.AddrFrame.Offset = context.Rbp;
    207   frame.AddrFrame.Mode = AddrModeFlat;
    208 
    209   HANDLE process = GetCurrentProcess();
    210 
    211   uint count = 0;
    212   for (; count < space.size(); count++) {
    213     if (!dbghelp.stackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread,
    214           &frame, &context, NULL, dbghelp.symFunctionTableAccess64,
    215           dbghelp.symGetModuleBase64, NULL)){
    216       break;
    217     }
    218 
    219     // Subtract 1 from each address so that we identify the calling instructions, rather than the
    220     // return addresses (which are typically the instruction after the call).
    221     space[count] = reinterpret_cast<void*>(frame.AddrPC.Offset - 1);
    222   }
    223 
    224   return space.slice(kj::min(ignoreCount, count), count);
    225 }
    226 
    227 }  // namespace
    228 #endif
    229 
    230 ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
    231   if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) {
    232     return nullptr;
    233   }
    234 
    235 #if KJ_USE_WIN32_DBGHELP
    236   CONTEXT context;
    237   RtlCaptureContext(&context);
    238   return getStackTrace(space, ignoreCount, GetCurrentThread(), context);
    239 #elif KJ_HAS_BACKTRACE
    240   size_t size = backtrace(space.begin(), space.size());
    241   for (auto& addr: space.slice(0, size)) {
    242     // The addresses produced by backtrace() are return addresses, which means they point to the
    243     // instruction immediately after the call. Invoking addr2line on these can be confusing because
    244     // it often points to the next line. If the next instruction is inlined from another function,
    245     // the trace can be extra-confusing, since now it claims to be in a function that was not
    246     // actually on the call stack. If we subtract 1 from each address, though, we get a much more
    247     // reasonable trace. This may cause the addresses to be invalid instruction pointers if the
    248     // instructions were multi-byte, but it appears addr2line is able to cope with this.
    249     addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - 1);
    250   }
    251   return space.slice(kj::min(ignoreCount + 1, size), size);
    252 #else
    253   return nullptr;
    254 #endif
    255 }
    256 
    257 String stringifyStackTrace(ArrayPtr<void* const> trace) {
    258   if (trace.size() == 0) return nullptr;
    259   if (getExceptionCallback().stackTraceMode() != ExceptionCallback::StackTraceMode::FULL) {
    260     return nullptr;
    261   }
    262 
    263 #if KJ_USE_WIN32_DBGHELP && _MSC_VER
    264 
    265   // Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since
    266   // this requires MSVC debug info.
    267   //
    268   // TODO(someday): We could perhaps shell out to addr2line on MinGW.
    269 
    270   const Dbghelp& dbghelp = getDbghelp();
    271   if (dbghelp.symGetLineFromAddr64 == nullptr) return nullptr;
    272 
    273   HANDLE process = GetCurrentProcess();
    274 
    275   KJ_STACK_ARRAY(String, lines, trace.size(), 32, 32);
    276 
    277   for (auto i: kj::indices(trace)) {
    278     IMAGEHLP_LINE64 lineInfo;
    279     memset(&lineInfo, 0, sizeof(lineInfo));
    280     lineInfo.SizeOfStruct = sizeof(lineInfo);
    281     if (dbghelp.symGetLineFromAddr64(process, reinterpret_cast<DWORD64>(trace[i]), NULL, &lineInfo)) {
    282       lines[i] = kj::str('\n', lineInfo.FileName, ':', lineInfo.LineNumber);
    283     }
    284   }
    285 
    286   return strArray(lines, "");
    287 
    288 #elif (__linux__ || __APPLE__ || __CYGWIN__) && !__ANDROID__
    289   // We want to generate a human-readable stack trace.
    290 
    291   // TODO(someday):  It would be really great if we could avoid farming out to another process
    292   //   and do this all in-process, but that may involve onerous requirements like large library
    293   //   dependencies or using -rdynamic.
    294 
    295   // The environment manipulation is not thread-safe, so lock a mutex.  This could still be
    296   // problematic if another thread is manipulating the environment in unrelated code, but there's
    297   // not much we can do about that.  This is debug-only anyway and only an issue when LD_PRELOAD
    298   // is in use.
    299   static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    300   pthread_mutex_lock(&mutex);
    301   KJ_DEFER(pthread_mutex_unlock(&mutex));
    302 
    303   // Don't heapcheck / intercept syscalls.
    304   const char* preload = getenv("LD_PRELOAD");
    305   String oldPreload;
    306   if (preload != nullptr) {
    307     oldPreload = heapString(preload);
    308     unsetenv("LD_PRELOAD");
    309   }
    310   KJ_DEFER(if (oldPreload != nullptr) { setenv("LD_PRELOAD", oldPreload.cStr(), true); });
    311 
    312   String lines[32];
    313   FILE* p = nullptr;
    314   auto strTrace = strArray(trace, " ");
    315 
    316 #if __linux__
    317   if (access("/proc/self/exe", R_OK) < 0) {
    318     // Apparently /proc is not available?
    319     return nullptr;
    320   }
    321 
    322   // Obtain symbolic stack trace using addr2line.
    323   // TODO(cleanup): Use fork() and exec() or maybe our own Subprocess API (once it exists), to
    324   //   avoid depending on a shell.
    325   p = popen(str("addr2line -e /proc/", getpid(), "/exe ", strTrace).cStr(), "r");
    326 #elif __APPLE__
    327   // The Mac OS X equivalent of addr2line is atos.
    328   // (Internally, it uses the private CoreSymbolication.framework library.)
    329   p = popen(str("xcrun atos -p ", getpid(), ' ', strTrace).cStr(), "r");
    330 #elif __CYGWIN__
    331   wchar_t exeWinPath[MAX_PATH];
    332   if (GetModuleFileNameW(nullptr, exeWinPath, sizeof(exeWinPath)) == 0) {
    333     return nullptr;
    334   }
    335   char exePosixPath[MAX_PATH * 2];
    336   if (cygwin_conv_path(CCP_WIN_W_TO_POSIX, exeWinPath, exePosixPath, sizeof(exePosixPath)) < 0) {
    337     return nullptr;
    338   }
    339   p = popen(str("addr2line -e '", exePosixPath, "' ", strTrace).cStr(), "r");
    340 #endif
    341 
    342   if (p == nullptr) {
    343     return nullptr;
    344   }
    345 
    346   char line[512];
    347   size_t i = 0;
    348   while (i < kj::size(lines) && fgets(line, sizeof(line), p) != nullptr) {
    349     // Don't include exception-handling infrastructure or promise infrastructure in stack trace.
    350     // addr2line output matches file names; atos output matches symbol names.
    351     if (strstr(line, "kj/common.c++") != nullptr ||
    352         strstr(line, "kj/exception.") != nullptr ||
    353         strstr(line, "kj/debug.") != nullptr ||
    354         strstr(line, "kj/async.") != nullptr ||
    355         strstr(line, "kj/async-prelude.h") != nullptr ||
    356         strstr(line, "kj/async-inl.h") != nullptr ||
    357         strstr(line, "kj::Exception") != nullptr ||
    358         strstr(line, "kj::_::Debug") != nullptr) {
    359       continue;
    360     }
    361 
    362     size_t len = strlen(line);
    363     if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';
    364     lines[i++] = str("\n    ", trimSourceFilename(line), ": returning here");
    365   }
    366 
    367   // Skip remaining input.
    368   while (fgets(line, sizeof(line), p) != nullptr) {}
    369 
    370   pclose(p);
    371 
    372   return strArray(arrayPtr(lines, i), "");
    373 
    374 #else
    375   return nullptr;
    376 #endif
    377 }
    378 
    379 String stringifyStackTraceAddresses(ArrayPtr<void* const> trace) {
    380 #if KJ_HAS_LIBDL
    381   return strArray(KJ_MAP(addr, trace) {
    382     Dl_info info;
    383     // Shared libraries are mapped near the end of the address space while the executable is mapped
    384     // near the beginning. We want to print addresses in the executable as raw addresses, not
    385     // offsets, since that's what addr2line expects for executables. For shared libraries it
    386     // expects offsets. In any case, most frames are likely to be in the main executable so it
    387     // makes the output cleaner if we don't repeatedly write its name.
    388     if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
    389       uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
    390                          reinterpret_cast<uintptr_t>(info.dli_fbase);
    391       return kj::str(info.dli_fname, '@', reinterpret_cast<void*>(offset));
    392     } else {
    393       return kj::str(addr);
    394     }
    395   }, " ");
    396 #else
    397   // TODO(someday): Support other platforms.
    398   return kj::strArray(trace, " ");
    399 #endif
    400 }
    401 
    402 StringPtr stringifyStackTraceAddresses(ArrayPtr<void* const> trace, ArrayPtr<char> scratch) {
    403   // Version which writes into a pre-allocated buffer. This is safe for signal handlers to the
    404   // extent that dladdr() is safe.
    405   //
    406   // TODO(cleanup): We should improve the KJ stringification framework so that there's a way to
    407   //   write this string directly into a larger message buffer with strPreallocated().
    408 
    409 #if KJ_HAS_LIBDL
    410   char* ptr = scratch.begin();
    411   char* limit = scratch.end() - 1;
    412 
    413   for (auto addr: trace) {
    414     Dl_info info;
    415     // Shared libraries are mapped near the end of the address space while the executable is mapped
    416     // near the beginning. We want to print addresses in the executable as raw addresses, not
    417     // offsets, since that's what addr2line expects for executables. For shared libraries it
    418     // expects offsets. In any case, most frames are likely to be in the main executable so it
    419     // makes the output cleaner if we don't repeatedly write its name.
    420     if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
    421       uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
    422                          reinterpret_cast<uintptr_t>(info.dli_fbase);
    423       ptr = _::fillLimited(ptr, limit, kj::StringPtr(info.dli_fname), "@0x"_kj, hex(offset));
    424     } else {
    425       ptr = _::fillLimited(ptr, limit, toCharSequence(addr));
    426     }
    427 
    428     ptr = _::fillLimited(ptr, limit, " "_kj);
    429   }
    430   *ptr = '\0';
    431   return StringPtr(scratch.begin(), ptr);
    432 #else
    433   // TODO(someday): Support other platforms.
    434   return kj::strPreallocated(scratch, kj::delimited(trace, " "));
    435 #endif
    436 }
    437 
    438 String getStackTrace() {
    439   void* space[32];
    440   auto trace = getStackTrace(space, 2);
    441   return kj::str(stringifyStackTraceAddresses(trace), stringifyStackTrace(trace));
    442 }
    443 
    444 namespace {
    445 
    446 #if !KJ_NO_EXCEPTIONS
    447 
    448 [[noreturn]] void terminateHandler() {
    449   void* traceSpace[32];
    450 
    451   // ignoreCount = 3 to ignore std::terminate entry.
    452   auto trace = kj::getStackTrace(traceSpace, 3);
    453 
    454   kj::String message;
    455 
    456   auto eptr = std::current_exception();
    457   if (eptr != nullptr) {
    458     try {
    459       std::rethrow_exception(eptr);
    460     } catch (const kj::Exception& exception) {
    461       message = kj::str("*** Fatal uncaught kj::Exception: ", exception, '\n');
    462     } catch (const std::exception& exception) {
    463       message = kj::str("*** Fatal uncaught std::exception: ", exception.what(),
    464                         "\nstack: ", stringifyStackTraceAddresses(trace),
    465                                      stringifyStackTrace(trace), '\n');
    466     } catch (...) {
    467       message = kj::str("*** Fatal uncaught exception of type: ", kj::getCaughtExceptionType(),
    468                         "\nstack: ", stringifyStackTraceAddresses(trace),
    469                                      stringifyStackTrace(trace), '\n');
    470     }
    471   } else {
    472     message = kj::str("*** std::terminate() called with no exception"
    473                       "\nstack: ", stringifyStackTraceAddresses(trace),
    474                                    stringifyStackTrace(trace), '\n');
    475   }
    476 
    477   kj::FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
    478   _exit(1);
    479 }
    480 
    481 #endif
    482 
    483 }  // namespace
    484 
    485 #if KJ_USE_WIN32_DBGHELP && !__CYGWIN__
    486 namespace {
    487 
    488 DWORD mainThreadId = 0;
    489 
    490 BOOL WINAPI breakHandler(DWORD type) {
    491   switch (type) {
    492     case CTRL_C_EVENT:
    493     case CTRL_BREAK_EVENT: {
    494       HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThreadId);
    495       if (thread != NULL) {
    496         if (SuspendThread(thread) != (DWORD)-1) {
    497           CONTEXT context;
    498           memset(&context, 0, sizeof(context));
    499           context.ContextFlags = CONTEXT_FULL;
    500           if (GetThreadContext(thread, &context)) {
    501             void* traceSpace[32];
    502             auto trace = getStackTrace(traceSpace, 0, thread, context);
    503             ResumeThread(thread);
    504             auto message = kj::str("*** Received CTRL+C. stack: ",
    505                                    stringifyStackTraceAddresses(trace),
    506                                    stringifyStackTrace(trace), '\n');
    507             FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
    508           } else {
    509             ResumeThread(thread);
    510           }
    511         }
    512         CloseHandle(thread);
    513       }
    514       break;
    515     }
    516     default:
    517       break;
    518   }
    519 
    520   return FALSE;  // still crash
    521 }
    522 
    523 kj::StringPtr exceptionDescription(DWORD code) {
    524   switch (code) {
    525     case EXCEPTION_ACCESS_VIOLATION: return "access violation";
    526     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "array bounds exceeded";
    527     case EXCEPTION_BREAKPOINT: return "breakpoint";
    528     case EXCEPTION_DATATYPE_MISALIGNMENT: return "datatype misalignment";
    529     case EXCEPTION_FLT_DENORMAL_OPERAND: return "denormal floating point operand";
    530     case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "floating point division by zero";
    531     case EXCEPTION_FLT_INEXACT_RESULT: return "inexact floating point result";
    532     case EXCEPTION_FLT_INVALID_OPERATION: return "invalid floating point operation";
    533     case EXCEPTION_FLT_OVERFLOW: return "floating point overflow";
    534     case EXCEPTION_FLT_STACK_CHECK: return "floating point stack overflow";
    535     case EXCEPTION_FLT_UNDERFLOW: return "floating point underflow";
    536     case EXCEPTION_ILLEGAL_INSTRUCTION: return "illegal instruction";
    537     case EXCEPTION_IN_PAGE_ERROR: return "page error";
    538     case EXCEPTION_INT_DIVIDE_BY_ZERO: return "integer divided by zero";
    539     case EXCEPTION_INT_OVERFLOW: return "integer overflow";
    540     case EXCEPTION_INVALID_DISPOSITION: return "invalid disposition";
    541     case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "noncontinuable exception";
    542     case EXCEPTION_PRIV_INSTRUCTION: return "privileged instruction";
    543     case EXCEPTION_SINGLE_STEP: return "single step";
    544     case EXCEPTION_STACK_OVERFLOW: return "stack overflow";
    545     default: return "(unknown exception code)";
    546   }
    547 }
    548 
    549 LONG WINAPI sehHandler(EXCEPTION_POINTERS* info) {
    550   void* traceSpace[32];
    551   auto trace = getStackTrace(traceSpace, 0, GetCurrentThread(), *info->ContextRecord);
    552   auto message = kj::str("*** Received structured exception #0x",
    553                          hex(info->ExceptionRecord->ExceptionCode), ": ",
    554                          exceptionDescription(info->ExceptionRecord->ExceptionCode),
    555                          "; stack: ",
    556                          stringifyStackTraceAddresses(trace),
    557                          stringifyStackTrace(trace), '\n');
    558   FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
    559   return EXCEPTION_EXECUTE_HANDLER;  // still crash
    560 }
    561 
    562 }  // namespace
    563 
    564 void printStackTraceOnCrash() {
    565   mainThreadId = GetCurrentThreadId();
    566   KJ_WIN32(SetConsoleCtrlHandler(breakHandler, TRUE));
    567   SetUnhandledExceptionFilter(&sehHandler);
    568 
    569 #if !KJ_NO_EXCEPTIONS
    570   // Also override std::terminate() handler with something nicer for KJ.
    571   std::set_terminate(&terminateHandler);
    572 #endif
    573 }
    574 
    575 #elif _WIN32
    576 // Windows, but KJ_USE_WIN32_DBGHELP is not enabled. We can't print useful stack traces, so don't
    577 // try to catch SEH nor ctrl+C.
    578 
    579 void printStackTraceOnCrash() {
    580 #if !KJ_NO_EXCEPTIONS
    581   std::set_terminate(&terminateHandler);
    582 #endif
    583 }
    584 
    585 #else
    586 namespace {
    587 
    588 [[noreturn]] void crashHandler(int signo, siginfo_t* info, void* context) {
    589   void* traceSpace[32];
    590 
    591 #if KJ_USE_WIN32_DBGHELP
    592   // Win32 backtracing can't trace its way out of a Cygwin signal handler. However, Cygwin gives
    593   // us direct access to the CONTEXT, which we can pass to the Win32 tracing functions.
    594   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
    595   // Cygwin's mcontext_t has the same layout as CONTEXT.
    596   // TODO(someday): Figure out why this produces garbage for SIGINT from ctrl+C. It seems to work
    597   //   correctly for SIGSEGV.
    598   CONTEXT win32Context;
    599   static_assert(sizeof(ucontext->uc_mcontext) >= sizeof(win32Context),
    600       "mcontext_t should be an extension of CONTEXT");
    601   memcpy(&win32Context, &ucontext->uc_mcontext, sizeof(win32Context));
    602   auto trace = getStackTrace(traceSpace, 0, GetCurrentThread(), win32Context);
    603 #else
    604   // ignoreCount = 2 to ignore crashHandler() and signal trampoline.
    605   auto trace = getStackTrace(traceSpace, 2);
    606 #endif
    607 
    608   auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
    609                          "\nstack: ", stringifyStackTraceAddresses(trace),
    610                          stringifyStackTrace(trace), '\n');
    611 
    612   FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
    613   _exit(1);
    614 }
    615 
    616 }  // namespace
    617 
    618 void printStackTraceOnCrash() {
    619   // Set up alternate signal stack so that stack overflows can be handled.
    620   stack_t stack;
    621   memset(&stack, 0, sizeof(stack));
    622 
    623 #ifndef MAP_ANONYMOUS
    624 #define MAP_ANONYMOUS MAP_ANON
    625 #endif
    626 #ifndef MAP_GROWSDOWN
    627 #define MAP_GROWSDOWN 0
    628 #endif
    629 
    630   stack.ss_size = 65536;
    631   // Note: ss_sp is char* on FreeBSD, void* on Linux and OSX.
    632   stack.ss_sp = reinterpret_cast<char*>(mmap(
    633       nullptr, stack.ss_size, PROT_READ | PROT_WRITE,
    634       MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0));
    635   KJ_SYSCALL(sigaltstack(&stack, nullptr));
    636 
    637   // Catch all relevant signals.
    638   struct sigaction action;
    639   memset(&action, 0, sizeof(action));
    640 
    641   action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
    642   action.sa_sigaction = &crashHandler;
    643 
    644   // Dump stack on common "crash" signals.
    645   KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr));
    646   KJ_SYSCALL(sigaction(SIGBUS, &action, nullptr));
    647   KJ_SYSCALL(sigaction(SIGFPE, &action, nullptr));
    648   KJ_SYSCALL(sigaction(SIGABRT, &action, nullptr));
    649   KJ_SYSCALL(sigaction(SIGILL, &action, nullptr));
    650 
    651   // Dump stack on unimplemented syscalls -- useful in seccomp sandboxes.
    652   KJ_SYSCALL(sigaction(SIGSYS, &action, nullptr));
    653 
    654 #ifdef KJ_DEBUG
    655   // Dump stack on keyboard interrupt -- useful for infinite loops. Only in debug mode, though,
    656   // because stack traces on ctrl+c can be obnoxious for, say, command-line tools.
    657   KJ_SYSCALL(sigaction(SIGINT, &action, nullptr));
    658 #endif
    659 
    660 #if !KJ_NO_EXCEPTIONS
    661   // Also override std::terminate() handler with something nicer for KJ.
    662   std::set_terminate(&terminateHandler);
    663 #endif
    664 }
    665 #endif
    666 
    667 kj::StringPtr trimSourceFilename(kj::StringPtr filename) {
    668   // Removes noisy prefixes from source code file name.
    669   //
    670   // The goal here is to produce the "canonical" filename given the filename returned by e.g.
    671   // addr2line. addr2line gives us the full path of the file as passed on the compiler
    672   // command-line, which in turn is affected by build system and by whether and where we're
    673   // performing an out-of-tree build.
    674   //
    675   // To deal with all this, we look for directory names in the path which we recognize to be
    676   // locations that represent roots of the source tree. We strip said root and everything before
    677   // it.
    678   //
    679   // On Windows, we often get filenames containing backslashes. Since we aren't allowed to allocate
    680   // a new string here, we can't do much about this, so our returned "canonical" name will
    681   // unfortunately end up with backslashes.
    682 
    683   static constexpr const char* ROOTS[] = {
    684     "ekam-provider/canonical/",  // Ekam source file.
    685     "ekam-provider/c++header/",  // Ekam include file.
    686     "src/",                      // Non-Ekam source root.
    687     "tmp/",                      // Non-Ekam generated code.
    688 #if _WIN32
    689     "src\\",                     // Win32 source root.
    690     "tmp\\",                     // Win32 generated code.
    691 #endif
    692   };
    693 
    694 retry:
    695   for (size_t i: kj::indices(filename)) {
    696     if (i == 0 || filename[i-1] == '/'
    697 #if _WIN32
    698                || filename[i-1] == '\\'
    699 #endif
    700         ) {
    701       // We're at the start of a directory name. Check for valid prefixes.
    702       for (kj::StringPtr root: ROOTS) {
    703         if (filename.slice(i).startsWith(root)) {
    704           filename = filename.slice(i + root.size());
    705 
    706           // We should keep searching to find the last instance of a root name. `i` is no longer
    707           // a valid index for `filename` so start the loop over.
    708           goto retry;
    709         }
    710       }
    711     }
    712   }
    713 
    714   return filename;
    715 }
    716 
    717 StringPtr KJ_STRINGIFY(Exception::Type type) {
    718   static const char* TYPE_STRINGS[] = {
    719     "failed",
    720     "overloaded",
    721     "disconnected",
    722     "unimplemented"
    723   };
    724 
    725   return TYPE_STRINGS[static_cast<uint>(type)];
    726 }
    727 
    728 String KJ_STRINGIFY(const Exception& e) {
    729   uint contextDepth = 0;
    730 
    731   Maybe<const Exception::Context&> contextPtr = e.getContext();
    732   for (;;) {
    733     KJ_IF_MAYBE(c, contextPtr) {
    734       ++contextDepth;
    735       contextPtr = c->next;
    736     } else {
    737       break;
    738     }
    739   }
    740 
    741   Array<String> contextText = heapArray<String>(contextDepth);
    742 
    743   contextDepth = 0;
    744   contextPtr = e.getContext();
    745   for (;;) {
    746     KJ_IF_MAYBE(c, contextPtr) {
    747       contextText[contextDepth++] =
    748           str(trimSourceFilename(c->file), ":", c->line, ": context: ", c->description, "\n");
    749       contextPtr = c->next;
    750     } else {
    751       break;
    752     }
    753   }
    754 
    755   // Note that we put "remote" before "stack" because trace frames are ordered callee before
    756   // caller, so this is the most natural presentation ordering.
    757   return str(strArray(contextText, ""),
    758              e.getFile(), ":", e.getLine(), ": ", e.getType(),
    759              e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
    760              e.getRemoteTrace().size() > 0 ? "\nremote: " : "",
    761              e.getRemoteTrace(),
    762              e.getStackTrace().size() > 0 ? "\nstack: " : "",
    763              stringifyStackTraceAddresses(e.getStackTrace()),
    764              stringifyStackTrace(e.getStackTrace()));
    765 }
    766 
    767 Exception::Exception(Type type, const char* file, int line, String description) noexcept
    768     : file(trimSourceFilename(file).cStr()), line(line), type(type), description(mv(description)),
    769       traceCount(0) {}
    770 
    771 Exception::Exception(Type type, String file, int line, String description) noexcept
    772     : ownFile(kj::mv(file)), file(trimSourceFilename(ownFile).cStr()), line(line), type(type),
    773       description(mv(description)), traceCount(0) {}
    774 
    775 Exception::Exception(const Exception& other) noexcept
    776     : file(other.file), line(other.line), type(other.type),
    777       description(heapString(other.description)), traceCount(other.traceCount) {
    778   if (file == other.ownFile.cStr()) {
    779     ownFile = heapString(other.ownFile);
    780     file = ownFile.cStr();
    781   }
    782 
    783   if (other.remoteTrace != nullptr) {
    784     remoteTrace = kj::str(other.remoteTrace);
    785   }
    786 
    787   memcpy(trace, other.trace, sizeof(trace[0]) * traceCount);
    788 
    789   KJ_IF_MAYBE(c, other.context) {
    790     context = heap(**c);
    791   }
    792 }
    793 
    794 Exception::~Exception() noexcept {}
    795 
    796 Exception::Context::Context(const Context& other) noexcept
    797     : file(other.file), line(other.line), description(str(other.description)) {
    798   KJ_IF_MAYBE(n, other.next) {
    799     next = heap(**n);
    800   }
    801 }
    802 
    803 void Exception::wrapContext(const char* file, int line, String&& description) {
    804   context = heap<Context>(file, line, mv(description), mv(context));
    805 }
    806 
    807 void Exception::extendTrace(uint ignoreCount, uint limit) {
    808   KJ_STACK_ARRAY(void*, newTraceSpace, kj::min(kj::size(trace), limit) + ignoreCount + 1,
    809       sizeof(trace)/sizeof(trace[0]) + 8, 128);
    810 
    811   auto newTrace = kj::getStackTrace(newTraceSpace, ignoreCount + 1);
    812   if (newTrace.size() > ignoreCount + 2) {
    813     // Remove suffix that won't fit into our static-sized trace.
    814     newTrace = newTrace.slice(0, kj::min(kj::size(trace) - traceCount, newTrace.size()));
    815 
    816     // Copy the rest into our trace.
    817     memcpy(trace + traceCount, newTrace.begin(), newTrace.asBytes().size());
    818     traceCount += newTrace.size();
    819   }
    820 }
    821 
    822 void Exception::truncateCommonTrace() {
    823   if (traceCount > 0) {
    824     // Create a "reference" stack trace that is a little bit deeper than the one in the exception.
    825     void* refTraceSpace[sizeof(this->trace) / sizeof(this->trace[0]) + 4];
    826     auto refTrace = kj::getStackTrace(refTraceSpace, 0);
    827 
    828     // We expect that the deepest frame in the exception's stack trace should be somewhere in our
    829     // own trace, since our own trace has a deeper limit. Search for it.
    830     for (uint i = refTrace.size(); i > 0; i--) {
    831       if (refTrace[i-1] == trace[traceCount-1]) {
    832         // See how many frames match.
    833         for (uint j = 0; j < i; j++) {
    834           if (j >= traceCount) {
    835             // We matched the whole trace, apparently?
    836             traceCount = 0;
    837             return;
    838           } else if (refTrace[i-j-1] != trace[traceCount-j-1]) {
    839             // Found mismatching entry.
    840 
    841             // If we matched more than half of the reference trace, guess that this is in fact
    842             // the prefix we're looking for.
    843             if (j > refTrace.size() / 2) {
    844               // Delete the matching suffix. Also delete one non-matched entry on the assumption
    845               // that both traces contain that stack frame but are simply at different points in
    846               // the function.
    847               traceCount -= j + 1;
    848               return;
    849             }
    850           }
    851         }
    852       }
    853     }
    854 
    855     // No match. Ignore.
    856   }
    857 }
    858 
    859 void Exception::addTrace(void* ptr) {
    860   if (traceCount < kj::size(trace)) {
    861     trace[traceCount++] = ptr;
    862   }
    863 }
    864 
    865 void Exception::addTraceHere() {
    866 #if __GNUC__
    867   addTrace(__builtin_return_address(0));
    868 #elif _MSC_VER
    869   addTrace(_ReturnAddress());
    870 #else
    871   #error "please implement for your compiler"
    872 #endif
    873 }
    874 
    875 #if !KJ_NO_EXCEPTIONS
    876 
    877 namespace {
    878 
    879 KJ_THREADLOCAL_PTR(ExceptionImpl) currentException = nullptr;
    880 
    881 }  // namespace
    882 
    883 class ExceptionImpl: public Exception, public std::exception {
    884 public:
    885   inline ExceptionImpl(Exception&& other): Exception(mv(other)) {
    886     insertIntoCurrentExceptions();
    887   }
    888   ExceptionImpl(const ExceptionImpl& other): Exception(other) {
    889     // No need to copy whatBuffer since it's just to hold the return value of what().
    890     insertIntoCurrentExceptions();
    891   }
    892   ~ExceptionImpl() {
    893     // Look for ourselves in the list.
    894     for (auto* ptr = &currentException; *ptr != nullptr; ptr = &(*ptr)->nextCurrentException) {
    895       if (*ptr == this) {
    896         *ptr = nextCurrentException;
    897         return;
    898       }
    899     }
    900 
    901     // Possibly the ExceptionImpl was destroyed on a different thread than created it? That's
    902     // pretty bad, we'd better abort.
    903     abort();
    904   }
    905 
    906   const char* what() const noexcept override;
    907 
    908 private:
    909   mutable String whatBuffer;
    910   ExceptionImpl* nextCurrentException = nullptr;
    911 
    912   void insertIntoCurrentExceptions() {
    913     nextCurrentException = currentException;
    914     currentException = this;
    915   }
    916 
    917   friend class InFlightExceptionIterator;
    918 };
    919 
    920 const char* ExceptionImpl::what() const noexcept {
    921   whatBuffer = str(*this);
    922   return whatBuffer.begin();
    923 }
    924 
    925 InFlightExceptionIterator::InFlightExceptionIterator()
    926     : ptr(currentException) {}
    927 
    928 Maybe<const Exception&> InFlightExceptionIterator::next() {
    929   if (ptr == nullptr) return nullptr;
    930 
    931   const ExceptionImpl& result = *static_cast<const ExceptionImpl*>(ptr);
    932   ptr = result.nextCurrentException;
    933   return result;
    934 }
    935 
    936 #endif  // !KJ_NO_EXCEPTIONS
    937 
    938 kj::Exception getDestructionReason(void* traceSeparator, kj::Exception::Type defaultType,
    939     const char* defaultFile, int defaultLine, kj::StringPtr defaultDescription) {
    940 #if !KJ_NO_EXCEPTIONS
    941   InFlightExceptionIterator iter;
    942   KJ_IF_MAYBE(e, iter.next()) {
    943     auto copy = kj::cp(*e);
    944     copy.truncateCommonTrace();
    945     return copy;
    946   } else {
    947 #endif
    948     // Darn, use a generic exception.
    949     kj::Exception exception(defaultType, defaultFile, defaultLine,
    950         kj::heapString(defaultDescription));
    951 
    952     // Let's give some context on where the PromiseFulfiller was destroyed.
    953     exception.extendTrace(2, 16);
    954 
    955     // Add a separator that hopefully makes this understandable...
    956     exception.addTrace(traceSeparator);
    957 
    958     return exception;
    959 #if !KJ_NO_EXCEPTIONS
    960   }
    961 #endif
    962 }
    963 
    964 // =======================================================================================
    965 
    966 namespace {
    967 
    968 KJ_THREADLOCAL_PTR(ExceptionCallback) threadLocalCallback = nullptr;
    969 
    970 }  // namespace
    971 
    972 ExceptionCallback::ExceptionCallback(): next(getExceptionCallback()) {
    973   char stackVar;
    974 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    975   ptrdiff_t offset = reinterpret_cast<char*>(this) - &stackVar;
    976   KJ_ASSERT(offset < 65536 && offset > -65536,
    977             "ExceptionCallback must be allocated on the stack.");
    978 #endif
    979 
    980   threadLocalCallback = this;
    981 }
    982 
    983 ExceptionCallback::ExceptionCallback(ExceptionCallback& next): next(next) {}
    984 
    985 ExceptionCallback::~ExceptionCallback() noexcept(false) {
    986   if (&next != this) {
    987     threadLocalCallback = &next;
    988   }
    989 }
    990 
    991 void ExceptionCallback::onRecoverableException(Exception&& exception) {
    992   next.onRecoverableException(mv(exception));
    993 }
    994 
    995 void ExceptionCallback::onFatalException(Exception&& exception) {
    996   next.onFatalException(mv(exception));
    997 }
    998 
    999 void ExceptionCallback::logMessage(
   1000     LogSeverity severity, const char* file, int line, int contextDepth, String&& text) {
   1001   next.logMessage(severity, file, line, contextDepth, mv(text));
   1002 }
   1003 
   1004 ExceptionCallback::StackTraceMode ExceptionCallback::stackTraceMode() {
   1005   return next.stackTraceMode();
   1006 }
   1007 
   1008 Function<void(Function<void()>)> ExceptionCallback::getThreadInitializer() {
   1009   return next.getThreadInitializer();
   1010 }
   1011 
   1012 namespace _ {  // private
   1013   uint uncaughtExceptionCount();  // defined later in this file
   1014 }
   1015 
   1016 class ExceptionCallback::RootExceptionCallback: public ExceptionCallback {
   1017 public:
   1018   RootExceptionCallback(): ExceptionCallback(*this) {}
   1019 
   1020   void onRecoverableException(Exception&& exception) override {
   1021 #if KJ_NO_EXCEPTIONS
   1022     logException(LogSeverity::ERROR, mv(exception));
   1023 #else
   1024     if (_::uncaughtExceptionCount() > 0) {
   1025       // Bad time to throw an exception.  Just log instead.
   1026       //
   1027       // TODO(someday): We should really compare uncaughtExceptionCount() against the count at
   1028       //   the innermost runCatchingExceptions() frame in this thread to tell if exceptions are
   1029       //   being caught correctly.
   1030       logException(LogSeverity::ERROR, mv(exception));
   1031     } else {
   1032       throw ExceptionImpl(mv(exception));
   1033     }
   1034 #endif
   1035   }
   1036 
   1037   void onFatalException(Exception&& exception) override {
   1038 #if KJ_NO_EXCEPTIONS
   1039     logException(LogSeverity::FATAL, mv(exception));
   1040 #else
   1041     throw ExceptionImpl(mv(exception));
   1042 #endif
   1043   }
   1044 
   1045   void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
   1046                   String&& text) override {
   1047     text = str(kj::repeat('_', contextDepth), file, ":", line, ": ", severity, ": ",
   1048                mv(text), '\n');
   1049 
   1050     StringPtr textPtr = text;
   1051 
   1052     while (textPtr != nullptr) {
   1053       miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size());
   1054       if (n <= 0) {
   1055         // stderr is broken.  Give up.
   1056         return;
   1057       }
   1058       textPtr = textPtr.slice(n);
   1059     }
   1060   }
   1061 
   1062   StackTraceMode stackTraceMode() override {
   1063 #ifdef KJ_DEBUG
   1064     return StackTraceMode::FULL;
   1065 #else
   1066     return StackTraceMode::ADDRESS_ONLY;
   1067 #endif
   1068   }
   1069 
   1070   Function<void(Function<void()>)> getThreadInitializer() override {
   1071     return [](Function<void()> func) {
   1072       // No initialization needed since RootExceptionCallback is automatically the root callback
   1073       // for new threads.
   1074       func();
   1075     };
   1076   }
   1077 
   1078 private:
   1079   void logException(LogSeverity severity, Exception&& e) {
   1080     // We intentionally go back to the top exception callback on the stack because we don't want to
   1081     // bypass whatever log processing is in effect.
   1082     //
   1083     // We intentionally don't log the context since it should get re-added by the exception callback
   1084     // anyway.
   1085     getExceptionCallback().logMessage(severity, e.getFile(), e.getLine(), 0, str(
   1086         e.getType(), e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
   1087         e.getRemoteTrace().size() > 0 ? "\nremote: " : "",
   1088         e.getRemoteTrace(),
   1089         e.getStackTrace().size() > 0 ? "\nstack: " : "",
   1090         stringifyStackTraceAddresses(e.getStackTrace()),
   1091         stringifyStackTrace(e.getStackTrace()), "\n"));
   1092   }
   1093 };
   1094 
   1095 ExceptionCallback& getExceptionCallback() {
   1096   static auto defaultCallback = lsanIgnoreObjectAndReturn(
   1097       new ExceptionCallback::RootExceptionCallback());
   1098   // We allocate on the heap because some objects may throw in their destructors. If those objects
   1099   // had static storage, they might get fully constructed before the root callback. If they however
   1100   // then throw an exception during destruction, there would be a lifetime issue because their
   1101   // destructor would end up getting registered after the root callback's destructor. One solution
   1102   // is to just leak this pointer & allocate on first-use. The cost is that the initialization is
   1103   // mildly more expensive (+ we need to annotate sanitizers to ignore the problem). A great
   1104   // compiler annotation that would simply things would be one that allowed static variables to have
   1105   // their destruction omitted wholesale. That would allow us to avoid the heap but still have the
   1106   // same robust safety semantics leaking would give us. A practical alternative that could be
   1107   // implemented without new compilers would be to define another static root callback in
   1108   // RootExceptionCallback's destructor (+ a separate pointer to share its value with this
   1109   // function). Since this would end up getting constructed during exit unwind, it would have the
   1110   // nice property of effectively being guaranteed to be evicted last.
   1111   //
   1112   // All this being said, I came back to leaking the object is the easiest tweak here:
   1113   //  * Can't go wrong
   1114   //  * Easy to maintain
   1115   //  * Throwing exceptions is bound to do be expensive and malloc-happy anyway, so the incremental
   1116   //    cost of 1 heap allocation is minimal.
   1117   //
   1118   // TODO(cleanup): Harris has an excellent suggestion in
   1119   //  https://github.com/capnproto/capnproto/pull/1255 that should ensure we initialize the root
   1120   //  callback once on first use as a global & never destroy it.
   1121 
   1122   ExceptionCallback* scoped = threadLocalCallback;
   1123   return scoped != nullptr ? *scoped : *defaultCallback;
   1124 }
   1125 
   1126 void throwFatalException(kj::Exception&& exception, uint ignoreCount) {
   1127   exception.extendTrace(ignoreCount + 1);
   1128   getExceptionCallback().onFatalException(kj::mv(exception));
   1129   abort();
   1130 }
   1131 
   1132 void throwRecoverableException(kj::Exception&& exception, uint ignoreCount) {
   1133   exception.extendTrace(ignoreCount + 1);
   1134   getExceptionCallback().onRecoverableException(kj::mv(exception));
   1135 }
   1136 
   1137 // =======================================================================================
   1138 
   1139 namespace _ {  // private
   1140 
   1141 #if __cplusplus >= 201703L
   1142 
   1143 uint uncaughtExceptionCount() {
   1144   return std::uncaught_exceptions();
   1145 }
   1146 
   1147 #elif __GNUC__
   1148 
   1149 // Horrible -- but working -- hack:  We can dig into __cxa_get_globals() in order to extract the
   1150 // count of uncaught exceptions.  This function is part of the C++ ABI implementation used on Linux,
   1151 // OSX, and probably other platforms that use GCC.  Unfortunately, __cxa_get_globals() is only
   1152 // actually defined in cxxabi.h on some platforms (e.g. Linux, but not OSX), and even where it is
   1153 // defined, it returns an incomplete type.  Here we use the same hack used by Evgeny Panasyuk:
   1154 //   https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
   1155 //
   1156 // Notice that a similar hack is possible on MSVC -- if its C++11 support ever gets to the point of
   1157 // supporting KJ in the first place.
   1158 //
   1159 // It appears likely that a future version of the C++ standard may include an
   1160 // uncaught_exception_count() function in the standard library, or an equivalent language feature.
   1161 // Some discussion:
   1162 //   https://groups.google.com/a/isocpp.org/d/msg/std-proposals/HglEslyZFYs/kKdu5jJw5AgJ
   1163 
   1164 struct FakeEhGlobals {
   1165   // Fake
   1166 
   1167   void* caughtExceptions;
   1168   uint uncaughtExceptions;
   1169 };
   1170 
   1171 // LLVM's libstdc++ doesn't declare __cxa_get_globals in its cxxabi.h. GNU does. Because it is
   1172 // extern "C", the compiler wills get upset if we re-declare it even in a different namespace.
   1173 #if _LIBCPPABI_VERSION
   1174 extern "C" void* __cxa_get_globals();
   1175 #else
   1176 using abi::__cxa_get_globals;
   1177 #endif
   1178 
   1179 uint uncaughtExceptionCount() {
   1180   return reinterpret_cast<FakeEhGlobals*>(__cxa_get_globals())->uncaughtExceptions;
   1181 }
   1182 
   1183 #elif _MSC_VER
   1184 
   1185 #if _MSC_VER >= 1900
   1186 // MSVC14 has a refactored CRT which now provides a direct accessor for this value.
   1187 // See https://svn.boost.org/trac/boost/ticket/10158 for a brief discussion.
   1188 extern "C" int *__cdecl __processing_throw();
   1189 
   1190 uint uncaughtExceptionCount() {
   1191   return static_cast<uint>(*__processing_throw());
   1192 }
   1193 
   1194 #elif _MSC_VER >= 1400
   1195 // The below was copied from:
   1196 // https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
   1197 
   1198 extern "C" char *__cdecl _getptd();
   1199 
   1200 uint uncaughtExceptionCount() {
   1201   return *reinterpret_cast<uint*>(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90));
   1202 }
   1203 #else
   1204 uint uncaughtExceptionCount() {
   1205   // Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect
   1206   // results in very obscure cases that Cap'n Proto doesn't really rely on anyway.
   1207   return std::uncaught_exception();
   1208 }
   1209 #endif
   1210 
   1211 #else
   1212 #error "This needs to be ported to your compiler / C++ ABI."
   1213 #endif
   1214 
   1215 }  // namespace _ (private)
   1216 
   1217 UnwindDetector::UnwindDetector(): uncaughtCount(_::uncaughtExceptionCount()) {}
   1218 
   1219 bool UnwindDetector::isUnwinding() const {
   1220   return _::uncaughtExceptionCount() > uncaughtCount;
   1221 }
   1222 
   1223 void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const {
   1224   // TODO(someday):  Attach the secondary exception to whatever primary exception is causing
   1225   //   the unwind.  For now we just drop it on the floor as this is probably fine most of the
   1226   //   time.
   1227   runCatchingExceptions(runnable);
   1228 }
   1229 
   1230 #if __GNUC__ && !KJ_NO_RTTI
   1231 static kj::String demangleTypeName(const char* name) {
   1232   if (name == nullptr) return kj::heapString("(nil)");
   1233 
   1234   int status;
   1235   char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status);
   1236   kj::String result = kj::heapString(buf == nullptr ? name : buf);
   1237   free(buf);
   1238   return kj::mv(result);
   1239 }
   1240 
   1241 kj::String getCaughtExceptionType() {
   1242   return demangleTypeName(abi::__cxa_current_exception_type()->name());
   1243 }
   1244 #else
   1245 kj::String getCaughtExceptionType() {
   1246   return kj::heapString("(unknown)");
   1247 }
   1248 #endif
   1249 
   1250 namespace {
   1251 
   1252 size_t sharedSuffixLength(kj::ArrayPtr<void* const> a, kj::ArrayPtr<void* const> b) {
   1253   size_t result = 0;
   1254   while (a.size() > 0 && b.size() > 0 && a.back() == b.back())  {
   1255     ++result;
   1256     a = a.slice(0, a.size() - 1);
   1257     b = b.slice(0, b.size() - 1);
   1258   }
   1259   return result;
   1260 }
   1261 
   1262 }  // namespace
   1263 
   1264 kj::ArrayPtr<void* const> computeRelativeTrace(
   1265     kj::ArrayPtr<void* const> trace, kj::ArrayPtr<void* const> relativeTo) {
   1266   using miniposix::ssize_t;
   1267 
   1268   static constexpr size_t MIN_MATCH_LEN = 4;
   1269   if (trace.size() < MIN_MATCH_LEN || relativeTo.size() < MIN_MATCH_LEN) {
   1270     return trace;
   1271   }
   1272 
   1273   kj::ArrayPtr<void* const> bestMatch = trace;
   1274   uint bestMatchLen = MIN_MATCH_LEN - 1;  // must beat this to choose something else
   1275 
   1276   // `trace` and `relativeTrace` may have been truncated at different points. We iterate through
   1277   // truncating various suffixes from one of the two and then seeing if the remaining suffixes
   1278   // match.
   1279   for (ssize_t i = -(ssize_t)(trace.size() - MIN_MATCH_LEN);
   1280        i <= (ssize_t)(relativeTo.size() - MIN_MATCH_LEN);
   1281        i++) {
   1282     // Negative values truncate `trace`, positive values truncate `relativeTo`.
   1283     kj::ArrayPtr<void* const> subtrace = trace.slice(0, trace.size() - kj::max<ssize_t>(0, -i));
   1284     kj::ArrayPtr<void* const> subrt = relativeTo
   1285         .slice(0, relativeTo.size() - kj::max<ssize_t>(0, i));
   1286 
   1287     uint matchLen = sharedSuffixLength(subtrace, subrt);
   1288     if (matchLen > bestMatchLen) {
   1289       bestMatchLen = matchLen;
   1290       bestMatch = subtrace.slice(0, subtrace.size() - matchLen + 1);
   1291     }
   1292   }
   1293 
   1294   return bestMatch;
   1295 }
   1296 
   1297 namespace _ {  // private
   1298 
   1299 class RecoverableExceptionCatcher: public ExceptionCallback {
   1300   // Catches a recoverable exception without using try/catch.  Used when compiled with
   1301   // -fno-exceptions.
   1302 
   1303 public:
   1304   virtual ~RecoverableExceptionCatcher() noexcept(false) {}
   1305 
   1306   void onRecoverableException(Exception&& exception) override {
   1307     if (caught == nullptr) {
   1308       caught = mv(exception);
   1309     } else {
   1310       // TODO(someday):  Consider it a secondary fault?
   1311     }
   1312   }
   1313 
   1314   Maybe<Exception> caught;
   1315 };
   1316 
   1317 Maybe<Exception> runCatchingExceptions(Runnable& runnable) {
   1318 #if KJ_NO_EXCEPTIONS
   1319   RecoverableExceptionCatcher catcher;
   1320   runnable.run();
   1321   KJ_IF_MAYBE(e, catcher.caught) {
   1322     e->truncateCommonTrace();
   1323   }
   1324   return mv(catcher.caught);
   1325 #else
   1326   try {
   1327     runnable.run();
   1328     return nullptr;
   1329   } catch (Exception& e) {
   1330     e.truncateCommonTrace();
   1331     return kj::mv(e);
   1332   } catch (CanceledException) {
   1333     throw;
   1334   } catch (std::bad_alloc& e) {
   1335     return Exception(Exception::Type::OVERLOADED,
   1336                      "(unknown)", -1, str("std::bad_alloc: ", e.what()));
   1337   } catch (std::exception& e) {
   1338     return Exception(Exception::Type::FAILED,
   1339                      "(unknown)", -1, str("std::exception: ", e.what()));
   1340   } catch (TopLevelProcessContext::CleanShutdownException) {
   1341     throw;
   1342   } catch (...) {
   1343 #if __GNUC__ && !KJ_NO_RTTI
   1344     return Exception(Exception::Type::FAILED, "(unknown)", -1, str(
   1345         "unknown non-KJ exception of type: ", getCaughtExceptionType()));
   1346 #else
   1347     return Exception(Exception::Type::FAILED, "(unknown)", -1, str("unknown non-KJ exception"));
   1348 #endif
   1349   }
   1350 #endif
   1351 }
   1352 
   1353 }  // namespace _ (private)
   1354 
   1355 }  // namespace kj