capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

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