annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/exception.h @ 69:33d812a61356

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
rev   line source
jpayne@69 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
jpayne@69 2 // Licensed under the MIT License:
jpayne@69 3 //
jpayne@69 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
jpayne@69 5 // of this software and associated documentation files (the "Software"), to deal
jpayne@69 6 // in the Software without restriction, including without limitation the rights
jpayne@69 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
jpayne@69 8 // copies of the Software, and to permit persons to whom the Software is
jpayne@69 9 // furnished to do so, subject to the following conditions:
jpayne@69 10 //
jpayne@69 11 // The above copyright notice and this permission notice shall be included in
jpayne@69 12 // all copies or substantial portions of the Software.
jpayne@69 13 //
jpayne@69 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
jpayne@69 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
jpayne@69 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
jpayne@69 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
jpayne@69 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jpayne@69 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
jpayne@69 20 // THE SOFTWARE.
jpayne@69 21
jpayne@69 22 #pragma once
jpayne@69 23
jpayne@69 24 #include "memory.h"
jpayne@69 25 #include "array.h"
jpayne@69 26 #include "string.h"
jpayne@69 27 #include "windows-sanity.h" // work-around macro conflict with `ERROR`
jpayne@69 28
jpayne@69 29 KJ_BEGIN_HEADER
jpayne@69 30
jpayne@69 31 namespace kj {
jpayne@69 32
jpayne@69 33 class ExceptionImpl;
jpayne@69 34 template <typename T> class Function;
jpayne@69 35
jpayne@69 36 class Exception {
jpayne@69 37 // Exception thrown in case of fatal errors.
jpayne@69 38 //
jpayne@69 39 // Actually, a subclass of this which also implements std::exception will be thrown, but we hide
jpayne@69 40 // that fact from the interface to avoid #including <exception>.
jpayne@69 41
jpayne@69 42 public:
jpayne@69 43 enum class Type {
jpayne@69 44 // What kind of failure?
jpayne@69 45
jpayne@69 46 FAILED = 0,
jpayne@69 47 // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
jpayne@69 48 // error type.
jpayne@69 49
jpayne@69 50 OVERLOADED = 1,
jpayne@69 51 // The call failed because of a temporary lack of resources. This could be space resources
jpayne@69 52 // (out of memory, out of disk space) or time resources (request queue overflow, operation
jpayne@69 53 // timed out).
jpayne@69 54 //
jpayne@69 55 // The operation might work if tried again, but it should NOT be repeated immediately as this
jpayne@69 56 // may simply exacerbate the problem.
jpayne@69 57
jpayne@69 58 DISCONNECTED = 2,
jpayne@69 59 // The call required communication over a connection that has been lost. The callee will need
jpayne@69 60 // to re-establish connections and try again.
jpayne@69 61
jpayne@69 62 UNIMPLEMENTED = 3
jpayne@69 63 // The requested method is not implemented. The caller may wish to revert to a fallback
jpayne@69 64 // approach based on other methods.
jpayne@69 65
jpayne@69 66 // IF YOU ADD A NEW VALUE:
jpayne@69 67 // - Update the stringifier.
jpayne@69 68 // - Update Cap'n Proto's RPC protocol's Exception.Type enum.
jpayne@69 69 };
jpayne@69 70
jpayne@69 71 Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
jpayne@69 72 Exception(Type type, String file, int line, String description = nullptr) noexcept;
jpayne@69 73 Exception(const Exception& other) noexcept;
jpayne@69 74 Exception(Exception&& other) = default;
jpayne@69 75 ~Exception() noexcept;
jpayne@69 76
jpayne@69 77 const char* getFile() const { return file; }
jpayne@69 78 int getLine() const { return line; }
jpayne@69 79 Type getType() const { return type; }
jpayne@69 80 StringPtr getDescription() const { return description; }
jpayne@69 81 ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
jpayne@69 82
jpayne@69 83 void setDescription(kj::String&& desc) { description = kj::mv(desc); }
jpayne@69 84
jpayne@69 85 StringPtr getRemoteTrace() const { return remoteTrace; }
jpayne@69 86 void setRemoteTrace(kj::String&& value) { remoteTrace = kj::mv(value); }
jpayne@69 87 // Additional stack trace data originating from a remote server. If present, then
jpayne@69 88 // `getStackTrace()` only traces up until entry into the RPC system, and the remote trace
jpayne@69 89 // contains any trace information returned over the wire. This string is human-readable but the
jpayne@69 90 // format is otherwise unspecified.
jpayne@69 91
jpayne@69 92 struct Context {
jpayne@69 93 // Describes a bit about what was going on when the exception was thrown.
jpayne@69 94
jpayne@69 95 const char* file;
jpayne@69 96 int line;
jpayne@69 97 String description;
jpayne@69 98 Maybe<Own<Context>> next;
jpayne@69 99
jpayne@69 100 Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
jpayne@69 101 : file(file), line(line), description(mv(description)), next(mv(next)) {}
jpayne@69 102 Context(const Context& other) noexcept;
jpayne@69 103 };
jpayne@69 104
jpayne@69 105 inline Maybe<const Context&> getContext() const {
jpayne@69 106 KJ_IF_MAYBE(c, context) {
jpayne@69 107 return **c;
jpayne@69 108 } else {
jpayne@69 109 return nullptr;
jpayne@69 110 }
jpayne@69 111 }
jpayne@69 112
jpayne@69 113 void wrapContext(const char* file, int line, String&& description);
jpayne@69 114 // Wraps the context in a new node. This becomes the head node returned by getContext() -- it
jpayne@69 115 // is expected that contexts will be added in reverse order as the exception passes up the
jpayne@69 116 // callback stack.
jpayne@69 117
jpayne@69 118 KJ_NOINLINE void extendTrace(uint ignoreCount, uint limit = kj::maxValue);
jpayne@69 119 // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
jpayne@69 120 // frames (see `getStackTrace()` for discussion of `ignoreCount`).
jpayne@69 121 //
jpayne@69 122 // If `limit` is set, limit the number of frames added to the given number.
jpayne@69 123
jpayne@69 124 KJ_NOINLINE void truncateCommonTrace();
jpayne@69 125 // Remove the part of the stack trace which the exception shares with the caller of this method.
jpayne@69 126 // This is used by the async library to remove the async infrastructure from the stack trace
jpayne@69 127 // before replacing it with the async trace.
jpayne@69 128
jpayne@69 129 void addTrace(void* ptr);
jpayne@69 130 // Append the given pointer to the backtrace, if it is not already full. This is used by the
jpayne@69 131 // async library to trace through the promise chain that led to the exception.
jpayne@69 132
jpayne@69 133 KJ_NOINLINE void addTraceHere();
jpayne@69 134 // Adds the location that called this method to the stack trace.
jpayne@69 135
jpayne@69 136 private:
jpayne@69 137 String ownFile;
jpayne@69 138 const char* file;
jpayne@69 139 int line;
jpayne@69 140 Type type;
jpayne@69 141 String description;
jpayne@69 142 Maybe<Own<Context>> context;
jpayne@69 143 String remoteTrace;
jpayne@69 144 void* trace[32];
jpayne@69 145 uint traceCount;
jpayne@69 146
jpayne@69 147 bool isFullTrace = false;
jpayne@69 148 // Is `trace` a full trace to the top of the stack (or as close as we could get before we ran
jpayne@69 149 // out of space)? If this is false, then `trace` is instead a partial trace covering just the
jpayne@69 150 // frames between where the exception was thrown and where it was caught.
jpayne@69 151 //
jpayne@69 152 // extendTrace() transitions this to true, and truncateCommonTrace() changes it back to false.
jpayne@69 153 //
jpayne@69 154 // In theory, an exception should only hold a full trace when it is in the process of being
jpayne@69 155 // thrown via the C++ exception handling mechanism -- extendTrace() is called before the throw
jpayne@69 156 // and truncateCommonTrace() after it is caught. Note that when exceptions propagate through
jpayne@69 157 // async promises, the trace is extended one frame at a time instead, so isFullTrace should
jpayne@69 158 // remain false.
jpayne@69 159
jpayne@69 160 friend class ExceptionImpl;
jpayne@69 161 };
jpayne@69 162
jpayne@69 163 struct CanceledException { };
jpayne@69 164 // This exception is thrown to force-unwind a stack in order to immediately cancel whatever that
jpayne@69 165 // stack was doing. It is used in the implementation of fibers in particular. Application code
jpayne@69 166 // should almost never catch this exception, unless you need to modify stack unwinding for some
jpayne@69 167 // reason. kj::runCatchingExceptions() does not catch it.
jpayne@69 168
jpayne@69 169 StringPtr KJ_STRINGIFY(Exception::Type type);
jpayne@69 170 String KJ_STRINGIFY(const Exception& e);
jpayne@69 171
jpayne@69 172 // =======================================================================================
jpayne@69 173
jpayne@69 174 enum class LogSeverity {
jpayne@69 175 INFO, // Information describing what the code is up to, which users may request to see
jpayne@69 176 // with a flag like `--verbose`. Does not indicate a problem. Not printed by
jpayne@69 177 // default; you must call setLogLevel(INFO) to enable.
jpayne@69 178 WARNING, // A problem was detected but execution can continue with correct output.
jpayne@69 179 ERROR, // Something is wrong, but execution can continue with garbage output.
jpayne@69 180 FATAL, // Something went wrong, and execution cannot continue.
jpayne@69 181 DBG // Temporary debug logging. See KJ_DBG.
jpayne@69 182
jpayne@69 183 // Make sure to update the stringifier if you add a new severity level.
jpayne@69 184 };
jpayne@69 185
jpayne@69 186 StringPtr KJ_STRINGIFY(LogSeverity severity);
jpayne@69 187
jpayne@69 188 class ExceptionCallback {
jpayne@69 189 // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
jpayne@69 190 // to perform your own exception handling. For example, a reasonable thing to do is to have
jpayne@69 191 // onRecoverableException() set a flag indicating that an error occurred, and then check for that
jpayne@69 192 // flag just before writing to storage and/or returning results to the user. If the flag is set,
jpayne@69 193 // discard whatever you have and return an error instead.
jpayne@69 194 //
jpayne@69 195 // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the
jpayne@69 196 // newest ExceptionCallback on the calling thread's stack is called. The default implementation
jpayne@69 197 // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks
jpayne@69 198 // behave a lot like try/catch blocks, except that they are called before any stack unwinding
jpayne@69 199 // occurs.
jpayne@69 200
jpayne@69 201 public:
jpayne@69 202 ExceptionCallback();
jpayne@69 203 KJ_DISALLOW_COPY_AND_MOVE(ExceptionCallback);
jpayne@69 204 virtual ~ExceptionCallback() noexcept(false);
jpayne@69 205
jpayne@69 206 virtual void onRecoverableException(Exception&& exception);
jpayne@69 207 // Called when an exception has been raised, but the calling code has the ability to continue by
jpayne@69 208 // producing garbage output. This method _should_ throw the exception, but is allowed to simply
jpayne@69 209 // return if garbage output is acceptable.
jpayne@69 210 //
jpayne@69 211 // The global default implementation throws an exception unless the library was compiled with
jpayne@69 212 // -fno-exceptions, in which case it logs an error and returns.
jpayne@69 213
jpayne@69 214 virtual void onFatalException(Exception&& exception);
jpayne@69 215 // Called when an exception has been raised and the calling code cannot continue. If this method
jpayne@69 216 // returns normally, abort() will be called. The method must throw the exception to avoid
jpayne@69 217 // aborting.
jpayne@69 218 //
jpayne@69 219 // The global default implementation throws an exception unless the library was compiled with
jpayne@69 220 // -fno-exceptions, in which case it logs an error and returns.
jpayne@69 221
jpayne@69 222 virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
jpayne@69 223 String&& text);
jpayne@69 224 // Called when something wants to log some debug text. `contextDepth` indicates how many levels
jpayne@69 225 // of context the message passed through; it may make sense to indent the message accordingly.
jpayne@69 226 //
jpayne@69 227 // The global default implementation writes the text to stderr.
jpayne@69 228
jpayne@69 229 enum class StackTraceMode {
jpayne@69 230 FULL,
jpayne@69 231 // Stringifying a stack trace will attempt to determine source file and line numbers. This may
jpayne@69 232 // be expensive. For example, on Linux, this shells out to `addr2line`.
jpayne@69 233 //
jpayne@69 234 // This is the default in debug builds.
jpayne@69 235
jpayne@69 236 ADDRESS_ONLY,
jpayne@69 237 // Stringifying a stack trace will only generate a list of code addresses.
jpayne@69 238 //
jpayne@69 239 // This is the default in release builds.
jpayne@69 240
jpayne@69 241 NONE
jpayne@69 242 // Generating a stack trace will always return an empty array.
jpayne@69 243 //
jpayne@69 244 // This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library
jpayne@69 245 // has been observed to be pretty slow, so exception-heavy code might benefit significantly
jpayne@69 246 // from this setting. (But exceptions should be rare...)
jpayne@69 247 };
jpayne@69 248
jpayne@69 249 virtual StackTraceMode stackTraceMode();
jpayne@69 250 // Returns the current preferred stack trace mode.
jpayne@69 251
jpayne@69 252 virtual Function<void(Function<void()>)> getThreadInitializer();
jpayne@69 253 // Called just before a new thread is spawned using kj::Thread. Returns a function which should
jpayne@69 254 // be invoked inside the new thread to initialize the thread's ExceptionCallback. The initializer
jpayne@69 255 // function itself receives, as its parameter, the thread's main function, which it must call.
jpayne@69 256
jpayne@69 257 protected:
jpayne@69 258 ExceptionCallback& next;
jpayne@69 259
jpayne@69 260 private:
jpayne@69 261 ExceptionCallback(ExceptionCallback& next);
jpayne@69 262
jpayne@69 263 class RootExceptionCallback;
jpayne@69 264 friend ExceptionCallback& getExceptionCallback();
jpayne@69 265
jpayne@69 266 friend class Thread;
jpayne@69 267 };
jpayne@69 268
jpayne@69 269 ExceptionCallback& getExceptionCallback();
jpayne@69 270 // Returns the current exception callback.
jpayne@69 271
jpayne@69 272 KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
jpayne@69 273 // Invoke the exception callback to throw the given fatal exception. If the exception callback
jpayne@69 274 // returns, abort.
jpayne@69 275
jpayne@69 276 KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
jpayne@69 277 // Invoke the exception callback to throw the given recoverable exception. If the exception
jpayne@69 278 // callback returns, return normally.
jpayne@69 279
jpayne@69 280 // =======================================================================================
jpayne@69 281
jpayne@69 282 namespace _ { class Runnable; }
jpayne@69 283
jpayne@69 284 template <typename Func>
jpayne@69 285 Maybe<Exception> runCatchingExceptions(Func&& func);
jpayne@69 286 // Executes the given function (usually, a lambda returning nothing) catching any exceptions that
jpayne@69 287 // are thrown. Returns the Exception if there was one, or null if the operation completed normally.
jpayne@69 288 // Non-KJ exceptions will be wrapped.
jpayne@69 289 //
jpayne@69 290 // If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
jpayne@69 291 // recoverable exceptions occurred while running the function and will return those.
jpayne@69 292
jpayne@69 293 #if !KJ_NO_EXCEPTIONS
jpayne@69 294
jpayne@69 295 kj::Exception getCaughtExceptionAsKj();
jpayne@69 296 // Call from the catch block of a try/catch to get a `kj::Exception` representing the exception
jpayne@69 297 // that was caught, the same way that `kj::runCatchingExceptions` would when catching an exception.
jpayne@69 298 // This is sometimes useful if `runCatchingExceptions()` doesn't quite fit your use case. You can
jpayne@69 299 // call this from any catch block, including `catch (...)`.
jpayne@69 300 //
jpayne@69 301 // Some exception types will actually be rethrown by this function, rather than returned. The most
jpayne@69 302 // common example is `CanceledException`, whose purpose is to unwind the stack and is not meant to
jpayne@69 303 // be caught.
jpayne@69 304
jpayne@69 305 #endif // !KJ_NO_EXCEPTIONS
jpayne@69 306
jpayne@69 307 class UnwindDetector {
jpayne@69 308 // Utility for detecting when a destructor is called due to unwind. Useful for:
jpayne@69 309 // - Avoiding throwing exceptions in this case, which would terminate the program.
jpayne@69 310 // - Detecting whether to commit or roll back a transaction.
jpayne@69 311 //
jpayne@69 312 // To use this class, either inherit privately from it or declare it as a member. The detector
jpayne@69 313 // works by comparing the exception state against that when the constructor was called, so for
jpayne@69 314 // an object that was actually constructed during exception unwind, it will behave as if no
jpayne@69 315 // unwind is taking place. This is usually the desired behavior.
jpayne@69 316
jpayne@69 317 public:
jpayne@69 318 UnwindDetector();
jpayne@69 319
jpayne@69 320 bool isUnwinding() const;
jpayne@69 321 // Returns true if the current thread is in a stack unwind that it wasn't in at the time the
jpayne@69 322 // object was constructed.
jpayne@69 323
jpayne@69 324 template <typename Func>
jpayne@69 325 void catchExceptionsIfUnwinding(Func&& func) const;
jpayne@69 326 // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are
jpayne@69 327 // caught and treated as secondary faults, meaning they are considered to be side-effects of the
jpayne@69 328 // exception that is unwinding the stack. Otherwise, exceptions are passed through normally.
jpayne@69 329
jpayne@69 330 private:
jpayne@69 331 uint uncaughtCount;
jpayne@69 332
jpayne@69 333 #if !KJ_NO_EXCEPTIONS
jpayne@69 334 void catchThrownExceptionAsSecondaryFault() const;
jpayne@69 335 #endif
jpayne@69 336 };
jpayne@69 337
jpayne@69 338 #if KJ_NO_EXCEPTIONS
jpayne@69 339
jpayne@69 340 namespace _ { // private
jpayne@69 341
jpayne@69 342 class Runnable {
jpayne@69 343 public:
jpayne@69 344 virtual void run() = 0;
jpayne@69 345 };
jpayne@69 346
jpayne@69 347 template <typename Func>
jpayne@69 348 class RunnableImpl: public Runnable {
jpayne@69 349 public:
jpayne@69 350 RunnableImpl(Func&& func): func(kj::fwd<Func>(func)) {}
jpayne@69 351 void run() override {
jpayne@69 352 func();
jpayne@69 353 }
jpayne@69 354 private:
jpayne@69 355 Func func;
jpayne@69 356 };
jpayne@69 357
jpayne@69 358 Maybe<Exception> runCatchingExceptions(Runnable& runnable);
jpayne@69 359
jpayne@69 360 } // namespace _ (private)
jpayne@69 361
jpayne@69 362 #endif // KJ_NO_EXCEPTIONS
jpayne@69 363
jpayne@69 364 template <typename Func>
jpayne@69 365 Maybe<Exception> runCatchingExceptions(Func&& func) {
jpayne@69 366 #if KJ_NO_EXCEPTIONS
jpayne@69 367 _::RunnableImpl<Func> runnable(kj::fwd<Func>(func));
jpayne@69 368 return _::runCatchingExceptions(runnable);
jpayne@69 369 #else
jpayne@69 370 try {
jpayne@69 371 func();
jpayne@69 372 return nullptr;
jpayne@69 373 } catch (...) {
jpayne@69 374 return getCaughtExceptionAsKj();
jpayne@69 375 }
jpayne@69 376 #endif
jpayne@69 377 }
jpayne@69 378
jpayne@69 379 template <typename Func>
jpayne@69 380 void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
jpayne@69 381 #if KJ_NO_EXCEPTIONS
jpayne@69 382 // Can't possibly be unwinding...
jpayne@69 383 func();
jpayne@69 384 #else
jpayne@69 385 if (isUnwinding()) {
jpayne@69 386 try {
jpayne@69 387 func();
jpayne@69 388 } catch (...) {
jpayne@69 389 catchThrownExceptionAsSecondaryFault();
jpayne@69 390 }
jpayne@69 391 } else {
jpayne@69 392 func();
jpayne@69 393 }
jpayne@69 394 #endif
jpayne@69 395 }
jpayne@69 396
jpayne@69 397 #define KJ_ON_SCOPE_SUCCESS(code) \
jpayne@69 398 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
jpayne@69 399 KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
jpayne@69 400 // Runs `code` if the current scope is exited normally (not due to an exception).
jpayne@69 401
jpayne@69 402 #define KJ_ON_SCOPE_FAILURE(code) \
jpayne@69 403 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
jpayne@69 404 KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
jpayne@69 405 // Runs `code` if the current scope is exited due to an exception.
jpayne@69 406
jpayne@69 407 // =======================================================================================
jpayne@69 408
jpayne@69 409 KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
jpayne@69 410 // Attempt to get the current stack trace, returning a list of pointers to instructions. The
jpayne@69 411 // returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
jpayne@69 412 // If the platform doesn't support stack traces, returns an empty array.
jpayne@69 413 //
jpayne@69 414 // `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
jpayne@69 415 // off a prefix of the trace that is uninteresting to the developer because it's just locations
jpayne@69 416 // inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
jpayne@69 417 // KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
jpayne@69 418 // ignored entries will still waste space in the `space` array (and the returned array's `begin()`
jpayne@69 419 // is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
jpayne@69 420 // since `getStackTrace()` needs to ignore its own internal frames).
jpayne@69 421
jpayne@69 422 String stringifyStackTrace(ArrayPtr<void* const>);
jpayne@69 423 // Convert the stack trace to a string with file names and line numbers. This may involve executing
jpayne@69 424 // suprocesses.
jpayne@69 425
jpayne@69 426 String stringifyStackTraceAddresses(ArrayPtr<void* const> trace);
jpayne@69 427 StringPtr stringifyStackTraceAddresses(ArrayPtr<void* const> trace, ArrayPtr<char> scratch);
jpayne@69 428 // Construct a string containing just enough information about a stack trace to be able to convert
jpayne@69 429 // it to file and line numbers later using offline tools. This produces a sequence of
jpayne@69 430 // space-separated code location identifiers. Each identifier may be an absolute address
jpayne@69 431 // (hex number starting with 0x) or may be a module-relative address "<module>@0x<hex>". The
jpayne@69 432 // latter case is preferred when ASLR is in effect and has loaded different modules at different
jpayne@69 433 // addresses.
jpayne@69 434
jpayne@69 435 String getStackTrace();
jpayne@69 436 // Get a stack trace right now and stringify it. Useful for debugging.
jpayne@69 437
jpayne@69 438 void printStackTraceOnCrash();
jpayne@69 439 // Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
jpayne@69 440 // a stack trace. You should call this as early as possible on program startup. Programs using
jpayne@69 441 // KJ_MAIN get this automatically.
jpayne@69 442
jpayne@69 443 void resetCrashHandlers();
jpayne@69 444 // Resets all signal handlers set by printStackTraceOnCrash().
jpayne@69 445
jpayne@69 446 kj::StringPtr trimSourceFilename(kj::StringPtr filename);
jpayne@69 447 // Given a source code file name, trim off noisy prefixes like "src/" or
jpayne@69 448 // "/ekam-provider/canonical/".
jpayne@69 449
jpayne@69 450 kj::String getCaughtExceptionType();
jpayne@69 451 // Utility function which attempts to return the human-readable type name of the exception
jpayne@69 452 // currently being thrown. This can be called inside a catch block, including a catch (...) block,
jpayne@69 453 // for the purpose of error logging. This function is best-effort; on some platforms it may simply
jpayne@69 454 // return "(unknown)".
jpayne@69 455
jpayne@69 456 #if !KJ_NO_EXCEPTIONS
jpayne@69 457
jpayne@69 458 class InFlightExceptionIterator {
jpayne@69 459 // A class that can be used to iterate over exceptions that are in-flight in the current thread,
jpayne@69 460 // meaning they are either uncaught, or caught by a catch block that is current executing.
jpayne@69 461 //
jpayne@69 462 // This is meant for debugging purposes, and the results are best-effort. The C++ standard
jpayne@69 463 // library does not provide any way to inspect uncaught exceptions, so this class can only
jpayne@69 464 // discover KJ exceptions thrown using throwFatalException() or throwRecoverableException().
jpayne@69 465 // All KJ code uses those two functions to throw exceptions, but if your own code uses a bare
jpayne@69 466 // `throw`, or if the standard library throws an exception, these cannot be inspected.
jpayne@69 467 //
jpayne@69 468 // This class is safe to use in a signal handler.
jpayne@69 469
jpayne@69 470 public:
jpayne@69 471 InFlightExceptionIterator();
jpayne@69 472
jpayne@69 473 Maybe<const Exception&> next();
jpayne@69 474
jpayne@69 475 private:
jpayne@69 476 const Exception* ptr;
jpayne@69 477 };
jpayne@69 478
jpayne@69 479 #endif // !KJ_NO_EXCEPTIONS
jpayne@69 480
jpayne@69 481 kj::Exception getDestructionReason(void* traceSeparator,
jpayne@69 482 kj::Exception::Type defaultType, const char* defaultFile, int defaultLine,
jpayne@69 483 kj::StringPtr defaultDescription);
jpayne@69 484 // Returns an exception that attempts to capture why a destructor has been invoked. If a KJ
jpayne@69 485 // exception is currently in-flight (see InFlightExceptionIterator), then that exception is
jpayne@69 486 // returned. Otherwise, an exception is constructed using the current stack trace and the type,
jpayne@69 487 // file, line, and description provided. In the latter case, `traceSeparator` is appended to the
jpayne@69 488 // stack trace; this should be a pointer to some dummy symbol which acts as a separator between the
jpayne@69 489 // original stack trace and any new trace frames added later.
jpayne@69 490
jpayne@69 491 kj::ArrayPtr<void* const> computeRelativeTrace(
jpayne@69 492 kj::ArrayPtr<void* const> trace, kj::ArrayPtr<void* const> relativeTo);
jpayne@69 493 // Given two traces expected to have started from the same root, try to find the part of `trace`
jpayne@69 494 // that is different from `relativeTo`, considering that either or both traces might be truncated.
jpayne@69 495 //
jpayne@69 496 // This is useful for debugging, when reporting several related traces at once.
jpayne@69 497
jpayne@69 498 void requireOnStack(void* ptr, kj::StringPtr description);
jpayne@69 499 // Throw an exception if `ptr` does not appear to point to something near the top of the stack.
jpayne@69 500 // Used as a safety check for types that must be stack-allocated, like ExceptionCallback.
jpayne@69 501
jpayne@69 502 } // namespace kj
jpayne@69 503
jpayne@69 504 KJ_END_HEADER