| author | Justin Lebar <justin.lebar@gmail.com> |
| Fri, 28 Jun 2013 18:38:30 -0700 | |
| changeset 136863 | 02d4ae55e1c3429bb95230496b21f1dabbda51e7 |
| parent 136862 | 6d731a339374fec6d97787d32e18fd0fef7b42f5 |
| child 136864 | 55c1f447549d5ad6245f8f78fbea89ebd5350b04 |
| push id | 24898 |
| push user | philringnalda@gmail.com |
| push date | Sat, 29 Jun 2013 13:54:45 +0000 |
| treeherder | mozilla-central@cbb24a4a96af [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | waldo |
| bugs | 763070 |
| milestone | 25.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| mfbt/Assertions.h | file | annotate | diff | comparison | revisions |
--- a/mfbt/Assertions.h +++ b/mfbt/Assertions.h @@ -128,92 +128,141 @@ #define MOZ_STATIC_ASSERT_IF(cond, expr, reason) MOZ_STATIC_ASSERT(!(cond) || (expr), reason) #ifdef __cplusplus extern "C" { #endif /* - * MOZ_CRASH crashes the program, plain and simple, in a Breakpad-compatible - * way, in both debug and release builds. - * - * MOZ_CRASH is a good solution for "handling" failure cases when you're - * unwilling or unable to handle them more cleanly -- for OOM, for likely memory - * corruption, and so on. It's also a good solution if you need safe behavior - * in release builds as well as debug builds. But if the failure is one that - * should be debugged and fixed, MOZ_ASSERT is generally preferable. - */ -#if defined(_MSC_VER) - /* - * On MSVC use the __debugbreak compiler intrinsic, which produces an inline - * (not nested in a system function) breakpoint. This distinctively invokes - * Breakpad without requiring system library symbols on all stack-processing - * machines, as a nested breakpoint would require. We use TerminateProcess - * with the exit code aborting would generate because we don't want to invoke - * atexit handlers, destructors, library unload handlers, and so on when our - * process might be in a compromised state. We don't use abort() because - * it'd cause Windows to annoyingly pop up the process error dialog multiple - * times. See bug 345118 and bug 426163. - * - * (Technically these are Windows requirements, not MSVC requirements. But - * practically you need MSVC for debugging, and we only ship builds created - * by MSVC, so doing it this way reduces complexity.) - */ -# ifdef __cplusplus -# define MOZ_CRASH() \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = 123; \ - ::TerminateProcess(::GetCurrentProcess(), 3); \ - } while (0) -# else -# define MOZ_CRASH() \ - do { \ - __debugbreak(); \ - *((volatile int*) NULL) = 123; \ - TerminateProcess(GetCurrentProcess(), 3); \ - } while (0) -# endif -#else -# ifdef __cplusplus -# define MOZ_CRASH() \ - do { \ - *((volatile int*) NULL) = 123; \ - ::abort(); \ - } while (0) -# else -# define MOZ_CRASH() \ - do { \ - *((volatile int*) NULL) = 123; \ - abort(); \ - } while (0) -# endif -#endif - -/* * Prints |s| as an assertion failure (using file and ln as the location of the * assertion) to the standard debug-output channel. * - * Usually you should use MOZ_ASSERT instead of this method. This method is - * primarily for internal use in this header, and only secondarily for use in - * implementing release-build assertions. + * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method. This + * method is primarily for internal use in this header, and only secondarily + * for use in implementing release-build assertions. */ static MOZ_ALWAYS_INLINE void MOZ_ReportAssertionFailure(const char* s, const char* file, int ln) { #ifdef ANDROID __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert", "Assertion failure: %s, at %s:%d\n", s, file, ln); #else fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln); fflush(stderr); #endif } +static MOZ_ALWAYS_INLINE void +MOZ_ReportCrash(const char* s, const char* file, int ln) +{ +#ifdef ANDROID + __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH", + "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln); +#else + fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln); + fflush(stderr); +#endif +} + +/** + * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH(). You should + * call MOZ_CRASH instead. + */ +#if defined(_MSC_VER) + /* + * On MSVC use the __debugbreak compiler intrinsic, which produces an inline + * (not nested in a system function) breakpoint. This distinctively invokes + * Breakpad without requiring system library symbols on all stack-processing + * machines, as a nested breakpoint would require. + * + * We use TerminateProcess with the exit code aborting would generate + * because we don't want to invoke atexit handlers, destructors, library + * unload handlers, and so on when our process might be in a compromised + * state. + * + * We don't use abort() because it'd cause Windows to annoyingly pop up the + * process error dialog multiple times. See bug 345118 and bug 426163. + * + * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the + * compiler doesn't hassle us to provide a return statement after a + * MOZ_REALLY_CRASH() call. + * + * (Technically these are Windows requirements, not MSVC requirements. But + * practically you need MSVC for debugging, and we only ship builds created + * by MSVC, so doing it this way reduces complexity.) + */ + +__declspec(noreturn) __inline void MOZ_NoReturn() {} + +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + __debugbreak(); \ + *((volatile int*) NULL) = 123; \ + ::TerminateProcess(::GetCurrentProcess(), 3); \ + ::MOZ_NoReturn(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + __debugbreak(); \ + *((volatile int*) NULL) = 123; \ + TerminateProcess(GetCurrentProcess(), 3); \ + MOZ_NoReturn(); \ + } while (0) +# endif +#else +# ifdef __cplusplus +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = 123; \ + ::abort(); \ + } while (0) +# else +# define MOZ_REALLY_CRASH() \ + do { \ + *((volatile int*) NULL) = 123; \ + abort(); \ + } while (0) +# endif +#endif + +/* + * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a + * Breakpad-compatible way, in both debug and release builds. + * + * MOZ_CRASH is a good solution for "handling" failure cases when you're + * unwilling or unable to handle them more cleanly -- for OOM, for likely memory + * corruption, and so on. It's also a good solution if you need safe behavior + * in release builds as well as debug builds. But if the failure is one that + * should be debugged and fixed, MOZ_ASSERT is generally preferable. + * + * The optional explanation-string, if provided, must be a string literal + * explaining why we're crashing. This argument is intended for use with + * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's + * obvious why we're crashing. + * + * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an + * explanation-string, we print the string to stderr. Otherwise, we don't + * print anything; this is because we want MOZ_CRASH to be 100% safe in release + * builds, and it's hard to print to stderr safely when memory might have been + * corrupted. + */ +#ifndef DEBUG +# define MOZ_CRASH(...) MOZ_REALLY_CRASH() +#else +# define MOZ_CRASH(...) \ + do { \ + MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \ + MOZ_REALLY_CRASH(); \ + } while(0) +#endif + #ifdef __cplusplus } /* extern "C" */ #endif /* * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in * debug builds. If it is, execution continues. Otherwise, an error message * including the expression and the explanation-string (if provided) is printed, @@ -246,25 +295,25 @@ MOZ_ReportAssertionFailure(const char* s * *only* during debugging, not "in the field". */ #ifdef DEBUG /* First the single-argument form. */ # define MOZ_ASSERT_HELPER1(expr) \ do { \ if (MOZ_UNLIKELY(!(expr))) { \ MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ - MOZ_CRASH(); \ + MOZ_REALLY_CRASH(); \ } \ } while (0) /* Now the two-argument form. */ # define MOZ_ASSERT_HELPER2(expr, explain) \ do { \ if (MOZ_UNLIKELY(!(expr))) { \ MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ - MOZ_CRASH(); \ + MOZ_REALLY_CRASH(); \ } \ } while (0) /* And now, helper macrology up the wazoo. */ /* * Count the number of arguments passed to MOZ_ASSERT, very carefully * tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a * single token in argument lists. See these URLs for details: *