Commit | Line | Data |
---|---|---|
d98421f2 PP |
1 | /* |
2 | * SPDX-License-Identifier: MIT | |
3 | * | |
4 | * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation | |
5 | * Copyright (c) 2018-2020 Philippe Proulx <pproulx@efficios.com> | |
6 | */ | |
7 | ||
8 | #ifndef BABELTRACE_ASSERT_COND_INTERNAL_H | |
9 | #define BABELTRACE_ASSERT_COND_INTERNAL_H | |
10 | ||
11 | /* | |
12 | * The macros in this header use macros defined in "lib/logging.h". We | |
13 | * don't want this header to automatically include "lib/logging.h" | |
14 | * because you need to manually define BT_LOG_TAG before including | |
15 | * "lib/logging.h" and it is unexpected that you also need to define it | |
16 | * before including this header. | |
17 | * | |
18 | * This is a reminder that in order to use "lib/assert-cond.h", you also | |
19 | * need to use logging explicitly. | |
20 | */ | |
21 | ||
22 | #ifndef BT_LIB_LOG_SUPPORTED | |
23 | # error Include "lib/logging.h" before this header. | |
24 | #endif | |
25 | ||
26 | #include <stdbool.h> | |
27 | #include <stdlib.h> | |
28 | #include <inttypes.h> | |
29 | #include "common/common.h" | |
30 | #include "common/macros.h" | |
31 | ||
32 | /* | |
33 | * Prints the details of an unsatisfied precondition or postcondition | |
34 | * without immediately aborting. You should use this within a function | |
35 | * which checks preconditions or postconditions, but which is called | |
36 | * from a BT_ASSERT_PRE() or BT_ASSERT_POST() context, so that the | |
37 | * function can still return its result for | |
38 | * BT_ASSERT_PRE()/BT_ASSERT_POST() to evaluate it. | |
39 | * | |
40 | * Example: | |
41 | * | |
42 | * static inline bool check_complex_precond(...) | |
43 | * { | |
44 | * ... | |
45 | * | |
46 | * if (...) { | |
47 | * BT_ASSERT_COND_MSG("Invalid object: ...", ...); | |
48 | * return false; | |
49 | * } | |
50 | * | |
51 | * ... | |
52 | * } | |
53 | * | |
54 | * ... | |
55 | * | |
56 | * BT_ASSERT_PRE(check_complex_precond(...), | |
57 | * "Precondition is not satisfied: ...", ...); | |
58 | */ | |
59 | #define BT_ASSERT_COND_MSG(_fmt, ...) \ | |
60 | do { \ | |
61 | bt_lib_log(_BT_LOG_SRCLOC_FUNCTION, __FILE__, \ | |
62 | __LINE__, BT_LOG_FATAL, BT_LOG_TAG, \ | |
63 | (_fmt), ##__VA_ARGS__); \ | |
64 | } while (0) | |
65 | ||
66 | /* | |
67 | * Internal to this file: asserts that the library condition `_cond` of | |
68 | * type `_cond_type` (`pre` or `post`) is satisfied. | |
69 | * | |
70 | * If `_cond` is false, this macro logs a fatal message using `_fmt` and | |
71 | * the optional arguments (same usage as BT_LIB_LOGF()), and abort. | |
72 | * | |
73 | * To assert that an internal precondition or postcondition is | |
74 | * satisfied, use BT_ASSERT() or BT_ASSERT_DBG(). | |
75 | */ | |
76 | #define _BT_ASSERT_COND(_cond_type, _cond, _fmt, ...) \ | |
77 | do { \ | |
78 | if (!(_cond)) { \ | |
79 | BT_ASSERT_COND_MSG("Babeltrace 2 library " _cond_type "condition not satisfied. Error is:"); \ | |
80 | BT_ASSERT_COND_MSG(_fmt, ##__VA_ARGS__); \ | |
81 | BT_ASSERT_COND_MSG("Aborting..."); \ | |
82 | bt_common_abort(); \ | |
83 | } \ | |
84 | } while (0) | |
85 | ||
86 | /* | |
87 | * Asserts that the library precondition `_cond` is satisfied. | |
88 | * | |
89 | * If `_cond` is false, log a fatal message using `_fmt` and the | |
90 | * optional arguments (same usage as BT_LIB_LOGF()), and abort. | |
91 | * | |
92 | * To assert that a library postcondition is satisfied (return from user | |
93 | * code), use BT_ASSERT_POST(). | |
94 | * | |
95 | * To assert that an internal precondition or postcondition is | |
96 | * satisfied, use BT_ASSERT() or BT_ASSERT_DBG(). | |
97 | */ | |
98 | #define BT_ASSERT_PRE(_cond, _fmt, ...) \ | |
99 | _BT_ASSERT_COND("pre", _cond, _fmt, ##__VA_ARGS__) | |
100 | ||
101 | /* | |
102 | * Asserts that the library postcondition `_cond` is satisfied. | |
103 | * | |
104 | * If `_cond` is false, log a fatal message using `_fmt` and the | |
105 | * optional arguments (same usage as BT_LIB_LOGF()), and abort. | |
106 | * | |
107 | * To assert that a library precondition is satisfied (return from user | |
108 | * code), use BT_ASSERT_PRE(). | |
109 | * | |
110 | * To assert that an internal precondition or postcondition is | |
111 | * satisfied, use BT_ASSERT() or BT_ASSERT_DBG(). | |
112 | */ | |
113 | #define BT_ASSERT_POST(_cond, _fmt, ...) \ | |
114 | _BT_ASSERT_COND("post", _cond, _fmt, ##__VA_ARGS__) | |
115 | ||
116 | /* | |
117 | * Asserts that a given variable `_obj` named `_obj_name` (capitalized) | |
118 | * is not `NULL`. | |
119 | */ | |
120 | #define BT_ASSERT_PRE_NON_NULL(_obj, _obj_name) \ | |
121 | BT_ASSERT_PRE((_obj), "%s is NULL: ", _obj_name) | |
122 | ||
123 | /* | |
124 | * Asserts that a given index `_index` is less than a given length | |
125 | * `_length`. | |
126 | */ | |
127 | #define BT_ASSERT_PRE_VALID_INDEX(_index, _length) \ | |
128 | BT_ASSERT_PRE((_index) < (_length), \ | |
129 | "Index is out of bounds: index=%" PRIu64 ", " \ | |
130 | "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length)) | |
131 | ||
132 | /* | |
133 | * Asserts that the current thread has no error set. | |
134 | */ | |
135 | #define BT_ASSERT_PRE_NO_ERROR() \ | |
136 | do { \ | |
137 | const struct bt_error *err = bt_current_thread_take_error(); \ | |
138 | if (err) { \ | |
139 | bt_current_thread_move_error(err); \ | |
140 | } \ | |
141 | BT_ASSERT_PRE(!err, \ | |
142 | "API function called while current thread has an " \ | |
143 | "error: function=%s", __func__); \ | |
144 | } while (0) | |
145 | ||
146 | /* | |
147 | * Asserts that, if the current thread has an error, `_status` is an | |
148 | * error status code. | |
149 | * | |
150 | * Puts back the error in place (if there is one) such that if this | |
151 | * macro aborts, it will be possible to inspect it with a debugger. | |
152 | */ | |
153 | #define BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(_status) \ | |
154 | do { \ | |
155 | const struct bt_error *err = bt_current_thread_take_error(); \ | |
156 | if (err) { \ | |
157 | bt_current_thread_move_error(err); \ | |
158 | } \ | |
159 | BT_ASSERT_POST(_status < 0 || !err, \ | |
160 | "Current thread has an error, but user function " \ | |
161 | "returned a non-error status: status=%s", \ | |
162 | bt_common_func_status_string(_status)); \ | |
163 | } while (0) | |
164 | ||
165 | /* | |
166 | * Asserts that the current thread has no error. | |
167 | */ | |
168 | #define BT_ASSERT_POST_NO_ERROR() \ | |
169 | BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(0) | |
170 | ||
171 | #ifdef BT_DEV_MODE | |
172 | /* Developer mode version of BT_ASSERT_PRE(). */ | |
173 | # define BT_ASSERT_PRE_DEV(_cond, _fmt, ...) \ | |
174 | BT_ASSERT_PRE((_cond), _fmt, ##__VA_ARGS__) | |
175 | ||
176 | /* Developer mode version of BT_ASSERT_PRE_NON_NULL() */ | |
177 | # define BT_ASSERT_PRE_DEV_NON_NULL(_obj, _obj_name) \ | |
178 | BT_ASSERT_PRE_NON_NULL((_obj), (_obj_name)) | |
179 | ||
180 | /* | |
181 | * Developer mode: asserts that a given object `_obj` named `_obj_name` | |
182 | * (capitalized) is NOT frozen. This macro checks the `frozen` field of | |
183 | * `_obj`. | |
184 | * | |
185 | * This currently only exists in developer mode because some freezing | |
186 | * functions can be called on the fast path, so they too are only | |
187 | * enabled in developer mode. | |
188 | */ | |
189 | # define BT_ASSERT_PRE_DEV_HOT(_obj, _obj_name, _fmt, ...) \ | |
190 | BT_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name, \ | |
191 | ##__VA_ARGS__) | |
192 | ||
193 | /* Developer mode version of BT_ASSERT_PRE_VALID_INDEX() */ | |
194 | # define BT_ASSERT_PRE_DEV_VALID_INDEX(_index, _length) \ | |
195 | BT_ASSERT_PRE_VALID_INDEX((_index), (_length)) | |
196 | ||
197 | /* Developer mode version of BT_ASSERT_PRE_NO_ERROR(). */ | |
198 | # define BT_ASSERT_PRE_DEV_NO_ERROR() \ | |
199 | BT_ASSERT_PRE_NO_ERROR() | |
200 | ||
201 | /* Developer mode version of BT_ASSERT_POST(). */ | |
202 | # define BT_ASSERT_POST_DEV(_cond, _fmt, ...) \ | |
203 | BT_ASSERT_POST((_cond), _fmt, ##__VA_ARGS__) | |
204 | ||
205 | /* | |
206 | * Developer mode version of | |
207 | * BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(). | |
208 | */ | |
209 | # define BT_ASSERT_POST_DEV_NO_ERROR_IF_NO_ERROR_STATUS(_status) \ | |
210 | BT_ASSERT_POST_NO_ERROR_IF_NO_ERROR_STATUS(_status) | |
211 | ||
212 | /* Developer mode version of BT_ASSERT_POST_NO_ERROR(). */ | |
213 | # define BT_ASSERT_POST_DEV_NO_ERROR() \ | |
214 | BT_ASSERT_POST_NO_ERROR() | |
215 | ||
216 | /* Developer mode version of BT_ASSERT_COND_MSG(). */ | |
217 | # define BT_ASSERT_COND_DEV_MSG(_fmt, ...) \ | |
218 | BT_ASSERT_COND_MSG(_fmt, ##__VA_ARGS__) | |
219 | ||
220 | /* | |
221 | * Marks a function as being only used within a BT_ASSERT_PRE_DEV() or | |
222 | * BT_ASSERT_POST_DEV() context. | |
223 | */ | |
224 | # define BT_ASSERT_COND_DEV_FUNC | |
225 | #else | |
226 | # define BT_ASSERT_COND_DEV_MSG(_fmt, ...) | |
227 | # define BT_ASSERT_PRE_DEV(_cond, _fmt, ...) ((void) sizeof((void) (_cond), 0)) | |
228 | # define BT_ASSERT_PRE_DEV_NON_NULL(_obj, _obj_name) \ | |
229 | ((void) sizeof((void) (_obj), (void) (_obj_name), 0)) | |
230 | # define BT_ASSERT_PRE_DEV_HOT(_obj, _obj_name, _fmt, ...) \ | |
231 | ((void) sizeof((void) (_obj), (void) (_obj_name), 0)) | |
232 | # define BT_ASSERT_PRE_DEV_VALID_INDEX(_index, _length) \ | |
233 | ((void) sizeof((void) (_index), (void) (_length), 0)) | |
234 | # define BT_ASSERT_PRE_DEV_NO_ERROR() | |
235 | # define BT_ASSERT_POST_DEV(_cond, _fmt, ...) ((void) sizeof((void) (_cond), 0)) | |
236 | # define BT_ASSERT_POST_DEV_NO_ERROR_IF_NO_ERROR_STATUS(_status) \ | |
237 | ((void) sizeof((void) (_status), 0)) | |
238 | # define BT_ASSERT_POST_DEV_NO_ERROR() | |
239 | # define BT_ASSERT_COND_DEV_FUNC __attribute__((unused)) | |
240 | #endif /* BT_DEV_MODE */ | |
241 | ||
242 | /* | |
243 | * Mark anything that includes this file as supporting precondition and | |
244 | * postcondition assertion macros. | |
245 | */ | |
246 | #define BT_ASSERT_COND_SUPPORTED | |
247 | ||
248 | #endif /* BABELTRACE_ASSERT_COND_INTERNAL_H */ |