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