Assertions.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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. /* Implementations of runtime and static assertion macros for C and C++. */
  7. #ifndef mozilla_Assertions_h
  8. #define mozilla_Assertions_h
  9. #if defined(MOZILLA_INTERNAL_API) && defined(__cplusplus)
  10. #define MOZ_DUMP_ASSERTION_STACK
  11. #endif
  12. #include "mozilla/Attributes.h"
  13. #include "mozilla/Compiler.h"
  14. #include "mozilla/Likely.h"
  15. #include "mozilla/MacroArgs.h"
  16. #include "mozilla/StaticAnalysisFunctions.h"
  17. #include "mozilla/Types.h"
  18. #ifdef MOZ_DUMP_ASSERTION_STACK
  19. #include "nsTraceRefcnt.h"
  20. #endif
  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. #if !defined(DEBUG) && (defined(MOZ_HAS_MOZGLUE) || defined(MOZILLA_INTERNAL_API))
  31. static inline void
  32. AnnotateMozCrashReason(const char* reason)
  33. {
  34. gMozCrashReason = reason;
  35. }
  36. # define MOZ_CRASH_ANNOTATE(...) AnnotateMozCrashReason(__VA_ARGS__)
  37. #else
  38. # define MOZ_CRASH_ANNOTATE(...) do { /* nothing */ } while (0)
  39. #endif
  40. #include <stddef.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #ifdef _MSC_VER
  44. /*
  45. * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
  46. * further depends on <windef.h>. We hardcode these few definitions manually
  47. * because those headers clutter the global namespace with a significant
  48. * number of undesired macros and symbols.
  49. */
  50. MOZ_BEGIN_EXTERN_C
  51. __declspec(dllimport) int __stdcall
  52. TerminateProcess(void* hProcess, unsigned int uExitCode);
  53. __declspec(dllimport) void* __stdcall GetCurrentProcess(void);
  54. MOZ_END_EXTERN_C
  55. #else
  56. # include <signal.h>
  57. #endif
  58. #ifdef ANDROID
  59. # include <android/log.h>
  60. #endif
  61. #if defined(__GNUC__)
  62. # define MOZ_UNUSED_ATTRIBUTE __attribute__((unused))
  63. #else
  64. # define MOZ_UNUSED_ATTRIBUTE /* nothing */
  65. #endif
  66. /*
  67. * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C.
  68. * In C++11, static_assert is provided by the compiler to the same effect.
  69. * This can be useful when you make certain assumptions about what must hold for
  70. * optimal, or even correct, behavior. For example, you might assert that the
  71. * size of a struct is a multiple of the target architecture's word size:
  72. *
  73. * struct S { ... };
  74. * // C
  75. * MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
  76. * "S should be a multiple of word size for efficiency");
  77. * // C++11
  78. * static_assert(sizeof(S) % sizeof(size_t) == 0,
  79. * "S should be a multiple of word size for efficiency");
  80. *
  81. * This macro can be used in any location where both an extern declaration and a
  82. * typedef could be used.
  83. */
  84. #ifndef __cplusplus
  85. /*
  86. * Some of the definitions below create an otherwise-unused typedef. This
  87. * triggers compiler warnings with some versions of gcc, so mark the typedefs
  88. * as permissibly-unused to disable the warnings.
  89. */
  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_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_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. MOZ_BEGIN_EXTERN_C
  132. /*
  133. * Prints |aStr| as an assertion failure (using aFilename and aLine as the
  134. * location of the assertion) to the standard debug-output channel.
  135. *
  136. * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This
  137. * method is primarily for internal use in this header, and only secondarily
  138. * for use in implementing release-build assertions.
  139. */
  140. MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void
  141. MOZ_ReportAssertionFailure(const char* aStr, const char* aFilename, int aLine)
  142. MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
  143. {
  144. #ifdef ANDROID
  145. __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
  146. "Assertion failure: %s, at %s:%d\n",
  147. aStr, aFilename, aLine);
  148. #else
  149. fprintf(stderr, "Assertion failure: %s, at %s:%d\n", aStr, aFilename, aLine);
  150. #if defined (MOZ_DUMP_ASSERTION_STACK)
  151. nsTraceRefcnt::WalkTheStack(stderr);
  152. #endif
  153. fflush(stderr);
  154. #endif
  155. }
  156. MOZ_MAYBE_UNUSED static MOZ_COLD MOZ_NEVER_INLINE void
  157. MOZ_ReportCrash(const char* aStr, const char* aFilename, int aLine)
  158. MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS
  159. {
  160. #ifdef ANDROID
  161. __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
  162. "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
  163. #else
  164. fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", aStr, aFilename, aLine);
  165. #if defined(MOZ_DUMP_ASSERTION_STACK)
  166. nsTraceRefcnt::WalkTheStack(stderr);
  167. #endif
  168. fflush(stderr);
  169. #endif
  170. }
  171. /**
  172. * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should
  173. * call MOZ_CRASH instead.
  174. */
  175. #if defined(_MSC_VER)
  176. /*
  177. * On MSVC use the __debugbreak compiler intrinsic, which produces an inline
  178. * (not nested in a system function) breakpoint. This distinctively invokes
  179. * Breakpad without requiring system library symbols on all stack-processing
  180. * machines, as a nested breakpoint would require.
  181. *
  182. * We use __LINE__ to prevent the compiler from folding multiple crash sites
  183. * together, which would make crash reports hard to understand.
  184. *
  185. * We use TerminateProcess with the exit code aborting would generate
  186. * because we don't want to invoke atexit handlers, destructors, library
  187. * unload handlers, and so on when our process might be in a compromised
  188. * state.
  189. *
  190. * We don't use abort() because it'd cause Windows to annoyingly pop up the
  191. * process error dialog multiple times. See bug 345118 and bug 426163.
  192. *
  193. * (Technically these are Windows requirements, not MSVC requirements. But
  194. * practically you need MSVC for debugging, and we only ship builds created
  195. * by MSVC, so doing it this way reduces complexity.)
  196. */
  197. static MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void MOZ_NoReturn(int aLine)
  198. {
  199. *((volatile int*) NULL) = aLine;
  200. TerminateProcess(GetCurrentProcess(), 3);
  201. }
  202. # define MOZ_REALLY_CRASH(line) \
  203. do { \
  204. __debugbreak(); \
  205. MOZ_NoReturn(line); \
  206. } while (0)
  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. * @note This macro causes data collection because crash strings are annotated
  266. * to crash-stats and are publicly visible. Firefox data stewards must do data
  267. * review on usages of this macro.
  268. */
  269. #ifndef DEBUG
  270. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
  271. MOZ_CrashOOL(int aLine, const char* aReason);
  272. # define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__LINE__, reason)
  273. #else
  274. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE void
  275. MOZ_CrashOOL(const char* aFilename, int aLine, const char* aReason);
  276. # define MOZ_CRASH_UNSAFE_OOL(reason) MOZ_CrashOOL(__FILE__, __LINE__, reason)
  277. #endif
  278. static const size_t sPrintfMaxArgs = 4;
  279. static const size_t sPrintfCrashReasonSize = 1024;
  280. #ifndef DEBUG
  281. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(2, 3) void
  282. MOZ_CrashPrintf(int aLine, const char* aFormat, ...);
  283. # define MOZ_CALL_CRASH_PRINTF(format, ...) \
  284. MOZ_CrashPrintf(__LINE__, format, __VA_ARGS__)
  285. #else
  286. MFBT_API MOZ_COLD MOZ_NORETURN MOZ_NEVER_INLINE MOZ_FORMAT_PRINTF(3, 4) void
  287. MOZ_CrashPrintf(const char* aFilename, int aLine, const char* aFormat, ...);
  288. # define MOZ_CALL_CRASH_PRINTF(format, ...) \
  289. MOZ_CrashPrintf(__FILE__, __LINE__, format, __VA_ARGS__)
  290. #endif
  291. /*
  292. * MOZ_CRASH_UNSAFE_PRINTF(format, arg1 [, args]) can be used when more
  293. * information is desired than a string literal can supply. The caller provides
  294. * a printf-style format string, which must be a string literal and between
  295. * 1 and 4 additional arguments. A regular MOZ_CRASH() is preferred wherever
  296. * possible, as passing arbitrary strings to printf from a potentially
  297. * compromised process is not without risk.
  298. *
  299. * @note This macro causes data collection because crash strings are annotated
  300. * to crash-stats and are publicly visible. Firefox data stewards must do data
  301. * review on usages of this macro.
  302. */
  303. #define MOZ_CRASH_UNSAFE_PRINTF(format, ...) \
  304. do { \
  305. static_assert( \
  306. MOZ_ARG_COUNT(__VA_ARGS__) > 0, \
  307. "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " \
  308. "Or maybe you want MOZ_CRASH instead?"); \
  309. static_assert( \
  310. MOZ_ARG_COUNT(__VA_ARGS__) <= sPrintfMaxArgs, \
  311. "Only up to 4 additional arguments are allowed!"); \
  312. static_assert(sizeof(format) <= sPrintfCrashReasonSize, \
  313. "The supplied format string is too long!"); \
  314. MOZ_CALL_CRASH_PRINTF("" format, __VA_ARGS__); \
  315. } while (0)
  316. MOZ_END_EXTERN_C
  317. /*
  318. * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
  319. * debug builds. If it is, execution continues. Otherwise, an error message
  320. * including the expression and the explanation-string (if provided) is printed,
  321. * an attempt is made to invoke any existing debugger, and execution halts.
  322. * MOZ_ASSERT is fatal: no recovery is possible. Do not assert a condition
  323. * which can correctly be falsy.
  324. *
  325. * The optional explanation-string, if provided, must be a string literal
  326. * explaining the assertion. It is intended for use with assertions whose
  327. * correctness or rationale is non-obvious, and for assertions where the "real"
  328. * condition being tested is best described prosaically. Don't provide an
  329. * explanation if it's not actually helpful.
  330. *
  331. * // No explanation needed: pointer arguments often must not be NULL.
  332. * MOZ_ASSERT(arg);
  333. *
  334. * // An explanation can be helpful to explain exactly how we know an
  335. * // assertion is valid.
  336. * MOZ_ASSERT(state == WAITING_FOR_RESPONSE,
  337. * "given that <thingA> and <thingB>, we must have...");
  338. *
  339. * // Or it might disambiguate multiple identical (save for their location)
  340. * // assertions of the same expression.
  341. * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
  342. * "we already set [[PrimitiveThis]] for this Boolean object");
  343. * MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
  344. * "we already set [[PrimitiveThis]] for this String object");
  345. *
  346. * MOZ_ASSERT has no effect in non-debug builds. It is designed to catch bugs
  347. * *only* during debugging, not "in the field". If you want the latter, use
  348. * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
  349. *
  350. * MOZ_DIAGNOSTIC_ASSERT works like MOZ_RELEASE_ASSERT in Nightly/Aurora and
  351. * MOZ_ASSERT in Beta/Release - use this when a condition is potentially rare
  352. * enough to require real user testing to hit, but is not security-sensitive.
  353. * This can cause user pain, so use it sparingly. If a MOZ_DIAGNOSTIC_ASSERT
  354. * is firing, it should promptly be converted to a MOZ_ASSERT while the failure
  355. * is being investigated, rather than letting users suffer.
  356. *
  357. * MOZ_DIAGNOSTIC_ASSERT_ENABLED is defined when MOZ_DIAGNOSTIC_ASSERT is like
  358. * MOZ_RELEASE_ASSERT rather than MOZ_ASSERT.
  359. */
  360. /*
  361. * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against
  362. * accidentally passing something unintended in lieu of an assertion condition.
  363. */
  364. #ifdef __cplusplus
  365. # include "mozilla/TypeTraits.h"
  366. namespace mozilla {
  367. namespace detail {
  368. template<typename T>
  369. struct AssertionConditionType
  370. {
  371. typedef typename RemoveReference<T>::Type ValueT;
  372. static_assert(!IsArray<ValueT>::value,
  373. "Expected boolean assertion condition, got an array or a "
  374. "string!");
  375. static_assert(!IsFunction<ValueT>::value,
  376. "Expected boolean assertion condition, got a function! Did "
  377. "you intend to call that function?");
  378. static_assert(!IsFloatingPoint<ValueT>::value,
  379. "It's often a bad idea to assert that a floating-point number "
  380. "is nonzero, because such assertions tend to intermittently "
  381. "fail. Shouldn't your code gracefully handle this case instead "
  382. "of asserting? Anyway, if you really want to do that, write an "
  383. "explicit boolean condition, like !!x or x!=0.");
  384. static const bool isValid = true;
  385. };
  386. } // namespace detail
  387. } // namespace mozilla
  388. # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) \
  389. static_assert(mozilla::detail::AssertionConditionType<decltype(x)>::isValid, \
  390. "invalid assertion condition")
  391. #else
  392. # define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x)
  393. #endif
  394. #if defined(DEBUG) || defined(MOZ_ASAN)
  395. # define MOZ_REPORT_ASSERTION_FAILURE(...) MOZ_ReportAssertionFailure(__VA_ARGS__)
  396. #else
  397. # define MOZ_REPORT_ASSERTION_FAILURE(...) do { /* nothing */ } while (0)
  398. #endif
  399. /* First the single-argument form. */
  400. #define MOZ_ASSERT_HELPER1(expr) \
  401. do { \
  402. MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
  403. if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
  404. MOZ_REPORT_ASSERTION_FAILURE(#expr, __FILE__, __LINE__); \
  405. MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ")"); \
  406. MOZ_REALLY_CRASH(__LINE__); \
  407. } \
  408. } while (0)
  409. /* Now the two-argument form. */
  410. #define MOZ_ASSERT_HELPER2(expr, explain) \
  411. do { \
  412. MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \
  413. if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \
  414. MOZ_REPORT_ASSERTION_FAILURE(#expr " (" explain ")", __FILE__, __LINE__); \
  415. MOZ_CRASH_ANNOTATE("MOZ_RELEASE_ASSERT(" #expr ") (" explain ")"); \
  416. MOZ_REALLY_CRASH(__LINE__); \
  417. } \
  418. } while (0)
  419. #define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
  420. #define MOZ_RELEASE_ASSERT(...) \
  421. MOZ_RELEASE_ASSERT_GLUE( \
  422. MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
  423. (__VA_ARGS__))
  424. #ifdef DEBUG
  425. # define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
  426. #else
  427. # define MOZ_ASSERT(...) do { } while (0)
  428. #endif /* DEBUG */
  429. #if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION)
  430. # define MOZ_DIAGNOSTIC_ASSERT MOZ_RELEASE_ASSERT
  431. # define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
  432. #else
  433. # define MOZ_DIAGNOSTIC_ASSERT MOZ_ASSERT
  434. # ifdef DEBUG
  435. # define MOZ_DIAGNOSTIC_ASSERT_ENABLED 1
  436. # endif
  437. #endif
  438. /*
  439. * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
  440. * true.
  441. *
  442. * MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
  443. *
  444. * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds. It is
  445. * designed to catch bugs during debugging, not "in the field".
  446. */
  447. #ifdef DEBUG
  448. # define MOZ_ASSERT_IF(cond, expr) \
  449. do { \
  450. if (cond) { \
  451. MOZ_ASSERT(expr); \
  452. } \
  453. } while (0)
  454. #else
  455. # define MOZ_ASSERT_IF(cond, expr) do { } while (0)
  456. #endif
  457. /*
  458. * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that
  459. * it is undefined behavior for execution to reach this point. No guarantees
  460. * are made about what will happen if this is reached at runtime. Most code
  461. * should use MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE because it has extra
  462. * asserts.
  463. */
  464. #if defined(__clang__) || defined(__GNUC__)
  465. # define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
  466. #elif defined(_MSC_VER)
  467. # define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
  468. #else
  469. # ifdef __cplusplus
  470. # define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
  471. # else
  472. # define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
  473. # endif
  474. #endif
  475. /*
  476. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE([reason]) tells the compiler that it
  477. * can assume that the macro call cannot be reached during execution. This lets
  478. * the compiler generate better-optimized code under some circumstances, at the
  479. * expense of the program's behavior being undefined if control reaches the
  480. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE.
  481. *
  482. * In Gecko, you probably should not use this macro outside of performance- or
  483. * size-critical code, because it's unsafe. If you don't care about code size
  484. * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH.
  485. *
  486. * SpiderMonkey is a different beast, and there it's acceptable to use
  487. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE more widely.
  488. *
  489. * Note that MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE is noreturn, so it's valid
  490. * not to return a value following a MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
  491. * call.
  492. *
  493. * Example usage:
  494. *
  495. * enum ValueType {
  496. * VALUE_STRING,
  497. * VALUE_INT,
  498. * VALUE_FLOAT
  499. * };
  500. *
  501. * int ptrToInt(ValueType type, void* value) {
  502. * {
  503. * // We know for sure that type is either INT or FLOAT, and we want this
  504. * // code to run as quickly as possible.
  505. * switch (type) {
  506. * case VALUE_INT:
  507. * return *(int*) value;
  508. * case VALUE_FLOAT:
  509. * return (int) *(float*) value;
  510. * default:
  511. * MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected ValueType");
  512. * }
  513. * }
  514. */
  515. /*
  516. * Unconditional assert in debug builds for (assumed) unreachable code paths
  517. * that have a safe return without crashing in release builds.
  518. */
  519. #define MOZ_ASSERT_UNREACHABLE(reason) \
  520. MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
  521. #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
  522. do { \
  523. MOZ_ASSERT_UNREACHABLE(reason); \
  524. MOZ_ASSUME_UNREACHABLE_MARKER(); \
  525. } while (0)
  526. /**
  527. * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
  528. * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
  529. * debug builds, but intentionally fall through in release builds to handle
  530. * unexpected values.
  531. *
  532. * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
  533. * release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
  534. * requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
  535. * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
  536. * `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
  537. * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
  538. * warning stalemate.
  539. *
  540. * // Example before MOZ_FALLTHROUGH_ASSERT:
  541. * switch (foo) {
  542. * default:
  543. * // This case wants to assert in debug builds, fall through in release.
  544. * MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
  545. * MOZ_FALLTHROUGH; // but -Wunreachable-code warning in debug builds!
  546. * case 5:
  547. * return 5;
  548. * }
  549. *
  550. * // Example with MOZ_FALLTHROUGH_ASSERT:
  551. * switch (foo) {
  552. * default:
  553. * // This case asserts in debug builds, falls through in release.
  554. * MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
  555. * case 5:
  556. * return 5;
  557. * }
  558. */
  559. #ifdef DEBUG
  560. # define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
  561. #else
  562. # define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
  563. #endif
  564. /*
  565. * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
  566. * expression, in debug builds and in release builds both. Then, in debug
  567. * builds only, the value of the expression is asserted either true or false
  568. * using MOZ_ASSERT.
  569. */
  570. #ifdef DEBUG
  571. # define MOZ_ALWAYS_TRUE(expr) \
  572. do { \
  573. if ((expr)) { \
  574. /* Do nothing. */ \
  575. } else { \
  576. MOZ_ASSERT(false, #expr); \
  577. } \
  578. } while (0)
  579. # define MOZ_ALWAYS_FALSE(expr) \
  580. do { \
  581. if ((expr)) { \
  582. MOZ_ASSERT(false, #expr); \
  583. } else { \
  584. /* Do nothing. */ \
  585. } \
  586. } while (0)
  587. # define MOZ_ALWAYS_OK(expr) MOZ_ASSERT((expr).isOk())
  588. # define MOZ_ALWAYS_ERR(expr) MOZ_ASSERT((expr).isErr())
  589. #else
  590. # define MOZ_ALWAYS_TRUE(expr) \
  591. do { \
  592. if ((expr)) { \
  593. /* Silence MOZ_MUST_USE. */ \
  594. } \
  595. } while (0)
  596. # define MOZ_ALWAYS_FALSE(expr) \
  597. do { \
  598. if ((expr)) { \
  599. /* Silence MOZ_MUST_USE. */ \
  600. } \
  601. } while (0)
  602. # define MOZ_ALWAYS_OK(expr) \
  603. do { \
  604. if ((expr).isOk()) { \
  605. /* Silence MOZ_MUST_USE. */ \
  606. } \
  607. } while (0)
  608. # define MOZ_ALWAYS_ERR(expr) \
  609. do { \
  610. if ((expr).isErr()) { \
  611. /* Silence MOZ_MUST_USE. */ \
  612. } \
  613. } while (0)
  614. #endif
  615. #undef MOZ_DUMP_ASSERTION_STACK
  616. #undef MOZ_CRASH_CRASHREPORT
  617. #endif /* mozilla_Assertions_h */