exception.c++ 35.4 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
3
//
Kenton Varda's avatar
Kenton Varda committed
4 5 6 7 8 9
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
10
//
Kenton Varda's avatar
Kenton Varda committed
11 12
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
13
//
Kenton Varda's avatar
Kenton Varda committed
14 15 16 17 18 19 20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
21

22
#ifndef _GNU_SOURCE
Ivan Shynkarenka's avatar
Ivan Shynkarenka committed
23 24 25
#define _GNU_SOURCE
#endif

26
#include "exception.h"
Kenton Varda's avatar
Kenton Varda committed
27
#include "string.h"
Kenton Varda's avatar
Kenton Varda committed
28
#include "debug.h"
29
#include "threadlocal.h"
30
#include "miniposix.h"
31
#include "function.h"
32
#include <stdlib.h>
33
#include <exception>
34
#include <new>
35
#include <signal.h>
36
#include <stdint.h>
37
#ifndef _WIN32
38
#include <sys/mman.h>
39
#endif
40
#include "io.h"
41

42 43 44 45 46 47 48
#if !KJ_NO_RTTI
#include <typeinfo>
#if __GNUC__
#include <cxxabi.h>
#endif
#endif

49
#if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__
50
#define KJ_HAS_BACKTRACE 1
51 52 53
#include <execinfo.h>
#endif

54 55 56 57 58 59 60
#if _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "windows-sanity.h"
#include <dbghelp.h>
#endif

61
#if (__linux__ || __APPLE__)
62
#include <stdio.h>
63
#include <pthread.h>
64 65
#endif

66 67 68 69
#if KJ_HAS_LIBDL
#include "dlfcn.h"
#endif

70
namespace kj {
71

72 73 74 75 76 77 78 79 80 81 82 83
StringPtr KJ_STRINGIFY(LogSeverity severity) {
  static const char* SEVERITY_STRINGS[] = {
    "info",
    "warning",
    "error",
    "fatal",
    "debug"
  };

  return SEVERITY_STRINGS[static_cast<uint>(severity)];
}

84 85 86 87 88 89 90 91 92 93 94 95
#if _WIN32 && _M_X64
// Currently the Win32 stack-trace code only supports x86_64. We could easily extend it to support
// i386 as well but it requires some code changes around how we read the context to start the
// trace.

namespace {

struct Dbghelp {
  // Load dbghelp.dll dynamically since we don't really need it, it's just for debugging.

  HINSTANCE lib;

96 97
  BOOL (WINAPI *symInitialize)(HANDLE hProcess,PCSTR UserSearchPath,BOOL fInvadeProcess);
  BOOL (WINAPI *stackWalk64)(
98 99 100 101 102 103
      DWORD MachineType,HANDLE hProcess,HANDLE hThread,
      LPSTACKFRAME64 StackFrame,PVOID ContextRecord,
      PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
      PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
      PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
      PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
104 105 106
  PVOID (WINAPI *symFunctionTableAccess64)(HANDLE hProcess,DWORD64 AddrBase);
  DWORD64 (WINAPI *symGetModuleBase64)(HANDLE hProcess,DWORD64 qwAddr);
  BOOL (WINAPI *symGetLineFromAddr64)(
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
      HANDLE hProcess,DWORD64 qwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE64 Line64);

  Dbghelp()
      : lib(LoadLibraryA("dbghelp.dll")),
        symInitialize(lib == nullptr ? nullptr :
            reinterpret_cast<decltype(symInitialize)>(
                GetProcAddress(lib, "SymInitialize"))),
        stackWalk64(symInitialize == nullptr ? nullptr :
            reinterpret_cast<decltype(stackWalk64)>(
                GetProcAddress(lib, "StackWalk64"))),
        symFunctionTableAccess64(symInitialize == nullptr ? nullptr :
            reinterpret_cast<decltype(symFunctionTableAccess64)>(
                GetProcAddress(lib, "SymFunctionTableAccess64"))),
        symGetModuleBase64(symInitialize == nullptr ? nullptr :
            reinterpret_cast<decltype(symGetModuleBase64)>(
                GetProcAddress(lib, "SymGetModuleBase64"))),
        symGetLineFromAddr64(symInitialize == nullptr ? nullptr :
            reinterpret_cast<decltype(symGetLineFromAddr64)>(
                GetProcAddress(lib, "SymGetLineFromAddr64"))) {
    if (symInitialize != nullptr) {
      symInitialize(GetCurrentProcess(), NULL, TRUE);
    }
  }
};

const Dbghelp& getDbghelp() {
  static Dbghelp dbghelp;
  return dbghelp;
}

ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount,
                                    HANDLE thread, CONTEXT& context) {
  const Dbghelp& dbghelp = getDbghelp();
  if (dbghelp.stackWalk64 == nullptr ||
      dbghelp.symFunctionTableAccess64 == nullptr ||
      dbghelp.symGetModuleBase64 == nullptr) {
    return nullptr;
  }

  STACKFRAME64 frame;
  memset(&frame, 0, sizeof(frame));

  frame.AddrPC.Offset = context.Rip;
  frame.AddrPC.Mode = AddrModeFlat;
  frame.AddrStack.Offset = context.Rsp;
  frame.AddrStack.Mode = AddrModeFlat;
  frame.AddrFrame.Offset = context.Rbp;
  frame.AddrFrame.Mode = AddrModeFlat;

  HANDLE process = GetCurrentProcess();

  uint count = 0;
  for (; count < space.size(); count++) {
    if (!dbghelp.stackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread,
          &frame, &context, NULL, dbghelp.symFunctionTableAccess64,
          dbghelp.symGetModuleBase64, NULL)){
      break;
    }

166 167 168
    // Subtract 1 from each address so that we identify the calling instructions, rather than the
    // return addresses (which are typically the instruction after the call).
    space[count] = reinterpret_cast<void*>(frame.AddrPC.Offset - 1);
169 170 171 172 173 174 175 176
  }

  return space.slice(kj::min(ignoreCount, count), count);
}

}  // namespace
#endif

Kenton Varda's avatar
Kenton Varda committed
177
ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount) {
178 179 180 181
  if (getExceptionCallback().stackTraceMode() == ExceptionCallback::StackTraceMode::NONE) {
    return nullptr;
  }

182 183 184 185 186
#if _WIN32 && _M_X64
  CONTEXT context;
  RtlCaptureContext(&context);
  return getStackTrace(space, ignoreCount, GetCurrentThread(), context);
#elif KJ_HAS_BACKTRACE
Kenton Varda's avatar
Kenton Varda committed
187
  size_t size = backtrace(space.begin(), space.size());
188 189 190 191 192 193 194 195 196 197
  for (auto& addr: space.slice(0, size)) {
    // The addresses produced by backtrace() are return addresses, which means they point to the
    // instruction immediately after the call. Invoking addr2line on these can be confusing because
    // it often points to the next line. If the next instruction is inlined from another function,
    // the trace can be extra-confusing, since now it claims to be in a function that was not
    // actually on the call stack. If we subtract 1 from each address, though, we get a much more
    // reasonable trace. This may cause the addresses to be invalid instruction pointers if the
    // instructions were multi-byte, but it appears addr2line is able to cope with this.
    addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) - 1);
  }
Kenton Varda's avatar
Kenton Varda committed
198
  return space.slice(kj::min(ignoreCount + 1, size), size);
199 200
#else
  return nullptr;
201 202
#endif
}
203

204
String stringifyStackTrace(ArrayPtr<void* const> trace) {
Kenton Varda's avatar
Kenton Varda committed
205
  if (trace.size() == 0) return nullptr;
206 207 208
  if (getExceptionCallback().stackTraceMode() != ExceptionCallback::StackTraceMode::FULL) {
    return nullptr;
  }
Kenton Varda's avatar
Kenton Varda committed
209

210
#if _WIN32 && _M_X64 && _MSC_VER
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

  // Try to get file/line using SymGetLineFromAddr64(). We don't bother if we aren't on MSVC since
  // this requires MSVC debug info.
  //
  // TODO(someday): We could perhaps shell out to addr2line on MinGW.

  const Dbghelp& dbghelp = getDbghelp();
  if (dbghelp.symGetLineFromAddr64 == nullptr) return nullptr;

  HANDLE process = GetCurrentProcess();

  KJ_STACK_ARRAY(String, lines, trace.size(), 32, 32);

  for (auto i: kj::indices(trace)) {
    IMAGEHLP_LINE64 lineInfo;
    memset(&lineInfo, 0, sizeof(lineInfo));
    lineInfo.SizeOfStruct = sizeof(lineInfo);
    if (dbghelp.symGetLineFromAddr64(process, reinterpret_cast<DWORD64>(trace[i]), NULL, &lineInfo)) {
      lines[i] = kj::str('\n', lineInfo.FileName, ':', lineInfo.LineNumber);
    }
  }

  return strArray(lines, "");

#elif (__linux__ || __APPLE__) && !__ANDROID__
236 237
  // We want to generate a human-readable stack trace.

238 239
  // TODO(someday):  It would be really great if we could avoid farming out to another process
  //   and do this all in-process, but that may involve onerous requirements like large library
240 241 242 243 244 245 246 247
  //   dependencies or using -rdynamic.

  // The environment manipulation is not thread-safe, so lock a mutex.  This could still be
  // problematic if another thread is manipulating the environment in unrelated code, but there's
  // not much we can do about that.  This is debug-only anyway and only an issue when LD_PRELOAD
  // is in use.
  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_lock(&mutex);
248
  KJ_DEFER(pthread_mutex_unlock(&mutex));
249

250
  // Don't heapcheck / intercept syscalls.
251 252 253 254 255 256
  const char* preload = getenv("LD_PRELOAD");
  String oldPreload;
  if (preload != nullptr) {
    oldPreload = heapString(preload);
    unsetenv("LD_PRELOAD");
  }
257
  KJ_DEFER(if (oldPreload != nullptr) { setenv("LD_PRELOAD", oldPreload.cStr(), true); });
258

259
  String lines[32];
260
  FILE* p = nullptr;
261
  auto strTrace = strArray(trace, " ");
262 263

#if __linux__
264 265
  if (access("/proc/self/exe", R_OK) < 0) {
    // Apparently /proc is not available?
266
    return nullptr;
267 268
  }

269 270 271 272
  // Obtain symbolic stack trace using addr2line.
  // TODO(cleanup): Use fork() and exec() or maybe our own Subprocess API (once it exists), to
  //   avoid depending on a shell.
  p = popen(str("addr2line -e /proc/", getpid(), "/exe ", strTrace).cStr(), "r");
273 274 275
#elif __APPLE__
  // The Mac OS X equivalent of addr2line is atos.
  // (Internally, it uses the private CoreSymbolication.framework library.)
276
  p = popen(str("xcrun atos -p ", getpid(), ' ', strTrace).cStr(), "r");
277
#endif
278 279

  if (p == nullptr) {
280
    return nullptr;
281 282 283
  }

  char line[512];
284 285
  size_t i = 0;
  while (i < kj::size(lines) && fgets(line, sizeof(line), p) != nullptr) {
Kenton Varda's avatar
Kenton Varda committed
286
    // Don't include exception-handling infrastructure or promise infrastructure in stack trace.
287
    // addr2line output matches file names; atos output matches symbol names.
Kenton Varda's avatar
Kenton Varda committed
288 289 290 291 292 293 294 295
    if (strstr(line, "kj/common.c++") != nullptr ||
        strstr(line, "kj/exception.") != nullptr ||
        strstr(line, "kj/debug.") != nullptr ||
        strstr(line, "kj/async.") != nullptr ||
        strstr(line, "kj/async-prelude.h") != nullptr ||
        strstr(line, "kj/async-inl.h") != nullptr ||
        strstr(line, "kj::Exception") != nullptr ||
        strstr(line, "kj::_::Debug") != nullptr) {
296 297 298 299 300
      continue;
    }

    size_t len = strlen(line);
    if (len > 0 && line[len-1] == '\n') line[len-1] = '\0';
Kenton Varda's avatar
Kenton Varda committed
301
    lines[i++] = str("\n    ", trimSourceFilename(line), ": returning here");
302 303 304 305 306 307 308
  }

  // Skip remaining input.
  while (fgets(line, sizeof(line), p) != nullptr) {}

  pclose(p);

309
  return strArray(arrayPtr(lines, i), "");
310

311 312 313 314 315
#else
  return nullptr;
#endif
}

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
String stringifyStackTraceAddresses(ArrayPtr<void* const> trace) {
#if KJ_HAS_LIBDL
  return strArray(KJ_MAP(addr, trace) {
    Dl_info info;
    // Shared libraries are mapped near the end of the address space while the executable is mapped
    // near the beginning. We want to print addresses in the executable as raw addresses, not
    // offsets, since that's what addr2line expects for executables. For shared libraries it
    // expects offsets. In any case, most frames are likely to be in the main executable so it
    // makes the output cleaner if we don't repeatedly write its name.
    if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
      uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
                         reinterpret_cast<uintptr_t>(info.dli_fbase);
      return kj::str(info.dli_fname, '@', reinterpret_cast<void*>(offset));
    } else {
      return kj::str(addr);
    }
  }, " ");
#else
  // TODO(someday): Support other platforms.
  return kj::strArray(trace, " ");
#endif
}

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
StringPtr stringifyStackTraceAddresses(ArrayPtr<void* const> trace, ArrayPtr<char> scratch) {
  // Version which writes into a pre-allocated buffer. This is safe for signal handlers to the
  // extent that dladdr() is safe.
  //
  // TODO(cleanup): We should improve the KJ stringification framework so that there's a way to
  //   write this string directly into a larger message buffer with strPreallocated().

#if KJ_HAS_LIBDL
  char* ptr = scratch.begin();
  char* limit = scratch.end() - 1;

  for (auto addr: trace) {
    Dl_info info;
    // Shared libraries are mapped near the end of the address space while the executable is mapped
    // near the beginning. We want to print addresses in the executable as raw addresses, not
    // offsets, since that's what addr2line expects for executables. For shared libraries it
    // expects offsets. In any case, most frames are likely to be in the main executable so it
    // makes the output cleaner if we don't repeatedly write its name.
    if (reinterpret_cast<uintptr_t>(addr) >= 0x400000000000ull && dladdr(addr, &info)) {
      uintptr_t offset = reinterpret_cast<uintptr_t>(addr) -
                         reinterpret_cast<uintptr_t>(info.dli_fbase);
      ptr = _::fillLimited(ptr, limit, kj::StringPtr(info.dli_fname), "@0x"_kj, hex(offset));
    } else {
      ptr = _::fillLimited(ptr, limit, toCharSequence(addr));
    }

    ptr = _::fillLimited(ptr, limit, " "_kj);
  }
  *ptr = '\0';
  return StringPtr(scratch.begin(), ptr);
#else
  // TODO(someday): Support other platforms.
  return kj::strPreallocated(scratch, kj::delimited(trace, " "));
#endif
}

375 376 377
String getStackTrace() {
  void* space[32];
  auto trace = getStackTrace(space, 2);
378
  return kj::str(stringifyStackTraceAddresses(trace), stringifyStackTrace(trace));
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
}

#if _WIN32 && _M_X64
namespace {

DWORD mainThreadId = 0;

BOOL WINAPI breakHandler(DWORD type) {
  switch (type) {
    case CTRL_C_EVENT:
    case CTRL_BREAK_EVENT: {
      HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThreadId);
      if (thread != NULL) {
        if (SuspendThread(thread) != (DWORD)-1) {
          CONTEXT context;
          memset(&context, 0, sizeof(context));
          context.ContextFlags = CONTEXT_FULL;
          if (GetThreadContext(thread, &context)) {
            void* traceSpace[32];
398
            auto trace = getStackTrace(traceSpace, 0, thread, context);
399
            ResumeThread(thread);
400 401
            auto message = kj::str("*** Received CTRL+C. stack: ",
                                   stringifyStackTraceAddresses(trace),
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
                                   stringifyStackTrace(trace), '\n');
            FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
          } else {
            ResumeThread(thread);
          }
        }
        CloseHandle(thread);
      }
      break;
    }
    default:
      break;
  }

  return FALSE;  // still crash
}

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
kj::StringPtr exceptionDescription(DWORD code) {
  switch (code) {
    case EXCEPTION_ACCESS_VIOLATION: return "access violation";
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "array bounds exceeded";
    case EXCEPTION_BREAKPOINT: return "breakpoint";
    case EXCEPTION_DATATYPE_MISALIGNMENT: return "datatype misalignment";
    case EXCEPTION_FLT_DENORMAL_OPERAND: return "denormal floating point operand";
    case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "floating point division by zero";
    case EXCEPTION_FLT_INEXACT_RESULT: return "inexact floating point result";
    case EXCEPTION_FLT_INVALID_OPERATION: return "invalid floating point operation";
    case EXCEPTION_FLT_OVERFLOW: return "floating point overflow";
    case EXCEPTION_FLT_STACK_CHECK: return "floating point stack overflow";
    case EXCEPTION_FLT_UNDERFLOW: return "floating point underflow";
    case EXCEPTION_ILLEGAL_INSTRUCTION: return "illegal instruction";
    case EXCEPTION_IN_PAGE_ERROR: return "page error";
    case EXCEPTION_INT_DIVIDE_BY_ZERO: return "integer divided by zero";
    case EXCEPTION_INT_OVERFLOW: return "integer overflow";
    case EXCEPTION_INVALID_DISPOSITION: return "invalid disposition";
    case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "noncontinuable exception";
    case EXCEPTION_PRIV_INSTRUCTION: return "privileged instruction";
    case EXCEPTION_SINGLE_STEP: return "single step";
    case EXCEPTION_STACK_OVERFLOW: return "stack overflow";
    default: return "(unknown exception code)";
  }
}

LONG WINAPI sehHandler(EXCEPTION_POINTERS* info) {
  void* traceSpace[32];
  auto trace = getStackTrace(traceSpace, 0, GetCurrentThread(), *info->ContextRecord);
  auto message = kj::str("*** Received structured exception #0x",
                         hex(info->ExceptionRecord->ExceptionCode), ": ",
                         exceptionDescription(info->ExceptionRecord->ExceptionCode),
                         "; stack: ",
                         stringifyStackTraceAddresses(trace),
                         stringifyStackTrace(trace), '\n');
  FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
  return EXCEPTION_EXECUTE_HANDLER;  // still crash
}

458 459 460 461 462
}  // namespace

void printStackTraceOnCrash() {
  mainThreadId = GetCurrentThreadId();
  KJ_WIN32(SetConsoleCtrlHandler(breakHandler, TRUE));
463
  SetUnhandledExceptionFilter(&sehHandler);
464 465 466
}

#elif KJ_HAS_BACKTRACE
467 468 469 470 471
namespace {

void crashHandler(int signo, siginfo_t* info, void* context) {
  void* traceSpace[32];

Kenton Varda's avatar
Kenton Varda committed
472 473
  // ignoreCount = 2 to ignore crashHandler() and signal trampoline.
  auto trace = getStackTrace(traceSpace, 2);
474 475

  auto message = kj::str("*** Received signal #", signo, ": ", strsignal(signo),
476
                         "\nstack: ", stringifyStackTraceAddresses(trace),
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
                         stringifyStackTrace(trace), '\n');

  FdOutputStream(STDERR_FILENO).write(message.begin(), message.size());
  _exit(1);
}

}  // namespace

void printStackTraceOnCrash() {
  // Set up alternate signal stack so that stack overflows can be handled.
  stack_t stack;
  memset(&stack, 0, sizeof(stack));

#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#ifndef MAP_GROWSDOWN
#define MAP_GROWSDOWN 0
#endif

  stack.ss_size = 65536;
  // Note: ss_sp is char* on FreeBSD, void* on Linux and OSX.
  stack.ss_sp = reinterpret_cast<char*>(mmap(
      nullptr, stack.ss_size, PROT_READ | PROT_WRITE,
      MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0));
  KJ_SYSCALL(sigaltstack(&stack, nullptr));

  // Catch all relevant signals.
  struct sigaction action;
  memset(&action, 0, sizeof(action));

  action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND;
  action.sa_sigaction = &crashHandler;

  // Dump stack on common "crash" signals.
  KJ_SYSCALL(sigaction(SIGSEGV, &action, nullptr));
  KJ_SYSCALL(sigaction(SIGBUS, &action, nullptr));
  KJ_SYSCALL(sigaction(SIGFPE, &action, nullptr));
  KJ_SYSCALL(sigaction(SIGABRT, &action, nullptr));
516
  KJ_SYSCALL(sigaction(SIGILL, &action, nullptr));
517 518 519 520 521 522 523 524 525 526

  // Dump stack on unimplemented syscalls -- useful in seccomp sandboxes.
  KJ_SYSCALL(sigaction(SIGSYS, &action, nullptr));

#ifdef KJ_DEBUG
  // Dump stack on keyboard interrupt -- useful for infinite loops. Only in debug mode, though,
  // because stack traces on ctrl+c can be obnoxious for, say, command-line tools.
  KJ_SYSCALL(sigaction(SIGINT, &action, nullptr));
#endif
}
527 528 529 530
#else
void printStackTraceOnCrash() {
}
#endif
531

532 533
kj::StringPtr trimSourceFilename(kj::StringPtr filename) {
  // Removes noisy prefixes from source code file name.
534 535 536 537 538 539 540 541 542
  //
  // The goal here is to produce the "canonical" filename given the filename returned by e.g.
  // addr2line. addr2line gives us the full path of the file as passed on the compiler
  // command-line, which in turn is affected by build system and by whether and where we're
  // performing an out-of-tree build.
  //
  // To deal with all this, we look for directory names in the path which we recognize to be
  // locations that represent roots of the source tree. We strip said root and everything before
  // it.
543 544 545 546
  //
  // On Windows, we often get filenames containing backslashes. Since we aren't allowed to allocate
  // a new string here, we can't do much about this, so our returned "canonical" name will
  // unfortunately end up with backslashes.
547 548 549 550 551

  static constexpr const char* ROOTS[] = {
    "ekam-provider/canonical/",  // Ekam source file.
    "ekam-provider/c++header/",  // Ekam include file.
    "src/",                      // Non-Ekam source root.
552 553 554 555 556
    "tmp/",                      // Non-Ekam generated code.
#if _WIN32
    "src\\",                     // Win32 source root.
    "tmp\\",                     // Win32 generated code.
#endif
557 558 559
  };

retry:
560
  for (size_t i: kj::indices(filename)) {
561 562 563 564 565
    if (i == 0 || filename[i-1] == '/'
#if _WIN32
               || filename[i-1] == '\\'
#endif
        ) {
566 567 568 569 570 571 572 573 574 575
      // We're at the start of a directory name. Check for valid prefixes.
      for (kj::StringPtr root: ROOTS) {
        if (filename.slice(i).startsWith(root)) {
          filename = filename.slice(i + root.size());

          // We should keep searching to find the last instance of a root name. `i` is no longer
          // a valid index for `filename` so start the loop over.
          goto retry;
        }
      }
576 577 578 579 580 581
    }
  }

  return filename;
}

582
StringPtr KJ_STRINGIFY(Exception::Type type) {
583 584 585 586 587
  static const char* TYPE_STRINGS[] = {
    "failed",
    "overloaded",
    "disconnected",
    "unimplemented"
588 589
  };

590
  return TYPE_STRINGS[static_cast<uint>(type)];
591 592
}

593 594 595 596 597 598 599
String KJ_STRINGIFY(const Exception& e) {
  uint contextDepth = 0;

  Maybe<const Exception::Context&> contextPtr = e.getContext();
  for (;;) {
    KJ_IF_MAYBE(c, contextPtr) {
      ++contextDepth;
600
      contextPtr = c->next;
601 602 603 604 605 606 607 608 609 610 611 612 613
    } else {
      break;
    }
  }

  Array<String> contextText = heapArray<String>(contextDepth);

  contextDepth = 0;
  contextPtr = e.getContext();
  for (;;) {
    KJ_IF_MAYBE(c, contextPtr) {
      contextText[contextDepth++] =
          str(c->file, ":", c->line, ": context: ", c->description, "\n");
614
      contextPtr = c->next;
615 616 617 618 619 620
    } else {
      break;
    }
  }

  return str(strArray(contextText, ""),
621
             e.getFile(), ":", e.getLine(), ": ", e.getType(),
622
             e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
623 624
             e.getStackTrace().size() > 0 ? "\nstack: " : "",
             stringifyStackTraceAddresses(e.getStackTrace()),
625
             stringifyStackTrace(e.getStackTrace()));
626 627
}

628
Exception::Exception(Type type, const char* file, int line, String description) noexcept
Kenton Varda's avatar
Kenton Varda committed
629 630
    : file(trimSourceFilename(file).cStr()), line(line), type(type), description(mv(description)),
      traceCount(0) {}
631

632
Exception::Exception(Type type, String file, int line, String description) noexcept
633
    : ownFile(kj::mv(file)), file(trimSourceFilename(ownFile).cStr()), line(line), type(type),
Kenton Varda's avatar
Kenton Varda committed
634
      description(mv(description)), traceCount(0) {}
635

636
Exception::Exception(const Exception& other) noexcept
637
    : file(other.file), line(other.line), type(other.type),
638 639 640 641 642 643
      description(heapString(other.description)), traceCount(other.traceCount) {
  if (file == other.ownFile.cStr()) {
    ownFile = heapString(other.ownFile);
    file = ownFile.cStr();
  }

644
  memcpy(trace, other.trace, sizeof(trace[0]) * traceCount);
645

646
  KJ_IF_MAYBE(c, other.context) {
647
    context = heap(**c);
648
  }
649
}
650 651 652

Exception::~Exception() noexcept {}

653 654
Exception::Context::Context(const Context& other) noexcept
    : file(other.file), line(other.line), description(str(other.description)) {
655
  KJ_IF_MAYBE(n, other.next) {
656
    next = heap(**n);
657 658 659
  }
}

Kenton Varda's avatar
Kenton Varda committed
660
void Exception::wrapContext(const char* file, int line, String&& description) {
Kenton Varda's avatar
Kenton Varda committed
661
  context = heap<Context>(file, line, mv(description), mv(context));
662 663
}

Kenton Varda's avatar
Kenton Varda committed
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
void Exception::extendTrace(uint ignoreCount) {
  KJ_STACK_ARRAY(void*, newTraceSpace, kj::size(trace) + ignoreCount + 1,
      sizeof(trace)/sizeof(trace[0]) + 8, 128);

  auto newTrace = kj::getStackTrace(newTraceSpace, ignoreCount + 1);
  if (newTrace.size() > ignoreCount + 2) {
    // Remove suffix that won't fit into our static-sized trace.
    newTrace = newTrace.slice(0, kj::min(kj::size(trace) - traceCount, newTrace.size()));

    // Copy the rest into our trace.
    memcpy(trace + traceCount, newTrace.begin(), newTrace.asBytes().size());
    traceCount += newTrace.size();
  }
}

void Exception::truncateCommonTrace() {
  if (traceCount > 0) {
    // Create a "reference" stack trace that is a little bit deeper than the one in the exception.
    void* refTraceSpace[sizeof(this->trace) / sizeof(this->trace[0]) + 4];
    auto refTrace = kj::getStackTrace(refTraceSpace, 0);

    // We expect that the deepest frame in the exception's stack trace should be somewhere in our
    // own trace, since our own trace has a deeper limit. Search for it.
    for (uint i = refTrace.size(); i > 0; i--) {
      if (refTrace[i-1] == trace[traceCount-1]) {
        // See how many frames match.
        for (uint j = 0; j < i; j++) {
          if (j >= traceCount) {
            // We matched the whole trace, apparently?
            traceCount = 0;
            return;
          } else if (refTrace[i-j-1] != trace[traceCount-j-1]) {
            // Found mismatching entry.

            // If we matched more than half of the reference trace, guess that this is in fact
            // the prefix we're looking for.
            if (j > refTrace.size() / 2) {
              // Delete the matching suffix. Also delete one non-matched entry on the assumption
              // that both traces contain that stack frame but are simply at different points in
              // the function.
              traceCount -= j + 1;
              return;
            }
          }
        }
      }
    }

    // No match. Ignore.
  }
}

void Exception::addTrace(void* ptr) {
  if (traceCount < kj::size(trace)) {
    trace[traceCount++] = ptr;
  }
}

722 723 724 725 726
class ExceptionImpl: public Exception, public std::exception {
public:
  inline ExceptionImpl(Exception&& other): Exception(mv(other)) {}
  ExceptionImpl(const ExceptionImpl& other): Exception(other) {
    // No need to copy whatBuffer since it's just to hold the return value of what().
727 728
  }

729
  const char* what() const noexcept override;
730

731 732 733
private:
  mutable String whatBuffer;
};
734

735 736
const char* ExceptionImpl::what() const noexcept {
  whatBuffer = str(*this);
737
  return whatBuffer.begin();
738 739 740 741 742 743
}

// =======================================================================================

namespace {

744
KJ_THREADLOCAL_PTR(ExceptionCallback) threadLocalCallback = nullptr;
745

746 747
}  // namespace

748 749 750
ExceptionCallback::ExceptionCallback(): next(getExceptionCallback()) {
  char stackVar;
  ptrdiff_t offset = reinterpret_cast<char*>(this) - &stackVar;
Kenton Varda's avatar
Kenton Varda committed
751
  KJ_ASSERT(offset < 65536 && offset > -65536,
752 753 754 755 756 757 758
            "ExceptionCallback must be allocated on the stack.");

  threadLocalCallback = this;
}

ExceptionCallback::ExceptionCallback(ExceptionCallback& next): next(next) {}

759
ExceptionCallback::~ExceptionCallback() noexcept(false) {
760 761
  if (&next != this) {
    threadLocalCallback = &next;
762 763 764 765
  }
}

void ExceptionCallback::onRecoverableException(Exception&& exception) {
766 767 768 769 770 771 772
  next.onRecoverableException(mv(exception));
}

void ExceptionCallback::onFatalException(Exception&& exception) {
  next.onFatalException(mv(exception));
}

773 774 775
void ExceptionCallback::logMessage(
    LogSeverity severity, const char* file, int line, int contextDepth, String&& text) {
  next.logMessage(severity, file, line, contextDepth, mv(text));
776 777
}

778 779 780 781
ExceptionCallback::StackTraceMode ExceptionCallback::stackTraceMode() {
  return next.stackTraceMode();
}

782 783 784 785
Function<void(Function<void()>)> ExceptionCallback::getThreadInitializer() {
  return next.getThreadInitializer();
}

786 787 788 789 790
class ExceptionCallback::RootExceptionCallback: public ExceptionCallback {
public:
  RootExceptionCallback(): ExceptionCallback(*this) {}

  void onRecoverableException(Exception&& exception) override {
Kenton Varda's avatar
Kenton Varda committed
791
#if KJ_NO_EXCEPTIONS
792
    logException(LogSeverity::ERROR, mv(exception));
793
#else
794 795
    if (std::uncaught_exception()) {
      // Bad time to throw an exception.  Just log instead.
796 797 798 799 800
      //
      // TODO(someday): We should really compare uncaughtExceptionCount() against the count at
      //   the innermost runCatchingExceptions() frame in this thread to tell if exceptions are
      //   being caught correctly.
      logException(LogSeverity::ERROR, mv(exception));
801 802 803
    } else {
      throw ExceptionImpl(mv(exception));
    }
804
#endif
805
  }
806

807
  void onFatalException(Exception&& exception) override {
Kenton Varda's avatar
Kenton Varda committed
808
#if KJ_NO_EXCEPTIONS
809
    logException(LogSeverity::FATAL, mv(exception));
810
#else
811
    throw ExceptionImpl(mv(exception));
812
#endif
813
  }
814

815 816 817 818
  void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
                  String&& text) override {
    text = str(kj::repeat('_', contextDepth), file, ":", line, ": ", severity, ": ",
               mv(text), '\n');
819

820
    StringPtr textPtr = text;
821

822
    while (textPtr != nullptr) {
823
      miniposix::ssize_t n = miniposix::write(STDERR_FILENO, textPtr.begin(), textPtr.size());
824 825 826 827 828 829 830
      if (n <= 0) {
        // stderr is broken.  Give up.
        return;
      }
      textPtr = textPtr.slice(n);
    }
  }
831

832 833 834 835 836 837 838 839
  StackTraceMode stackTraceMode() override {
#ifdef KJ_DEBUG
    return StackTraceMode::FULL;
#else
    return StackTraceMode::ADDRESS_ONLY;
#endif
  }

840 841 842 843 844 845 846 847
  Function<void(Function<void()>)> getThreadInitializer() override {
    return [](Function<void()> func) {
      // No initialization needed since RootExceptionCallback is automatically the root callback
      // for new threads.
      func();
    };
  }

848
private:
849
  void logException(LogSeverity severity, Exception&& e) {
850 851 852 853 854
    // We intentionally go back to the top exception callback on the stack because we don't want to
    // bypass whatever log processing is in effect.
    //
    // We intentionally don't log the context since it should get re-added by the exception callback
    // anyway.
855
    getExceptionCallback().logMessage(severity, e.getFile(), e.getLine(), 0, str(
856
        e.getType(), e.getDescription() == nullptr ? "" : ": ", e.getDescription(),
857 858
        e.getStackTrace().size() > 0 ? "\nstack: " : "",
        stringifyStackTraceAddresses(e.getStackTrace()),
859
        stringifyStackTrace(e.getStackTrace()), "\n"));
860 861
  }
};
862

863
ExceptionCallback& getExceptionCallback() {
864 865 866
  static ExceptionCallback::RootExceptionCallback defaultCallback;
  ExceptionCallback* scoped = threadLocalCallback;
  return scoped != nullptr ? *scoped : defaultCallback;
867 868
}

Kenton Varda's avatar
Kenton Varda committed
869 870
void throwFatalException(kj::Exception&& exception, uint ignoreCount) {
  exception.extendTrace(ignoreCount + 1);
871 872 873 874
  getExceptionCallback().onFatalException(kj::mv(exception));
  abort();
}

Kenton Varda's avatar
Kenton Varda committed
875 876
void throwRecoverableException(kj::Exception&& exception, uint ignoreCount) {
  exception.extendTrace(ignoreCount + 1);
877 878 879
  getExceptionCallback().onRecoverableException(kj::mv(exception));
}

880 881
// =======================================================================================

882
namespace _ {  // private
883

884 885 886 887 888 889 890
#if __cplusplus >= 201703L

uint uncaughtExceptionCount() {
  return std::uncaught_exceptions();
}

#elif __GNUC__
891

892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
// Horrible -- but working -- hack:  We can dig into __cxa_get_globals() in order to extract the
// count of uncaught exceptions.  This function is part of the C++ ABI implementation used on Linux,
// OSX, and probably other platforms that use GCC.  Unfortunately, __cxa_get_globals() is only
// actually defined in cxxabi.h on some platforms (e.g. Linux, but not OSX), and even where it is
// defined, it returns an incomplete type.  Here we use the same hack used by Evgeny Panasyuk:
//   https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
//
// Notice that a similar hack is possible on MSVC -- if its C++11 support ever gets to the point of
// supporting KJ in the first place.
//
// It appears likely that a future version of the C++ standard may include an
// uncaught_exception_count() function in the standard library, or an equivalent language feature.
// Some discussion:
//   https://groups.google.com/a/isocpp.org/d/msg/std-proposals/HglEslyZFYs/kKdu5jJw5AgJ

struct FakeEhGlobals {
  // Fake

  void* caughtExceptions;
911 912 913
  uint uncaughtExceptions;
};

914 915 916 917 918 919 920
// LLVM's libstdc++ doesn't declare __cxa_get_globals in its cxxabi.h. GNU does. Because it is
// extern "C", the compiler wills get upset if we re-declare it even in a different namespace.
#if _LIBCPPABI_VERSION
extern "C" void* __cxa_get_globals();
#else
using abi::__cxa_get_globals;
#endif
921

922
uint uncaughtExceptionCount() {
923
  return reinterpret_cast<FakeEhGlobals*>(__cxa_get_globals())->uncaughtExceptions;
924 925
}

926 927
#elif _MSC_VER

928
#if _MSC_VER >= 1900
929
// MSVC14 has a refactored CRT which now provides a direct accessor for this value.
930
// See https://svn.boost.org/trac/boost/ticket/10158 for a brief discussion.
931
extern "C" int *__cdecl __processing_throw();
932 933

uint uncaughtExceptionCount() {
934
  return static_cast<uint>(*__processing_throw());
935 936 937 938 939
}

#elif _MSC_VER >= 1400
// The below was copied from:
// https://github.com/panaseleus/stack_unwinding/blob/master/boost/exception/uncaught_exception_count.hpp
940

941 942 943 944
extern "C" char *__cdecl _getptd();

uint uncaughtExceptionCount() {
  return *reinterpret_cast<uint*>(_getptd() + (sizeof(void*) == 8 ? 0x100 : 0x90));
945
}
946
#else
947 948 949 950
uint uncaughtExceptionCount() {
  // Since the above doesn't work, fall back to uncaught_exception(). This will produce incorrect
  // results in very obscure cases that Cap'n Proto doesn't really rely on anyway.
  return std::uncaught_exception();
951
}
952
#endif
953

954 955 956 957
#else
#error "This needs to be ported to your compiler / C++ ABI."
#endif

958
}  // namespace _ (private)
959

960
UnwindDetector::UnwindDetector(): uncaughtCount(_::uncaughtExceptionCount()) {}
961 962

bool UnwindDetector::isUnwinding() const {
963
  return _::uncaughtExceptionCount() > uncaughtCount;
964 965 966 967 968 969 970 971 972
}

void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const {
  // TODO(someday):  Attach the secondary exception to whatever primary exception is causing
  //   the unwind.  For now we just drop it on the floor as this is probably fine most of the
  //   time.
  runCatchingExceptions(runnable);
}

973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
#if __GNUC__ && !KJ_NO_RTTI
static kj::String demangleTypeName(const char* name) {
  if (name == nullptr) return kj::heapString("(nil)");

  int status;
  char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status);
  kj::String result = kj::heapString(buf == nullptr ? name : buf);
  free(buf);
  return kj::mv(result);
}

kj::String getCaughtExceptionType() {
  return demangleTypeName(abi::__cxa_current_exception_type()->name());
}
#else
kj::String getCaughtExceptionType() {
  return kj::heapString("(unknown)");
}
#endif

993 994 995 996 997 998 999
namespace _ {  // private

class RecoverableExceptionCatcher: public ExceptionCallback {
  // Catches a recoverable exception without using try/catch.  Used when compiled with
  // -fno-exceptions.

public:
1000
  virtual ~RecoverableExceptionCatcher() noexcept(false) {}
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012

  void onRecoverableException(Exception&& exception) override {
    if (caught == nullptr) {
      caught = mv(exception);
    } else {
      // TODO(someday):  Consider it a secondary fault?
    }
  }

  Maybe<Exception> caught;
};

1013
Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
1014 1015 1016
#if KJ_NO_EXCEPTIONS
  RecoverableExceptionCatcher catcher;
  runnable.run();
Kenton Varda's avatar
Kenton Varda committed
1017 1018 1019
  KJ_IF_MAYBE(e, catcher.caught) {
    e->truncateCommonTrace();
  }
1020 1021 1022 1023 1024 1025
  return mv(catcher.caught);
#else
  try {
    runnable.run();
    return nullptr;
  } catch (Exception& e) {
Kenton Varda's avatar
Kenton Varda committed
1026
    e.truncateCommonTrace();
1027
    return kj::mv(e);
1028 1029 1030
  } catch (std::bad_alloc& e) {
    return Exception(Exception::Type::OVERLOADED,
                     "(unknown)", -1, str("std::bad_alloc: ", e.what()));
1031
  } catch (std::exception& e) {
1032
    return Exception(Exception::Type::FAILED,
1033 1034
                     "(unknown)", -1, str("std::exception: ", e.what()));
  } catch (...) {
1035 1036 1037 1038 1039 1040
#if __GNUC__ && !KJ_NO_RTTI
    return Exception(Exception::Type::FAILED, "(unknown)", -1, str(
        "unknown non-KJ exception of type: ", getCaughtExceptionType()));
#else
    return Exception(Exception::Type::FAILED, "(unknown)", -1, str("unknown non-KJ exception"));
#endif
1041 1042 1043 1044 1045 1046
  }
#endif
}

}  // namespace _ (private)

1047
}  // namespace kj