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