Assertions.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* Implementations of runtime and static assertion macros for C and C++. */
  6. #ifndef mozilla_Assertions_h
  7. #define mozilla_Assertions_h
  8. #if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus)
  9. #define MOZ_DUMP_ASSERTION_STACK
  10. #endif
  11. #include "mozilla/Attributes.h"
  12. #include "mozilla/Compiler.h"
  13. #include "mozilla/Likely.h"
  14. #include "mozilla/MacroArgs.h"
  15. #include "mozilla/StaticAnalysisFunctions.h"
  16. #include "mozilla/Types.h"
  17. #ifdef MOZ_DUMP_ASSERTION_STACK
  18. #include "nsTraceRefcnt.h"
  19. #endif
  20. #if defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API)
  21. /*
  22. * The crash reason set by MOZ_CRASH_ANNOTATE is consumed by the crash reporter
  23. * if present. It is declared here (and defined in Assertions.cpp) to make it
  24. * available to all code, even libraries that don't link with the crash reporter
  25. * directly.
  26. */
  27. MOZ_BEGIN_EXTERN_C
  28. extern MFBT_DATA const char* gMozCrashReason;
  29. MOZ_END_EXTERN_C
  30. static inline void
  31. AnnotateMozCrashReason(const char* reason)
  32. {
  33. gMozCrashReason = reason;
  34. }
  35. # define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__)
  36. #else
  37. # define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0)
  38. #endif
  39. #include <stddef.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #ifdef WIN32
  43. /*
  44. * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
  45. * further depends on <windef.h>. We hardcode these few definitions manually
  46. * because those headers clutter the global namespace with a significant
  47. * number of undesired macros and symbols.
  48. */
  49. # ifdef __cplusplus
  50. extern "C" {
  51. # endif
  52. __declspec(dllimport) int __stdcall
  53. TerminateProcess(void* hProcess, unsigned int uExitCode);
  54. __declspec(dllimport) void* __stdcall GetCurrentProcess(void);
  55. # ifdef __cplusplus
  56. }
  57. # endif
  58. #else
  59. # include <signal.h>
  60. #endif
  61. /*
  62. * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C.
  63. * In C++11, static_assert is provided by the compiler to the same effect.
  64. * This can be useful when you make certain assumptions about what must hold for
  65. * optimal, or even correct, behavior. For example, you might assert that the
  66. * size of a struct is a multiple of the target architecture's word size:
  67. *
  68. * struct S { ... };
  69. * // C
  70. * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
  71. * "S should be a multiple of word size for efficiency");
  72. * // C++11
  73. * static_assert(sizeof(S) % sizeof(size_t) == 0,
  74. * "S should be a multiple of word size for efficiency");
  75. *
  76. * This macro can be used in any location where both an extern declaration and a
  77. * typedef could be used.
  78. */
  79. #ifndef __cplusplus
  80. /*
  81. * Some of the definitions below create an otherwise-unused typedef. This
  82. * triggers compiler warnings with some versions of gcc, so mark the typedefs
  83. * as permissibly-unused to disable the warnings.
  84. */
  85. # if defined(__GNUC__)
  86. # define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
  87. # else
  88. # define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */
  89. # endif
  90. # define MOZ_STATIC_ASSERT_GLUE1(x, y) x##y
  91. # define MOZ_STATIC_ASSERT_GLUE(x, y) MOZ_STATIC_ASSERT_GLUE1(x, y)
  92. # if defined(__SUNPRO_CC)
  93. /*
  94. * The Sun Studio C++ compiler is buggy when declaring, inside a function,
  95. * another extern'd function with an array argument whose length contains a
  96. * sizeof, triggering the error message "sizeof expression not accepted as
  97. * size of array parameter". This bug (6688515, not public yet) would hit
  98. * defining moz_static_assert as a function, so we always define an extern
  99. * array for Sun Studio.
  100. *
  101. * We include the line number in the symbol name in a best-effort attempt
  102. * to avoid conflicts (see below).
  103. */
  104. # define MOZ_STATIC_ASSERT(cond, reason) \
  105. extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1]
  106. # elif defined(__COUNTER__)
  107. /*
  108. * If there was no preferred alternative, use a compiler-agnostic version.
  109. *
  110. * Note that the non-__COUNTER__ version has a bug in C++: it can't be used
  111. * in both |extern "C"| and normal C++ in the same translation unit. (Alas
  112. * |extern "C"| isn't allowed in a function.) The only affected compiler
  113. * we really care about is gcc 4.2. For that compiler and others like it,
  114. * we include the line number in the function name to do the best we can to
  115. * avoid conflicts. These should be rare: a conflict would require use of
  116. * MOZ_STATIC_ASSERT on the same line in separate files in the same
  117. * translation unit, *and* the uses would have to be in code with
  118. * different linkage, *and* the first observed use must be in C++-linkage
  119. * code.
  120. */
  121. # define MOZ_STATIC_ASSERT(cond, reason) \
  122. typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
  123. # else
  124. # define MOZ_STATIC_ASSERT(cond, reason) \
  125. extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
  126. # endif
  127. #define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
  128. #else
  129. #define MOZ_STATIC_ASSERT_IF(cond, expr, reason) static_assert(!(cond) || (expr), reason)
  130. #endif
  131. #ifdef __cplusplus
  132. extern "C" {
  133. #endif
  134. /*
  135. * Prints |aStr| as an assertion failure (using aFilename and aLine as the
  136. * location of the assertion) to the standard debug-output channel.
  137. *
  138. * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
  139. * method is primarily for internal use in this header, and only secondarily
  140. * for use in implementing release-build assertions.
  141. */
  142. static MOZ_COLD MOZ_ALWAYS_INLINE void
  143. MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
  144. MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
  145. {
  146. fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
  147. #if defined (MOZ_DUMP_ASSERTION_STACK)
  148. nsTraceRefcnt::WalkTheStack(stderr);
  149. #endif
  150. fflush(stderr);
  151. }
  152. static MOZ_COLD MOZ_ALWAYS_INLINE void
  153. MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
  154. MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
  155. {
  156. fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
  157. #if defined(MOZ_DUMP_ASSERTION_STACK)
  158. nsTraceRefcnt::WalkTheStack(stderr);
  159. #endif
  160. fflush(stderr);
  161. }
  162. /**
  163. * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should
  164. * call MOZ_CRASH instead.
  165. */
  166. #if defined(_MSC_VER)
  167. /*
  168. * On MSVC use the __debugbreak compiler intrinsic, which produces an inline
  169. * (not nested in a system function) breakpoint. This distinctively invokes
  170. * Breakpad without requiring system library symbols on all stack-processing
  171. * machines, as a nested breakpoint would require.
  172. *
  173. * We use TerminateProcess with the exit code aborting would generate
  174. * because we don't want to invoke atexit handlers, destructors, library
  175. * unload handlers, and so on when our process might be in a compromised
  176. * state.
  177. *
  178. * We don't use abort() because it'd cause Windows to annoyingly pop up the
  179. * process error dialog multiple times. See bug 345118 and bug 426163.
  180. *
  181. * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the
  182. * compiler doesn't hassle us to provide a return statement after a
  183. * MOZ_REALLY_CRASH() call.
  184. *
  185. * (Technically these are Windows requirements, not MSVC requirements. But
  186. * practically you need MSVC for debugging, and we only ship builds created
  187. * by MSVC, so doing it this way reduces complexity.)
  188. */
  189. __declspec(noreturn) __inline void MOZ_NoReturn() {}
  190. # ifdef __cplusplus
  191. # define MOZ_REALLY_CRASH(line) \
  192. do { \
  193. ::__debugbreak(); \
  194. *((volatile int*) NULL) = line; \
  195. ::TerminateProcess(::GetCurrentProcess(), 3); \
  196. ::MOZ_NoReturn(); \
  197. } while (0)
  198. # else
  199. # define MOZ_REALLY_CRASH(line) \
  200. do { \
  201. __debugbreak(); \
  202. *((volatile int*) NULL) = line; \
  203. TerminateProcess(GetCurrentProcess(), 3); \
  204. MOZ_NoReturn(); \
  205. } while (0)
  206. # endif
  207. #else
  208. # ifdef __cplusplus
  209. # define MOZ_REALLY_CRASH(line) \
  210. do { \
  211. *((volatile int*) NULL) = line; \
  212. ::abort(); \
  213. } while (0)
  214. # else
  215. # define MOZ_REALLY_CRASH(line) \
  216. do { \
  217. *((volatile int*) NULL) = line; \
  218. abort(); \
  219. } while (0)
  220. # endif
  221. #endif
  222. /*
  223. * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a
  224. * Breakpad-compatible way, in both debug and release builds.
  225. *
  226. * MOZ_CRASH is a good solution for "handling" failure cases when you're
  227. * unwilling or unable to handle them more cleanly -- for OOM, for likely memory
  228. * corruption, and so on. It's also a good solution if you need safe behavior
  229. * in release builds as well as debug builds. But if the failure is one that
  230. * should be debugged and fixed, MOZ_ASSERT is generally preferable.
  231. *
  232. * The optional explanation-string, if provided, must be a string literal
  233. * explaining why we're crashing. This argument is intended for use with
  234. * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's
  235. * obvious why we're crashing.
  236. *
  237. * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an
  238. * explanation-string, we print the string to stderr. Otherwise, we don't
  239. * print anything; this is because we want MOZ_CRASH to be 100% safe in release
  240. * builds, and it's hard to print to stderr safely when memory might have been
  241. * corrupted.
  242. */
  243. #ifndef DEBUG
  244. # define MOZ_CRASH(...) \
  245. do { \
  246. MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
  247. MOZ_REALLY_CRASH(__LINE__); \
  248. } while (0)
  249. #else
  250. # define MOZ_CRASH(...) \
  251. do { \
  252. MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \
  253. MOZ_CRASH_ANNOTATE("MOZ_CRASH(" __VA_ARGS__ ")"); \
  254. MOZ_REALLY_CRASH(__LINE__); \
  255. } while (0)
  256. #endif
  257. /*
  258. * MOZ_CRASH_UNSAFE_OOL(explanation-string) can be used if the explanation
  259. * string cannot be a string literal (but no other processing needs to be done
  260. * on it). A regular MOZ_CRASH() is preferred wherever possible, as passing
  261. * arbitrary strings from a potentially compromised process is not without risk.
  262. * If the string being passed is the result of a printf-style function,
  263. * consider using MOZ_CRASH_UNSAFE_PRINTF instead.
  264. */
  265. #ifndef DEBUG
  266. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
  267. MOZ_CrashOOL(int aLine, const char* aReason);
  268. # define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__LINE__, reason)
  269. #else
  270. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
  271. MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason);
  272. # define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__FILE__, __LINE__, reason)
  273. #endif
  274. static const size_t sPrintfMaxArgs = 4;
  275. static const size_t sPrintfCrashReasonSize = 1024;
  276. #ifndef DEBUG
  277. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void
  278. MOZ_CrashPrintf(int aLine, const char* aFormat, ...);
  279. # define MOZ_CALL_CRASH_PRINTF(format, ...) \
  280. MOZ_CrashPrintf(__LINE__, format, __VA_ARGS__)
  281. #else
  282. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void
  283. MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...);
  284. # define MOZ_CALL_CRASH_PRINTF(format, ...) \
  285. MOZ_CrashPrintf(__FILE__, __LINE__, format, __VA_ARGS__)
  286. #endif
  287. /*
  288. * MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more
  289. * information is desired than a string literal can supply. The caller provides
  290. * a printf-style format string, which must be a string literal and between
  291. * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever
  292. * possible, as passing arbitrary strings to printf from a potentially
  293. * compromised process is not without risk.
  294. */
  295. #define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
  296. do { \
  297. MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__); \
  298. static_assert( \
  299. MOZ_PASTE_PREFIX_AND_ARG_COUNT(, __VA_ARGS__) <= sPrintfMaxArgs, \
  300. "Only up to 4 additional arguments are allowed!"); \
  301. static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
  302. "The supplied format string is too long!"); \
  303. MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \
  304. } while (0)
  305. #ifdef __cplusplus
  306. } /* extern "C" */
  307. #endif
  308. /*
  309. * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
  310. * debug builds. If it is, execution continues. Otherwise, an error message
  311. * including the expression and the explanation-string (if provided) is printed,
  312. * an attempt is made to invoke any existing debugger, and execution halts.
  313. * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition
  314. * which can correctly be falsy.
  315. *
  316. * The optional explanation-string, if provided, must be a string literal
  317. * explaining the assertion. It is intended for use with assertions whose
  318. * correctness or rationale is non-obvious, and for assertions where the "real"
  319. * condition being tested is best described prosaically. Don't provide an
  320. * explanation if it's not actually helpful.
  321. *
  322. * // No explanation needed: pointer arguments often must not be NULL.
  323. * MOZ_ASSERT(arg);
  324. *
  325. * // An explanation can be helpful to explain exactly how we know an
  326. * // assertion is valid.
  327. * MOZ_ASSERT(state == WAITING_FOR_RESPONSE,
  328. * "given that <thingA> and <thingB>, we must have...");
  329. *
  330. * // Or it might disambiguate multiple identical (save for their location)
  331. * // assertions of the same expression.
  332. * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
  333. * "we already set [[PrimitiveThis]] for this Boolean object");
  334. * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
  335. * "we already set [[PrimitiveThis]] for this String object");
  336. *
  337. * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs
  338. * *only* during debugging, not "in the field". If you want the latter, use
  339. * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
  340. *
  341. * MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and
  342. * MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare
  343. * enough to require real user testing to hit, but is not security-sensitive.
  344. * This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT
  345. * is firing, it should promptly be converted to a MOZ_ASSERT while the failure
  346. * is being investigated, rather than letting users suffer.
  347. */
  348. /*
  349. * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against
  350. * accidentally passing something unintended in lieu of an assertion condition.
  351. */
  352. #ifdef __cplusplus
  353. # include "mozilla/TypeTraits.h"
  354. namespace mozilla {
  355. namespace detail {
  356. template<typename T>
  357. struct AssertionConditionType
  358. {
  359. typedef typename RemoveReference<T>::Type ValueT;
  360. static_assert(!IsArray<ValueT>::value,
  361. "Expected boolean assertion condition, got an array or a "
  362. "string!");
  363. static_assert(!IsFunction<ValueT>::value,
  364. "Expected boolean assertion condition, got a function! Did "
  365. "you intend to call that function?");
  366. static_assert(!IsFloatingPoint<ValueT>::value,
  367. "It's often a bad idea to assert that a floating-point number "
  368. "is nonzero, because such assertions tend to intermittently "
  369. "fail. Shouldn't your code gracefully handle this case instead "
  370. "of asserting? Anyway, if you really want to do that, write an "
  371. "explicit boolean condition, like !!x or x!=0.");
  372. static const bool isValid = true;
  373. };
  374. } // namespace detail
  375. } // namespace mozilla
  376. # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
  377. static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \
  378. "invalid assertion condition")
  379. #else
  380. # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
  381. #endif
  382. /* First the single-argument form. */
  383. #define MOZ_ASSERT_HELPER1(expr) \
  384. do { \
  385. MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
  386. if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
  387. MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
  388. MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \
  389. MOZ_REALLY_CRASH(__LINE__); \
  390. } \
  391. } while (0)
  392. /* Now the two-argument form. */
  393. #define MOZ_ASSERT_HELPER2(expr, explain) \
  394. do { \
  395. MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
  396. if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
  397. MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
  398. MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \
  399. MOZ_REALLY_CRASH(__LINE__); \
  400. } \
  401. } while (0)
  402. #define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
  403. #define MOZ_RELEASE_ASSERT(...) \
  404. MOZ_RELEASE_ASSERT_GLUE( \
  405. MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
  406. (__VA_ARGS__))
  407. #ifdef DEBUG
  408. # define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
  409. #else
  410. # define MOZ_ASSERT(...) do { } while (0)
  411. #endif /* DEBUG */
  412. #ifdef RELEASE_OR_BETA
  413. # define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
  414. #else
  415. # define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
  416. #endif
  417. /*
  418. * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
  419. * true.
  420. *
  421. * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
  422. *
  423. * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is
  424. * designed to catch bugs during debugging, not "in the field".
  425. */
  426. #ifdef DEBUG
  427. # define MOZ_ASSERT_IF(cond, expr) \
  428. do { \
  429. if (cond) { \
  430. MOZ_ASSERT(expr); \
  431. } \
  432. } while (0)
  433. #else
  434. # define MOZ_ASSERT_IF(cond, expr) do { } while (0)
  435. #endif
  436. /*
  437. * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
  438. * it is undefined behavior for execution to reach this point. No guarantees
  439. * are made about what will happen if this is reached at runtime. Most code
  440. * should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
  441. * asserts.
  442. */
  443. #if defined(__clang__) || defined(__GNUC__)
  444. # define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
  445. #elif defined(_MSC_VER)
  446. # define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
  447. #else
  448. # ifdef __cplusplus
  449. # define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
  450. # else
  451. # define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
  452. # endif
  453. #endif
  454. /*
  455. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it
  456. * can assume that the macro call cannot be reached during execution. This lets
  457. * the compiler generate better-optimized code under some circumstances, at the
  458. * expense of the program's behavior being undefined if control reaches the
  459. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE.
  460. *
  461. * In Gecko, you probably should not use this macro outside of performance- or
  462. * size-critical code, because it's unsafe. If you don't care about code size
  463. * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH.
  464. *
  465. * SpiderMonkey is a different beast, and there it's acceptable to use
  466. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely.
  467. *
  468. * Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid
  469. * not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
  470. * call.
  471. *
  472. * Example usage:
  473. *
  474. * enum ValueType {
  475. * VALUE_STRING,
  476. * VALUE_INT,
  477. * VALUE_FLOAT
  478. * };
  479. *
  480. * int ptrToInt(ValueType type, void* value) {
  481. * {
  482. * // We know for sure that type is either INT or FLOAT, and we want this
  483. * // code to run as quickly as possible.
  484. * switch (type) {
  485. * case VALUE_INT:
  486. * return *(int*) value;
  487. * case VALUE_FLOAT:
  488. * return (int) *(float*) value;
  489. * default:
  490. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType");
  491. * }
  492. * }
  493. */
  494. /*
  495. * Unconditional assert in debug builds for (assumed) unreachable code paths
  496. * that have a safe return without crashing in release builds.
  497. */
  498. #define MOZ_ASSERT_UNREACHABLE(reason) \
  499. MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
  500. #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
  501. do { \
  502. MOZ_ASSERT_UNREACHABLE(reason); \
  503. MOZ_ASSUME_UNREACHABLE_MARKER(); \
  504. } while (0)
  505. /**
  506. * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
  507. * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
  508. * debug builds, but intentionally fall through in release builds to handle
  509. * unexpected values.
  510. *
  511. * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
  512. * release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
  513. * requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
  514. * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
  515. * `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
  516. * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
  517. * warning stalemate.
  518. *
  519. * // Example before MOZ_FALLTHROUGH_ASSERT:
  520. * switch (foo) {
  521. * default:
  522. * // This case wants to assert in debug builds, fall through in release.
  523. * MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
  524. * MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds!
  525. * case 5:
  526. * return 5;
  527. * }
  528. *
  529. * // Example with MOZ_FALLTHROUGH_ASSERT:
  530. * switch (foo) {
  531. * default:
  532. * // This case asserts in debug builds, falls through in release.
  533. * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
  534. * case 5:
  535. * return 5;
  536. * }
  537. */
  538. #ifdef DEBUG
  539. # define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
  540. #else
  541. # define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
  542. #endif
  543. /*
  544. * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
  545. * expression, in debug builds and in release builds both. Then, in debug
  546. * builds only, the value of the expression is asserted either true or false
  547. * using MOZ_ASSERT.
  548. */
  549. #ifdef DEBUG
  550. # define MOZ_ALWAYS_TRUE(expr) \
  551. do { \
  552. if ((expr)) { \
  553. /* Do nothing. */ \
  554. } else { \
  555. MOZ_ASSERT(false, #expr); \
  556. } \
  557. } while (0)
  558. # define MOZ_ALWAYS_FALSE(expr) \
  559. do { \
  560. if ((expr)) { \
  561. MOZ_ASSERT(false, #expr); \
  562. } else { \
  563. /* Do nothing. */ \
  564. } \
  565. } while (0)
  566. #else
  567. # define MOZ_ALWAYS_TRUE(expr) \
  568. do { \
  569. if ((expr)) { \
  570. /* Silence MOZ_MUST_USE. */ \
  571. } \
  572. } while (0)
  573. # define MOZ_ALWAYS_FALSE(expr) \
  574. do { \
  575. if ((expr)) { \
  576. /* Silence MOZ_MUST_USE. */ \
  577. } \
  578. } while (0)
  579. #endif
  580. #undef MOZ_DUMP_ASSERTION_STACK
  581. #undef MOZ_CRASH_CRASHREPORT
  582. #endif /* mozilla_Assertions_h */