mfbt/Assertions.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/Assertions.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,428 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/* Implementations of runtime and static assertion macros for C and C++. */
    1.11 +
    1.12 +#ifndef mozilla_Assertions_h
    1.13 +#define mozilla_Assertions_h
    1.14 +
    1.15 +#include "mozilla/Attributes.h"
    1.16 +#include "mozilla/Compiler.h"
    1.17 +#include "mozilla/Likely.h"
    1.18 +#include "mozilla/MacroArgs.h"
    1.19 +
    1.20 +#include <stddef.h>
    1.21 +#include <stdio.h>
    1.22 +#include <stdlib.h>
    1.23 +#ifdef WIN32
    1.24 +   /*
    1.25 +    * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
    1.26 +    * further depends on <windef.h>.  We hardcode these few definitions manually
    1.27 +    * because those headers clutter the global namespace with a significant
    1.28 +    * number of undesired macros and symbols.
    1.29 +    */
    1.30 +#  ifdef __cplusplus
    1.31 +   extern "C" {
    1.32 +#  endif
    1.33 +   __declspec(dllimport) int __stdcall
    1.34 +   TerminateProcess(void* hProcess, unsigned int uExitCode);
    1.35 +   __declspec(dllimport) void* __stdcall GetCurrentProcess(void);
    1.36 +#  ifdef __cplusplus
    1.37 +   }
    1.38 +#  endif
    1.39 +#else
    1.40 +#  include <signal.h>
    1.41 +#endif
    1.42 +#ifdef ANDROID
    1.43 +#  include <android/log.h>
    1.44 +#endif
    1.45 +
    1.46 +/*
    1.47 + * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time* in C.
    1.48 + * In C++11, static_assert is provided by the compiler to the same effect.
    1.49 + * This can be useful when you make certain assumptions about what must hold for
    1.50 + * optimal, or even correct, behavior.  For example, you might assert that the
    1.51 + * size of a struct is a multiple of the target architecture's word size:
    1.52 + *
    1.53 + *   struct S { ... };
    1.54 + *   // C
    1.55 + *   MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
    1.56 + *                     "S should be a multiple of word size for efficiency");
    1.57 + *   // C++11
    1.58 + *   static_assert(sizeof(S) % sizeof(size_t) == 0,
    1.59 + *                 "S should be a multiple of word size for efficiency");
    1.60 + *
    1.61 + * This macro can be used in any location where both an extern declaration and a
    1.62 + * typedef could be used.
    1.63 + */
    1.64 +#ifndef __cplusplus
    1.65 +   /*
    1.66 +    * Some of the definitions below create an otherwise-unused typedef.  This
    1.67 +    * triggers compiler warnings with some versions of gcc, so mark the typedefs
    1.68 +    * as permissibly-unused to disable the warnings.
    1.69 +    */
    1.70 +#  if defined(__GNUC__)
    1.71 +#    define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
    1.72 +#  else
    1.73 +#    define MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE /* nothing */
    1.74 +#  endif
    1.75 +#  define MOZ_STATIC_ASSERT_GLUE1(x, y)          x##y
    1.76 +#  define MOZ_STATIC_ASSERT_GLUE(x, y)           MOZ_STATIC_ASSERT_GLUE1(x, y)
    1.77 +#  if defined(__SUNPRO_CC)
    1.78 +     /*
    1.79 +      * The Sun Studio C++ compiler is buggy when declaring, inside a function,
    1.80 +      * another extern'd function with an array argument whose length contains a
    1.81 +      * sizeof, triggering the error message "sizeof expression not accepted as
    1.82 +      * size of array parameter".  This bug (6688515, not public yet) would hit
    1.83 +      * defining moz_static_assert as a function, so we always define an extern
    1.84 +      * array for Sun Studio.
    1.85 +      *
    1.86 +      * We include the line number in the symbol name in a best-effort attempt
    1.87 +      * to avoid conflicts (see below).
    1.88 +      */
    1.89 +#    define MOZ_STATIC_ASSERT(cond, reason) \
    1.90 +       extern char MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)[(cond) ? 1 : -1]
    1.91 +#  elif defined(__COUNTER__)
    1.92 +     /*
    1.93 +      * If there was no preferred alternative, use a compiler-agnostic version.
    1.94 +      *
    1.95 +      * Note that the non-__COUNTER__ version has a bug in C++: it can't be used
    1.96 +      * in both |extern "C"| and normal C++ in the same translation unit.  (Alas
    1.97 +      * |extern "C"| isn't allowed in a function.)  The only affected compiler
    1.98 +      * we really care about is gcc 4.2.  For that compiler and others like it,
    1.99 +      * we include the line number in the function name to do the best we can to
   1.100 +      * avoid conflicts.  These should be rare: a conflict would require use of
   1.101 +      * MOZ_STATIC_ASSERT on the same line in separate files in the same
   1.102 +      * translation unit, *and* the uses would have to be in code with
   1.103 +      * different linkage, *and* the first observed use must be in C++-linkage
   1.104 +      * code.
   1.105 +      */
   1.106 +#    define MOZ_STATIC_ASSERT(cond, reason) \
   1.107 +       typedef int MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __COUNTER__)[(cond) ? 1 : -1] MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
   1.108 +#  else
   1.109 +#    define MOZ_STATIC_ASSERT(cond, reason) \
   1.110 +       extern void MOZ_STATIC_ASSERT_GLUE(moz_static_assert, __LINE__)(int arg[(cond) ? 1 : -1]) MOZ_STATIC_ASSERT_UNUSED_ATTRIBUTE
   1.111 +#  endif
   1.112 +
   1.113 +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason)  MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
   1.114 +#else
   1.115 +#define MOZ_STATIC_ASSERT_IF(cond, expr, reason)  static_assert(!(cond) || (expr), reason)
   1.116 +#endif
   1.117 +
   1.118 +#ifdef __cplusplus
   1.119 +extern "C" {
   1.120 +#endif
   1.121 +
   1.122 +/*
   1.123 + * Prints |s| as an assertion failure (using file and ln as the location of the
   1.124 + * assertion) to the standard debug-output channel.
   1.125 + *
   1.126 + * Usually you should use MOZ_ASSERT or MOZ_CRASH instead of this method.  This
   1.127 + * method is primarily for internal use in this header, and only secondarily
   1.128 + * for use in implementing release-build assertions.
   1.129 + */
   1.130 +static MOZ_ALWAYS_INLINE void
   1.131 +MOZ_ReportAssertionFailure(const char* s, const char* file, int ln)
   1.132 +{
   1.133 +#ifdef ANDROID
   1.134 +  __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
   1.135 +                      "Assertion failure: %s, at %s:%d\n", s, file, ln);
   1.136 +#else
   1.137 +  fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
   1.138 +  fflush(stderr);
   1.139 +#endif
   1.140 +}
   1.141 +
   1.142 +static MOZ_ALWAYS_INLINE void
   1.143 +MOZ_ReportCrash(const char* s, const char* file, int ln)
   1.144 +{
   1.145 +#ifdef ANDROID
   1.146 +    __android_log_print(ANDROID_LOG_FATAL, "MOZ_CRASH",
   1.147 +                        "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln);
   1.148 +#else
   1.149 +  fprintf(stderr, "Hit MOZ_CRASH(%s) at %s:%d\n", s, file, ln);
   1.150 +  fflush(stderr);
   1.151 +#endif
   1.152 +}
   1.153 +
   1.154 +/**
   1.155 + * MOZ_REALLY_CRASH is used in the implementation of MOZ_CRASH().  You should
   1.156 + * call MOZ_CRASH instead.
   1.157 + */
   1.158 +#if defined(_MSC_VER)
   1.159 +   /*
   1.160 +    * On MSVC use the __debugbreak compiler intrinsic, which produces an inline
   1.161 +    * (not nested in a system function) breakpoint.  This distinctively invokes
   1.162 +    * Breakpad without requiring system library symbols on all stack-processing
   1.163 +    * machines, as a nested breakpoint would require.
   1.164 +    *
   1.165 +    * We use TerminateProcess with the exit code aborting would generate
   1.166 +    * because we don't want to invoke atexit handlers, destructors, library
   1.167 +    * unload handlers, and so on when our process might be in a compromised
   1.168 +    * state.
   1.169 +    *
   1.170 +    * We don't use abort() because it'd cause Windows to annoyingly pop up the
   1.171 +    * process error dialog multiple times.  See bug 345118 and bug 426163.
   1.172 +    *
   1.173 +    * We follow TerminateProcess() with a call to MOZ_NoReturn() so that the
   1.174 +    * compiler doesn't hassle us to provide a return statement after a
   1.175 +    * MOZ_REALLY_CRASH() call.
   1.176 +    *
   1.177 +    * (Technically these are Windows requirements, not MSVC requirements.  But
   1.178 +    * practically you need MSVC for debugging, and we only ship builds created
   1.179 +    * by MSVC, so doing it this way reduces complexity.)
   1.180 +    */
   1.181 +
   1.182 +__declspec(noreturn) __inline void MOZ_NoReturn() {}
   1.183 +
   1.184 +#  ifdef __cplusplus
   1.185 +#    define MOZ_REALLY_CRASH() \
   1.186 +       do { \
   1.187 +         ::__debugbreak(); \
   1.188 +         *((volatile int*) NULL) = 123; \
   1.189 +         ::TerminateProcess(::GetCurrentProcess(), 3); \
   1.190 +         ::MOZ_NoReturn(); \
   1.191 +       } while (0)
   1.192 +#  else
   1.193 +#    define MOZ_REALLY_CRASH() \
   1.194 +       do { \
   1.195 +         __debugbreak(); \
   1.196 +         *((volatile int*) NULL) = 123; \
   1.197 +         TerminateProcess(GetCurrentProcess(), 3); \
   1.198 +         MOZ_NoReturn(); \
   1.199 +       } while (0)
   1.200 +#  endif
   1.201 +#else
   1.202 +#  ifdef __cplusplus
   1.203 +#    define MOZ_REALLY_CRASH() \
   1.204 +       do { \
   1.205 +         *((volatile int*) NULL) = 123; \
   1.206 +         ::abort(); \
   1.207 +       } while (0)
   1.208 +#  else
   1.209 +#    define MOZ_REALLY_CRASH() \
   1.210 +       do { \
   1.211 +         *((volatile int*) NULL) = 123; \
   1.212 +         abort(); \
   1.213 +       } while (0)
   1.214 +#  endif
   1.215 +#endif
   1.216 +
   1.217 +/*
   1.218 + * MOZ_CRASH([explanation-string]) crashes the program, plain and simple, in a
   1.219 + * Breakpad-compatible way, in both debug and release builds.
   1.220 + *
   1.221 + * MOZ_CRASH is a good solution for "handling" failure cases when you're
   1.222 + * unwilling or unable to handle them more cleanly -- for OOM, for likely memory
   1.223 + * corruption, and so on.  It's also a good solution if you need safe behavior
   1.224 + * in release builds as well as debug builds.  But if the failure is one that
   1.225 + * should be debugged and fixed, MOZ_ASSERT is generally preferable.
   1.226 + *
   1.227 + * The optional explanation-string, if provided, must be a string literal
   1.228 + * explaining why we're crashing.  This argument is intended for use with
   1.229 + * MOZ_CRASH() calls whose rationale is non-obvious; don't use it if it's
   1.230 + * obvious why we're crashing.
   1.231 + *
   1.232 + * If we're a DEBUG build and we crash at a MOZ_CRASH which provides an
   1.233 + * explanation-string, we print the string to stderr.  Otherwise, we don't
   1.234 + * print anything; this is because we want MOZ_CRASH to be 100% safe in release
   1.235 + * builds, and it's hard to print to stderr safely when memory might have been
   1.236 + * corrupted.
   1.237 + */
   1.238 +#ifndef DEBUG
   1.239 +#  define MOZ_CRASH(...) MOZ_REALLY_CRASH()
   1.240 +#else
   1.241 +#  define MOZ_CRASH(...) \
   1.242 +     do { \
   1.243 +       MOZ_ReportCrash("" __VA_ARGS__, __FILE__, __LINE__); \
   1.244 +       MOZ_REALLY_CRASH(); \
   1.245 +     } while(0)
   1.246 +#endif
   1.247 +
   1.248 +#ifdef __cplusplus
   1.249 +} /* extern "C" */
   1.250 +#endif
   1.251 +
   1.252 +/*
   1.253 + * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
   1.254 + * debug builds.  If it is, execution continues.  Otherwise, an error message
   1.255 + * including the expression and the explanation-string (if provided) is printed,
   1.256 + * an attempt is made to invoke any existing debugger, and execution halts.
   1.257 + * MOZ_ASSERT is fatal: no recovery is possible.  Do not assert a condition
   1.258 + * which can correctly be falsy.
   1.259 + *
   1.260 + * The optional explanation-string, if provided, must be a string literal
   1.261 + * explaining the assertion.  It is intended for use with assertions whose
   1.262 + * correctness or rationale is non-obvious, and for assertions where the "real"
   1.263 + * condition being tested is best described prosaically.  Don't provide an
   1.264 + * explanation if it's not actually helpful.
   1.265 + *
   1.266 + *   // No explanation needed: pointer arguments often must not be NULL.
   1.267 + *   MOZ_ASSERT(arg);
   1.268 + *
   1.269 + *   // An explanation can be helpful to explain exactly how we know an
   1.270 + *   // assertion is valid.
   1.271 + *   MOZ_ASSERT(state == WAITING_FOR_RESPONSE,
   1.272 + *              "given that <thingA> and <thingB>, we must have...");
   1.273 + *
   1.274 + *   // Or it might disambiguate multiple identical (save for their location)
   1.275 + *   // assertions of the same expression.
   1.276 + *   MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
   1.277 + *              "we already set [[PrimitiveThis]] for this Boolean object");
   1.278 + *   MOZ_ASSERT(getSlot(PRIMITIVE_THIS_SLOT).isUndefined(),
   1.279 + *              "we already set [[PrimitiveThis]] for this String object");
   1.280 + *
   1.281 + * MOZ_ASSERT has no effect in non-debug builds.  It is designed to catch bugs
   1.282 + * *only* during debugging, not "in the field". If you want the latter, use
   1.283 + * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well.
   1.284 + */
   1.285 +
   1.286 +/* First the single-argument form. */
   1.287 +#define MOZ_ASSERT_HELPER1(expr) \
   1.288 +   do { \
   1.289 +     if (MOZ_UNLIKELY(!(expr))) { \
   1.290 +       MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \
   1.291 +       MOZ_REALLY_CRASH(); \
   1.292 +     } \
   1.293 +   } while (0)
   1.294 +/* Now the two-argument form. */
   1.295 +#define MOZ_ASSERT_HELPER2(expr, explain) \
   1.296 +   do { \
   1.297 +     if (MOZ_UNLIKELY(!(expr))) { \
   1.298 +       MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
   1.299 +       MOZ_REALLY_CRASH(); \
   1.300 +     } \
   1.301 +   } while (0)
   1.302 +
   1.303 +#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
   1.304 +#define MOZ_RELEASE_ASSERT(...) \
   1.305 +   MOZ_RELEASE_ASSERT_GLUE( \
   1.306 +     MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
   1.307 +     (__VA_ARGS__))
   1.308 +
   1.309 +#ifdef DEBUG
   1.310 +#  define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
   1.311 +#else
   1.312 +#  define MOZ_ASSERT(...) do { } while(0)
   1.313 +#endif /* DEBUG */
   1.314 +
   1.315 +/*
   1.316 + * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
   1.317 + * true.
   1.318 + *
   1.319 + *   MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
   1.320 + *
   1.321 + * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds.  It is
   1.322 + * designed to catch bugs during debugging, not "in the field".
   1.323 + */
   1.324 +#ifdef DEBUG
   1.325 +#  define MOZ_ASSERT_IF(cond, expr) \
   1.326 +     do { \
   1.327 +       if (cond) \
   1.328 +         MOZ_ASSERT(expr); \
   1.329 +     } while (0)
   1.330 +#else
   1.331 +#  define MOZ_ASSERT_IF(cond, expr)  do { } while (0)
   1.332 +#endif
   1.333 +
   1.334 +/*
   1.335 + * MOZ_ASSUME_UNREACHABLE_MARKER() expands to an expression which states that it is
   1.336 + * undefined behavior for execution to reach this point.  No guarantees are made
   1.337 + * about what will happen if this is reached at runtime.  Most code should
   1.338 + * probably use the higher level MOZ_ASSUME_UNREACHABLE, which uses this when
   1.339 + * appropriate.
   1.340 + */
   1.341 +#if defined(__clang__)
   1.342 +#  define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
   1.343 +#elif defined(__GNUC__)
   1.344 +   /*
   1.345 +    * __builtin_unreachable() was implemented in gcc 4.5.  If we don't have
   1.346 +    * that, call a noreturn function; abort() will do nicely.  Qualify the call
   1.347 +    * in C++ in case there's another abort() visible in local scope.
   1.348 +    */
   1.349 +#  if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0)
   1.350 +#    define MOZ_ASSUME_UNREACHABLE_MARKER() __builtin_unreachable()
   1.351 +#  else
   1.352 +#    ifdef __cplusplus
   1.353 +#      define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
   1.354 +#    else
   1.355 +#      define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
   1.356 +#    endif
   1.357 +#  endif
   1.358 +#elif defined(_MSC_VER)
   1.359 +#  define MOZ_ASSUME_UNREACHABLE_MARKER() __assume(0)
   1.360 +#else
   1.361 +#  ifdef __cplusplus
   1.362 +#    define MOZ_ASSUME_UNREACHABLE_MARKER() ::abort()
   1.363 +#  else
   1.364 +#    define MOZ_ASSUME_UNREACHABLE_MARKER() abort()
   1.365 +#  endif
   1.366 +#endif
   1.367 +
   1.368 +/*
   1.369 + * MOZ_ASSUME_UNREACHABLE([reason]) tells the compiler that it can assume that
   1.370 + * the macro call cannot be reached during execution.  This lets the compiler
   1.371 + * generate better-optimized code under some circumstances, at the expense of
   1.372 + * the program's behavior being undefined if control reaches the
   1.373 + * MOZ_ASSUME_UNREACHABLE.
   1.374 + *
   1.375 + * In Gecko, you probably should not use this macro outside of performance- or
   1.376 + * size-critical code, because it's unsafe.  If you don't care about code size
   1.377 + * or performance, you should probably use MOZ_ASSERT or MOZ_CRASH.
   1.378 + *
   1.379 + * SpiderMonkey is a different beast, and there it's acceptable to use
   1.380 + * MOZ_ASSUME_UNREACHABLE more widely.
   1.381 + *
   1.382 + * Note that MOZ_ASSUME_UNREACHABLE is noreturn, so it's valid not to return a
   1.383 + * value following a MOZ_ASSUME_UNREACHABLE call.
   1.384 + *
   1.385 + * Example usage:
   1.386 + *
   1.387 + *   enum ValueType {
   1.388 + *     VALUE_STRING,
   1.389 + *     VALUE_INT,
   1.390 + *     VALUE_FLOAT
   1.391 + *   };
   1.392 + *
   1.393 + *   int ptrToInt(ValueType type, void* value) {
   1.394 + *   {
   1.395 + *     // We know for sure that type is either INT or FLOAT, and we want this
   1.396 + *     // code to run as quickly as possible.
   1.397 + *     switch (type) {
   1.398 + *     case VALUE_INT:
   1.399 + *       return *(int*) value;
   1.400 + *     case VALUE_FLOAT:
   1.401 + *       return (int) *(float*) value;
   1.402 + *     default:
   1.403 + *       MOZ_ASSUME_UNREACHABLE("can only handle VALUE_INT and VALUE_FLOAT");
   1.404 + *     }
   1.405 + *   }
   1.406 + */
   1.407 +#if defined(DEBUG)
   1.408 +#  define MOZ_ASSUME_UNREACHABLE(...) \
   1.409 +     do { \
   1.410 +       MOZ_ASSERT(false, "MOZ_ASSUME_UNREACHABLE(" __VA_ARGS__ ")"); \
   1.411 +       MOZ_ASSUME_UNREACHABLE_MARKER(); \
   1.412 +     } while (0)
   1.413 +#else
   1.414 +#  define MOZ_ASSUME_UNREACHABLE(reason)  MOZ_ASSUME_UNREACHABLE_MARKER()
   1.415 +#endif
   1.416 +
   1.417 +/*
   1.418 + * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
   1.419 + * expression, in debug builds and in release builds both.  Then, in debug
   1.420 + * builds only, the value of the expression is asserted either true or false
   1.421 + * using MOZ_ASSERT.
   1.422 + */
   1.423 +#ifdef DEBUG
   1.424 +#  define MOZ_ALWAYS_TRUE(expr)      MOZ_ASSERT((expr))
   1.425 +#  define MOZ_ALWAYS_FALSE(expr)     MOZ_ASSERT(!(expr))
   1.426 +#else
   1.427 +#  define MOZ_ALWAYS_TRUE(expr)      ((void)(expr))
   1.428 +#  define MOZ_ALWAYS_FALSE(expr)     ((void)(expr))
   1.429 +#endif
   1.430 +
   1.431 +#endif /* mozilla_Assertions_h */

mercurial