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 = ¤tException; *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