1 /* 2 * Arm SCP/MCP Software 3 * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 8 #ifndef FWK_ASSERT_H 9 #define FWK_ASSERT_H 10 11 #include <fwk_attributes.h> 12 #include <fwk_noreturn.h> 13 14 #include <assert.h> 15 #include <stdbool.h> 16 17 /*! 18 * \addtogroup GroupLibFramework 19 * \defgroup GroupAssert Assertion Helpers 20 * 21 * \details The framework provides a number of assertion helpers to aid in 22 * debugging and documenting code. Most of these trigger a standard library 23 * assertion in some way, but they differ in when. 24 * 25 * Choosing the most appropriate assertion helper can be complex, so their 26 * individual purposes are summarised below: 27 * 28 * - ::fwk_trap() - it is unsafe to continue at all 29 * - ::fwk_unreachable() - this code is unreachable in normal 30 * operation, and it is unsafe to continue 31 * - ::fwk_unexpected() - this code is unreachable in normal operation, 32 * but it is safe to continue 33 * - ::fwk_assert(condition) - this condition holds true in normal 34 * operation, and it is unsafe to continue 35 * - ::fwk_check(condition) - this condition holds true in normal 36 * operation, but it is safe to continue (statements only) 37 * - ::fwk_expect(condition) - this condition holds true in normal 38 * operation, but it is safe to continue (branch conditions only) 39 * 40 * \{ 41 */ 42 43 /*! 44 * \brief Force a target-dependent abnormal program abort. 45 * 46 * \note The only behaviour guaranteed by this macro is that the program will 47 * terminate abnormally at the point that this macro is called. 48 */ 49 #define fwk_trap() __builtin_trap() 50 51 /*! 52 * \def fwk_unreachable 53 * 54 * \brief Mark a code path as unreachable. 55 * 56 * \details In debug builds, this macro will trigger an assertion. In release 57 * builds this code path will be marked as unreachable to the compiler. 58 * 59 * #### Example 60 * 61 * \code{.c} 62 * int do_something(int x) { 63 * switch (x) { 64 * case 0: 65 * return FWK_E_STATE; 66 * 67 * case 10: 68 * return FWK_SUCCESS; 69 * 70 * default: 71 * fwk_unreachable(); 72 * } 73 * } 74 * \endcode 75 * 76 * In this example, the code will assert in a debug build if the 77 * unreachable code is reached. In a release build the behaviour of the 78 * program is undefined. 79 */ 80 81 #if defined(NDEBUG) || defined(__clang_analyzer__) 82 # define fwk_unreachable() __builtin_unreachable() 83 #else 84 # define fwk_unreachable() fwk_assert((bool)false) 85 #endif 86 87 /*! 88 * \def fwk_unexpected 89 * 90 * \brief Mark a code path as unexpected. 91 * 92 * \details Unexpected code paths are paths which the code should never have 93 * taken, but which have associated error handling. 94 * 95 * In debug builds, this macro will trigger an assertion. In release 96 * builds, or if running tests, it will do nothing. 97 * 98 * #### Example 99 * 100 * \code{.c} 101 * if (rand() == 42) { 102 * fwk_unexpected(); 103 * 104 * return FWK_E_STATE; 105 * } 106 * 107 * return FWK_E_SUCCESS; 108 * \endcode 109 * 110 * In this example, the code will assert in a debug build if `rand()` 111 * returns `42`. In a release build the expectation will be removed and the 112 * function will return `FWK_E_STATE`. 113 */ 114 115 #if defined(NDEBUG) || defined(BUILD_TESTS) || defined(__clang_analyzer__) 116 # define fwk_unexpected() ((void)0) 117 #else 118 # define fwk_unexpected() fwk_assert((bool)false) 119 #endif 120 121 /*! 122 * \def fwk_assert 123 * 124 * \brief Assert an invariant. 125 * 126 * \details This macro will pass the condition to the standard C library's 127 * `assert()` macro, which will evaluate the condition and abort the 128 * program if the condition fails. 129 * 130 * Unlike `assert()`, this macro will _evaluate_ the condition regardless 131 * of whether assertions are enabled or not. 132 * 133 * \param condition Condition to test. 134 */ 135 136 #ifdef NDEBUG 137 # if FWK_HAS_BUILTIN(__builtin_assume) 138 # define fwk_assert(condition) \ 139 do { \ 140 bool c = (condition); \ 141 __builtin_assume(c); \ 142 } while (0) 143 # else 144 # define fwk_assert(condition) ((void)(condition)) 145 # endif 146 #else 147 # define fwk_assert(condition) assert(condition) 148 #endif 149 150 /*! 151 * \def fwk_check 152 * 153 * \brief Expect the success of a condition in a statement. 154 * 155 * \details In debug builds, the macro will evaluate the condition and trigger 156 * an assertion if it fails. In release builds, or if running tests, the 157 * macro will evaluate the condition and discard its result. 158 * 159 * #### Example 160 * 161 * \code{.c} 162 * fwk_check(*x > 5); 163 * 164 * *x = 42; 165 * \endcode 166 * 167 * In this example, the code will assert in a debug build if `*x` is 168 * greater than 5. In a release build the check will be removed and `*x` 169 * will be assigned `42`. 170 * 171 * \note This macro is similar to ::fwk_expect(), but expands to a statement 172 * rather than an expression, and does not do any branch weighting. 173 * 174 * \param condition Condition to test. 175 */ 176 177 #if defined(NDEBUG) || defined(BUILD_TESTS) 178 # define fwk_check(condition) ((void)(condition)) 179 #else 180 # define fwk_check(condition) fwk_assert(condition) 181 #endif 182 183 /*! 184 * \def fwk_expect 185 * 186 * \brief Expect the success of a condition in an expression. 187 * 188 * \details In debug builds, the macro will evaluate the condition and trigger 189 * an assertion if it fails. In release builds, or if running tests, the 190 * macro will evaluate the condition and discard its result. 191 * 192 * #### Example 193 * 194 * \code{.c} 195 * if (!fwk_expect(rand() != 42)) 196 * return FWK_E_STATE; 197 * 198 * return FWK_E_SUCCESS; 199 * \endcode 200 * 201 * In this example, the code will assert in a debug build if `rand` is 202 * equal to 42. In a release build the branch will be taken. 203 * 204 * \param condition Condition to test. 205 * 206 * \return The value of `condition`. 207 */ 208 209 #if defined(NDEBUG) || defined(BUILD_TESTS) 210 # define fwk_expect(condition) (bool)__builtin_expect((condition), 1) 211 #else 212 # define fwk_expect(condition) (bool)(fwk_check(condition), 1) 213 #endif 214 215 /*! 216 * \} 217 */ 218 219 #endif /* FWK_ASSERT_H */ 220