]>
Commit | Line | Data |
---|---|---|
6465356a A |
1 | /* Copyright (c) 2012, 2012 Apple Inc. All rights reserved. |
2 | * | |
3 | * @APPLE_LICENSE_HEADER_START@ | |
4 | * | |
5 | * This file contains Original Code and/or Modifications of Original Code | |
6 | * as defined in and that are subject to the Apple Public Source License | |
7 | * Version 2.0 (the 'License'). You may not use this file except in | |
8 | * compliance with the License. Please obtain a copy of the License at | |
9 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
10 | * file. | |
11 | * | |
12 | * The Original Code and all software distributed under the License are | |
13 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
17 | * Please see the License for the specific language governing rights and | |
18 | * limitations under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | #ifndef __OS_ASSUMES_H__ | |
24 | #define __OS_ASSUMES_H__ | |
25 | ||
26 | #include <sys/cdefs.h> | |
b061a43b | 27 | #include <stdalign.h> |
6465356a A |
28 | |
29 | __BEGIN_DECLS | |
30 | ||
31 | #include <Availability.h> | |
32 | #include <TargetConditionals.h> | |
33 | #include <stdlib.h> | |
34 | #include <stdint.h> | |
35 | #include <stdarg.h> | |
36 | #include <stdbool.h> | |
37 | #include <_simple.h> | |
6465356a | 38 | #include <errno.h> |
23e20b00 | 39 | #include <os/base_private.h> |
70ad1dc8 | 40 | #include <stdint.h> |
23e20b00 A |
41 | |
42 | #if __GNUC__ | |
43 | #define os_constant(x) __builtin_constant_p((x)) | |
44 | #define os_hardware_trap() __asm__ __volatile__ (""); __builtin_trap() | |
45 | #define __OS_COMPILETIME_ASSERT__(e) __extension__({ \ | |
a9aaacca A |
46 | _Pragma("clang diagnostic push") \ |
47 | _Pragma("clang diagnostic ignored \"-Wvla\"") \ | |
23e20b00 A |
48 | char __compile_time_assert__[(e) ? 1 : -1]; \ |
49 | (void)__compile_time_assert__; \ | |
a9aaacca | 50 | _Pragma("clang diagnostic pop") \ |
23e20b00 A |
51 | }) |
52 | #else /* __GNUC__ */ | |
53 | #define os_constant(x) ((long)0) | |
54 | #define os_hardware_trap() abort() | |
55 | #define __OS_COMPILETIME_ASSERT__(e) (e) | |
56 | #endif /* __GNUC__ */ | |
6465356a | 57 | |
b061a43b | 58 | #pragma mark os_crash |
5f125488 | 59 | |
b061a43b A |
60 | /* |
61 | * os_crash() is like os_hardware_trap(), except you get to pass in a crash | |
5f125488 | 62 | * message, and it can be redirected to a callback function using |
b061a43b A |
63 | * os_set_crash_callback() |
64 | */ | |
65 | ||
66 | #define __os_crash_simple(msg) \ | |
5f125488 A |
67 | ({ \ |
68 | _os_crash(msg); \ | |
69 | os_hardware_trap(); \ | |
70 | }) | |
71 | ||
b061a43b A |
72 | #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE) |
73 | #include <os/log_private.h> | |
74 | ||
75 | #define __os_crash_fmt(...) \ | |
76 | ({ \ | |
77 | const size_t size = os_log_pack_size(__VA_ARGS__); \ | |
78 | uint8_t buf[size] __attribute__((aligned(alignof(os_log_pack_s)))); \ | |
79 | os_log_pack_t pack = (os_log_pack_t)&buf; \ | |
80 | os_log_pack_fill(pack, size, errno, __VA_ARGS__); \ | |
81 | _os_crash_fmt(pack, size); \ | |
82 | os_hardware_trap(); \ | |
83 | }) | |
6465356a | 84 | |
b061a43b A |
85 | #define __os_crash_N(msg) __os_crash_simple(msg) |
86 | #define __os_crash_Y(...) __os_crash_fmt(__VA_ARGS__) | |
6465356a | 87 | |
b061a43b A |
88 | // Returns Y if >1 argument, N if just one argument. |
89 | #define __thirty_second_argument(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \ | |
90 | _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \ | |
91 | _26, _27, _28, _29, _30, _31, _32, ...) _32 | |
92 | #define __has_more_than_one_argument(...) __thirty_second_argument(__VA_ARGS__, \ | |
93 | Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, \ | |
94 | Y, Y, Y, Y, Y, Y, Y, N, EXTRA) | |
95 | ||
96 | #define __os_crash_invoke(variant, ...) \ | |
97 | OS_CONCAT(__os_crash_, variant)(__VA_ARGS__) | |
98 | ||
99 | #define os_crash(...) \ | |
100 | __os_crash_invoke(__has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__) | |
101 | ||
507116e3 | 102 | OS_COLD |
b061a43b A |
103 | extern void |
104 | _os_crash_fmt(os_log_pack_t, size_t); | |
105 | ||
70ad1dc8 A |
106 | /*! |
107 | * @function os_assert_sprintf | |
108 | * A routine to assert the result of a call to snprintf(3) or vsnprintf(3). | |
109 | * | |
110 | * @param ret | |
111 | * The return value from {v}snprintf(3). | |
112 | * | |
113 | * @param buff_size | |
114 | * The size of the buffer given to {v}snprintf(3). | |
115 | * | |
116 | * @discussion | |
117 | * If ret is less than zero or greater than size, the routine will abort the | |
118 | * caller with a message indicating the nature of the failure in the Application | |
119 | * Specific Information section of the resulting crash log. | |
120 | * | |
121 | * This routine is useful for printing paths that are expected to succeed with a | |
122 | * statically-sized buffer. | |
123 | */ | |
124 | API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) | |
507116e3 | 125 | OS_ALWAYS_INLINE OS_COLD |
70ad1dc8 A |
126 | static inline void |
127 | os_assert_sprintf(int ret, size_t buff_size) | |
128 | { | |
70ad1dc8 A |
129 | if (ret < 0) { |
130 | os_crash("error printing buffer: %s", strerror(errno)); | |
131 | } | |
132 | ||
507116e3 | 133 | if ((size_t)ret > buff_size) { |
70ad1dc8 A |
134 | os_crash("buffer too small: needed = %d, actual = %lu", |
135 | ret, buff_size); | |
136 | } | |
137 | } | |
138 | ||
e1ee4b85 A |
139 | /*! |
140 | * @function os_assert_asprintf | |
141 | * A routine to assert the result of a call to {v}asprintf(3). | |
142 | * | |
143 | * @param ret | |
144 | * The return value from {v}asnprintf(3). | |
145 | * | |
146 | * @discussion | |
147 | * If ret is less than zero, the routine will abort the caller with a message | |
148 | * indicating the nature of the failure in the Application Specific Information | |
149 | * section of the resulting crash log. | |
150 | */ | |
151 | API_AVAILABLE(macos(10.15.2), ios(13.3), tvos(13.3), watchos(6.1.1)) | |
152 | OS_ALWAYS_INLINE OS_COLD | |
153 | static inline void | |
154 | os_assert_asprintf(int ret) | |
155 | { | |
156 | if (ret < 0) { | |
157 | os_crash("error printing buffer: %s", strerror(errno)); | |
158 | } | |
159 | } | |
160 | ||
70ad1dc8 A |
161 | /*! |
162 | * @function os_assert_malloc | |
163 | * A routine to assert the result of allocations which may fail. | |
164 | * | |
165 | * @param desc | |
166 | * A string describing the object whose allocation was attempted. | |
167 | * | |
168 | * @param p | |
169 | * The result of a call to malloc(3), calloc(3), et al. | |
170 | * | |
171 | * @param alloc_size | |
172 | * The size of the attempted allocation. | |
173 | * | |
174 | * @discussion | |
175 | * If {@link p} is NULL, the routine will abort the caller with a message | |
176 | * indicating the nature of the failure in the Application Specific Information | |
177 | * section of the resulting crash log. | |
178 | */ | |
179 | API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) | |
180 | OS_ALWAYS_INLINE | |
181 | static inline void | |
182 | os_assert_malloc(const char *desc, const void *const p, size_t alloc_size) | |
183 | { | |
184 | if (!p) { | |
185 | os_crash("allocation failed: obj = %s, size = %lu, error = %s", | |
186 | desc, alloc_size, strerror(errno)); | |
187 | } | |
188 | } | |
189 | ||
190 | /*! | |
191 | * @function os_assert_mach | |
192 | * A routine to assert the result of a Mach kernel routine. | |
193 | * | |
194 | * @param op | |
195 | * A human-readable description of the operation. | |
196 | * | |
197 | * @param kr | |
198 | * The return code. | |
199 | * | |
200 | * @discsussion | |
201 | * If {@link kr} is non-zero, this routine will abort the caller with a message | |
202 | * indicating the nature of the failure in the Application Specific Information | |
203 | * section of the resulting crash log. | |
204 | */ | |
205 | API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) | |
507116e3 | 206 | OS_EXPORT OS_NONNULL1 OS_COLD |
70ad1dc8 A |
207 | void |
208 | os_assert_mach(const char *op, kern_return_t kr); | |
209 | ||
507116e3 A |
210 | #define os_assert_mach(op, kr) ({ \ |
211 | kern_return_t __kr = (kr); \ | |
212 | if (os_unlikely(__kr != KERN_SUCCESS)) os_assert_mach(op, kr); \ | |
213 | }) | |
214 | ||
70ad1dc8 A |
215 | /*! |
216 | * @function os_assert_mach_port_status | |
217 | * A routine to assert the status of a Mach port. | |
218 | * | |
219 | * @param desc | |
220 | * A human-readable description of the port's purpose. | |
221 | * | |
222 | * @param p | |
223 | * The port. | |
224 | * | |
225 | * @param expected | |
226 | * A pointer to a mach_port_status_t describing the expected attributes of the | |
227 | * port. If no particular value is expected for a given field in the structure, | |
228 | * a sentinel value may be provided for each expected field to indicate that its | |
229 | * check should be elided. The sentival values are: | |
230 | * | |
231 | * mps_pset => UINT32_MAX | |
232 | * mps_seqno => UINT32_MAX | |
233 | * mps_mscount => UINT32_MAX | |
234 | * mps_qlimit => UINT32_MAX | |
235 | * mps_msgcount => UINT32_MAX | |
236 | * mps_sorights => UINT32_MAX | |
237 | * mps_srights => INT32_MAX | |
238 | * mps_pdrequest => INT32_MAX | |
239 | * mps_nsrequest => INT32_MAX | |
240 | * mps_flags => 0 | |
241 | * | |
242 | * @discussion | |
243 | * If there are any mismatches in the expected and actual status of the port, | |
244 | * the implementation will abort the caller. If status cannot be obtained for | |
245 | * the given port, the implementation will abort the caller. | |
246 | */ | |
247 | API_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) | |
248 | OS_EXPORT | |
249 | void | |
250 | os_assert_mach_port_status(const char *desc, mach_port_t p, | |
251 | mach_port_status_t *expected); | |
252 | ||
b061a43b | 253 | #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE |
6465356a | 254 | |
b061a43b A |
255 | #define os_crash(msg) __os_crash_simple(msg) |
256 | ||
257 | #endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE | |
258 | ||
259 | /* | |
260 | * An executable can register a callback to be made upon a crash using the | |
261 | * os_set_crash_callback function. If a crash callback is not set, the symbol | |
262 | * `os_crash_function` will be called in the main binary, if it exists. | |
263 | */ | |
5f125488 A |
264 | |
265 | typedef void (*os_crash_callback_t) (const char *); | |
266 | ||
b061a43b | 267 | /* private: use accessors below */ |
5f125488 A |
268 | extern os_crash_callback_t _os_crash_callback; |
269 | ||
270 | static inline os_crash_callback_t | |
271 | os_get_crash_callback() { | |
272 | return _os_crash_callback; | |
273 | } | |
274 | ||
275 | static inline void | |
276 | os_set_crash_callback(os_crash_callback_t callback) { | |
277 | _os_crash_callback = callback; | |
278 | } | |
279 | ||
b061a43b | 280 | #pragma mark os_assert |
6465356a | 281 | |
b061a43b | 282 | #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE) |
6465356a | 283 | |
b061a43b A |
284 | #define _os_assert_crash(value, expression) ({ \ |
285 | os_crash("assertion failure: \"" expression "\" -> %lld", value); \ | |
286 | }) | |
287 | ||
288 | #define _os_assert_crash_errno(value, expression) ({ \ | |
289 | os_crash("assertion failure: \"" expression "\" -> %{errno}d", value); \ | |
290 | }) | |
291 | ||
292 | #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE | |
293 | ||
294 | #define _os_assert_crash(e, ...) ({ \ | |
295 | char *_fail_message = _os_assert_log(e); \ | |
296 | os_crash(_fail_message); \ | |
297 | free(_fail_message); \ | |
298 | }) | |
299 | ||
300 | #define _os_assert_crash_errno(...) _os_assert_crash(__VA_ARGS__) | |
301 | ||
302 | #endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE | |
303 | ||
304 | #define __os_assert(e) __extension__({ \ | |
305 | __typeof__(e) _e = (e); \ | |
306 | if (os_unlikely(!_e)) { \ | |
307 | if (os_constant(e)) { __OS_COMPILETIME_ASSERT__((e)); } \ | |
308 | _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \ | |
6465356a | 309 | } \ |
6465356a A |
310 | }) |
311 | ||
b061a43b A |
312 | #define __os_assert_zero(e) __extension__({ \ |
313 | __typeof__(e) _e = (e); \ | |
314 | if (os_unlikely(_e)) { \ | |
315 | if (os_constant(e)) { __OS_COMPILETIME_ASSERT__(!(e)); } \ | |
316 | _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \ | |
6465356a | 317 | } \ |
6465356a A |
318 | }) |
319 | ||
b061a43b A |
320 | /* |
321 | * This variant is for use with old-style POSIX APIs that return -1 on failure | |
6465356a | 322 | * and set errno. If the return code is -1, the value logged will be as though |
b061a43b | 323 | * os_assert_zero(errno) was used. It encapsulates the following pattern: |
6465356a A |
324 | * |
325 | * int tubes[2]; | |
326 | * if (pipe(tubes) == -1) { | |
b061a43b | 327 | * (void)os_assert_zero(errno); |
6465356a A |
328 | * } |
329 | */ | |
b061a43b A |
330 | #define __posix_assert_zero(e) __extension__({ \ |
331 | __typeof__(e) _e = (e); \ | |
332 | if (os_unlikely(_e == (__typeof__(e))-1)) { \ | |
333 | _os_assert_crash_errno(errno, #e); \ | |
6465356a | 334 | } \ |
6465356a A |
335 | }) |
336 | ||
b061a43b A |
337 | #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE) |
338 | ||
339 | #define __os_assert_msg(e, fmt, ...) __extension__({ \ | |
340 | __typeof__(e) _e = (e); \ | |
341 | if (os_unlikely(!_e)) { \ | |
342 | os_crash("assertion failure: " fmt, ##__VA_ARGS__); \ | |
343 | } \ | |
344 | }) | |
345 | ||
346 | #define __os_assert_zero_msg(e, fmt, ...) __extension__({ \ | |
347 | __typeof__(e) _e = (e); \ | |
348 | if (os_unlikely(_e)) { \ | |
349 | os_crash("assertion failure (%lld): " fmt, value, ##__VA_ARGS__); \ | |
350 | } \ | |
351 | }) | |
352 | ||
353 | #define __posix_assert_zero_msg(e, fmt, ...) __extension__({ \ | |
354 | __typeof__(e) _e = (e); \ | |
355 | if (os_unlikely(_e == (__typeof__(e))-1)) { \ | |
356 | os_crash("assertion failure (%{errno}d): " fmt, errno, ##__VA_ARGS__); \ | |
357 | } \ | |
358 | }) | |
359 | ||
360 | #define __os_assert_N(e) __os_assert(e) | |
361 | #define __os_assert_Y(...) __os_assert_msg(__VA_ARGS__) | |
362 | #define __os_assert_zero_N(e) __os_assert_zero(e) | |
363 | #define __os_assert_zero_Y(...) __os_assert_zero_msg(__VA_ARGS__) | |
364 | #define __posix_assert_zero_N(e) __posix_assert_zero(e) | |
365 | #define __posix_assert_zero_Y(...) __posix_assert_zero_msg(__VA_ARGS__) | |
366 | ||
367 | #define __os_assert_invoke(function, variant, ...) \ | |
368 | OS_CONCAT(function, variant)(__VA_ARGS__) | |
369 | ||
370 | #define os_assert(...) \ | |
371 | __os_assert_invoke(__os_assert_, \ | |
372 | __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__) | |
373 | #define os_assert_zero(...) \ | |
374 | __os_assert_invoke(__os_assert_zero_, \ | |
375 | __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__) | |
376 | #define posix_assert_zero(...) \ | |
377 | __os_assert_invoke(__posix_assert_zero_, \ | |
378 | __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__) | |
379 | ||
380 | #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE | |
381 | ||
382 | #define os_assert(e) __os_assert(e) | |
383 | #define os_assert_zero(e) __os_assert_zero(e) | |
384 | #define posix_assert_zero(e) __posix_assert_zero(e) | |
385 | ||
386 | #endif | |
387 | ||
388 | #pragma mark os_assumes | |
389 | ||
390 | ||
391 | #define os_assumes(e) __extension__({ \ | |
6465356a A |
392 | __typeof__(e) _e = os_fastpath(e); \ |
393 | if (!_e) { \ | |
394 | if (os_constant(e)) { \ | |
395 | __OS_COMPILETIME_ASSERT__(e); \ | |
396 | } \ | |
b061a43b | 397 | _os_assumes_log((uint64_t)(uintptr_t)_e); \ |
6465356a | 398 | } \ |
b061a43b | 399 | _e; \ |
6465356a A |
400 | }) |
401 | ||
b061a43b | 402 | #define os_assumes_zero(e) __extension__({ \ |
6465356a A |
403 | __typeof__(e) _e = os_slowpath(e); \ |
404 | if (_e) { \ | |
405 | if (os_constant(e)) { \ | |
974e3884 | 406 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a | 407 | } \ |
b061a43b | 408 | _os_assumes_log((uint64_t)(uintptr_t)_e); \ |
6465356a | 409 | } \ |
b061a43b | 410 | _e; \ |
6465356a A |
411 | }) |
412 | ||
b061a43b | 413 | #define posix_assumes_zero(e) __extension__({ \ |
6465356a A |
414 | __typeof__(e) _e = os_slowpath(e); \ |
415 | if (_e == (__typeof__(e))-1) { \ | |
b061a43b | 416 | _os_assumes_log((uint64_t)(uintptr_t)errno); \ |
6465356a | 417 | } \ |
b061a43b | 418 | _e; \ |
6465356a A |
419 | }) |
420 | ||
b061a43b A |
421 | #pragma mark assumes redirection |
422 | ||
423 | /* This is useful for clients who wish for the messages generated by assumes() | |
424 | * failures to go somewhere other than (or in addition to) the system log. If | |
425 | * you don't wish for the message to be logged to the system log, then return | |
426 | * true (to indicate that the message has been handled). If you want the default | |
427 | * behavior, return false. | |
428 | */ | |
429 | typedef bool (*os_redirect_t)(const char *); | |
430 | struct _os_redirect_assumes_s { | |
431 | os_redirect_t redirect; | |
432 | }; | |
433 | ||
434 | #define OS_ASSUMES_REDIRECT_SEG "__DATA" | |
435 | #define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log" | |
436 | ||
437 | #define os_redirect_assumes(func) \ | |
438 | __attribute__((__used__)) \ | |
439 | __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \ | |
440 | static struct _os_redirect_assumes_s _os_redirect_##func = { \ | |
441 | .redirect = &func, \ | |
442 | }; | |
443 | ||
444 | #pragma mark _ctx variants | |
445 | ||
446 | /* | |
447 | * These are for defining your own assumes()-like wrapper calls so that you can | |
6465356a A |
448 | * log additional information, such as the about-PID, sender, etc. They're |
449 | * generally not useful for direct inclusion in your code. | |
450 | */ | |
b061a43b A |
451 | |
452 | /* | |
453 | * The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will | |
454 | * direct the message to the MessageTracer diagnostic messages store rather than | |
455 | * the default system log store. | |
456 | */ | |
457 | typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *); | |
458 | ||
459 | ||
6465356a A |
460 | #define os_assumes_ctx(f, ctx, e) __extension__({ \ |
461 | __typeof__(e) _e = os_fastpath(e); \ | |
462 | if (!_e) { \ | |
463 | if (os_constant(e)) { \ | |
464 | __OS_COMPILETIME_ASSERT__(e); \ | |
465 | } \ | |
466 | _os_assumes_log_ctx(f, ctx, (uintptr_t)_e); \ | |
6465356a A |
467 | } \ |
468 | _e; \ | |
469 | }) | |
470 | ||
471 | #define os_assumes_zero_ctx(f, ctx, e) __extension__({ \ | |
472 | __typeof__(e) _e = os_slowpath(e); \ | |
473 | if (_e) { \ | |
474 | if (os_constant(e)) { \ | |
974e3884 | 475 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
476 | } \ |
477 | _os_assumes_log_ctx((f), (ctx), (uintptr_t)_e); \ | |
6465356a A |
478 | } \ |
479 | _e; \ | |
480 | }) | |
481 | ||
482 | #define posix_assumes_zero_ctx(f, ctx, e) __extension__({ \ | |
483 | __typeof__(e) _e = os_slowpath(e); \ | |
484 | if (_e == (__typeof__(e))-1) { \ | |
485 | _os_assumes_log_ctx((f), (ctx), (uintptr_t)errno); \ | |
6465356a A |
486 | } \ |
487 | _e; \ | |
488 | }) | |
489 | ||
490 | #define os_assert_ctx(f, ctx, e) __extension__({ \ | |
491 | __typeof__(e) _e = os_fastpath(e); \ | |
492 | if (!_e) { \ | |
493 | if (os_constant(e)) { \ | |
494 | __OS_COMPILETIME_ASSERT__(e); \ | |
495 | } \ | |
5f125488 | 496 | \ |
6465356a | 497 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \ |
5f125488 | 498 | os_crash(_fail_message); \ |
6465356a A |
499 | free(_fail_message); \ |
500 | } \ | |
501 | }) | |
502 | ||
503 | #define os_assert_zero_ctx(f, ctx, e) __extension__({ \ | |
504 | __typeof__(e) _e = os_slowpath(e); \ | |
505 | if (_e) { \ | |
506 | if (os_constant(e)) { \ | |
974e3884 | 507 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
508 | } \ |
509 | \ | |
510 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \ | |
5f125488 | 511 | os_crash(_fail_message); \ |
6465356a A |
512 | free(_fail_message); \ |
513 | } \ | |
514 | }) | |
515 | ||
516 | #define posix_assert_zero_ctx(f, ctx, e) __extension__({ \ | |
517 | __typeof__(e) _e = os_slowpath(e); \ | |
518 | if (_e == (__typeof__(e))-1) { \ | |
519 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)errno); \ | |
5f125488 | 520 | os_crash(_fail_message); \ |
6465356a A |
521 | free(_fail_message); \ |
522 | } \ | |
523 | }) | |
524 | ||
b061a43b A |
525 | #pragma mark internal symbols |
526 | ||
5f125488 | 527 | __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0) |
507116e3 | 528 | OS_COLD OS_NOT_TAIL_CALLED |
5f125488 A |
529 | extern void |
530 | _os_crash(const char *); | |
531 | ||
6465356a | 532 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) |
507116e3 | 533 | OS_COLD OS_NOT_TAIL_CALLED |
6465356a A |
534 | extern void |
535 | _os_assumes_log(uint64_t code); | |
536 | ||
537 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
507116e3 | 538 | OS_COLD OS_NOT_TAIL_CALLED |
6465356a A |
539 | extern char * |
540 | _os_assert_log(uint64_t code); | |
541 | ||
542 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
507116e3 | 543 | OS_COLD OS_NOT_TAIL_CALLED |
6465356a A |
544 | extern void |
545 | _os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code); | |
546 | ||
547 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
507116e3 | 548 | OS_COLD OS_NOT_TAIL_CALLED |
6465356a A |
549 | extern char * |
550 | _os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code); | |
551 | ||
552 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
553 | extern void | |
554 | _os_avoid_tail_call(void); | |
555 | ||
556 | __END_DECLS | |
557 | ||
558 | #endif /* __OS_ASSUMES_H__ */ |