Home | History | Annotate | Line # | Download | only in utils
      1 // Copyright 2010 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 // * Redistributions of source code must retain the above copyright
      9 //   notice, this list of conditions and the following disclaimer.
     10 // * Redistributions in binary form must reproduce the above copyright
     11 //   notice, this list of conditions and the following disclaimer in the
     12 //   documentation and/or other materials provided with the distribution.
     13 // * Neither the name of Google Inc. nor the names of its contributors
     14 //   may be used to endorse or promote products derived from this software
     15 //   without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 /// \file utils/sanity.hpp
     30 ///
     31 /// Set of macros that replace the standard assert(3) macro with more semantical
     32 /// expressivity and meaningful diagnostics.  Code should never use assert(3)
     33 /// directly.
     34 ///
     35 /// In general, the checks performed by the macros in this code are only
     36 /// executed if the code is built with debugging support (that is, if the NDEBUG
     37 /// macro is NOT defined).
     38 
     39 #if !defined(UTILS_SANITY_HPP)
     40 #define UTILS_SANITY_HPP
     41 
     42 #include <cstddef>
     43 #include <string>
     44 
     45 #include "utils/defs.hpp"
     46 
     47 namespace utils {
     48 
     49 
     50 /// Enumeration to define the assertion type.
     51 ///
     52 /// The assertion type is used by the module to format the assertion messages
     53 /// appropriately.
     54 enum assert_type {
     55     invariant,
     56     postcondition,
     57     precondition,
     58     unreachable,
     59 };
     60 
     61 
     62 void sanity_failure(const assert_type, const char*, const size_t,
     63                     const std::string&) UTILS_NORETURN;
     64 
     65 
     66 void install_crash_handlers(const std::string&);
     67 
     68 
     69 }  // namespace utils
     70 
     71 
     72 /// \def _UTILS_ASSERT(type, expr, message)
     73 /// \brief Performs an assertion check.
     74 ///
     75 /// This macro is internal and should not be used directly.
     76 ///
     77 /// Ensures that the given expression expr is true and, if not, terminates
     78 /// execution by calling utils::sanity_failure().  The check is only performed
     79 /// in debug builds.
     80 ///
     81 /// \param type The assertion type as defined by assert_type.
     82 /// \param expr A boolean expression.
     83 /// \param message A string describing the nature of the error.
     84 #if !defined(NDEBUG)
     85 #   define _UTILS_ASSERT(type, expr, message) \
     86     do { \
     87         if (!(expr)) \
     88             utils::sanity_failure(type, __FILE__, __LINE__, message); \
     89     } while (0)
     90 #else  // defined(NDEBUG)
     91 #   define _UTILS_ASSERT(type, expr, message) do {} while (0)
     92 #endif  // !defined(NDEBUG)
     93 
     94 
     95 /// Ensures that an invariant holds.
     96 ///
     97 /// If the invariant does not hold, execution is immediately terminated.  The
     98 /// check is only performed in debug builds.
     99 ///
    100 /// The error message printed by this macro is a textual representation of the
    101 /// boolean condition.  If you want to provide a custom error message, use
    102 /// INV_MSG instead.
    103 ///
    104 /// \param expr A boolean expression describing the invariant.
    105 #define INV(expr) _UTILS_ASSERT(utils::invariant, expr, #expr)
    106 
    107 
    108 /// Ensures that an invariant holds using a custom error message.
    109 ///
    110 /// If the invariant does not hold, execution is immediately terminated.  The
    111 /// check is only performed in debug builds.
    112 ///
    113 /// \param expr A boolean expression describing the invariant.
    114 /// \param msg The error message to print if the condition is false.
    115 #define INV_MSG(expr, msg) _UTILS_ASSERT(utils::invariant, expr, msg)
    116 
    117 
    118 /// Ensures that a precondition holds.
    119 ///
    120 /// If the precondition does not hold, execution is immediately terminated.  The
    121 /// check is only performed in debug builds.
    122 ///
    123 /// The error message printed by this macro is a textual representation of the
    124 /// boolean condition.  If you want to provide a custom error message, use
    125 /// PRE_MSG instead.
    126 ///
    127 /// \param expr A boolean expression describing the precondition.
    128 #define PRE(expr) _UTILS_ASSERT(utils::precondition, expr, #expr)
    129 
    130 
    131 /// Ensures that a precondition holds using a custom error message.
    132 ///
    133 /// If the precondition does not hold, execution is immediately terminated.  The
    134 /// check is only performed in debug builds.
    135 ///
    136 /// \param expr A boolean expression describing the precondition.
    137 /// \param msg The error message to print if the condition is false.
    138 #define PRE_MSG(expr, msg) _UTILS_ASSERT(utils::precondition, expr, msg)
    139 
    140 
    141 /// Ensures that an postcondition holds.
    142 ///
    143 /// If the postcondition does not hold, execution is immediately terminated.
    144 /// The check is only performed in debug builds.
    145 ///
    146 /// The error message printed by this macro is a textual representation of the
    147 /// boolean condition.  If you want to provide a custom error message, use
    148 /// POST_MSG instead.
    149 ///
    150 /// \param expr A boolean expression describing the postcondition.
    151 #define POST(expr) _UTILS_ASSERT(utils::postcondition, expr, #expr)
    152 
    153 
    154 /// Ensures that a postcondition holds using a custom error message.
    155 ///
    156 /// If the postcondition does not hold, execution is immediately terminated.
    157 /// The check is only performed in debug builds.
    158 ///
    159 /// \param expr A boolean expression describing the postcondition.
    160 /// \param msg The error message to print if the condition is false.
    161 #define POST_MSG(expr, msg) _UTILS_ASSERT(utils::postcondition, expr, msg)
    162 
    163 
    164 /// Ensures that a code path is not reached.
    165 ///
    166 /// If the code path in which this macro is located is reached, execution is
    167 /// immediately terminated.  Given that such a condition is critical for the
    168 /// execution of the program (and to prevent build failures due to some code
    169 /// paths not initializing variables, for example), this condition is fatal both
    170 /// in debug and production builds.
    171 ///
    172 /// The error message printed by this macro is a textual representation of the
    173 /// boolean condition.  If you want to provide a custom error message, use
    174 /// POST_MSG instead.
    175 #define UNREACHABLE UNREACHABLE_MSG("")
    176 
    177 
    178 /// Ensures that a code path is not reached using a custom error message.
    179 ///
    180 /// If the code path in which this macro is located is reached, execution is
    181 /// immediately terminated.  Given that such a condition is critical for the
    182 /// execution of the program (and to prevent build failures due to some code
    183 /// paths not initializing variables, for example), this condition is fatal both
    184 /// in debug and production builds.
    185 ///
    186 /// \param msg The error message to print if the condition is false.
    187 #define UNREACHABLE_MSG(msg) \
    188     do { \
    189         utils::sanity_failure(utils::unreachable, __FILE__, __LINE__, msg); \
    190     } while (0)
    191 
    192 
    193 #endif  // !defined(UTILS_SANITY_HPP)
    194