comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/exception.h @ 69:33d812a61356

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