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

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 17:55:14 -0400
parents
children
rev   line source
jpayne@69 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
jpayne@69 2 // Licensed under the MIT License:
jpayne@69 3 //
jpayne@69 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
jpayne@69 5 // of this software and associated documentation files (the "Software"), to deal
jpayne@69 6 // in the Software without restriction, including without limitation the rights
jpayne@69 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
jpayne@69 8 // copies of the Software, and to permit persons to whom the Software is
jpayne@69 9 // furnished to do so, subject to the following conditions:
jpayne@69 10 //
jpayne@69 11 // The above copyright notice and this permission notice shall be included in
jpayne@69 12 // all copies or substantial portions of the Software.
jpayne@69 13 //
jpayne@69 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
jpayne@69 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
jpayne@69 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
jpayne@69 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
jpayne@69 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jpayne@69 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
jpayne@69 20 // THE SOFTWARE.
jpayne@69 21
jpayne@69 22 // This file declares convenient macros for debug logging and error handling. The macros make
jpayne@69 23 // it excessively easy to extract useful context information from code. Example:
jpayne@69 24 //
jpayne@69 25 // KJ_ASSERT(a == b, a, b, "a and b must be the same.");
jpayne@69 26 //
jpayne@69 27 // On failure, this will throw an exception whose description looks like:
jpayne@69 28 //
jpayne@69 29 // myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same.
jpayne@69 30 //
jpayne@69 31 // As you can see, all arguments after the first provide additional context.
jpayne@69 32 //
jpayne@69 33 // The macros available are:
jpayne@69 34 //
jpayne@69 35 // * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can
jpayne@69 36 // intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`,
jpayne@69 37 // `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the
jpayne@69 38 // user should be able to pass a flag like `--verbose` to enable them. Other log levels are
jpayne@69 39 // enabled by default. Log messages -- like exceptions -- can be intercepted by registering an
jpayne@69 40 // ExceptionCallback.
jpayne@69 41 //
jpayne@69 42 // * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while
jpayne@69 43 // debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing
jpayne@69 44 // code. It is suggested that you set up a pre-commit hook that checks for this.
jpayne@69 45 //
jpayne@69 46 // * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if
jpayne@69 47 // exceptions are disabled. This macro should be used to check for bugs in the surrounding code
jpayne@69 48 // and its dependencies, but NOT to check for invalid input. The macro may be followed by a
jpayne@69 49 // brace-delimited code block; if so, the block will be executed in the case where the assertion
jpayne@69 50 // fails, before throwing the exception. If control jumps out of the block (e.g. with "break",
jpayne@69 51 // "return", or "goto"), then the error is considered "recoverable" -- in this case, if
jpayne@69 52 // exceptions are disabled, execution will continue normally rather than aborting (but if
jpayne@69 53 // exceptions are enabled, an exception will still be thrown on exiting the block). A "break"
jpayne@69 54 // statement in particular will jump to the code immediately after the block (it does not break
jpayne@69 55 // any surrounding loop or switch). Example:
jpayne@69 56 //
jpayne@69 57 // KJ_ASSERT(value >= 0, "Value cannot be negative.", value) {
jpayne@69 58 // // Assertion failed. Set value to zero to "recover".
jpayne@69 59 // value = 0;
jpayne@69 60 // // Don't abort if exceptions are disabled. Continue normally.
jpayne@69 61 // // (Still throw an exception if they are enabled, though.)
jpayne@69 62 // break;
jpayne@69 63 // }
jpayne@69 64 // // When exceptions are disabled, we'll get here even if the assertion fails.
jpayne@69 65 // // Otherwise, we get here only if the assertion passes.
jpayne@69 66 //
jpayne@69 67 // * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to
jpayne@69 68 // validate parameters passed from a caller. A failure indicates that the caller is buggy.
jpayne@69 69 //
jpayne@69 70 // * `KJ_ASSUME(condition, ...)`: Like `KJ_ASSERT`, but in release mode (if KJ_DEBUG is not
jpayne@69 71 // defined; see below) instead warrants to the compiler that the condition can be assumed to
jpayne@69 72 // hold, allowing it to optimize accordingly. This can result in undefined behavior, so use
jpayne@69 73 // this macro *only* if you can prove to your satisfaction that the condition is guaranteed by
jpayne@69 74 // surrounding code, and if the condition failing to hold would in any case result in undefined
jpayne@69 75 // behavior in its dependencies.
jpayne@69 76 //
jpayne@69 77 // * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result
jpayne@69 78 // is considered an error, with error code reported via `errno`. EINTR is handled by retrying.
jpayne@69 79 // Other errors are handled by throwing an exception. If you need to examine the return code,
jpayne@69 80 // assign it to a variable like so:
jpayne@69 81 //
jpayne@69 82 // int fd;
jpayne@69 83 // KJ_SYSCALL(fd = open(filename, O_RDONLY), filename);
jpayne@69 84 //
jpayne@69 85 // `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`.
jpayne@69 86 //
jpayne@69 87 // * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on
jpayne@69 88 // EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it
jpayne@69 89 // indicates an error; in this case, it can assume the error was EAGAIN because any other error
jpayne@69 90 // would have caused an exception to be thrown.
jpayne@69 91 //
jpayne@69 92 // * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown
jpayne@69 93 // from within the current scope. That is, until control exits the block in which KJ_CONTEXT()
jpayne@69 94 // is used, if any exception is generated, it will contain the given information in its context
jpayne@69 95 // chain. This is helpful because it can otherwise be very difficult to come up with error
jpayne@69 96 // messages that make sense within low-level helper code. Note that the parameters to
jpayne@69 97 // KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables
jpayne@69 98 // used must remain valid until the end of the scope.
jpayne@69 99 //
jpayne@69 100 // Notes:
jpayne@69 101 // * Do not write expressions with side-effects in the message content part of the macro, as the
jpayne@69 102 // message will not necessarily be evaluated.
jpayne@69 103 // * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report
jpayne@69 104 // failures that already happened. For the macros that check a boolean condition, `FAIL_FOO`
jpayne@69 105 // omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and
jpayne@69 106 // `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters.
jpayne@69 107 // The string should be the name of the failed system call.
jpayne@69 108 // * For every macro `FOO` above except `ASSUME`, there is a `DFOO` version (or
jpayne@69 109 // `RECOVERABLE_DFOO`) which is only executed in debug mode, i.e. when KJ_DEBUG is defined.
jpayne@69 110 // KJ_DEBUG is defined automatically by common.h when compiling without optimization (unless
jpayne@69 111 // NDEBUG is defined), but you can also define it explicitly (e.g. -DKJ_DEBUG). Generally,
jpayne@69 112 // production builds should NOT use KJ_DEBUG as it may enable expensive checks that are unlikely
jpayne@69 113 // to fail.
jpayne@69 114
jpayne@69 115 #pragma once
jpayne@69 116
jpayne@69 117 #include "string.h"
jpayne@69 118 #include "exception.h"
jpayne@69 119 #include "windows-sanity.h" // work-around macro conflict with `ERROR`
jpayne@69 120
jpayne@69 121 KJ_BEGIN_HEADER
jpayne@69 122
jpayne@69 123 namespace kj {
jpayne@69 124
jpayne@69 125 #if KJ_MSVC_TRADITIONAL_CPP
jpayne@69 126 // MSVC does __VA_ARGS__ differently from GCC:
jpayne@69 127 // - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
jpayne@69 128 // you to request this behavior with "##__VA_ARGS__".
jpayne@69 129 // - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
jpayne@69 130 // *single* argument rather than an argument list. This can be worked around by wrapping the
jpayne@69 131 // outer macro call in KJ_EXPAND(), which apparently forces __VA_ARGS__ to be expanded before
jpayne@69 132 // the macro is evaluated. I don't understand the C preprocessor.
jpayne@69 133 // - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
jpayne@69 134 // empty, rather than expanding to an empty string literal. We can work around by concatenating
jpayne@69 135 // with an empty string literal.
jpayne@69 136
jpayne@69 137 #define KJ_EXPAND(X) X
jpayne@69 138
jpayne@69 139 #define KJ_LOG(severity, ...) \
jpayne@69 140 for (bool _kj_shouldLog = ::kj::_::Debug::shouldLog(::kj::LogSeverity::severity); \
jpayne@69 141 _kj_shouldLog; _kj_shouldLog = false) \
jpayne@69 142 ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
jpayne@69 143 "" #__VA_ARGS__, __VA_ARGS__)
jpayne@69 144
jpayne@69 145 #define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
jpayne@69 146
jpayne@69 147 #define KJ_REQUIRE(cond, ...) \
jpayne@69 148 if (auto _kjCondition = ::kj::_::MAGIC_ASSERT << cond) {} else \
jpayne@69 149 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 150 #cond, "_kjCondition," #__VA_ARGS__, _kjCondition, __VA_ARGS__);; f.fatal())
jpayne@69 151
jpayne@69 152 #define KJ_FAIL_REQUIRE(...) \
jpayne@69 153 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 154 nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 155
jpayne@69 156 #define KJ_SYSCALL(call, ...) \
jpayne@69 157 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
jpayne@69 158 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 159 _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 160
jpayne@69 161 #define KJ_NONBLOCKING_SYSCALL(call, ...) \
jpayne@69 162 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
jpayne@69 163 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 164 _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 165
jpayne@69 166 #define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
jpayne@69 167 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 168 errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 169
jpayne@69 170 #if _WIN32 || __CYGWIN__
jpayne@69 171
jpayne@69 172 #define KJ_WIN32(call, ...) \
jpayne@69 173 if (auto _kjWin32Result = ::kj::_::Debug::win32Call(call)) {} else \
jpayne@69 174 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 175 _kjWin32Result, #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 176
jpayne@69 177 #define KJ_WINSOCK(call, ...) \
jpayne@69 178 if (auto _kjWin32Result = ::kj::_::Debug::winsockCall(call)) {} else \
jpayne@69 179 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 180 _kjWin32Result, #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 181
jpayne@69 182 #define KJ_FAIL_WIN32(code, errorNumber, ...) \
jpayne@69 183 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 184 ::kj::_::Debug::Win32Result(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 185
jpayne@69 186 #endif
jpayne@69 187
jpayne@69 188 #define KJ_UNIMPLEMENTED(...) \
jpayne@69 189 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
jpayne@69 190 nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
jpayne@69 191
jpayne@69 192 // TODO(msvc): MSVC mis-deduces `ContextImpl<decltype(func)>` as `ContextImpl<int>` in some edge
jpayne@69 193 // cases, such as inside nested lambdas inside member functions. Wrapping the type in
jpayne@69 194 // `decltype(instance<...>())` helps it deduce the context function's type correctly.
jpayne@69 195 #define KJ_CONTEXT(...) \
jpayne@69 196 auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
jpayne@69 197 return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
jpayne@69 198 ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \
jpayne@69 199 }; \
jpayne@69 200 decltype(::kj::instance<::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))>>()) \
jpayne@69 201 KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
jpayne@69 202
jpayne@69 203 #define KJ_REQUIRE_NONNULL(value, ...) \
jpayne@69 204 (*[&] { \
jpayne@69 205 auto _kj_result = ::kj::_::readMaybe(value); \
jpayne@69 206 if (KJ_UNLIKELY(!_kj_result)) { \
jpayne@69 207 ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 208 #value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
jpayne@69 209 } \
jpayne@69 210 return _kj_result; \
jpayne@69 211 }())
jpayne@69 212
jpayne@69 213 #define KJ_EXCEPTION(type, ...) \
jpayne@69 214 ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
jpayne@69 215 ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__))
jpayne@69 216
jpayne@69 217 #else
jpayne@69 218
jpayne@69 219 #define KJ_LOG(severity, ...) \
jpayne@69 220 for (bool _kj_shouldLog = ::kj::_::Debug::shouldLog(::kj::LogSeverity::severity); \
jpayne@69 221 _kj_shouldLog; _kj_shouldLog = false) \
jpayne@69 222 ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
jpayne@69 223 #__VA_ARGS__, ##__VA_ARGS__)
jpayne@69 224
jpayne@69 225 #define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__)
jpayne@69 226
jpayne@69 227 #define KJ_REQUIRE(cond, ...) \
jpayne@69 228 if (auto _kjCondition = ::kj::_::MAGIC_ASSERT << cond) {} else \
jpayne@69 229 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 230 #cond, "_kjCondition," #__VA_ARGS__, _kjCondition, ##__VA_ARGS__);; f.fatal())
jpayne@69 231
jpayne@69 232 #define KJ_FAIL_REQUIRE(...) \
jpayne@69 233 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 234 nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 235
jpayne@69 236 #define KJ_SYSCALL(call, ...) \
jpayne@69 237 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
jpayne@69 238 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 239 _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 240
jpayne@69 241 #define KJ_NONBLOCKING_SYSCALL(call, ...) \
jpayne@69 242 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
jpayne@69 243 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 244 _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 245
jpayne@69 246 #define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
jpayne@69 247 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 248 errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 249
jpayne@69 250 #if _WIN32 || __CYGWIN__
jpayne@69 251
jpayne@69 252 #define KJ_WIN32(call, ...) \
jpayne@69 253 if (auto _kjWin32Result = ::kj::_::Debug::win32Call(call)) {} else \
jpayne@69 254 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 255 _kjWin32Result, #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 256 // Invoke a Win32 syscall that returns either BOOL or HANDLE, and throw an exception if it fails.
jpayne@69 257
jpayne@69 258 #define KJ_WINSOCK(call, ...) \
jpayne@69 259 if (auto _kjWin32Result = ::kj::_::Debug::winsockCall(call)) {} else \
jpayne@69 260 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 261 _kjWin32Result, #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 262 // Like KJ_WIN32 but for winsock calls which return `int` with SOCKET_ERROR indicating failure.
jpayne@69 263 //
jpayne@69 264 // Unfortunately, it's impossible to distinguish these from BOOL-returning Win32 calls by type,
jpayne@69 265 // since BOOL is in fact an alias for `int`. :(
jpayne@69 266
jpayne@69 267 #define KJ_FAIL_WIN32(code, errorNumber, ...) \
jpayne@69 268 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
jpayne@69 269 ::kj::_::Debug::Win32Result(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 270
jpayne@69 271 #endif
jpayne@69 272
jpayne@69 273 #define KJ_UNIMPLEMENTED(...) \
jpayne@69 274 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
jpayne@69 275 nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
jpayne@69 276
jpayne@69 277 #define KJ_CONTEXT(...) \
jpayne@69 278 auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
jpayne@69 279 return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
jpayne@69 280 ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \
jpayne@69 281 }; \
jpayne@69 282 ::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
jpayne@69 283 KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
jpayne@69 284
jpayne@69 285 #if _MSC_VER && !defined(__clang__)
jpayne@69 286
jpayne@69 287 #define KJ_REQUIRE_NONNULL(value, ...) \
jpayne@69 288 (*([&] { \
jpayne@69 289 auto _kj_result = ::kj::_::readMaybe(value); \
jpayne@69 290 if (KJ_UNLIKELY(!_kj_result)) { \
jpayne@69 291 ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 292 #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
jpayne@69 293 } \
jpayne@69 294 return _kj_result; \
jpayne@69 295 }()))
jpayne@69 296
jpayne@69 297 #else
jpayne@69 298
jpayne@69 299 #define KJ_REQUIRE_NONNULL(value, ...) \
jpayne@69 300 (*({ \
jpayne@69 301 auto _kj_result = ::kj::_::readMaybe(value); \
jpayne@69 302 if (KJ_UNLIKELY(!_kj_result)) { \
jpayne@69 303 ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
jpayne@69 304 #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
jpayne@69 305 } \
jpayne@69 306 kj::mv(_kj_result); \
jpayne@69 307 }))
jpayne@69 308
jpayne@69 309 #endif
jpayne@69 310
jpayne@69 311 #define KJ_EXCEPTION(type, ...) \
jpayne@69 312 ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
jpayne@69 313 ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__))
jpayne@69 314
jpayne@69 315 #endif
jpayne@69 316
jpayne@69 317 #define KJ_SYSCALL_HANDLE_ERRORS(call) \
jpayne@69 318 if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \
jpayne@69 319 switch (int error KJ_UNUSED = _kjSyscallError)
jpayne@69 320 // Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the
jpayne@69 321 // error. Additionally, the int value `error` is defined within the block. So you can do:
jpayne@69 322 //
jpayne@69 323 // KJ_SYSCALL_HANDLE_ERRORS(foo()) {
jpayne@69 324 // case ENOENT:
jpayne@69 325 // handleNoSuchFile();
jpayne@69 326 // break;
jpayne@69 327 // case EEXIST:
jpayne@69 328 // handleExists();
jpayne@69 329 // break;
jpayne@69 330 // default:
jpayne@69 331 // KJ_FAIL_SYSCALL("foo()", error);
jpayne@69 332 // } else {
jpayne@69 333 // handleSuccessCase();
jpayne@69 334 // }
jpayne@69 335
jpayne@69 336 #if _WIN32 || __CYGWIN__
jpayne@69 337
jpayne@69 338 #define KJ_WIN32_HANDLE_ERRORS(call) \
jpayne@69 339 if (uint _kjWin32Error = ::kj::_::Debug::win32Call(call).number) \
jpayne@69 340 switch (uint error KJ_UNUSED = _kjWin32Error)
jpayne@69 341 // Like KJ_WIN32, but doesn't throw. Instead, the block after the macro is a switch block on the
jpayne@69 342 // error. Additionally, the int value `error` is defined within the block. So you can do:
jpayne@69 343 //
jpayne@69 344 // KJ_SYSCALL_HANDLE_ERRORS(foo()) {
jpayne@69 345 // case ERROR_FILE_NOT_FOUND:
jpayne@69 346 // handleNoSuchFile();
jpayne@69 347 // break;
jpayne@69 348 // case ERROR_FILE_EXISTS:
jpayne@69 349 // handleExists();
jpayne@69 350 // break;
jpayne@69 351 // default:
jpayne@69 352 // KJ_FAIL_WIN32("foo()", error);
jpayne@69 353 // } else {
jpayne@69 354 // handleSuccessCase();
jpayne@69 355 // }
jpayne@69 356
jpayne@69 357 #endif
jpayne@69 358
jpayne@69 359 #define KJ_ASSERT KJ_REQUIRE
jpayne@69 360 #define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE
jpayne@69 361 #define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL
jpayne@69 362 // Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code.
jpayne@69 363 // That is, if the assert ever fails, it indicates that the immediate surrounding code is broken.
jpayne@69 364
jpayne@69 365 #ifdef KJ_DEBUG
jpayne@69 366 #define KJ_DLOG KJ_LOG
jpayne@69 367 #define KJ_DASSERT KJ_ASSERT
jpayne@69 368 #define KJ_DREQUIRE KJ_REQUIRE
jpayne@69 369 #define KJ_ASSUME KJ_ASSERT
jpayne@69 370 #else
jpayne@69 371 #define KJ_DLOG(...) do {} while (false)
jpayne@69 372 #define KJ_DASSERT(...) do {} while (false)
jpayne@69 373 #define KJ_DREQUIRE(...) do {} while (false)
jpayne@69 374 #if defined(__GNUC__)
jpayne@69 375 #define KJ_ASSUME(cond, ...) do { if (cond) {} else __builtin_unreachable(); } while (false)
jpayne@69 376 #elif defined(__clang__)
jpayne@69 377 #define KJ_ASSUME(cond, ...) __builtin_assume(cond)
jpayne@69 378 #elif defined(_MSC_VER)
jpayne@69 379 #define KJ_ASSUME(cond, ...) __assume(cond)
jpayne@69 380 #else
jpayne@69 381 #define KJ_ASSUME(...) do {} while (false)
jpayne@69 382 #endif
jpayne@69 383
jpayne@69 384 #endif
jpayne@69 385
jpayne@69 386 namespace _ { // private
jpayne@69 387
jpayne@69 388 class Debug {
jpayne@69 389 public:
jpayne@69 390 Debug() = delete;
jpayne@69 391
jpayne@69 392 typedef LogSeverity Severity; // backwards-compatibility
jpayne@69 393
jpayne@69 394 #if _WIN32 || __CYGWIN__
jpayne@69 395 struct Win32Result {
jpayne@69 396 uint number;
jpayne@69 397 inline explicit Win32Result(uint number): number(number) {}
jpayne@69 398 operator bool() const { return number == 0; }
jpayne@69 399 };
jpayne@69 400 #endif
jpayne@69 401
jpayne@69 402 static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; }
jpayne@69 403 // Returns whether messages of the given severity should be logged.
jpayne@69 404
jpayne@69 405 static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; }
jpayne@69 406 // Set the minimum message severity which will be logged.
jpayne@69 407 //
jpayne@69 408 // TODO(someday): Expose publicly.
jpayne@69 409
jpayne@69 410 template <typename... Params>
jpayne@69 411 static void log(const char* file, int line, LogSeverity severity, const char* macroArgs,
jpayne@69 412 Params&&... params);
jpayne@69 413
jpayne@69 414 class Fault {
jpayne@69 415 public:
jpayne@69 416 template <typename Code, typename... Params>
jpayne@69 417 Fault(const char* file, int line, Code code,
jpayne@69 418 const char* condition, const char* macroArgs, Params&&... params);
jpayne@69 419 Fault(const char* file, int line, Exception::Type type,
jpayne@69 420 const char* condition, const char* macroArgs);
jpayne@69 421 Fault(const char* file, int line, int osErrorNumber,
jpayne@69 422 const char* condition, const char* macroArgs);
jpayne@69 423 #if _WIN32 || __CYGWIN__
jpayne@69 424 Fault(const char* file, int line, Win32Result osErrorNumber,
jpayne@69 425 const char* condition, const char* macroArgs);
jpayne@69 426 #endif
jpayne@69 427 ~Fault() noexcept(false);
jpayne@69 428
jpayne@69 429 KJ_NOINLINE KJ_NORETURN(void fatal());
jpayne@69 430 // Throw the exception.
jpayne@69 431
jpayne@69 432 private:
jpayne@69 433 void init(const char* file, int line, Exception::Type type,
jpayne@69 434 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
jpayne@69 435 void init(const char* file, int line, int osErrorNumber,
jpayne@69 436 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
jpayne@69 437 #if _WIN32 || __CYGWIN__
jpayne@69 438 void init(const char* file, int line, Win32Result osErrorNumber,
jpayne@69 439 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
jpayne@69 440 #endif
jpayne@69 441
jpayne@69 442 Exception* exception;
jpayne@69 443 };
jpayne@69 444
jpayne@69 445 class SyscallResult {
jpayne@69 446 public:
jpayne@69 447 inline SyscallResult(int errorNumber): errorNumber(errorNumber) {}
jpayne@69 448 inline operator void*() { return errorNumber == 0 ? this : nullptr; }
jpayne@69 449 inline int getErrorNumber() { return errorNumber; }
jpayne@69 450
jpayne@69 451 private:
jpayne@69 452 int errorNumber;
jpayne@69 453 };
jpayne@69 454
jpayne@69 455 template <typename Call>
jpayne@69 456 static SyscallResult syscall(Call&& call, bool nonblocking);
jpayne@69 457 template <typename Call>
jpayne@69 458 static int syscallError(Call&& call, bool nonblocking);
jpayne@69 459
jpayne@69 460 #if _WIN32 || __CYGWIN__
jpayne@69 461 static Win32Result win32Call(int boolean);
jpayne@69 462 static Win32Result win32Call(void* handle);
jpayne@69 463 static Win32Result winsockCall(int result);
jpayne@69 464 static uint getWin32ErrorCode();
jpayne@69 465 #endif
jpayne@69 466
jpayne@69 467 class Context: public ExceptionCallback {
jpayne@69 468 public:
jpayne@69 469 Context();
jpayne@69 470 KJ_DISALLOW_COPY_AND_MOVE(Context);
jpayne@69 471 virtual ~Context() noexcept(false);
jpayne@69 472
jpayne@69 473 struct Value {
jpayne@69 474 const char* file;
jpayne@69 475 int line;
jpayne@69 476 String description;
jpayne@69 477
jpayne@69 478 inline Value(const char* file, int line, String&& description)
jpayne@69 479 : file(file), line(line), description(mv(description)) {}
jpayne@69 480 };
jpayne@69 481
jpayne@69 482 virtual Value evaluate() = 0;
jpayne@69 483
jpayne@69 484 virtual void onRecoverableException(Exception&& exception) override;
jpayne@69 485 virtual void onFatalException(Exception&& exception) override;
jpayne@69 486 virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
jpayne@69 487 String&& text) override;
jpayne@69 488
jpayne@69 489 private:
jpayne@69 490 bool logged;
jpayne@69 491 Maybe<Value> value;
jpayne@69 492
jpayne@69 493 Value ensureInitialized();
jpayne@69 494 };
jpayne@69 495
jpayne@69 496 template <typename Func>
jpayne@69 497 class ContextImpl: public Context {
jpayne@69 498 public:
jpayne@69 499 inline ContextImpl(Func& func): func(func) {}
jpayne@69 500 KJ_DISALLOW_COPY_AND_MOVE(ContextImpl);
jpayne@69 501
jpayne@69 502 Value evaluate() override {
jpayne@69 503 return func();
jpayne@69 504 }
jpayne@69 505 private:
jpayne@69 506 Func& func;
jpayne@69 507 };
jpayne@69 508
jpayne@69 509 template <typename... Params>
jpayne@69 510 static String makeDescription(const char* macroArgs, Params&&... params);
jpayne@69 511
jpayne@69 512 private:
jpayne@69 513 static LogSeverity minSeverity;
jpayne@69 514
jpayne@69 515 static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs,
jpayne@69 516 ArrayPtr<String> argValues);
jpayne@69 517 static String makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues);
jpayne@69 518
jpayne@69 519 static int getOsErrorNumber(bool nonblocking);
jpayne@69 520 // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
jpayne@69 521 };
jpayne@69 522
jpayne@69 523 template <typename... Params>
jpayne@69 524 void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs,
jpayne@69 525 Params&&... params) {
jpayne@69 526 String argValues[sizeof...(Params)] = {str(params)...};
jpayne@69 527 logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
jpayne@69 528 }
jpayne@69 529
jpayne@69 530 template <>
jpayne@69 531 inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) {
jpayne@69 532 logInternal(file, line, severity, macroArgs, nullptr);
jpayne@69 533 }
jpayne@69 534
jpayne@69 535 template <typename Code, typename... Params>
jpayne@69 536 Debug::Fault::Fault(const char* file, int line, Code code,
jpayne@69 537 const char* condition, const char* macroArgs, Params&&... params)
jpayne@69 538 : exception(nullptr) {
jpayne@69 539 String argValues[sizeof...(Params)] = {str(params)...};
jpayne@69 540 init(file, line, code, condition, macroArgs,
jpayne@69 541 arrayPtr(argValues, sizeof...(Params)));
jpayne@69 542 }
jpayne@69 543
jpayne@69 544 inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber,
jpayne@69 545 const char* condition, const char* macroArgs)
jpayne@69 546 : exception(nullptr) {
jpayne@69 547 init(file, line, osErrorNumber, condition, macroArgs, nullptr);
jpayne@69 548 }
jpayne@69 549
jpayne@69 550 inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type,
jpayne@69 551 const char* condition, const char* macroArgs)
jpayne@69 552 : exception(nullptr) {
jpayne@69 553 init(file, line, type, condition, macroArgs, nullptr);
jpayne@69 554 }
jpayne@69 555
jpayne@69 556 #if _WIN32 || __CYGWIN__
jpayne@69 557 inline Debug::Fault::Fault(const char* file, int line, Win32Result osErrorNumber,
jpayne@69 558 const char* condition, const char* macroArgs)
jpayne@69 559 : exception(nullptr) {
jpayne@69 560 init(file, line, osErrorNumber, condition, macroArgs, nullptr);
jpayne@69 561 }
jpayne@69 562
jpayne@69 563 inline Debug::Win32Result Debug::win32Call(int boolean) {
jpayne@69 564 return boolean ? Win32Result(0) : Win32Result(getWin32ErrorCode());
jpayne@69 565 }
jpayne@69 566 inline Debug::Win32Result Debug::win32Call(void* handle) {
jpayne@69 567 // Assume null and INVALID_HANDLE_VALUE mean failure.
jpayne@69 568 return win32Call(handle != nullptr && handle != (void*)-1);
jpayne@69 569 }
jpayne@69 570 inline Debug::Win32Result Debug::winsockCall(int result) {
jpayne@69 571 // Expect a return value of SOCKET_ERROR means failure.
jpayne@69 572 return win32Call(result != -1);
jpayne@69 573 }
jpayne@69 574 #endif
jpayne@69 575
jpayne@69 576 template <typename Call>
jpayne@69 577 Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
jpayne@69 578 while (call() < 0) {
jpayne@69 579 int errorNum = getOsErrorNumber(nonblocking);
jpayne@69 580 // getOsErrorNumber() returns -1 to indicate EINTR.
jpayne@69 581 // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
jpayne@69 582 // non-error.
jpayne@69 583 if (errorNum != -1) {
jpayne@69 584 return SyscallResult(errorNum);
jpayne@69 585 }
jpayne@69 586 }
jpayne@69 587 return SyscallResult(0);
jpayne@69 588 }
jpayne@69 589
jpayne@69 590 template <typename Call>
jpayne@69 591 int Debug::syscallError(Call&& call, bool nonblocking) {
jpayne@69 592 while (call() < 0) {
jpayne@69 593 int errorNum = getOsErrorNumber(nonblocking);
jpayne@69 594 // getOsErrorNumber() returns -1 to indicate EINTR.
jpayne@69 595 // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
jpayne@69 596 // non-error.
jpayne@69 597 if (errorNum != -1) {
jpayne@69 598 return errorNum;
jpayne@69 599 }
jpayne@69 600 }
jpayne@69 601 return 0;
jpayne@69 602 }
jpayne@69 603
jpayne@69 604 template <typename... Params>
jpayne@69 605 String Debug::makeDescription(const char* macroArgs, Params&&... params) {
jpayne@69 606 String argValues[sizeof...(Params)] = {str(params)...};
jpayne@69 607 return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
jpayne@69 608 }
jpayne@69 609
jpayne@69 610 template <>
jpayne@69 611 inline String Debug::makeDescription<>(const char* macroArgs) {
jpayne@69 612 return makeDescriptionInternal(macroArgs, nullptr);
jpayne@69 613 }
jpayne@69 614
jpayne@69 615 // =======================================================================================
jpayne@69 616 // Magic Asserts!
jpayne@69 617 //
jpayne@69 618 // When KJ_ASSERT(foo == bar) fails, `foo` and `bar`'s actual values will be stringified in the
jpayne@69 619 // error message. How does it work? We use template magic and operator precedence. The assertion
jpayne@69 620 // actually evaluates something like this:
jpayne@69 621 //
jpayne@69 622 // if (auto _kjCondition = kj::_::MAGIC_ASSERT << foo == bar)
jpayne@69 623 //
jpayne@69 624 // `<<` has operator precedence slightly above `==`, so `kj::_::MAGIC_ASSERT << foo` gets evaluated
jpayne@69 625 // first. This wraps `foo` in a little wrapper that captures the comparison operators and keeps
jpayne@69 626 // enough information around to be able to stringify the left and right sides of the comparison
jpayne@69 627 // independently. As always, the stringification only actually occurs if the assert fails.
jpayne@69 628 //
jpayne@69 629 // You might ask why we use operator `<<` and not e.g. operator `<=`, since operators of the same
jpayne@69 630 // precedence are evaluated left-to-right. The answer is that some compilers trigger all sorts of
jpayne@69 631 // warnings when you seem to be using a comparison as the input to another comparison. The
jpayne@69 632 // particular warning GCC produces is its general "-Wparentheses" warning which is broadly useful,
jpayne@69 633 // so we don't want to disable it. `<<` also produces some warnings, but only on Clang and the
jpayne@69 634 // specific warning is one we're comfortable disabling (see below). This does mean that we have to
jpayne@69 635 // explicitly overload `operator<<` ourselves to make sure using it in an assert still works.
jpayne@69 636 //
jpayne@69 637 // You might also ask, if we're using operator `<<` anyway, why not start it from the right, in
jpayne@69 638 // which case it would bind after computing any `<<` operators that were actually in the user's
jpayne@69 639 // code? I tried this, but it resulted in a somewhat broader warning from clang that I felt worse
jpayne@69 640 // about disabling (a warning about `<<` precedence not applying specifically to overloads) and
jpayne@69 641 // also created ambiguous overload errors in the KJ units code.
jpayne@69 642
jpayne@69 643 #if __clang__
jpayne@69 644 // We intentionally overload operator << for the specific purpose of evaluating it before
jpayne@69 645 // evaluating comparison expressions, so stop Clang from warning about it. Unfortunately this means
jpayne@69 646 // eliminating a warning that would otherwise be useful for people using iostreams... sorry.
jpayne@69 647 #pragma GCC diagnostic ignored "-Woverloaded-shift-op-parentheses"
jpayne@69 648 #endif
jpayne@69 649
jpayne@69 650 template <typename T>
jpayne@69 651 struct DebugExpression;
jpayne@69 652
jpayne@69 653 template <typename T, typename = decltype(toCharSequence(instance<T&>()))>
jpayne@69 654 inline auto tryToCharSequence(T* value) { return kj::toCharSequence(*value); }
jpayne@69 655 inline StringPtr tryToCharSequence(...) { return "(can't stringify)"_kj; }
jpayne@69 656 // SFINAE to stringify a value if and only if it can be stringified.
jpayne@69 657
jpayne@69 658 template <typename Left, typename Right>
jpayne@69 659 struct DebugComparison {
jpayne@69 660 Left left;
jpayne@69 661 Right right;
jpayne@69 662 StringPtr op;
jpayne@69 663 bool result;
jpayne@69 664
jpayne@69 665 inline operator bool() const { return KJ_LIKELY(result); }
jpayne@69 666
jpayne@69 667 template <typename T> inline void operator&(T&& other) = delete;
jpayne@69 668 template <typename T> inline void operator^(T&& other) = delete;
jpayne@69 669 template <typename T> inline void operator|(T&& other) = delete;
jpayne@69 670 };
jpayne@69 671
jpayne@69 672 template <typename Left, typename Right>
jpayne@69 673 String KJ_STRINGIFY(DebugComparison<Left, Right>& cmp) {
jpayne@69 674 return _::concat(tryToCharSequence(&cmp.left), cmp.op, tryToCharSequence(&cmp.right));
jpayne@69 675 }
jpayne@69 676
jpayne@69 677 template <typename T>
jpayne@69 678 struct DebugExpression {
jpayne@69 679 DebugExpression(T&& value): value(kj::fwd<T>(value)) {}
jpayne@69 680 T value;
jpayne@69 681
jpayne@69 682 // Handle comparison operations by constructing a DebugComparison value.
jpayne@69 683 #define DEFINE_OPERATOR(OP) \
jpayne@69 684 template <typename U> \
jpayne@69 685 DebugComparison<T, U> operator OP(U&& other) { \
jpayne@69 686 bool result = value OP other; \
jpayne@69 687 return { kj::fwd<T>(value), kj::fwd<U>(other), " " #OP " "_kj, result }; \
jpayne@69 688 }
jpayne@69 689 DEFINE_OPERATOR(==);
jpayne@69 690 DEFINE_OPERATOR(!=);
jpayne@69 691 DEFINE_OPERATOR(<=);
jpayne@69 692 DEFINE_OPERATOR(>=);
jpayne@69 693 DEFINE_OPERATOR(< );
jpayne@69 694 DEFINE_OPERATOR(> );
jpayne@69 695 #undef DEFINE_OPERATOR
jpayne@69 696
jpayne@69 697 // Handle binary operators that have equal or lower precedence than comparisons by performing
jpayne@69 698 // the operation and wrapping the result.
jpayne@69 699 #define DEFINE_OPERATOR(OP) \
jpayne@69 700 template <typename U> inline auto operator OP(U&& other) { \
jpayne@69 701 return DebugExpression<decltype(kj::fwd<T>(value) OP kj::fwd<U>(other))>(\
jpayne@69 702 kj::fwd<T>(value) OP kj::fwd<U>(other)); \
jpayne@69 703 }
jpayne@69 704 DEFINE_OPERATOR(<<);
jpayne@69 705 DEFINE_OPERATOR(>>);
jpayne@69 706 DEFINE_OPERATOR(&);
jpayne@69 707 DEFINE_OPERATOR(^);
jpayne@69 708 DEFINE_OPERATOR(|);
jpayne@69 709 #undef DEFINE_OPERATOR
jpayne@69 710
jpayne@69 711 inline operator bool() {
jpayne@69 712 // No comparison performed, we're just asserting the expression is truthy. This also covers
jpayne@69 713 // the case of the logic operators && and || -- we cannot overload those because doing so would
jpayne@69 714 // break short-circuiting behavior.
jpayne@69 715 return value;
jpayne@69 716 }
jpayne@69 717 };
jpayne@69 718
jpayne@69 719 template <typename T>
jpayne@69 720 StringPtr KJ_STRINGIFY(const DebugExpression<T>& exp) {
jpayne@69 721 // Hack: This will only ever be called in cases where the expression's truthiness was asserted
jpayne@69 722 // directly, and was determined to be falsy.
jpayne@69 723 return "false"_kj;
jpayne@69 724 }
jpayne@69 725
jpayne@69 726 struct DebugExpressionStart {
jpayne@69 727 template <typename T>
jpayne@69 728 DebugExpression<T> operator<<(T&& value) const {
jpayne@69 729 return DebugExpression<T>(kj::fwd<T>(value));
jpayne@69 730 }
jpayne@69 731 };
jpayne@69 732 static constexpr DebugExpressionStart MAGIC_ASSERT;
jpayne@69 733
jpayne@69 734 } // namespace _ (private)
jpayne@69 735 } // namespace kj
jpayne@69 736
jpayne@69 737 KJ_END_HEADER