annotate win64-msvc/include/kj/exception.h @ 138:eb184393b244

Rebuild with DW2 exception handling to match Qt
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 27 Oct 2016 10:26:57 +0100
parents 42a73082be24
children 0f2d93caa50c
rev   line source
cannam@132 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@132 2 // Licensed under the MIT License:
cannam@132 3 //
cannam@132 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@132 5 // of this software and associated documentation files (the "Software"), to deal
cannam@132 6 // in the Software without restriction, including without limitation the rights
cannam@132 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@132 8 // copies of the Software, and to permit persons to whom the Software is
cannam@132 9 // furnished to do so, subject to the following conditions:
cannam@132 10 //
cannam@132 11 // The above copyright notice and this permission notice shall be included in
cannam@132 12 // all copies or substantial portions of the Software.
cannam@132 13 //
cannam@132 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@132 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@132 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@132 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@132 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@132 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@132 20 // THE SOFTWARE.
cannam@132 21
cannam@132 22 #ifndef KJ_EXCEPTION_H_
cannam@132 23 #define KJ_EXCEPTION_H_
cannam@132 24
cannam@132 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
cannam@132 26 #pragma GCC system_header
cannam@132 27 #endif
cannam@132 28
cannam@132 29 #include "memory.h"
cannam@132 30 #include "array.h"
cannam@132 31 #include "string.h"
cannam@132 32
cannam@132 33 namespace kj {
cannam@132 34
cannam@132 35 class ExceptionImpl;
cannam@132 36
cannam@132 37 class Exception {
cannam@132 38 // Exception thrown in case of fatal errors.
cannam@132 39 //
cannam@132 40 // Actually, a subclass of this which also implements std::exception will be thrown, but we hide
cannam@132 41 // that fact from the interface to avoid #including <exception>.
cannam@132 42
cannam@132 43 public:
cannam@132 44 enum class Type {
cannam@132 45 // What kind of failure?
cannam@132 46
cannam@132 47 FAILED = 0,
cannam@132 48 // Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
cannam@132 49 // error type.
cannam@132 50
cannam@132 51 OVERLOADED = 1,
cannam@132 52 // The call failed because of a temporary lack of resources. This could be space resources
cannam@132 53 // (out of memory, out of disk space) or time resources (request queue overflow, operation
cannam@132 54 // timed out).
cannam@132 55 //
cannam@132 56 // The operation might work if tried again, but it should NOT be repeated immediately as this
cannam@132 57 // may simply exacerbate the problem.
cannam@132 58
cannam@132 59 DISCONNECTED = 2,
cannam@132 60 // The call required communication over a connection that has been lost. The callee will need
cannam@132 61 // to re-establish connections and try again.
cannam@132 62
cannam@132 63 UNIMPLEMENTED = 3
cannam@132 64 // The requested method is not implemented. The caller may wish to revert to a fallback
cannam@132 65 // approach based on other methods.
cannam@132 66
cannam@132 67 // IF YOU ADD A NEW VALUE:
cannam@132 68 // - Update the stringifier.
cannam@132 69 // - Update Cap'n Proto's RPC protocol's Exception.Type enum.
cannam@132 70 };
cannam@132 71
cannam@132 72 Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
cannam@132 73 Exception(Type type, String file, int line, String description = nullptr) noexcept;
cannam@132 74 Exception(const Exception& other) noexcept;
cannam@132 75 Exception(Exception&& other) = default;
cannam@132 76 ~Exception() noexcept;
cannam@132 77
cannam@132 78 const char* getFile() const { return file; }
cannam@132 79 int getLine() const { return line; }
cannam@132 80 Type getType() const { return type; }
cannam@132 81 StringPtr getDescription() const { return description; }
cannam@132 82 ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
cannam@132 83
cannam@132 84 struct Context {
cannam@132 85 // Describes a bit about what was going on when the exception was thrown.
cannam@132 86
cannam@132 87 const char* file;
cannam@132 88 int line;
cannam@132 89 String description;
cannam@132 90 Maybe<Own<Context>> next;
cannam@132 91
cannam@132 92 Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
cannam@132 93 : file(file), line(line), description(mv(description)), next(mv(next)) {}
cannam@132 94 Context(const Context& other) noexcept;
cannam@132 95 };
cannam@132 96
cannam@132 97 inline Maybe<const Context&> getContext() const {
cannam@132 98 KJ_IF_MAYBE(c, context) {
cannam@132 99 return **c;
cannam@132 100 } else {
cannam@132 101 return nullptr;
cannam@132 102 }
cannam@132 103 }
cannam@132 104
cannam@132 105 void wrapContext(const char* file, int line, String&& description);
cannam@132 106 // Wraps the context in a new node. This becomes the head node returned by getContext() -- it
cannam@132 107 // is expected that contexts will be added in reverse order as the exception passes up the
cannam@132 108 // callback stack.
cannam@132 109
cannam@132 110 KJ_NOINLINE void extendTrace(uint ignoreCount);
cannam@132 111 // Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
cannam@132 112 // frames (see `getStackTrace()` for discussion of `ignoreCount`).
cannam@132 113
cannam@132 114 KJ_NOINLINE void truncateCommonTrace();
cannam@132 115 // Remove the part of the stack trace which the exception shares with the caller of this method.
cannam@132 116 // This is used by the async library to remove the async infrastructure from the stack trace
cannam@132 117 // before replacing it with the async trace.
cannam@132 118
cannam@132 119 void addTrace(void* ptr);
cannam@132 120 // Append the given pointer to the backtrace, if it is not already full. This is used by the
cannam@132 121 // async library to trace through the promise chain that led to the exception.
cannam@132 122
cannam@132 123 private:
cannam@132 124 String ownFile;
cannam@132 125 const char* file;
cannam@132 126 int line;
cannam@132 127 Type type;
cannam@132 128 String description;
cannam@132 129 Maybe<Own<Context>> context;
cannam@132 130 void* trace[32];
cannam@132 131 uint traceCount;
cannam@132 132
cannam@132 133 friend class ExceptionImpl;
cannam@132 134 };
cannam@132 135
cannam@132 136 StringPtr KJ_STRINGIFY(Exception::Type type);
cannam@132 137 String KJ_STRINGIFY(const Exception& e);
cannam@132 138
cannam@132 139 // =======================================================================================
cannam@132 140
cannam@132 141 enum class LogSeverity {
cannam@132 142 INFO, // Information describing what the code is up to, which users may request to see
cannam@132 143 // with a flag like `--verbose`. Does not indicate a problem. Not printed by
cannam@132 144 // default; you must call setLogLevel(INFO) to enable.
cannam@132 145 WARNING, // A problem was detected but execution can continue with correct output.
cannam@132 146 ERROR, // Something is wrong, but execution can continue with garbage output.
cannam@132 147 FATAL, // Something went wrong, and execution cannot continue.
cannam@132 148 DBG // Temporary debug logging. See KJ_DBG.
cannam@132 149
cannam@132 150 // Make sure to update the stringifier if you add a new severity level.
cannam@132 151 };
cannam@132 152
cannam@132 153 StringPtr KJ_STRINGIFY(LogSeverity severity);
cannam@132 154
cannam@132 155 class ExceptionCallback {
cannam@132 156 // If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
cannam@132 157 // to perform your own exception handling. For example, a reasonable thing to do is to have
cannam@132 158 // onRecoverableException() set a flag indicating that an error occurred, and then check for that
cannam@132 159 // flag just before writing to storage and/or returning results to the user. If the flag is set,
cannam@132 160 // discard whatever you have and return an error instead.
cannam@132 161 //
cannam@132 162 // ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the
cannam@132 163 // newest ExceptionCallback on the calling thread's stack is called. The default implementation
cannam@132 164 // of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks
cannam@132 165 // behave a lot like try/catch blocks, except that they are called before any stack unwinding
cannam@132 166 // occurs.
cannam@132 167
cannam@132 168 public:
cannam@132 169 ExceptionCallback();
cannam@132 170 KJ_DISALLOW_COPY(ExceptionCallback);
cannam@132 171 virtual ~ExceptionCallback() noexcept(false);
cannam@132 172
cannam@132 173 virtual void onRecoverableException(Exception&& exception);
cannam@132 174 // Called when an exception has been raised, but the calling code has the ability to continue by
cannam@132 175 // producing garbage output. This method _should_ throw the exception, but is allowed to simply
cannam@132 176 // return if garbage output is acceptable.
cannam@132 177 //
cannam@132 178 // The global default implementation throws an exception unless the library was compiled with
cannam@132 179 // -fno-exceptions, in which case it logs an error and returns.
cannam@132 180
cannam@132 181 virtual void onFatalException(Exception&& exception);
cannam@132 182 // Called when an exception has been raised and the calling code cannot continue. If this method
cannam@132 183 // returns normally, abort() will be called. The method must throw the exception to avoid
cannam@132 184 // aborting.
cannam@132 185 //
cannam@132 186 // The global default implementation throws an exception unless the library was compiled with
cannam@132 187 // -fno-exceptions, in which case it logs an error and returns.
cannam@132 188
cannam@132 189 virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
cannam@132 190 String&& text);
cannam@132 191 // Called when something wants to log some debug text. `contextDepth` indicates how many levels
cannam@132 192 // of context the message passed through; it may make sense to indent the message accordingly.
cannam@132 193 //
cannam@132 194 // The global default implementation writes the text to stderr.
cannam@132 195
cannam@132 196 protected:
cannam@132 197 ExceptionCallback& next;
cannam@132 198
cannam@132 199 private:
cannam@132 200 ExceptionCallback(ExceptionCallback& next);
cannam@132 201
cannam@132 202 class RootExceptionCallback;
cannam@132 203 friend ExceptionCallback& getExceptionCallback();
cannam@132 204 };
cannam@132 205
cannam@132 206 ExceptionCallback& getExceptionCallback();
cannam@132 207 // Returns the current exception callback.
cannam@132 208
cannam@132 209 KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
cannam@132 210 // Invoke the exception callback to throw the given fatal exception. If the exception callback
cannam@132 211 // returns, abort.
cannam@132 212
cannam@132 213 KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
cannam@132 214 // Invoke the exception callback to throw the given recoverable exception. If the exception
cannam@132 215 // callback returns, return normally.
cannam@132 216
cannam@132 217 // =======================================================================================
cannam@132 218
cannam@132 219 namespace _ { class Runnable; }
cannam@132 220
cannam@132 221 template <typename Func>
cannam@132 222 Maybe<Exception> runCatchingExceptions(Func&& func) noexcept;
cannam@132 223 // Executes the given function (usually, a lambda returning nothing) catching any exceptions that
cannam@132 224 // are thrown. Returns the Exception if there was one, or null if the operation completed normally.
cannam@132 225 // Non-KJ exceptions will be wrapped.
cannam@132 226 //
cannam@132 227 // If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
cannam@132 228 // recoverable exceptions occurred while running the function and will return those.
cannam@132 229
cannam@132 230 class UnwindDetector {
cannam@132 231 // Utility for detecting when a destructor is called due to unwind. Useful for:
cannam@132 232 // - Avoiding throwing exceptions in this case, which would terminate the program.
cannam@132 233 // - Detecting whether to commit or roll back a transaction.
cannam@132 234 //
cannam@132 235 // To use this class, either inherit privately from it or declare it as a member. The detector
cannam@132 236 // works by comparing the exception state against that when the constructor was called, so for
cannam@132 237 // an object that was actually constructed during exception unwind, it will behave as if no
cannam@132 238 // unwind is taking place. This is usually the desired behavior.
cannam@132 239
cannam@132 240 public:
cannam@132 241 UnwindDetector();
cannam@132 242
cannam@132 243 bool isUnwinding() const;
cannam@132 244 // Returns true if the current thread is in a stack unwind that it wasn't in at the time the
cannam@132 245 // object was constructed.
cannam@132 246
cannam@132 247 template <typename Func>
cannam@132 248 void catchExceptionsIfUnwinding(Func&& func) const;
cannam@132 249 // Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are
cannam@132 250 // caught and treated as secondary faults, meaning they are considered to be side-effects of the
cannam@132 251 // exception that is unwinding the stack. Otherwise, exceptions are passed through normally.
cannam@132 252
cannam@132 253 private:
cannam@132 254 uint uncaughtCount;
cannam@132 255
cannam@132 256 void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
cannam@132 257 };
cannam@132 258
cannam@132 259 namespace _ { // private
cannam@132 260
cannam@132 261 class Runnable {
cannam@132 262 public:
cannam@132 263 virtual void run() = 0;
cannam@132 264 };
cannam@132 265
cannam@132 266 template <typename Func>
cannam@132 267 class RunnableImpl: public Runnable {
cannam@132 268 public:
cannam@132 269 RunnableImpl(Func&& func): func(kj::mv(func)) {}
cannam@132 270 void run() override {
cannam@132 271 func();
cannam@132 272 }
cannam@132 273 private:
cannam@132 274 Func func;
cannam@132 275 };
cannam@132 276
cannam@132 277 Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
cannam@132 278
cannam@132 279 } // namespace _ (private)
cannam@132 280
cannam@132 281 template <typename Func>
cannam@132 282 Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
cannam@132 283 _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
cannam@132 284 return _::runCatchingExceptions(runnable);
cannam@132 285 }
cannam@132 286
cannam@132 287 template <typename Func>
cannam@132 288 void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
cannam@132 289 if (isUnwinding()) {
cannam@132 290 _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
cannam@132 291 catchExceptionsAsSecondaryFaults(runnable);
cannam@132 292 } else {
cannam@132 293 func();
cannam@132 294 }
cannam@132 295 }
cannam@132 296
cannam@132 297 #define KJ_ON_SCOPE_SUCCESS(code) \
cannam@132 298 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
cannam@132 299 KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
cannam@132 300 // Runs `code` if the current scope is exited normally (not due to an exception).
cannam@132 301
cannam@132 302 #define KJ_ON_SCOPE_FAILURE(code) \
cannam@132 303 ::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
cannam@132 304 KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
cannam@132 305 // Runs `code` if the current scope is exited due to an exception.
cannam@132 306
cannam@132 307 // =======================================================================================
cannam@132 308
cannam@132 309 KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
cannam@132 310 // Attempt to get the current stack trace, returning a list of pointers to instructions. The
cannam@132 311 // returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
cannam@132 312 // If the platform doesn't support stack traces, returns an empty array.
cannam@132 313 //
cannam@132 314 // `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
cannam@132 315 // off a prefix of the trace that is uninteresting to the developer because it's just locations
cannam@132 316 // inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
cannam@132 317 // KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
cannam@132 318 // ignored entries will still waste space in the `space` array (and the returned array's `begin()`
cannam@132 319 // is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
cannam@132 320 // since `getStackTrace()` needs to ignore its own internal frames).
cannam@132 321
cannam@132 322 String stringifyStackTrace(ArrayPtr<void* const>);
cannam@132 323 // Convert the stack trace to a string with file names and line numbers. This may involve executing
cannam@132 324 // suprocesses.
cannam@132 325
cannam@132 326 void printStackTraceOnCrash();
cannam@132 327 // Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
cannam@132 328 // a stack trace. You should call this as early as possible on program startup. Programs using
cannam@132 329 // KJ_MAIN get this automatically.
cannam@132 330
cannam@132 331 kj::StringPtr trimSourceFilename(kj::StringPtr filename);
cannam@132 332 // Given a source code file name, trim off noisy prefixes like "src/" or
cannam@132 333 // "/ekam-provider/canonical/".
cannam@132 334
cannam@132 335 } // namespace kj
cannam@132 336
cannam@132 337 #endif // KJ_EXCEPTION_H_