Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 1 | .. _module-pw_assert: |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 2 | |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 3 | ========= |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 4 | pw_assert |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 5 | ========= |
| 6 | |
| 7 | -------- |
| 8 | Overview |
| 9 | -------- |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 10 | Pigweed's assert module enables applications to check preconditions, triggering |
| 11 | a crash if the condition is not met. Consistent use of asserts is one aspect of |
| 12 | defensive programming that can lead to more reliable and less buggy code. |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 13 | |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 14 | The assert API facilitates flexible crash handling through Pigweed's facade |
Shiva Rajagopal | 9e51656 | 2021-05-11 17:04:15 -0700 | [diff] [blame] | 15 | mechanism. The API is designed to enable features like: |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 16 | |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 17 | - Optional ancillary printf-style messages along assertions |
| 18 | - Capturing actual values of binary operator assertions like ``a < b`` |
| 19 | - Compatibility with pw_tokenizer for reduced binary code size |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 20 | |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 21 | The ``pw_assert`` API provides three classes of macros: |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 22 | |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 23 | - **PW_CRASH(format, ...)** - Trigger a crash with a message. |
| 24 | - **PW_CHECK(condition[, format, ...])** - Assert a condition, optionally with |
| 25 | a message. |
| 26 | - **PW_CHECK_<type>_<cmp>(a, b[, fmt, ...])** - Assert that the expression ``a |
| 27 | <cmp> b`` is true, optionally with a message. |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 28 | - **PW_ASSERT(condition)** - Header- and constexpr-safe assert. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 29 | |
| 30 | .. tip:: |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 31 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 32 | All of the ``CHECK`` macros optionally support a message with additional |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 33 | arguments, to assist in debugging when an assert triggers: |
| 34 | |
| 35 | .. code-block:: cpp |
| 36 | |
| 37 | PW_CHECK_INT_LE(ItemCount(), 100); |
| 38 | PW_CHECK_INT_LE(ItemCount(), 100, "System state: %s", GetStateStr()); |
| 39 | |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 40 | Example |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 41 | ======= |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 42 | |
| 43 | .. code-block:: cpp |
| 44 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 45 | #include "pw_assert/check.h" |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 46 | |
| 47 | int main() { |
| 48 | bool sensor_running = StartSensor(&msg); |
| 49 | PW_CHECK(sensor_running, "Sensor failed to start; code: %s", msg); |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 50 | |
| 51 | int temperature_c = ReadSensorCelcius(); |
| 52 | PW_CHECK_INT_LE(temperature_c, 100, |
| 53 | "System is way out of heat spec; state=%s", |
| 54 | ReadSensorStateString()); |
Keir Mierle | 3cee879 | 2020-01-22 17:08:13 -0800 | [diff] [blame] | 55 | } |
| 56 | |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 57 | .. tip:: |
| 58 | |
| 59 | All macros have both a ``CHECK`` and ``DCHECK`` variant. The ``CHECK`` |
| 60 | variant is always enabled, even in production. Generally, we advise making |
| 61 | most asserts ``CHECK`` rather than ``DCHECK``, unless there is a critical |
| 62 | performance or code size reason to use ``DCHECK``. |
| 63 | |
| 64 | .. code-block:: cpp |
| 65 | |
| 66 | // This assert is always enabled, even in production. |
| 67 | PW_CHECK_INT_LE(ItemCount(), 100); |
| 68 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 69 | // This assert is enabled based on ``PW_ASSERT_ENABLE_DEBUG``. |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 70 | // The functions ItemCount() and GetStateStr() are never called. |
| 71 | PW_DCHECK_INT_LE(ItemCount(), 100, "System state: %s", GetStateStr()); |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 72 | |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 73 | .. tip:: |
| 74 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 75 | Use ``PW_ASSERT`` from ``pw_assert/assert.h`` for asserts in headers or |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 76 | asserting in ``constexpr`` contexts. |
| 77 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 78 | Structure of Assert Modules |
| 79 | =========================== |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 80 | The module is split into two components: |
| 81 | |
| 82 | 1. The **facade** (this module) which is only a macro interface layer, and |
| 83 | performs the actual checks for the conditions. |
| 84 | 2. The **backend**, provided elsewhere, that handles the consequences of an |
| 85 | assert failing. Example backends include ``pw_assert_basic``, which prints a |
| 86 | useful message and either quits the application (on host) or hangs in a |
| 87 | while loop (on device). In the future, there will be a tokenized assert |
| 88 | backend. This is also where application or product specific crash handling |
| 89 | would go. |
| 90 | |
Wyatt Hepler | 1d22124 | 2021-09-07 15:42:21 -0700 | [diff] [blame] | 91 | .. mermaid:: |
Wyatt Hepler | 79ea2cf | 2021-09-07 13:24:26 -0700 | [diff] [blame] | 92 | |
Wyatt Hepler | 1d22124 | 2021-09-07 15:42:21 -0700 | [diff] [blame] | 93 | graph LR |
| 94 | facade --> backend |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 95 | |
| 96 | See the Backend API section below for more details. |
| 97 | |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 98 | ---------- |
| 99 | Facade API |
| 100 | ---------- |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 101 | The below functions describe the assert API functions that applications should |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 102 | invoke to assert. These macros are found in the ``pw_assert/check.h`` header. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 103 | |
| 104 | .. cpp:function:: PW_CRASH(format, ...) |
| 105 | |
| 106 | Trigger a crash with a message. Replaces LOG_FATAL() in other systems. Can |
| 107 | include a message with format arguments; for example: |
| 108 | |
| 109 | .. code-block:: cpp |
| 110 | |
| 111 | PW_CRASH("Unexpected: frobnitz in state: %s", frobnitz_state); |
| 112 | |
| 113 | Note: ``PW_CRASH`` is the equivalent of ``LOG_FATAL`` in other systems, where |
| 114 | a device crash is triggered with a message. In Pigweed, logging and |
| 115 | crashing/asserting are separated. There is a ``LOG_CRITICAL`` level in the |
| 116 | logging module, but it does not have side effects; for ``LOG_FATAL``, instead |
| 117 | use this macro (``PW_CRASH``). |
| 118 | |
| 119 | .. cpp:function:: PW_CHECK(condition) |
| 120 | .. cpp:function:: PW_CHECK(condition, format, ...) |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 121 | .. cpp:function:: PW_DCHECK(condition) |
| 122 | .. cpp:function:: PW_DCHECK(condition, format, ...) |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 123 | |
| 124 | Assert that a condition is true, optionally including a message with |
| 125 | arguments to report if the codition is false. |
| 126 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 127 | The ``DCHECK`` variants only run if ``PW_ASSERT_ENABLE_DEBUG`` is enabled; |
| 128 | otherwise, the entire statement is removed (and the expression not evaluated). |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 129 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 130 | Example: |
| 131 | |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 132 | .. code-block:: cpp |
| 133 | |
| 134 | PW_CHECK(StartTurbines()); |
| 135 | PW_CHECK(StartWarpDrive(), "Oddly warp drive couldn't start; ruh-roh!"); |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 136 | PW_CHECK(RunSelfTest(), "Failure in self test; try %d", TestAttempts()); |
| 137 | |
| 138 | .. attention:: |
| 139 | |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 140 | Don't use use ``PW_CHECK`` for binary comparisons or status checks! |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 141 | |
| 142 | Instead, use the ``PW_CHECK_<TYPE>_<OP>`` macros. These macros enable |
| 143 | capturing the value of the operands, and also tokenizing them if using a |
| 144 | tokenizing assert backend. For example, if ``x`` and ``b`` are integers, |
| 145 | use instead ``PW_CHECK_INT_LT(x, b)``. |
| 146 | |
Wyatt Hepler | 1b3da3a | 2021-01-07 13:26:57 -0800 | [diff] [blame] | 147 | Additionally, use ``PW_CHECK_OK(status)`` when checking for an OK status, |
| 148 | since it enables showing a human-readable status string rather than an |
| 149 | integer (e.g. ``status == RESOURCE_EXHAUSTED`` instead of ``status == 5``. |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 150 | |
| 151 | +------------------------------------+-------------------------------------+ |
| 152 | | **Do NOT do this** | **Do this instead** | |
| 153 | +------------------------------------+-------------------------------------+ |
| 154 | | ``PW_CHECK(a_int < b_int)`` | ``PW_CHECK_INT_LT(a_int, b_int)`` | |
| 155 | +------------------------------------+-------------------------------------+ |
| 156 | | ``PW_CHECK(a_ptr <= b_ptr)`` | ``PW_CHECK_PTR_LE(a_ptr, b_ptr)`` | |
| 157 | +------------------------------------+-------------------------------------+ |
Ewout van Bekkum | 9e97cfd | 2020-07-16 13:57:24 -0700 | [diff] [blame] | 158 | | ``PW_CHECK(Temp() <= 10.0)`` | ``PW_CHECK_FLOAT_EXACT_LE(`` | |
| 159 | | | `` Temp(), 10.0)`` | |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 160 | +------------------------------------+-------------------------------------+ |
Wyatt Hepler | 1b3da3a | 2021-01-07 13:26:57 -0800 | [diff] [blame] | 161 | | ``PW_CHECK(Foo() == OkStatus())`` | ``PW_CHECK_OK(Foo())`` | |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 162 | +------------------------------------+-------------------------------------+ |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 163 | |
Keir Mierle | fa8f89d | 2020-04-15 16:20:02 -0700 | [diff] [blame] | 164 | .. cpp:function:: PW_CHECK_NOTNULL(ptr) |
| 165 | .. cpp:function:: PW_CHECK_NOTNULL(ptr, format, ...) |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 166 | .. cpp:function:: PW_DCHECK_NOTNULL(ptr) |
| 167 | .. cpp:function:: PW_DCHECK_NOTNULL(ptr, format, ...) |
Keir Mierle | fa8f89d | 2020-04-15 16:20:02 -0700 | [diff] [blame] | 168 | |
| 169 | Assert that the given pointer is not ``NULL``, optionally including a message |
| 170 | with arguments to report if the pointer is ``NULL``. |
| 171 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 172 | The ``DCHECK`` variants only run if ``PW_ASSERT_ENABLE_DEBUG`` is enabled; |
| 173 | otherwise, the entire statement is removed (and the expression not evaluated). |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 174 | |
Keir Mierle | fa8f89d | 2020-04-15 16:20:02 -0700 | [diff] [blame] | 175 | .. code-block:: cpp |
| 176 | |
| 177 | Foo* foo = GetTheFoo() |
| 178 | PW_CHECK_NOTNULL(foo); |
| 179 | |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 180 | Bar* bar = GetSomeBar(); |
Keir Mierle | fa8f89d | 2020-04-15 16:20:02 -0700 | [diff] [blame] | 181 | PW_CHECK_NOTNULL(bar, "Weirdly got NULL bar; state: %d", MyState()); |
| 182 | |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 183 | .. cpp:function:: PW_CHECK_TYPE_OP(a, b) |
| 184 | .. cpp:function:: PW_CHECK_TYPE_OP(a, b, format, ...) |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 185 | .. cpp:function:: PW_DCHECK_TYPE_OP(a, b) |
| 186 | .. cpp:function:: PW_DCHECK_TYPE_OP(a, b, format, ...) |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 187 | |
| 188 | Asserts that ``a OP b`` is true, where ``a`` and ``b`` are converted to |
| 189 | ``TYPE``; with ``OP`` and ``TYPE`` described below. |
| 190 | |
| 191 | If present, the optional format message is reported on failure. Depending on |
| 192 | the backend, values of ``a`` and ``b`` will also be reported. |
| 193 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 194 | The ``DCHECK`` variants only run if ``PW_ASSERT_ENABLE_DEBUG`` is enabled; |
| 195 | otherwise, the entire statement is removed (and the expression not evaluated). |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 196 | |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 197 | Example, with no message: |
| 198 | |
| 199 | .. code-block:: cpp |
| 200 | |
| 201 | PW_CHECK_INT_LE(CurrentTemperature(), 100); |
| 202 | PW_CHECK_INT_LE(ItemCount(), 100); |
| 203 | |
| 204 | Example, with an included message and arguments: |
| 205 | |
| 206 | .. code-block:: cpp |
| 207 | |
Ewout van Bekkum | 9e97cfd | 2020-07-16 13:57:24 -0700 | [diff] [blame] | 208 | PW_CHECK_FLOAT_EXACT_GE(BatteryVoltage(), 3.2, |
| 209 | "System state=%s", SysState()); |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 210 | |
| 211 | Below is the full list of binary comparison assert macros, along with the |
| 212 | type specifier. The specifier is irrelevant to application authors but is |
| 213 | needed for backend implementers. |
| 214 | |
Ewout van Bekkum | 9e97cfd | 2020-07-16 13:57:24 -0700 | [diff] [blame] | 215 | +-------------------------+--------------+-----------+-----------------------+ |
| 216 | | Macro | a, b type | condition | a, b format specifier | |
| 217 | +-------------------------+--------------+-----------+-----------------------+ |
| 218 | | PW_CHECK_INT_LE | int | a <= b | %d | |
| 219 | +-------------------------+--------------+-----------+-----------------------+ |
| 220 | | PW_CHECK_INT_LT | int | a < b | %d | |
| 221 | +-------------------------+--------------+-----------+-----------------------+ |
| 222 | | PW_CHECK_INT_GE | int | a >= b | %d | |
| 223 | +-------------------------+--------------+-----------+-----------------------+ |
| 224 | | PW_CHECK_INT_GT | int | a > b | %d | |
| 225 | +-------------------------+--------------+-----------+-----------------------+ |
| 226 | | PW_CHECK_INT_EQ | int | a == b | %d | |
| 227 | +-------------------------+--------------+-----------+-----------------------+ |
| 228 | | PW_CHECK_INT_NE | int | a != b | %d | |
| 229 | +-------------------------+--------------+-----------+-----------------------+ |
| 230 | | PW_CHECK_UINT_LE | unsigned int | a <= b | %u | |
| 231 | +-------------------------+--------------+-----------+-----------------------+ |
| 232 | | PW_CHECK_UINT_LT | unsigned int | a < b | %u | |
| 233 | +-------------------------+--------------+-----------+-----------------------+ |
| 234 | | PW_CHECK_UINT_GE | unsigned int | a >= b | %u | |
| 235 | +-------------------------+--------------+-----------+-----------------------+ |
| 236 | | PW_CHECK_UINT_GT | unsigned int | a > b | %u | |
| 237 | +-------------------------+--------------+-----------+-----------------------+ |
| 238 | | PW_CHECK_UINT_EQ | unsigned int | a == b | %u | |
| 239 | +-------------------------+--------------+-----------+-----------------------+ |
| 240 | | PW_CHECK_UINT_NE | unsigned int | a != b | %u | |
| 241 | +-------------------------+--------------+-----------+-----------------------+ |
| 242 | | PW_CHECK_PTR_LE | void* | a <= b | %p | |
| 243 | +-------------------------+--------------+-----------+-----------------------+ |
| 244 | | PW_CHECK_PTR_LT | void* | a < b | %p | |
| 245 | +-------------------------+--------------+-----------+-----------------------+ |
| 246 | | PW_CHECK_PTR_GE | void* | a >= b | %p | |
| 247 | +-------------------------+--------------+-----------+-----------------------+ |
| 248 | | PW_CHECK_PTR_GT | void* | a > b | %p | |
| 249 | +-------------------------+--------------+-----------+-----------------------+ |
| 250 | | PW_CHECK_PTR_EQ | void* | a == b | %p | |
| 251 | +-------------------------+--------------+-----------+-----------------------+ |
| 252 | | PW_CHECK_PTR_NE | void* | a != b | %p | |
| 253 | +-------------------------+--------------+-----------+-----------------------+ |
| 254 | | PW_CHECK_FLOAT_EXACT_LE | float | a <= b | %f | |
| 255 | +-------------------------+--------------+-----------+-----------------------+ |
| 256 | | PW_CHECK_FLOAT_EXACT_LT | float | a < b | %f | |
| 257 | +-------------------------+--------------+-----------+-----------------------+ |
| 258 | | PW_CHECK_FLOAT_EXACT_GE | float | a >= b | %f | |
| 259 | +-------------------------+--------------+-----------+-----------------------+ |
| 260 | | PW_CHECK_FLOAT_EXACT_GT | float | a > b | %f | |
| 261 | +-------------------------+--------------+-----------+-----------------------+ |
| 262 | | PW_CHECK_FLOAT_EXACT_EQ | float | a == b | %f | |
| 263 | +-------------------------+--------------+-----------+-----------------------+ |
| 264 | | PW_CHECK_FLOAT_EXACT_NE | float | a != b | %f | |
| 265 | +-------------------------+--------------+-----------+-----------------------+ |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 266 | |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 267 | The above ``CHECK_*_*()`` are also available in DCHECK variants, which will |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 268 | only evaluate their arguments and trigger if the ``PW_ASSERT_ENABLE_DEBUG`` |
| 269 | macro is enabled. |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 270 | |
Ewout van Bekkum | 9e97cfd | 2020-07-16 13:57:24 -0700 | [diff] [blame] | 271 | +--------------------------+--------------+-----------+----------------------+ |
| 272 | | Macro | a, b type | condition | a, b format | |
| 273 | | | | | specifier | |
| 274 | +--------------------------+--------------+-----------+----------------------+ |
| 275 | | PW_DCHECK_INT_LE | int | a <= b | %d | |
| 276 | +--------------------------+--------------+-----------+----------------------+ |
| 277 | | PW_DCHECK_INT_LT | int | a < b | %d | |
| 278 | +--------------------------+--------------+-----------+----------------------+ |
| 279 | | PW_DCHECK_INT_GE | int | a >= b | %d | |
| 280 | +--------------------------+--------------+-----------+----------------------+ |
| 281 | | PW_DCHECK_INT_GT | int | a > b | %d | |
| 282 | +--------------------------+--------------+-----------+----------------------+ |
| 283 | | PW_DCHECK_INT_EQ | int | a == b | %d | |
| 284 | +--------------------------+--------------+-----------+----------------------+ |
| 285 | | PW_DCHECK_INT_NE | int | a != b | %d | |
| 286 | +--------------------------+--------------+-----------+----------------------+ |
| 287 | | PW_DCHECK_UINT_LE | unsigned int | a <= b | %u | |
| 288 | +--------------------------+--------------+-----------+----------------------+ |
| 289 | | PW_DCHECK_UINT_LT | unsigned int | a < b | %u | |
| 290 | +--------------------------+--------------+-----------+----------------------+ |
| 291 | | PW_DCHECK_UINT_GE | unsigned int | a >= b | %u | |
| 292 | +--------------------------+--------------+-----------+----------------------+ |
| 293 | | PW_DCHECK_UINT_GT | unsigned int | a > b | %u | |
| 294 | +--------------------------+--------------+-----------+----------------------+ |
| 295 | | PW_DCHECK_UINT_EQ | unsigned int | a == b | %u | |
| 296 | +--------------------------+--------------+-----------+----------------------+ |
| 297 | | PW_DCHECK_UINT_NE | unsigned int | a != b | %u | |
| 298 | +--------------------------+--------------+-----------+----------------------+ |
| 299 | | PW_DCHECK_PTR_LE | void* | a <= b | %p | |
| 300 | +--------------------------+--------------+-----------+----------------------+ |
| 301 | | PW_DCHECK_PTR_LT | void* | a < b | %p | |
| 302 | +--------------------------+--------------+-----------+----------------------+ |
| 303 | | PW_DCHECK_PTR_GE | void* | a >= b | %p | |
| 304 | +--------------------------+--------------+-----------+----------------------+ |
| 305 | | PW_DCHECK_PTR_GT | void* | a > b | %p | |
| 306 | +--------------------------+--------------+-----------+----------------------+ |
| 307 | | PW_DCHECK_PTR_EQ | void* | a == b | %p | |
| 308 | +--------------------------+--------------+-----------+----------------------+ |
| 309 | | PW_DCHECK_PTR_NE | void* | a != b | %p | |
| 310 | +--------------------------+--------------+-----------+----------------------+ |
| 311 | | PW_DCHECK_FLOAT_EXACT_LE | float | a <= b | %f | |
| 312 | +--------------------------+--------------+-----------+----------------------+ |
| 313 | | PW_DCHECK_FLOAT_EXACT_LT | float | a < b | %f | |
| 314 | +--------------------------+--------------+-----------+----------------------+ |
| 315 | | PW_DCHECK_FLOAT_EXACT_GE | float | a >= b | %f | |
| 316 | +--------------------------+--------------+-----------+----------------------+ |
| 317 | | PW_DCHECK_FLOAT_EXACT_GT | float | a > b | %f | |
| 318 | +--------------------------+--------------+-----------+----------------------+ |
| 319 | | PW_DCHECK_FLOAT_EXACT_EQ | float | a == b | %f | |
| 320 | +--------------------------+--------------+-----------+----------------------+ |
| 321 | | PW_DCHECK_FLOAT_EXACT_NE | float | a != b | %f | |
| 322 | +--------------------------+--------------+-----------+----------------------+ |
| 323 | |
| 324 | .. attention:: |
| 325 | |
| 326 | For float, proper comparator checks which take floating point |
| 327 | precision and ergo error accumulation into account are not provided on |
| 328 | purpose as this comes with some complexity and requires application |
| 329 | specific tolerances in terms of Units of Least Precision (ULP). Instead, |
| 330 | we recommend developers carefully consider how floating point precision and |
| 331 | error impact the data they are bounding and whether checks are appropriate. |
| 332 | |
| 333 | .. cpp:function:: PW_CHECK_FLOAT_NEAR(a, b, abs_tolerance) |
| 334 | .. cpp:function:: PW_CHECK_FLOAT_NEAR(a, b, abs_tolerance, format, ...) |
| 335 | .. cpp:function:: PW_DCHECK_FLOAT_NEAR(a, b, abs_tolerance) |
| 336 | .. cpp:function:: PW_DCHECK_FLOAT_NEAR(a, b, abs_tolerance, format, ...) |
| 337 | |
| 338 | Asserts that ``(a >= b - abs_tolerance) && (a <= b + abs_tolerance)`` is true, |
| 339 | where ``a``, ``b``, and ``abs_tolerance`` are converted to ``float``. |
| 340 | |
| 341 | .. note:: |
| 342 | This also asserts that ``abs_tolerance >= 0``. |
| 343 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 344 | The ``DCHECK`` variants only run if ``PW_ASSERT_ENABLE_DEBUG`` is enabled; |
| 345 | otherwise, the entire statement is removed (and the expression not evaluated). |
Ewout van Bekkum | 9e97cfd | 2020-07-16 13:57:24 -0700 | [diff] [blame] | 346 | |
| 347 | Example, with no message: |
| 348 | |
| 349 | .. code-block:: cpp |
| 350 | |
| 351 | PW_CHECK_FLOAT_NEAR(cos(0.0f), 1, 0.001); |
| 352 | |
| 353 | Example, with an included message and arguments: |
| 354 | |
| 355 | .. code-block:: cpp |
| 356 | |
| 357 | PW_CHECK_FLOAT_NEAR(FirstOperation(), RedundantOperation(), 0.1, |
| 358 | "System state=%s", SysState()); |
Keir Mierle | b9b8816 | 2020-04-15 20:43:09 -0700 | [diff] [blame] | 359 | |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 360 | .. cpp:function:: PW_CHECK_OK(status) |
| 361 | .. cpp:function:: PW_CHECK_OK(status, format, ...) |
| 362 | .. cpp:function:: PW_DCHECK_OK(status) |
| 363 | .. cpp:function:: PW_DCHECK_OK(status, format, ...) |
| 364 | |
Wyatt Hepler | 1b3da3a | 2021-01-07 13:26:57 -0800 | [diff] [blame] | 365 | Assert that ``status`` evaluates to ``pw::OkStatus()`` (in C++) or |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 366 | ``PW_STATUS_OK`` (in C). Optionally include a message with arguments to |
| 367 | report. |
| 368 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 369 | The ``DCHECK`` variants only run if ``PW_ASSERT_ENABLE_DEBUG`` is defined; |
| 370 | otherwise, the entire statement is removed (and the expression not evaluated). |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 371 | |
| 372 | .. code-block:: cpp |
| 373 | |
| 374 | pw::Status operation_status = DoSomeOperation(); |
| 375 | PW_CHECK_OK(operation_status); |
| 376 | |
| 377 | // Any expression that evaluates to a pw::Status or pw_Status works. |
| 378 | PW_CHECK_OK(DoTheThing(), "System state: %s", SystemState()); |
| 379 | |
| 380 | // C works too. |
| 381 | pw_Status c_status = DoMoreThings(); |
| 382 | PW_CHECK_OK(c_status, "System state: %s", SystemState()); |
| 383 | |
| 384 | .. note:: |
| 385 | |
Wyatt Hepler | 1b3da3a | 2021-01-07 13:26:57 -0800 | [diff] [blame] | 386 | Using ``PW_CHECK_OK(status)`` instead of ``PW_CHECK(status == OkStatus())`` |
Keir Mierle | 0fa7f7d | 2020-05-07 12:34:00 -0700 | [diff] [blame] | 387 | enables displaying an error message with a string version of the error |
| 388 | code; for example ``status == RESOURCE_EXHAUSTED`` instead of ``status == |
| 389 | 5``. |
| 390 | |
Erik Gilling | 703abad | 2021-11-09 11:54:44 -0800 | [diff] [blame] | 391 | .. _module-pw_assert-assert-api: |
| 392 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 393 | ---------- |
| 394 | Assert API |
| 395 | ---------- |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 396 | The normal ``PW_CHECK_*`` and ``PW_DCHECK_*`` family of macros are intended to |
| 397 | provide rich debug information, like the file, line number, value of operands |
| 398 | in boolean comparisons, and more. However, this comes at a cost: these macros |
| 399 | depend directly on the backend headers, and may perform complicated call-site |
| 400 | transformations like tokenization. |
| 401 | |
| 402 | There are several issues with the normal ``PW_CHECK_*`` suite of macros: |
| 403 | |
| 404 | 1. ``PW_CHECK_*`` in headers can cause ODR violations in the case of tokenized |
| 405 | asserts, due to differing module choices. |
| 406 | 2. ``PW_CHECK_*`` is not constexpr-safe. |
| 407 | 3. ``PW_CHECK_*`` can cause code bloat with some backends; this is the tradeoff |
| 408 | to get rich assert information. |
| 409 | 4. ``PW_CHECK_*`` can trigger circular dependencies when asserts are used from |
| 410 | low-level contexts, like in ``<span>``. |
| 411 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 412 | **PW_ASSERT** solves all of the above problems: No risk of ODR violations, are |
| 413 | constexpr safe, and have a tiny call site footprint; and there is no header |
| 414 | dependency on the backend preventing circular include issues. However, there |
| 415 | are **no format messages, no captured line number, no captured file, no captured |
| 416 | expression, or anything other than a binary indication of failure**. |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 417 | |
| 418 | Example |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 419 | ======= |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 420 | |
| 421 | .. code-block:: cpp |
| 422 | |
| 423 | // This example demonstrates asserting in a header. |
| 424 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 425 | #include "pw_assert/assert.h" |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 426 | |
| 427 | class InlinedSubsystem { |
| 428 | public: |
| 429 | void DoSomething() { |
| 430 | // GOOD: No problem; PW_ASSERT is fine to inline and place in a header. |
| 431 | PW_ASSERT(IsEnabled()); |
| 432 | } |
| 433 | void DoSomethingElse() { |
| 434 | // BAD: Generally avoid using PW_DCHECK() or PW_CHECK in headers. If you |
| 435 | // want rich asserts or logs, move the function into the .cc file, and |
| 436 | // then use PW_CHECK there. |
| 437 | PW_DCHECK(IsEnabled()); // DON'T DO THIS |
| 438 | } |
| 439 | }; |
| 440 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 441 | PW_ASSERT API Reference |
| 442 | ======================= |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 443 | .. cpp:function:: PW_ASSERT(condition) |
| 444 | |
| 445 | A header- and constexpr-safe version of ``PW_CHECK()``. |
| 446 | |
| 447 | If the given condition is false, crash the system. Otherwise, do nothing. |
| 448 | The condition is guaranteed to be evaluated. This assert implementation is |
| 449 | guaranteed to be constexpr-safe. |
| 450 | |
| 451 | .. cpp:function:: PW_DASSERT(condition) |
| 452 | |
| 453 | A header- and constexpr-safe version of ``PW_DCHECK()``. |
| 454 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 455 | Same as ``PW_ASSERT()``, except that if ``PW_ASSERT_ENABLE_DEBUG == 0``, the |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 456 | assert is disabled and condition is not evaluated. |
| 457 | |
| 458 | .. attention:: |
| 459 | |
| 460 | Unlike the ``PW_CHECK_*()`` suite of macros, ``PW_ASSERT()`` and |
| 461 | ``PW_DASSERT()`` capture no rich information like line numbers, the file, |
| 462 | expression arguments, or the stringified expression. Use these macros **only |
Alexei Frolov | 5a0450d | 2020-10-28 21:10:47 -0700 | [diff] [blame] | 463 | when absolutely necessary**---in headers, constexpr contexts, or in rare cases |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 464 | where the call site overhead of a full PW_CHECK must be avoided. |
| 465 | |
| 466 | Use ``PW_CHECK_*()`` whenever possible. |
| 467 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 468 | PW_ASSERT API Backend |
| 469 | ===================== |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 470 | The ``PW_ASSERT`` API ultimately calls the C function |
| 471 | ``pw_assert_HandleFailure()``, which must be provided by the ``pw_assert`` |
Wyatt Hepler | 6606466 | 2021-05-03 09:15:40 -0700 | [diff] [blame] | 472 | backend. The ``pw_assert_HandleFailure()`` function must not return. |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 473 | |
Wyatt Hepler | 8bd4fb0 | 2021-05-03 15:30:58 -0700 | [diff] [blame] | 474 | .. _module-pw_assert-circular-deps: |
| 475 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 476 | Avoiding Circular Dependencies With ``PW_ASSERT`` |
| 477 | ================================================= |
Wyatt Hepler | 3d0e315 | 2021-04-29 17:08:31 -0700 | [diff] [blame] | 478 | Because asserts are so widely used, including in low-level libraries, it is |
Wyatt Hepler | 8bd4fb0 | 2021-05-03 15:30:58 -0700 | [diff] [blame] | 479 | common for the ``pw_assert`` backend to cause circular dependencies. Because of |
| 480 | this, assert backends may avoid declaring explicit dependencies, instead relying |
| 481 | on include paths to access header files. |
Wyatt Hepler | 3d0e315 | 2021-04-29 17:08:31 -0700 | [diff] [blame] | 482 | |
Wyatt Hepler | 6166322 | 2021-05-06 10:57:43 -0700 | [diff] [blame] | 483 | In GN, the ``pw_assert`` backend's full implementation with true dependencies is |
| 484 | made available through the ``$dir_pw_assert:impl`` group. When |
| 485 | ``pw_assert_BACKEND`` is set, ``$dir_pw_assert:impl`` must be listed in the |
| 486 | ``pw_build_LINK_DEPS`` variable. See :ref:`module-pw_build-link-deps`. |
Wyatt Hepler | 8bd4fb0 | 2021-05-03 15:30:58 -0700 | [diff] [blame] | 487 | |
Wyatt Hepler | 6166322 | 2021-05-06 10:57:43 -0700 | [diff] [blame] | 488 | In the ``pw_assert``, the backend's full implementation is placed in the |
| 489 | ``$pw_assert_BACKEND.impl`` target. ``$dir_pw_assert:impl`` depends on this |
| 490 | backend target. The ``$pw_assert_BACKEND.impl`` target may be an empty group if |
| 491 | the backend target can use its dependencies directly without causing circular |
| 492 | dependencies. |
| 493 | |
| 494 | In order to break dependency cycles, the ``pw_assert_BACKEND`` target may need |
| 495 | to directly provide dependencies through include paths only, rather than GN |
| 496 | ``public_deps``. In this case, GN header checking can be disabled with |
| 497 | ``check_includes = false``. |
Wyatt Hepler | 3d0e315 | 2021-04-29 17:08:31 -0700 | [diff] [blame] | 498 | |
Armando Montanez | 179aa8e | 2021-03-10 11:46:35 -0800 | [diff] [blame] | 499 | .. _module-pw_assert-backend_api: |
| 500 | |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 501 | ----------- |
| 502 | Backend API |
| 503 | ----------- |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 504 | The backend controls what to do in the case of an assertion failure. In the |
| 505 | most basic cases, the backend could display the assertion failure on something |
| 506 | like sys_io and halt in a while loop waiting for a debugger. In other cases, |
| 507 | the backend could store crash details like the current thread's stack to flash. |
| 508 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 509 | This facade module (``pw_assert``) does not provide a backend. See |
Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 510 | :ref:`module-pw_assert_basic` for a basic implementation. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 511 | |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 512 | .. attention:: |
| 513 | |
| 514 | The facade macros (``PW_CRASH`` and related) are expected to behave like they |
Wyatt Hepler | 3d0e315 | 2021-04-29 17:08:31 -0700 | [diff] [blame] | 515 | have the ``[[noreturn]]`` attribute set. This implies that the backend handler |
| 516 | functions, ``PW_HANDLE_*`` defined by the backend, must not return. |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 517 | |
| 518 | In other words, the device must reboot. |
| 519 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 520 | The backend must provide the header |
| 521 | |
| 522 | ``pw_assert_backend/backend.h`` |
| 523 | |
| 524 | and that header must define the following macros: |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 525 | |
| 526 | .. cpp:function:: PW_HANDLE_CRASH(message, ...) |
| 527 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 528 | Trigger a system crash or halt, and if possible, deliver the specified |
| 529 | message and arguments to the user or developer. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 530 | |
| 531 | .. cpp:function:: PW_HANDLE_ASSERT_FAILURE(condition_str, message, ...) |
| 532 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 533 | Trigger a system crash or halt, and if possible, deliver the condition string |
| 534 | (indicating what expression was false) and the message with format arguments, |
| 535 | to the user or developer. |
| 536 | |
| 537 | This macro is invoked from the ``PW_CHECK`` facade macro if condition is |
| 538 | false. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 539 | |
| 540 | .. cpp:function:: PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE( \ |
| 541 | a_str, a_val, op_str, b_str, b_val, type_fmt, message, ...) |
| 542 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 543 | Trigger a system crash or halt for a failed binary comparison assert (e.g. |
| 544 | any of the ``PW_CHECK_<type>_<op>`` macros). The handler should combine the |
| 545 | assert components into a useful message for the user; though in some cases |
| 546 | this may not be possible. |
Keir Mierle | ec9bf1b | 2020-03-03 10:27:01 -0800 | [diff] [blame] | 547 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 548 | Consider the following example: |
| 549 | |
| 550 | .. code-block:: cpp |
| 551 | |
| 552 | int temp = 16; |
| 553 | int max_temp = 15; |
| 554 | PW_CHECK_INT_LE(temp, MAX_TEMP, "Got too hot; state: %s", GetSystemState()); |
| 555 | |
| 556 | In this block, the assert will trigger, which will cause the facade to invoke |
| 557 | the handler macro. Below is the meaning of the arguments, referencing to the |
| 558 | example: |
| 559 | |
| 560 | - ``a_str`` - Stringified first operand. In the example: ``"temp"``. |
| 561 | - ``a_val`` - The value of the first operand. In the example: ``16``. |
| 562 | - ``op_str`` - The string version of the operator. In the example: "<=". |
| 563 | - ``b_str`` - Stringified second operand. In the example: ``"max_temp"``. |
| 564 | - ``b_val`` - The value of the second operand. In the example: ``15``. |
| 565 | - ``type_fmt`` - The format code for the type. In the example: ``"%d"``. |
| 566 | - ``message, ...`` - A formatted message to go with the assert. In the |
| 567 | example: ``"Got too hot; state: %s", "ON_FIRE"``. |
| 568 | |
| 569 | .. tip:: |
| 570 | |
Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 571 | See :ref:`module-pw_assert_basic` for one way to combine these arguments |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 572 | into a meaningful error message. |
| 573 | |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 574 | Additionally, the backend must provide a link-time function for the |
| 575 | ``PW_ASSERT`` assert handler. This does not need to appear in the backend |
| 576 | header, but instead is in a ``.cc`` file. |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 577 | |
| 578 | .. cpp:function:: pw_assert_HandleFailure() |
| 579 | |
| 580 | Handle a low-level crash. This crash entry happens through |
Wyatt Hepler | a59998f | 2021-03-19 14:35:10 -0700 | [diff] [blame] | 581 | ``pw_assert/assert.h``. In this crash handler, there is no access to line, |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 582 | file, expression, or other rich assert information. Backends should do |
| 583 | something reasonable in this case; typically, capturing the stack is useful. |
| 584 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 585 | Backend Build Targets |
| 586 | ===================== |
Wyatt Hepler | 6166322 | 2021-05-06 10:57:43 -0700 | [diff] [blame] | 587 | In GN, the backend must provide a ``pw_assert.impl`` build target in the same |
| 588 | directory as the backend target. If the main backend target's dependencies would |
| 589 | cause dependency cycles, the actual backend implementation with its full |
| 590 | dependencies is placed in the ``pw_assert.impl`` target. If this is not |
| 591 | necessary, ``pw_assert.impl`` can be an empty group. Circular dependencies are a |
| 592 | common problem with ``pw_assert`` because it is so widely used. See |
| 593 | :ref:`module-pw_assert-circular-deps`. |
Wyatt Hepler | 8bd4fb0 | 2021-05-03 15:30:58 -0700 | [diff] [blame] | 594 | |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 595 | -------------------------- |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 596 | Frequently Asked Questions |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 597 | -------------------------- |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 598 | |
Keir Mierle | 3f35672 | 2020-07-31 00:43:43 -0700 | [diff] [blame] | 599 | When should DCHECK_* be used instead of CHECK_* and vice versa? |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 600 | =============================================================== |
Keir Mierle | 3f35672 | 2020-07-31 00:43:43 -0700 | [diff] [blame] | 601 | There is no hard and fast rule for when to use one or the other. |
| 602 | |
| 603 | In theory, ``DCHECK_*`` macros should never be used and all the asserts should |
| 604 | remain active in production. In practice, **assert statements come at a binary |
| 605 | size and runtime cost**, even when using extensions like a tokenized assert |
| 606 | backend that strips the stringified assert expression from the binary. Each |
| 607 | assert is **at least a branch with a function call**; depending on the assert |
| 608 | backend, that function call may take several arguments (like the message, the |
| 609 | file line number, the module, etc). These function calls can take 10-20 bytes |
| 610 | or more of ROM each. Thus, there is a balance to be struct between ``DCHECK_*`` |
| 611 | and ``CHECK_*``. |
| 612 | |
| 613 | Pigweed uses these conventions to decide between ``CHECK_*`` and ``DCHECK_*``: |
| 614 | |
| 615 | - **Prefer to use CHECK_* at public API boundaries** of modules, where an |
| 616 | invalid value is a clear programmer bug. In certain cases use ``DCHECK_*`` to |
| 617 | keep binary size small when in production; for example, in modules with a |
| 618 | large public API surface, or modules with many inlined functions in headers. |
| 619 | - **Avoid using CHECK_* macros in headers.** It is still OK to use ``CHECK_*`` |
| 620 | macros in headers, but carefully consider the cost, since inlined use of the |
| 621 | ``CHECK_*`` macros in headers will expand to the full assert cost for every |
| 622 | translation unit that includes the header and calls the function with the |
| 623 | ``CHECK_*`` instance. ``DCHECK_*`` macros are are better, but even they come |
| 624 | at a cost, since it is preferable to be able to compile a binary in debug |
| 625 | mode for as long as possible on the road to production. |
| 626 | - **Prefer to use DCHECK_* variants for internal asserts** that attempt to |
| 627 | catch module-author level programming errors. For example, use DCHECKs to |
| 628 | verify internal function preconditions, or other invariants that should |
| 629 | always be true but will likely never fire in production. In some cases using |
| 630 | ``CHECK_*`` macros for internal consistency checking can make sense, if the |
| 631 | runtime cost is low and there are only a couple of instances. |
| 632 | |
| 633 | .. tip:: |
| 634 | |
Keir Mierle | 481d829 | 2020-07-31 01:10:05 -0700 | [diff] [blame] | 635 | **Do not return error status codes for obvious API misuse** |
Keir Mierle | 3f35672 | 2020-07-31 00:43:43 -0700 | [diff] [blame] | 636 | |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 637 | Returning an error code may **mask the earliest sign of a bug** because |
| 638 | notifying the developer of the problem depends on correct propagation of the |
| 639 | error to upper levels of the system. Instead, prefer to use the ``CHECK_*`` |
| 640 | or ``DCHECK_*`` macros to ensure a prompt termination and warning to the |
| 641 | developer. |
Keir Mierle | 3f35672 | 2020-07-31 00:43:43 -0700 | [diff] [blame] | 642 | |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 643 | **Error status codes should be reserved for system misbehaviour or expected |
| 644 | exceptional cases**, like a sensor is not yet ready, or a storage subsystem |
| 645 | is full when writing. Doing ``CHECK_*`` assertions in those cases would be a |
Keir Mierle | 3f35672 | 2020-07-31 00:43:43 -0700 | [diff] [blame] | 646 | mistake; so use error codes in those cases instead. |
| 647 | |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 648 | How should objects be asserted against or compared? |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 649 | =================================================== |
Shiva Rajagopal | 9e51656 | 2021-05-11 17:04:15 -0700 | [diff] [blame] | 650 | Unfortunately, there is no native mechanism for this, and instead the way to |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 651 | assert object states or comparisons is with the normal ``PW_CHECK_*`` macros |
| 652 | that operate on booleans, ints, and floats. |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 653 | |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 654 | This is due to the requirement of supporting C and also tokenization. It may be |
Shiva Rajagopal | 9e51656 | 2021-05-11 17:04:15 -0700 | [diff] [blame] | 655 | possible support rich object comparisons by defining a convention for |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 656 | stringifying objects; however, this hasn't been added yet. Additionally, such a |
| 657 | mechanism would not work well with tokenization. In particular, it would |
| 658 | require runtime stringifying arguments and rendering them with ``%s``, which |
| 659 | leads to binary bloat even with tokenization. So it is likely that a rich |
| 660 | object assert API won't be added. |
| 661 | |
| 662 | Why was the assert facade designed this way? |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 663 | ============================================ |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 664 | The Pigweed assert API was designed taking into account the needs of several |
| 665 | past projects the team members were involved with. Based on those experiences, |
| 666 | the following were key requirements for the API: |
| 667 | |
| 668 | 1. **C compatibility** - Since asserts are typically invoked from arbitrary |
| 669 | contexts, including from vendor or third party code, the assert system must |
| 670 | have a C-compatible API. Some API functions working only in C++ is |
| 671 | acceptable, as long as the key functions work in C. |
| 672 | 2. **Capturing both expressions and values** - Since asserts can trigger in |
| 673 | ways that are not repeatable, it is important to capture rich diagnostic |
| 674 | information to help identifying the root cause of the fault. For asserts, |
| 675 | this means including the failing expression text, and optionally also |
| 676 | capturing failing expression values. For example, instead of capturing an |
| 677 | error with the expression (``x < y``), capturing an error with the |
| 678 | expression and values(``x < y, with x = 10, y = 0``). |
| 679 | 3. **Tokenization compatible** - It's important that the assert expressions |
| 680 | support tokenization; both the expression itself (e.g. ``a < b``) and the |
| 681 | message attached to the expression. For example: ``PW_CHECK(ItWorks(), "Ruh |
| 682 | roh: %d", some_int)``. |
| 683 | 4. **Customizable assert handling** - Most products need to support custom |
| 684 | handling of asserts. In some cases, an assert might trigger printing out |
| 685 | details to a UART; in other cases, it might trigger saving a log entry to |
| 686 | flash. The assert system must support this customization. |
| 687 | |
| 688 | The combination of #1, #2, and #3 led to the structure of the API. In |
| 689 | particular, the need to support tokenized asserts and the need to support |
| 690 | capturing values led to the choice of having ``PW_CHECK_INT_LE(a, b)`` instead |
| 691 | of ``PW_CHECK(a <= b)``. Needing to support tokenization is what drove the |
| 692 | facade & backend arrangement, since the backend must provide the raw macros for |
| 693 | asserting in that case, rather than terminating at a C-style API. |
| 694 | |
| 695 | Why isn't there a ``PW_CHECK_LE``? Why is the type (e.g. ``INT``) needed? |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 696 | ========================================================================= |
Keir Mierle | 49f8e7e | 2020-07-30 17:57:30 -0700 | [diff] [blame] | 697 | The problem with asserts like ``PW_CHECK_LE(a, b)`` instead of |
| 698 | ``PW_CHECK_INT_LE(a, b)`` or ``PW_CHECK_FLOAT_EXACT_LE(a, b)`` is that to |
| 699 | capture the arguments with the tokenizer, we need to know the types. Using the |
| 700 | preprocessor, it is impossible to dispatch based on the types of ``a`` and |
| 701 | ``b``, so unfortunately having a separate macro for each of the types commonly |
| 702 | asserted on is necessary. |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 703 | |
Ewout van Bekkum | 2aff88e | 2021-11-12 15:36:57 -0800 | [diff] [blame] | 704 | ---------------------------- |
| 705 | Module Configuration Options |
| 706 | ---------------------------- |
| 707 | The following configurations can be adjusted via compile-time configuration of |
| 708 | this module, see the |
| 709 | :ref:`module documentation <module-structure-compile-time-configuration>` for |
| 710 | more details. |
| 711 | |
| 712 | .. c:macro:: PW_ASSERT_ENABLE_DEBUG |
| 713 | |
| 714 | Controls whether ``DCHECK`` and ``DASSERT`` are enabled. |
| 715 | |
| 716 | This defaults to being disabled if ``NDEBUG`` is defined, else it is enabled |
| 717 | by default. |
| 718 | |
Keir Mierle | c1cb12d | 2020-06-01 11:59:41 -0700 | [diff] [blame] | 719 | ------------- |
| 720 | Compatibility |
| 721 | ------------- |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 722 | The facade is compatible with both C and C++. |
| 723 | |
| 724 | ---------------- |
| 725 | Roadmap & Status |
| 726 | ---------------- |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 727 | The Pigweed assert subsystem consiststs of several modules that work in |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 728 | coordination. This module is the facade (API), then a number of backends are |
| 729 | available to handle assert failures. Products can also define their own |
| 730 | backends. In some cases, the backends will have backends (like |
| 731 | ``pw_log_tokenized``). |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 732 | |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 733 | Below is a brief summary of what modules are ready for use: |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 734 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 735 | Available Assert Backends |
| 736 | ========================= |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 737 | - ``pw_assert`` - **Stable** - The assert facade (this module). This module is |
| 738 | stable, and in production use. The documentation is comprehensive and covers |
| 739 | the functionality. There are (a) tests for the facade macro processing logic, |
| 740 | using a fake assert backend; and (b) compile tests to verify that the |
| 741 | selected backend compiles with all supported assert constructions and types. |
| 742 | - ``pw_assert_basic`` - **Stable** - The assert basic module is a simple assert |
| 743 | handler that displays the failed assert line and the values of captured |
| 744 | arguments. Output is directed to ``pw_sys_io``. This module is a great |
| 745 | ready-to-roll module when bringing up a system, but is likely not the best |
| 746 | choice for production. |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 747 | - ``pw_assert_log`` - **Stable** - This assert backend redirects to logging, |
| 748 | but with a logging flag set that indicates an assert failure. This is our |
| 749 | advised approach to get **tokenized asserts**--by using tokenized logging, |
| 750 | then using the ``pw_assert_log`` backend. |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 751 | |
Keir Mierle | 854adec | 2020-09-03 14:07:19 -0700 | [diff] [blame] | 752 | Note: If one desires a null assert module (where asserts are removed), use |
| 753 | ``pw_assert_log`` in combination with ``pw_log_null``. This will direct asserts |
| 754 | to logs, then the logs are removed due to the null backend. |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 755 | |
Erik Gilling | 4091550 | 2021-11-12 17:16:48 +0000 | [diff] [blame] | 756 | Missing Functionality |
| 757 | ===================== |
Keir Mierle | 77d3cbd | 2020-08-03 21:14:38 -0700 | [diff] [blame] | 758 | - **Stack traces** - Pigweed doesn't have a reliable stack walker, which makes |
| 759 | displaying a stack trace on crash harder. We plan to add this eventually. |
| 760 | - **Snapshot integration** - Pigweed doesn't yet have a rich system state |
| 761 | capture system that can capture state like number of tasks, available memory, |
| 762 | and so on. Snapshot facilities are the obvious ones to run inside an assert |
| 763 | handler. It'll happen someday. |