Assertions.h (31846B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Implementations of runtime and static assertion macros for C and C++. */ 8 9 #ifndef mozilla_Assertions_h 10 #define mozilla_Assertions_h 11 12 #if (defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)) && \ 13 !defined(__wasi__) 14 # define MOZ_DUMP_ASSERTION_STACK 15 #endif 16 #if defined(XP_WIN) && (defined(DEBUG) || defined(FUZZING)) 17 # define MOZ_BUFFER_STDERR 18 #endif 19 20 // It appears that this is sometimes compiled without XP_WIN 21 #if defined(_WIN32) 22 # include <process.h> 23 # define MOZ_GET_PID() _getpid() 24 #elif !defined(__wasi__) 25 # include <unistd.h> 26 # define MOZ_GET_PID() getpid() 27 #else 28 // Prevent compiler warning 29 # define MOZ_GET_PID() -1 30 #endif 31 32 #include "mozilla/Attributes.h" 33 #include "mozilla/Fuzzing.h" 34 #include "mozilla/Likely.h" 35 #include "mozilla/MacroArgs.h" 36 #include "mozilla/StaticAnalysisFunctions.h" 37 #include "mozilla/Types.h" 38 #ifdef MOZ_DUMP_ASSERTION_STACK 39 # include "mozilla/StackWalk.h" 40 #endif 41 42 /* 43 * The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter 44 * if present. It is declared here (and defined in Assertions.cpp) to make it 45 * available to all code, even libraries that don't link with the crash reporter 46 * directly. 47 */ 48 MOZ_BEGIN_EXTERN_C 49 extern MFBT_DATA const char* gMozCrashReason; 50 MOZ_END_EXTERN_C 51 52 #if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API) 53 static inline void AnnotateMozCrashReason(const char* reason) { 54 gMozCrashReason = reason; 55 // The following assembly fakes a memory read/write to the compiler, which 56 // prevents the removal of gMozCrashReason store. See bug 1681846 and 1945507. 57 # if defined(__clang__) 58 asm volatile("" : "+r,m"(gMozCrashReason) : : "memory"); 59 # else 60 asm volatile("" : "+m,r"(gMozCrashReason) : : "memory"); 61 # endif 62 } 63 # define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__) 64 #else 65 # define MOZ_CRASH_ANNOTATE(...) \ 66 do { /* nothing */ \ 67 } while (false) 68 #endif 69 70 #include <stddef.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #ifdef _MSC_VER 74 /* 75 * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which 76 * further depends on <windef.h>. We hardcode these few definitions manually 77 * because those headers clutter the global namespace with a significant 78 * number of undesired macros and symbols. 79 */ 80 MOZ_BEGIN_EXTERN_C 81 __declspec(dllimport) int __stdcall TerminateProcess(void* hProcess, 82 unsigned int uExitCode); 83 __declspec(dllimport) void* __stdcall GetCurrentProcess(void); 84 MOZ_END_EXTERN_C 85 #elif defined(__wasi__) 86 /* 87 * On Wasm/WASI platforms, we just call __builtin_trap(). 88 */ 89 #else 90 # include <signal.h> 91 #endif 92 #ifdef ANDROID 93 # include <android/log.h> 94 #endif 95 96 MOZ_BEGIN_EXTERN_C 97 98 #if defined(ANDROID) && defined(MOZ_DUMP_ASSERTION_STACK) 99 [[maybe_unused]] static void MOZ_ReportAssertionFailurePrintFrame( 100 const char* aBuf) { 101 __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", "%s", aBuf); 102 } 103 [[maybe_unused]] static void MOZ_CrashPrintFrame(const char* aBuf) { 104 __android_log_print(ANDROID_LOG_FATAL, "MOZ_Crash", "%s", aBuf); 105 } 106 #endif 107 108 /* 109 * Prints |aStr| as an assertion failure (using aFilename and aLine as the 110 * location of the assertion) to the standard debug-output channel. 111 * 112 * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This 113 * method is primarily for internal use in this header, and only secondarily 114 * for use in implementing release-build assertions. 115 */ 116 117 [[maybe_unused]] static MOZ_COLD MOZ_NEVER_INLINE void 118 MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, 119 int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { 120 MOZ_FUZZING_HANDLE_CRASH_EVENT4("MOZ_ASSERT", aFilename, aLine, aStr); 121 #ifdef ANDROID 122 __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", 123 "[%d] Assertion failure: %s, at %s:%d\n", MOZ_GET_PID(), 124 aStr, aFilename, aLine); 125 # if defined(MOZ_DUMP_ASSERTION_STACK) 126 MozWalkTheStackWithWriter(MOZ_ReportAssertionFailurePrintFrame, CallerPC(), 127 /* aMaxFrames */ 0); 128 # endif 129 #else 130 # if defined(MOZ_BUFFER_STDERR) 131 char msg[1024] = ""; 132 snprintf(msg, sizeof(msg) - 1, "[%d] Assertion failure: %s, at %s:%d\n", 133 MOZ_GET_PID(), aStr, aFilename, aLine); 134 fputs(msg, stderr); 135 # else 136 fprintf(stderr, "[%d] Assertion failure: %s, at %s:%d\n", MOZ_GET_PID(), aStr, 137 aFilename, aLine); 138 # endif 139 # if defined(MOZ_DUMP_ASSERTION_STACK) 140 MozWalkTheStack(stderr, CallerPC(), /* aMaxFrames */ 0); 141 # endif 142 fflush(stderr); 143 #endif 144 } 145 146 [[maybe_unused]] static MOZ_COLD MOZ_NEVER_INLINE void MOZ_ReportCrash( 147 const char* aStr, const char* aFilename, 148 int aLine) MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS { 149 #ifdef ANDROID 150 __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", 151 "[%d] Hit MOZ_CRASH(%s) at %s:%d\n", MOZ_GET_PID(), aStr, 152 aFilename, aLine); 153 # if defined(MOZ_DUMP_ASSERTION_STACK) 154 MozWalkTheStackWithWriter(MOZ_CrashPrintFrame, CallerPC(), 155 /* aMaxFrames */ 0); 156 # endif 157 #else 158 # if defined(MOZ_BUFFER_STDERR) 159 char msg[1024] = ""; 160 snprintf(msg, sizeof(msg) - 1, "[%d] Hit MOZ_CRASH(%s) at %s:%d\n", 161 MOZ_GET_PID(), aStr, aFilename, aLine); 162 fputs(msg, stderr); 163 # else 164 fprintf(stderr, "[%d] Hit MOZ_CRASH(%s) at %s:%d\n", MOZ_GET_PID(), aStr, 165 aFilename, aLine); 166 # endif 167 # if defined(MOZ_DUMP_ASSERTION_STACK) 168 MozWalkTheStack(stderr, CallerPC(), /* aMaxFrames */ 0); 169 # endif 170 fflush(stderr); 171 #endif 172 } 173 174 /* 175 * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that 176 * it is undefined behavior for execution to reach this point. No guarantees 177 * are made about what will happen if this is reached at runtime. Most code 178 * should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra 179 * asserts. 180 */ 181 #define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable() 182 183 /** 184 * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should 185 * call MOZ_CRASH instead. 186 */ 187 #if defined(_MSC_VER) 188 /* 189 * On MSVC use the __debugbreak compiler intrinsic, which produces an inline 190 * (not nested in a system function) breakpoint. This distinctively invokes 191 * Breakpad without requiring system library symbols on all stack-processing 192 * machines, as a nested breakpoint would require. 193 * 194 * We use __LINE__ to prevent the compiler from folding multiple crash sites 195 * together, which would make crash reports hard to understand. 196 * 197 * We use TerminateProcess with the exit code aborting would generate 198 * because we don't want to invoke atexit handlers, destructors, library 199 * unload handlers, and so on when our process might be in a compromised 200 * state. 201 * 202 * We don't use abort() because it'd cause Windows to annoyingly pop up the 203 * process error dialog multiple times. See bug 345118 and bug 426163. 204 * 205 * (Technically these are Windows requirements, not MSVC requirements. But 206 * practically you need MSVC for debugging, and we only ship builds created 207 * by MSVC, so doing it this way reduces complexity.) 208 */ 209 210 [[maybe_unused, noreturn]] static MOZ_COLD MOZ_NEVER_INLINE void MOZ_NoReturn( 211 int aLine) { 212 *((volatile int*)NULL) = aLine; 213 TerminateProcess(GetCurrentProcess(), 3); 214 MOZ_ASSUME_UNREACHABLE_MARKER(); 215 } 216 217 # define MOZ_REALLY_CRASH(line) \ 218 do { \ 219 MOZ_NOMERGE __debugbreak(); \ 220 MOZ_NoReturn(line); \ 221 } while (false) 222 223 #elif __wasi__ 224 225 # define MOZ_REALLY_CRASH(line) __builtin_trap() 226 227 #else 228 229 /* 230 * MOZ_CrashSequence() executes a sequence that causes the process to crash by 231 * writing the line number specified in the `aLine` parameter to the address 232 * provide by `aAddress`. The store is implemented as volatile assembly code to 233 * ensure it's always included in the output and always executed. 234 */ 235 static inline void MOZ_CrashSequence(void* aAddress, intptr_t aLine) { 236 # if defined(__i386__) || defined(__x86_64__) 237 asm volatile( 238 "mov %1, (%0);\n" // Write the line number to the crashing address 239 : // no output registers 240 : "r"(aAddress), "r"(aLine)); 241 # elif defined(__arm__) || defined(__aarch64__) 242 asm volatile( 243 "str %1,[%0];\n" // Write the line number to the crashing address 244 : // no output registers 245 : "r"(aAddress), "r"(aLine)); 246 # elif (defined(__riscv) && (__riscv_xlen == 64)) || defined(__mips64) 247 asm volatile( 248 "sd %1,0(%0);\n" // Write the line number to the crashing address 249 : // no output registers 250 : "r"(aAddress), "r"(aLine)); 251 # elif defined(__sparc__) && defined(__arch64__) 252 asm volatile( 253 "stx %1,[%0];\n" // Write the line number to the crashing address 254 : // no output registers 255 : "r"(aAddress), "r"(aLine)); 256 # elif defined(__loongarch64) 257 asm volatile( 258 "st.d %1,%0,0;\n" // Write the line number to the crashing address 259 : // no output registers 260 : "r"(aAddress), "r"(aLine)); 261 # else 262 # warning \ 263 "Unsupported architecture, replace the code below with assembly suitable to crash the process" 264 asm volatile("" ::: "memory"); 265 *((volatile int*)aAddress) = aLine; /* NOLINT */ 266 # endif 267 } 268 269 /* 270 * MOZ_CRASH_WRITE_ADDR is the address to be used when performing a forced 271 * crash. NULL is preferred however if for some reason NULL cannot be used 272 * this makes choosing another value possible. 273 * 274 * In the case of UBSan certain checks, bounds specifically, cause the compiler 275 * to emit the 'ud2' instruction when storing to 0x0. This causes forced 276 * crashes to manifest as ILL (at an arbitrary address) instead of the expected 277 * SEGV at 0x0. 278 */ 279 # ifdef MOZ_UBSAN 280 # define MOZ_CRASH_WRITE_ADDR ((void*)0x1) 281 # else 282 # define MOZ_CRASH_WRITE_ADDR NULL 283 # endif 284 285 # ifdef __cplusplus 286 # define MOZ_REALLY_CRASH(line) \ 287 do { \ 288 MOZ_CrashSequence(MOZ_CRASH_WRITE_ADDR, line); \ 289 MOZ_NOMERGE ::abort(); \ 290 } while (false) 291 # else 292 # define MOZ_REALLY_CRASH(line) \ 293 do { \ 294 MOZ_CrashSequence(MOZ_CRASH_WRITE_ADDR, line); \ 295 MOZ_NOMERGE abort(); \ 296 } while (false) 297 # endif 298 #endif 299 300 /* 301 * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a 302 * Breakpad-compatible way, in both debug and release builds. 303 * 304 * MOZ_CRASH is a good solution for "handling" failure cases when you're 305 * unwilling or unable to handle them more cleanly -- for OOM, for likely memory 306 * corruption, and so on. It's also a good solution if you need safe behavior 307 * in release builds as well as debug builds. But if the failure is one that 308 * should be debugged and fixed, MOZ_ASSERT is generally preferable. 309 * 310 * The optional explanation-string, if provided, must be a string literal 311 * explaining why we're crashing. This argument is intended for use with 312 * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's 313 * obvious why we're crashing. 314 * 315 * If we're a DEBUG, ASAN or FUZZING build and we crash at a MOZ_CRASH which 316 * provides an explanation-string, we print the string to stderr. Otherwise, 317 * we don't print anything; this is because we want MOZ_CRASH to be 100% safe 318 * in release builds, and it's hard to print to stderr safely when memory might 319 * have been corrupted. 320 */ 321 #if !(defined(DEBUG) || defined(MOZ_ASAN) || defined(FUZZING)) 322 # define MOZ_CRASH(...) \ 323 do { \ 324 MOZ_FUZZING_HANDLE_CRASH_EVENT4("MOZ_CRASH", __FILE__, __LINE__, NULL); \ 325 MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ 326 MOZ_REALLY_CRASH(__LINE__); \ 327 } while (false) 328 #else 329 # define MOZ_CRASH(...) \ 330 do { \ 331 MOZ_FUZZING_HANDLE_CRASH_EVENT4("MOZ_CRASH", __FILE__, __LINE__, NULL); \ 332 MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ 333 MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \ 334 MOZ_REALLY_CRASH(__LINE__); \ 335 } while (false) 336 #endif 337 338 /* 339 * MOZ_DIAGNOSTIC_CRASH acts like MOZ_CRASH in a MOZ_DIAGNOSTIC_ASSERT_ENABLED 340 * build, and does nothing otherwise. See the comment later in this file for a 341 * description of when MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined. 342 */ 343 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED) 344 # define MOZ_DIAGNOSTIC_CRASH(...) MOZ_CRASH(__VA_ARGS__) 345 #else 346 # define MOZ_DIAGNOSTIC_CRASH(...) \ 347 do { /* nothing */ \ 348 } while (false) 349 #endif 350 351 /* 352 * MOZ_CRASH_UNSAFE(explanation-string) can be used if the explanation string 353 * cannot be a string literal (but no other processing needs to be done on it). 354 * A regular MOZ_CRASH() is preferred wherever possible, as passing arbitrary 355 * strings from a potentially compromised process is not without risk. If the 356 * string being passed is the result of a printf-style function, consider using 357 * MOZ_CRASH_UNSAFE_PRINTF instead. 358 * 359 * @note This macro causes data collection because crash strings are annotated 360 * to crash-stats and are publicly visible. Firefox data stewards must do data 361 * review on usages of this macro. 362 */ 363 #ifdef __cplusplus 364 [[noreturn]] 365 #else 366 _Noreturn 367 #endif 368 static MOZ_ALWAYS_INLINE_EVEN_DEBUG MOZ_COLD void MOZ_Crash( 369 const char* aFilename, int aLine, const char* aReason) { 370 MOZ_FUZZING_HANDLE_CRASH_EVENT4("MOZ_CRASH", aFilename, aLine, aReason); 371 #if defined(DEBUG) || defined(MOZ_ASAN) || defined(FUZZING) 372 MOZ_ReportCrash(aReason, aFilename, aLine); 373 #endif 374 MOZ_CRASH_ANNOTATE(aReason); 375 MOZ_REALLY_CRASH(aLine); 376 } 377 #define MOZ_CRASH_UNSAFE(reason) MOZ_Crash(__FILE__, __LINE__, reason) 378 379 static const size_t sPrintfMaxArgs = 4; 380 static const size_t sPrintfCrashReasonSize = 1024; 381 382 MFBT_API MOZ_COLD MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(1, 2) const 383 char* MOZ_CrashPrintf(const char* aFormat, ...); 384 385 /* 386 * MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more 387 * information is desired than a string literal can supply. The caller provides 388 * a printf-style format string, which must be a string literal and between 389 * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever 390 * possible, as passing arbitrary strings to printf from a potentially 391 * compromised process is not without risk. 392 * 393 * @note This macro causes data collection because crash strings are annotated 394 * to crash-stats and are publicly visible. Firefox data stewards must do data 395 * review on usages of this macro. 396 */ 397 #define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \ 398 do { \ 399 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \ 400 "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \ 401 "Or maybe you want MOZ_CRASH instead?"); \ 402 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) <= sPrintfMaxArgs, \ 403 "Only up to 4 additional arguments are allowed!"); \ 404 static_assert(sizeof(format) <= sPrintfCrashReasonSize, \ 405 "The supplied format string is too long!"); \ 406 MOZ_Crash(__FILE__, __LINE__, MOZ_CrashPrintf("" format, __VA_ARGS__)); \ 407 } while (false) 408 409 MOZ_END_EXTERN_C 410 411 /* 412 * MOZ_CRASH_UNSAFE_FMT(format, arg1 [, args]) can be used when more 413 * information is desired than a string literal can supply. The caller provides 414 * a {fmt}-style format string and arguments. A regular MOZ_CRASH() is preferred 415 * wherever possible, as passing arbitrary strings to format from a potentially 416 * compromised process is not without risk. 417 * 418 * @note This macro causes data collection because crash strings are annotated 419 * to crash-stats and are publicly visible. Firefox data stewards must do data 420 * review on usages of this macro. 421 */ 422 #ifdef __cplusplus 423 424 namespace mozilla::detail { 425 template <typename... Args> 426 const char* CrashFmtImpl(const char* format, Args&&... args); 427 } 428 429 # define MOZ_CRASH_UNSAFE_FMT(format, ...) \ 430 do { \ 431 static_assert(MOZ_ARG_COUNT(__VA_ARGS__) > 0, \ 432 "Did you forget arguments to MOZ_CRASH_UNSAFE_FMT? " \ 433 "Or maybe you want MOZ_CRASH instead?"); \ 434 MOZ_Crash(__FILE__, __LINE__, \ 435 mozilla::detail::CrashFmtImpl("" format, __VA_ARGS__)); \ 436 } while (false) 437 #else 438 # define MOZ_CRASH_UNSAFE_FMT(...) \ 439 static_assert(false, "MOZ_CRASH_UNSAFE_FMT requires C++") 440 #endif 441 442 /* 443 * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in 444 * debug builds. If it is, execution continues. Otherwise, an error message 445 * including the expression and the explanation-string (if provided) is printed, 446 * an attempt is made to invoke any existing debugger, and execution halts. 447 * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition 448 * which can correctly be falsy. 449 * 450 * The optional explanation-string, if provided, must be a string literal 451 * explaining the assertion. It is intended for use with assertions whose 452 * correctness or rationale is non-obvious, and for assertions where the "real" 453 * condition being tested is best described prosaically. Don't provide an 454 * explanation if it's not actually helpful. 455 * 456 * // No explanation needed: pointer arguments often must not be NULL. 457 * MOZ_ASSERT(arg); 458 * 459 * // An explanation can be helpful to explain exactly how we know an 460 * // assertion is valid. 461 * MOZ_ASSERT(state == WAITING_FOR_RESPONSE, 462 * "given that <thingA> and <thingB>, we must have..."); 463 * 464 * // Or it might disambiguate multiple identical (save for their location) 465 * // assertions of the same expression. 466 * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), 467 * "we already set [[PrimitiveThis]] for this Boolean object"); 468 * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(), 469 * "we already set [[PrimitiveThis]] for this String object"); 470 * 471 * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs 472 * *only* during debugging, not "in the field". If you want the latter, use 473 * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well. 474 * 475 * MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly and early beta 476 * and MOZ_ASSERT in late Beta and Release - use this when a condition is 477 * potentially rare enough to require real user testing to hit, but is not 478 * security-sensitive. This can cause user pain, so use it sparingly. If a 479 * MOZ_DIAGNOSTIC_ASSERT is firing, it should promptly be converted to a 480 * MOZ_ASSERT while the failure is being investigated, rather than letting users 481 * suffer. 482 * 483 * MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined when MOZ_DIAGNOSTIC_ASSERT is like 484 * MOZ_RELEASE_ASSERT rather than MOZ_ASSERT. 485 */ 486 487 /* 488 * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against 489 * accidentally passing something unintended in lieu of an assertion condition. 490 */ 491 492 #ifdef __cplusplus 493 # include <type_traits> 494 namespace mozilla { 495 namespace detail { 496 497 template <typename T> 498 struct AssertionConditionType { 499 using ValueT = std::remove_reference_t<T>; 500 static_assert(!std::is_array_v<ValueT>, 501 "Expected boolean assertion condition, got an array or a " 502 "string!"); 503 static_assert(!std::is_function_v<ValueT>, 504 "Expected boolean assertion condition, got a function! Did " 505 "you intend to call that function?"); 506 static_assert(!std::is_floating_point_v<ValueT>, 507 "It's often a bad idea to assert that a floating-point number " 508 "is nonzero, because such assertions tend to intermittently " 509 "fail. Shouldn't your code gracefully handle this case instead " 510 "of asserting? Anyway, if you really want to do that, write an " 511 "explicit boolean condition, like !!x or x!=0."); 512 513 static const bool isValid = true; 514 }; 515 516 } // namespace detail 517 } // namespace mozilla 518 # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \ 519 static_assert( \ 520 mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \ 521 "invalid assertion condition") 522 #else 523 # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) 524 #endif 525 526 #if defined(DEBUG) || defined(MOZ_ASAN) || defined(FUZZING) 527 # define MOZ_REPORT_ASSERTION_FAILURE(...) \ 528 MOZ_ReportAssertionFailure(__VA_ARGS__) 529 #else 530 # define MOZ_REPORT_ASSERTION_FAILURE(...) \ 531 do { /* nothing */ \ 532 } while (false) 533 #endif 534 535 /* First the single-argument form. */ 536 #define MOZ_ASSERT_HELPER1(kind, expr) \ 537 do { \ 538 MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ 539 if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ 540 MOZ_FUZZING_HANDLE_CRASH_EVENT2(kind, #expr); \ 541 MOZ_REPORT_ASSERTION_FAILURE(#expr, __FILE__, __LINE__); \ 542 MOZ_CRASH_ANNOTATE(kind "(" #expr ")"); \ 543 MOZ_REALLY_CRASH(__LINE__); \ 544 } \ 545 } while (false) 546 /* Now the two-argument form. */ 547 #define MOZ_ASSERT_HELPER2(kind, expr, explain) \ 548 do { \ 549 MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ 550 if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ 551 MOZ_FUZZING_HANDLE_CRASH_EVENT2(kind, #expr); \ 552 MOZ_REPORT_ASSERTION_FAILURE(#expr " (" explain ")", __FILE__, \ 553 __LINE__); \ 554 MOZ_CRASH_ANNOTATE(kind "(" #expr ") (" explain ")"); \ 555 MOZ_REALLY_CRASH(__LINE__); \ 556 } \ 557 } while (false) 558 559 #define MOZ_ASSERT_GLUE(a, b) a b 560 #define MOZ_RELEASE_ASSERT(...) \ 561 MOZ_ASSERT_GLUE( \ 562 MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ 563 ("MOZ_RELEASE_ASSERT", __VA_ARGS__)) 564 565 #ifdef DEBUG 566 # define MOZ_ASSERT(...) \ 567 MOZ_ASSERT_GLUE( \ 568 MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ 569 ("MOZ_ASSERT", __VA_ARGS__)) 570 #else 571 # define MOZ_ASSERT(...) \ 572 do { /* nothing */ \ 573 } while (false) 574 #endif /* DEBUG */ 575 576 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED) 577 # define MOZ_DIAGNOSTIC_ASSERT(...) \ 578 MOZ_ASSERT_GLUE( \ 579 MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ 580 ("MOZ_DIAGNOSTIC_ASSERT", __VA_ARGS__)) 581 #else 582 # define MOZ_DIAGNOSTIC_ASSERT(...) \ 583 do { /* nothing */ \ 584 } while (false) 585 #endif 586 587 /* 588 * MOZ_ASSERT_DEBUG_OR_FUZZING is like a MOZ_ASSERT but also enabled in builds 589 * that are non-DEBUG but FUZZING. This is useful for checks that are too 590 * expensive for Nightly in general but are still indicating potentially 591 * critical bugs. 592 * In fuzzing builds, the assert is rewritten to be a diagnostic assert because 593 * we already use this in other sensitive places and fuzzing automation is 594 * set to act on these under all circumstances. 595 */ 596 #ifdef FUZZING 597 # define MOZ_ASSERT_DEBUG_OR_FUZZING(...) MOZ_DIAGNOSTIC_ASSERT(__VA_ARGS__) 598 #else 599 # define MOZ_ASSERT_DEBUG_OR_FUZZING(...) MOZ_ASSERT(__VA_ARGS__) 600 #endif 601 602 /* 603 * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is 604 * true. 605 * 606 * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num)); 607 * 608 * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is 609 * designed to catch bugs during debugging, not "in the field". 610 */ 611 #ifdef DEBUG 612 # define MOZ_ASSERT_IF(cond, expr) \ 613 do { \ 614 if (cond) { \ 615 MOZ_ASSERT(expr); \ 616 } \ 617 } while (false) 618 #else 619 # define MOZ_ASSERT_IF(cond, expr) \ 620 do { /* nothing */ \ 621 } while (false) 622 #endif 623 624 /* 625 * MOZ_DIAGNOSTIC_ASSERT_IF is like MOZ_ASSERT_IF, but using 626 * MOZ_DIAGNOSTIC_ASSERT as the underlying assert. 627 * 628 * See the block comment for MOZ_DIAGNOSTIC_ASSERT above for more details on how 629 * diagnostic assertions work and how to use them. 630 */ 631 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 632 # define MOZ_DIAGNOSTIC_ASSERT_IF(cond, expr) \ 633 do { \ 634 if (cond) { \ 635 MOZ_DIAGNOSTIC_ASSERT(expr); \ 636 } \ 637 } while (false) 638 #else 639 # define MOZ_DIAGNOSTIC_ASSERT_IF(cond, expr) \ 640 do { /* nothing */ \ 641 } while (false) 642 #endif 643 644 /* 645 * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it 646 * can assume that the macro call cannot be reached during execution. This lets 647 * the compiler generate better-optimized code under some circumstances, at the 648 * expense of the program's behavior being undefined if control reaches the 649 * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE. 650 * 651 * In Gecko, you probably should not use this macro outside of performance- or 652 * size-critical code, because it's unsafe. If you don't care about code size 653 * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH. 654 * 655 * SpiderMonkey is a different beast, and there it's acceptable to use 656 * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely. 657 * 658 * Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid 659 * not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE 660 * call. 661 * 662 * Example usage: 663 * 664 * enum ValueType { 665 * VALUE_STRING, 666 * VALUE_INT, 667 * VALUE_FLOAT 668 * }; 669 * 670 * int ptrToInt(ValueType type, void* value) { 671 * { 672 * // We know for sure that type is either INT or FLOAT, and we want this 673 * // code to run as quickly as possible. 674 * switch (type) { 675 * case VALUE_INT: 676 * return *(int*) value; 677 * case VALUE_FLOAT: 678 * return (int) *(float*) value; 679 * default: 680 * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType"); 681 * } 682 * } 683 */ 684 685 /* 686 * Unconditional assert in debug builds for (assumed) unreachable code paths 687 * that have a safe return without crashing in release builds. 688 */ 689 #define MOZ_ASSERT_UNREACHABLE(reason) \ 690 MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason) 691 692 #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \ 693 do { \ 694 MOZ_ASSERT_UNREACHABLE(reason); \ 695 MOZ_ASSUME_UNREACHABLE_MARKER(); \ 696 } while (false) 697 698 /** 699 * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about 700 * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in 701 * debug builds, but intentionally fall through in release builds to handle 702 * unexpected values. 703 * 704 * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to [[fallthrough]]? In 705 * release builds, the MOZ_ASSERT(false) will expand to `do { } while (false)`, 706 * requiring a [[fallthrough]] annotation to suppress a -Wimplicit-fallthrough 707 * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like 708 * `if (true) { MOZ_CRASH(); }` and the [[fallthrough]] annotation will cause 709 * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this 710 * warning stalemate. 711 * 712 * // Example before MOZ_FALLTHROUGH_ASSERT: 713 * switch (foo) { 714 * default: 715 * // This case wants to assert in debug builds, fall through in release. 716 * MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds! 717 * [[fallthrough]]; // but -Wunreachable-code warning in debug builds! 718 * case 5: 719 * return 5; 720 * } 721 * 722 * // Example with MOZ_FALLTHROUGH_ASSERT: 723 * switch (foo) { 724 * default: 725 * // This case asserts in debug builds, falls through in release. 726 * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!"); 727 * case 5: 728 * return 5; 729 * } 730 */ 731 #ifdef DEBUG 732 # define MOZ_FALLTHROUGH_ASSERT(...) \ 733 MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " __VA_ARGS__) 734 #else 735 # define MOZ_FALLTHROUGH_ASSERT(...) [[fallthrough]] 736 #endif 737 738 /* 739 * MOZ_ALWAYS_TRUE(expr) and friends always evaluate the provided expression, in 740 * both debug and release builds. Then, in debug builds and Nightly and early 741 * beta builds, we crash using the string value of the expression as the message 742 * using MOZ_DIAGNOSTIC_CRASH. 743 */ 744 #define MOZ_ALWAYS_TRUE(expr) \ 745 do { \ 746 if (MOZ_LIKELY(expr)) { \ 747 /* Silence [[nodiscard]]. */ \ 748 } else { \ 749 MOZ_DIAGNOSTIC_CRASH(#expr); \ 750 } \ 751 } while (false) 752 753 #define MOZ_ALWAYS_FALSE(expr) MOZ_ALWAYS_TRUE(!(expr)) 754 #define MOZ_ALWAYS_OK(expr) MOZ_ALWAYS_TRUE((expr).isOk()) 755 #define MOZ_ALWAYS_ERR(expr) MOZ_ALWAYS_TRUE((expr).isErr()) 756 757 /* 758 * These are disabled when fuzzing 759 */ 760 #ifdef FUZZING 761 # define MOZ_CRASH_UNLESS_FUZZING(...) \ 762 do { /* nothing */ \ 763 } while (0) 764 # define MOZ_ASSERT_UNLESS_FUZZING(...) \ 765 do { /* nothing */ \ 766 } while (0) 767 #else 768 # define MOZ_CRASH_UNLESS_FUZZING(...) MOZ_CRASH(__VA_ARGS__) 769 # define MOZ_ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(__VA_ARGS__) 770 #endif 771 772 #undef MOZ_BUFFER_STDERR 773 #undef MOZ_CRASH_CRASHREPORT 774 #undef MOZ_DUMP_ASSERTION_STACK 775 776 /* 777 * This is only used by Array and nsTArray classes, therefore it is not 778 * required when included from C code. 779 */ 780 #ifdef __cplusplus 781 namespace mozilla::detail { 782 [[noreturn]] MFBT_API MOZ_COLD void InvalidArrayIndex_CRASH(size_t aIndex, 783 size_t aLength); 784 } // namespace mozilla::detail 785 #endif // __cplusplus 786 787 /* 788 * Provide a fake default value to be used when a value is required but none can 789 * sensibily be provided without adding undefined behavior or security issues. 790 * 791 * This function asserts and aborts if it ever executed. 792 * 793 * Example usage: 794 * 795 * class Trooper { 796 * const Droid& lookFor; 797 * Trooper() : lookFor(MakeCompilerAssumeUnreachableFakeValue< 798 const Droid&>()) { 799 * // The class might be instantiated due to existing caller 800 * // but this never happens in practice. 801 * } 802 * }; 803 * 804 */ 805 #ifdef __cplusplus 806 namespace mozilla { 807 template <typename T> 808 static inline T MakeCompilerAssumeUnreachableFakeValue() { 809 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(); 810 } 811 } // namespace mozilla 812 #endif // __cplusplus 813 814 #undef MOZ_GET_PID 815 816 #endif /* mozilla_Assertions_h */