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
33namespace kj {
34
35class ExceptionImpl;
36template <typename T> class Function;
37
38class 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
44public:
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
124private:
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
137StringPtr KJ_STRINGIFY(Exception::Type type);
138String KJ_STRINGIFY(const Exception& e);
139
140// =======================================================================================
141
142enum 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
154StringPtr KJ_STRINGIFY(LogSeverity severity);
155
156class 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
169public:
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
225protected:
226 ExceptionCallback& next;
227
228private:
229 ExceptionCallback(ExceptionCallback& next);
230
231 class RootExceptionCallback;
232 friend ExceptionCallback& getExceptionCallback();
233
234 friend class Thread;
235};
236
237ExceptionCallback& getExceptionCallback();
238// Returns the current exception callback.
239
240KJ_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
244KJ_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
250namespace _ { class Runnable; }
251
252template <typename Func>
253Maybe<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
261class 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
271public:
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
284private:
285 uint uncaughtCount;
286
287 void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
288};
289
290namespace _ { // private
291
292class Runnable {
293public:
294 virtual void run() = 0;
295};
296
297template <typename Func>
298class RunnableImpl: public Runnable {
299public:
300 RunnableImpl(Func&& func): func(kj::mv(func)) {}
301 void run() override {
302 func();
303 }
304private:
305 Func func;
306};
307
308Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
309
310} // namespace _ (private)
311
312template <typename Func>
313Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
314 _::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
315 return _::runCatchingExceptions(runnable);
316}
317
318template <typename Func>
319void 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
340KJ_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
353String 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
357String stringifyStackTraceAddresses(ArrayPtr<void* const> trace);
358StringPtr 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
366String getStackTrace();
367// Get a stack trace right now and stringify it. Useful for debugging.
368
369void 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
374kj::StringPtr trimSourceFilename(kj::StringPtr filename);
375// Given a source code file name, trim off noisy prefixes like "src/" or
376// "/ekam-provider/canonical/".
377
378kj::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