1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #ifdef __cplusplus
17 #include <type_traits>
18 #else
19 #include <stddef.h>
20 #endif // __cplusplus
21
22 // IWYU pragma: private, include "pw_assert/check.h"
23 // Note: This file depends on the backend header already being included.
24
25 #include "pw_assert/config.h"
26 #include "pw_preprocessor/compiler.h"
27
28 // PW_CRASH - Crash the system, with a message.
29 #define PW_CRASH(...) \
30 do { \
31 if (0) { /* Check args but don't execute to avoid multiple evaluation */ \
32 _pw_assert_CheckMessageArguments(" " __VA_ARGS__); \
33 } \
34 PW_HANDLE_CRASH(__VA_ARGS__); \
35 } while (0)
36
37 // PW_CHECK - If condition evaluates to false, crash. Message optional.
38 #define PW_CHECK(condition, ...) \
39 do { \
40 if (!(condition)) { \
41 _pw_assert_ConditionCannotContainThePercentCharacter( \
42 #condition); /* cannot use '%' in PW_CHECK conditions */ \
43 if (0) { /* Check args but don't execute to avoid multiple evaluation */ \
44 _pw_assert_CheckMessageArguments(" " __VA_ARGS__); \
45 } \
46 PW_HANDLE_ASSERT_FAILURE(#condition, "" __VA_ARGS__); \
47 } \
48 } while (0)
49
50 #define PW_DCHECK(...) \
51 do { \
52 if (PW_ASSERT_ENABLE_DEBUG) { \
53 PW_CHECK(__VA_ARGS__); \
54 } \
55 } while (0)
56
57 // PW_D?CHECK_<type>_<comparison> macros - Binary comparison asserts.
58 //
59 // The below blocks are structured in table form, violating the 80-column
60 // Pigweed style, in order to make it clearer what is common and what isn't
61 // between the multitude of assert macro instantiations. To best view this
62 // section, turn off editor wrapping or make your editor wide.
63 //
64 // clang-format off
65
66 // Checks for int: LE, LT, GE, GT, EQ.
67 #define PW_CHECK_INT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, int, "%d", __VA_ARGS__)
68 #define PW_CHECK_INT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, int, "%d", __VA_ARGS__)
69 #define PW_CHECK_INT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, int, "%d", __VA_ARGS__)
70 #define PW_CHECK_INT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, int, "%d", __VA_ARGS__)
71 #define PW_CHECK_INT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, int, "%d", __VA_ARGS__)
72 #define PW_CHECK_INT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, int, "%d", __VA_ARGS__)
73
74 // Debug checks for int: LE, LT, GE, GT, EQ.
75 #define PW_DCHECK_INT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_LE(__VA_ARGS__)
76 #define PW_DCHECK_INT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_LT(__VA_ARGS__)
77 #define PW_DCHECK_INT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_GE(__VA_ARGS__)
78 #define PW_DCHECK_INT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_GT(__VA_ARGS__)
79 #define PW_DCHECK_INT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_EQ(__VA_ARGS__)
80 #define PW_DCHECK_INT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_INT_NE(__VA_ARGS__)
81
82 // Checks for unsigned int: LE, LT, GE, GT, EQ.
83 #define PW_CHECK_UINT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, unsigned int, "%u", __VA_ARGS__)
84 #define PW_CHECK_UINT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, unsigned int, "%u", __VA_ARGS__)
85 #define PW_CHECK_UINT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, unsigned int, "%u", __VA_ARGS__)
86 #define PW_CHECK_UINT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, unsigned int, "%u", __VA_ARGS__)
87 #define PW_CHECK_UINT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, unsigned int, "%u", __VA_ARGS__)
88 #define PW_CHECK_UINT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, unsigned int, "%u", __VA_ARGS__)
89
90 // Debug checks for unsigned int: LE, LT, GE, GT, EQ.
91 #define PW_DCHECK_UINT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_LE(__VA_ARGS__)
92 #define PW_DCHECK_UINT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_LT(__VA_ARGS__)
93 #define PW_DCHECK_UINT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_GE(__VA_ARGS__)
94 #define PW_DCHECK_UINT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_GT(__VA_ARGS__)
95 #define PW_DCHECK_UINT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_EQ(__VA_ARGS__)
96 #define PW_DCHECK_UINT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_UINT_NE(__VA_ARGS__)
97
98 // Checks for pointer: LE, LT, GE, GT, EQ, NE.
99 #define PW_CHECK_PTR_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, const void*, "%p", __VA_ARGS__)
100 #define PW_CHECK_PTR_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, const void*, "%p", __VA_ARGS__)
101 #define PW_CHECK_PTR_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, const void*, "%p", __VA_ARGS__)
102 #define PW_CHECK_PTR_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, const void*, "%p", __VA_ARGS__)
103 #define PW_CHECK_PTR_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, const void*, "%p", __VA_ARGS__)
104 #define PW_CHECK_PTR_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, const void*, "%p", __VA_ARGS__)
105
106 // Check for pointer: NOTNULL. Use "nullptr" in C++, "NULL" in C.
107 #ifdef __cplusplus
108 #define PW_CHECK_NOTNULL(arga, ...) \
109 _PW_CHECK_BINARY_CMP_IMPL(arga, !=, nullptr, const void*, "%p", __VA_ARGS__)
110 #else // __cplusplus
111 #define PW_CHECK_NOTNULL(arga, ...) \
112 _PW_CHECK_BINARY_CMP_IMPL(arga, !=, NULL, const void*, "%p", __VA_ARGS__)
113 #endif // __cplusplus
114
115 // Debug checks for pointer: LE, LT, GE, GT, EQ, NE, and NOTNULL.
116 #define PW_DCHECK_PTR_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_LE(__VA_ARGS__)
117 #define PW_DCHECK_PTR_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_LT(__VA_ARGS__)
118 #define PW_DCHECK_PTR_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_GE(__VA_ARGS__)
119 #define PW_DCHECK_PTR_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_GT(__VA_ARGS__)
120 #define PW_DCHECK_PTR_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_EQ(__VA_ARGS__)
121 #define PW_DCHECK_PTR_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_PTR_NE(__VA_ARGS__)
122 #define PW_DCHECK_NOTNULL(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_NOTNULL(__VA_ARGS__)
123
124 // Checks for float: EXACT_LE, EXACT_LT, EXACT_GE, EXACT_GT, EXACT_EQ, EXACT_NE,
125 // NEAR.
126 #define PW_CHECK_FLOAT_NEAR(arga, argb, abs_tolerance, ...) \
127 _PW_CHECK_FLOAT_NEAR(arga, argb, abs_tolerance, __VA_ARGS__)
128 #define PW_CHECK_FLOAT_EXACT_LE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, <=, argb, float, "%f", __VA_ARGS__)
129 #define PW_CHECK_FLOAT_EXACT_LT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, < , argb, float, "%f", __VA_ARGS__)
130 #define PW_CHECK_FLOAT_EXACT_GE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, >=, argb, float, "%f", __VA_ARGS__)
131 #define PW_CHECK_FLOAT_EXACT_GT(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, > , argb, float, "%f", __VA_ARGS__)
132 #define PW_CHECK_FLOAT_EXACT_EQ(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, ==, argb, float, "%f", __VA_ARGS__)
133 #define PW_CHECK_FLOAT_EXACT_NE(arga, argb, ...) _PW_CHECK_BINARY_CMP_IMPL(arga, !=, argb, float, "%f", __VA_ARGS__)
134
135 // Debug checks for float: NEAR, EXACT_LE, EXACT_LT, EXACT_GE, EXACT_GT,
136 // EXACT_EQ.
137 #define PW_DCHECK_FLOAT_NEAR(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_NEAR(__VA_ARGS__)
138 #define PW_DCHECK_FLOAT_EXACT_LE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_LE(__VA_ARGS__)
139 #define PW_DCHECK_FLOAT_EXACT_LT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_LT(__VA_ARGS__)
140 #define PW_DCHECK_FLOAT_EXACT_GE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_GE(__VA_ARGS__)
141 #define PW_DCHECK_FLOAT_EXACT_GT(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_GT(__VA_ARGS__)
142 #define PW_DCHECK_FLOAT_EXACT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_EQ(__VA_ARGS__)
143 #define PW_DCHECK_FLOAT_EXACT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_NE(__VA_ARGS__)
144
145 // Debug checks for integer overflows: ADD, SUB, MUL.
146 #define PW_CHECK_ADD(a, b, out, ...) PW_CHECK(!PW_ADD_OVERFLOW(a, b, out), __VA_ARGS__)
147 #define PW_CHECK_SUB(a, b, out, ...) PW_CHECK(!PW_SUB_OVERFLOW(a, b, out), __VA_ARGS__)
148 #define PW_CHECK_MUL(a, b, out, ...) PW_CHECK(!PW_MUL_OVERFLOW(a, b, out), __VA_ARGS__)
149
150 // Debug checks for integer overflows: ADD, SUB, MUL.
151 #define PW_DCHECK_ADD(a, b, out, ...) PW_DCHECK(!PW_ADD_OVERFLOW(a, b, out), __VA_ARGS__)
152 #define PW_DCHECK_SUB(a, b, out, ...) PW_DCHECK(!PW_SUB_OVERFLOW(a, b, out), __VA_ARGS__)
153 #define PW_DCHECK_MUL(a, b, out, ...) PW_DCHECK(!PW_MUL_OVERFLOW(a, b, out), __VA_ARGS__)
154
155 // clang-format on
156
157 // PW_CHECK_OK - If expression does not evaluate to PW_STATUS_OK, crash.
158 // Message optional.
159 //
160 // In C++, expression must evaluate to a value convertible to Status via
161 // pw::internal::ConvertToStatus().
162 //
163 // In C, expression must evaluate to a pw_Status value.
164 #define PW_CHECK_OK(expression, ...) \
165 do { \
166 const _PW_CHECK_OK_STATUS _pw_assert_check_ok_status = \
167 _PW_CHECK_OK_TO_STATUS(expression); \
168 if (_pw_assert_check_ok_status != PW_STATUS_OK) { \
169 _PW_CHECK_BINARY_ARG_HANDLER( \
170 #expression, \
171 pw_StatusString(_pw_assert_check_ok_status), \
172 "==", \
173 "OkStatus()", \
174 "OK", \
175 "%s", \
176 "" __VA_ARGS__); \
177 } \
178 } while (0)
179
180 #ifdef __cplusplus
181 #define _PW_CHECK_OK_STATUS ::pw::Status
182 #define _PW_CHECK_OK_TO_STATUS(expr) ::pw::internal::ConvertToStatus(expr)
183 #else
184 #define _PW_CHECK_OK_STATUS pw_Status
185 #define _PW_CHECK_OK_TO_STATUS(expr) (expr)
186 #endif // __cplusplus
187
188 #define PW_DCHECK_OK(...) \
189 if (!(PW_ASSERT_ENABLE_DEBUG)) { \
190 } else \
191 PW_CHECK_OK(__VA_ARGS__)
192
193 // Use a static_cast in C++ to avoid accidental comparisons between e.g. an
194 // integer and the CHECK message const char*.
195 #if defined(__cplusplus) && __cplusplus >= 201703L
196
197 namespace pw::assert::internal {
198
199 template <typename T, typename U>
ConvertToType(U * value)200 constexpr const void* ConvertToType(U* value) {
201 if constexpr (std::is_function<U>()) {
202 return reinterpret_cast<const void*>(value);
203 } else {
204 return static_cast<const void*>(value);
205 }
206 }
207
208 template <typename T, typename U>
ConvertToType(const U & value)209 constexpr T ConvertToType(const U& value) {
210 return static_cast<T>(value);
211 }
212
213 } // namespace pw::assert::internal
214
215 #define _PW_CHECK_CONVERT(type, name, arg) \
216 type name = ::pw::assert::internal::ConvertToType<type>(arg)
217 #else
218 #define _PW_CHECK_CONVERT(type, name, arg) type name = (type)(arg)
219 #endif // __cplusplus
220
221 // For the binary assertions, this private macro is re-used for almost all of
222 // the variants. Due to limitations of C formatting, it is necessary to have
223 // separate macros for the types.
224 //
225 // The macro avoids evaluating the arguments multiple times at the cost of some
226 // macro complexity.
227 #define _PW_CHECK_BINARY_CMP_IMPL( \
228 arg_a, comparison_op, arg_b, type_decl, type_fmt, ...) \
229 do { \
230 _PW_CHECK_CONVERT(type_decl, evaluated_argument_a, arg_a); \
231 _PW_CHECK_CONVERT(type_decl, evaluated_argument_b, arg_b); \
232 if (!(evaluated_argument_a comparison_op evaluated_argument_b)) { \
233 _PW_CHECK_BINARY_ARG_HANDLER(#arg_a, \
234 evaluated_argument_a, \
235 #comparison_op, \
236 #arg_b, \
237 evaluated_argument_b, \
238 type_fmt, \
239 "" __VA_ARGS__); \
240 } \
241 } while (0)
242
243 // All binary comparison CHECK macros are directed to this handler before
244 // hitting the CHECK backend. This controls whether evaluated values are
245 // captured.
246 #if PW_ASSERT_CAPTURE_VALUES
247 #define _PW_CHECK_BINARY_ARG_HANDLER(arg_a_str, \
248 arg_a_val, \
249 comparison_op_str, \
250 arg_b_str, \
251 arg_b_val, \
252 type_fmt, \
253 ...) \
254 \
255 _pw_assert_ConditionCannotContainThePercentCharacter( \
256 arg_a_str arg_b_str); /* cannot use '%' in PW_CHECK conditions */ \
257 if (0) { /* Check args but don't execute to avoid multiple evaluation */ \
258 _pw_assert_CheckMessageArguments(" " __VA_ARGS__); \
259 } \
260 PW_HANDLE_ASSERT_BINARY_COMPARE_FAILURE(arg_a_str, \
261 arg_a_val, \
262 comparison_op_str, \
263 arg_b_str, \
264 arg_b_val, \
265 type_fmt, \
266 __VA_ARGS__)
267 #else
268 #define _PW_CHECK_BINARY_ARG_HANDLER(arg_a_str, \
269 arg_a_val, \
270 comparison_op_str, \
271 arg_b_str, \
272 arg_b_val, \
273 type_fmt, \
274 ...) \
275 _pw_assert_ConditionCannotContainThePercentCharacter( \
276 arg_a_str arg_b_str); /* cannot use '%' in PW_CHECK conditions */ \
277 if (0) { /* Check args but don't execute to avoid multiple evaluation */ \
278 _pw_assert_CheckMessageArguments(" " __VA_ARGS__); \
279 } \
280 PW_HANDLE_ASSERT_FAILURE(arg_a_str " " comparison_op_str " " arg_b_str, \
281 __VA_ARGS__)
282 #endif // PW_ASSERT_CAPTURE_VALUES
283
284 // Custom implementation for FLOAT_NEAR which is implemented through two
285 // underlying checks which are not trivially replaced through the use of
286 // FLOAT_EXACT_LE & FLOAT_EXACT_GE.
287 #define _PW_CHECK_FLOAT_NEAR(argument_a, argument_b, abs_tolerance, ...) \
288 do { \
289 PW_CHECK_FLOAT_EXACT_GE(abs_tolerance, 0.0f); \
290 float evaluated_argument_a = (float)(argument_a); \
291 float evaluated_argument_b_min = (float)(argument_b) - abs_tolerance; \
292 float evaluated_argument_b_max = (float)(argument_b) + abs_tolerance; \
293 if (!(evaluated_argument_a >= evaluated_argument_b_min)) { \
294 _PW_CHECK_BINARY_ARG_HANDLER(#argument_a, \
295 evaluated_argument_a, \
296 ">=", \
297 #argument_b " - abs_tolerance", \
298 evaluated_argument_b_min, \
299 "%f", \
300 "" __VA_ARGS__); \
301 } else if (!(evaluated_argument_a <= evaluated_argument_b_max)) { \
302 _PW_CHECK_BINARY_ARG_HANDLER(#argument_a, \
303 evaluated_argument_a, \
304 "<=", \
305 #argument_b " + abs_tolerance", \
306 evaluated_argument_b_max, \
307 "%f", \
308 "" __VA_ARGS__); \
309 } \
310 } while (0)
311
312 // This empty function allows the compiler to verify that the condition contains
313 // no % characters (modulus operator). Backends (pw_assert-tokenized in
314 // particular) may include the condition in the format string as a size
315 // optimization. Unintentionally introducing an extra argument could lead to
316 // problems. Checking the condition here ensures that the behavior is consistent
317 // for all backends.
318 //
319 // TODO: b/235149326 - Remove this restriction when pw_assert macros no longer
320 // accept arbitrary arguments.
321 static inline void _pw_assert_ConditionCannotContainThePercentCharacter(
322 const char* format, ...) PW_PRINTF_FORMAT(1, 2);
323
_pw_assert_ConditionCannotContainThePercentCharacter(const char * format,...)324 static inline void _pw_assert_ConditionCannotContainThePercentCharacter(
325 const char* format, ...) {
326 (void)format;
327 }
328
329 // Empty function for checking that arguments match the format string. This
330 // function also ensures arguments are considered "used" in PW_CHECK, even if
331 // the backend does not use them.
332 static inline void _pw_assert_CheckMessageArguments(const char* format, ...)
333 PW_PRINTF_FORMAT(1, 2);
334
_pw_assert_CheckMessageArguments(const char * format,...)335 static inline void _pw_assert_CheckMessageArguments(const char* format, ...) {
336 (void)format;
337 }
338