Mercurial > repos > rliterman > csp2
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 |