X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/490019cf9519204c5fb36b2fba54ceb983bb6b72..4ba76501152d51ccb5647018f3192c6096367d48:/libkern/os/overflow.h diff --git a/libkern/os/overflow.h b/libkern/os/overflow.h index 2b6034ca6..f00a6024f 100644 --- a/libkern/os/overflow.h +++ b/libkern/os/overflow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Apple Inc. All rights reserved. + * Copyright (c) 2015-2018 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -42,70 +42,77 @@ #define _OS_OVERFLOW_H #include +#include +#include -/* compile-time assertion that 'x' and 'y' are equivalent types */ -#define __OS_TYPE_CHECK(x, y) do { \ - _Static_assert(__builtin_types_compatible_p(typeof(x),typeof(y)), \ - "overflow arithmetic: incompatible types"); \ -} while (0) - -#define __os_add_overflow_func(T,U,V) _Generic((T), \ - unsigned: __builtin_uadd_overflow, \ - unsigned long: __builtin_uaddl_overflow, \ - unsigned long long: __builtin_uaddll_overflow, \ - int: __builtin_sadd_overflow, \ - long: __builtin_saddl_overflow, \ - long long: __builtin_saddll_overflow \ - )(T,U,V) - -#define __os_sub_overflow_func(T,U,V) _Generic((T), \ - unsigned: __builtin_usub_overflow, \ - unsigned long: __builtin_usubl_overflow, \ - unsigned long long: __builtin_usubll_overflow, \ - int: __builtin_ssub_overflow, \ - long: __builtin_ssubl_overflow, \ - long long: __builtin_ssubll_overflow \ - )(T,U,V) - -#define __os_mul_overflow_func(T,U,V) _Generic((T), \ - unsigned: __builtin_umul_overflow, \ - unsigned long: __builtin_umull_overflow, \ - unsigned long long: __builtin_umulll_overflow, \ - int: __builtin_smul_overflow, \ - long: __builtin_smull_overflow, \ - long long: __builtin_smulll_overflow \ - )(T,U,V) - -int __header_always_inline __attribute__((__warn_unused_result__)) -__os_warn_unused(const int x) +bool __header_always_inline OS_WARN_RESULT +__os_warn_unused(__const bool x) { return x; } -#define os_add_overflow(a, b, res) __os_warn_unused(({ \ - __OS_TYPE_CHECK((a), (b)); \ - __OS_TYPE_CHECK((b), *(res)); \ - __os_add_overflow_func((a), (b), (res)); \ -})) +#if __has_builtin(__builtin_add_overflow) && \ + __has_builtin(__builtin_sub_overflow) && \ + __has_builtin(__builtin_mul_overflow) + +#define os_add_overflow(a, b, res) __os_warn_unused(__builtin_add_overflow((a), (b), (res))) +#define os_sub_overflow(a, b, res) __os_warn_unused(__builtin_sub_overflow((a), (b), (res))) +#define os_mul_overflow(a, b, res) __os_warn_unused(__builtin_mul_overflow((a), (b), (res))) -#define os_add3_overflow(a, b, c, res) __os_warn_unused(({ \ - typeof(a) _tmp; \ - int _s, _t; \ +#else +# error os_overflow expects type-generic builtins +#endif /* __has_builtin(...) */ + +/* os_add3_overflow(a, b, c) -> (a + b + c) */ +#define os_add3_overflow(a, b, c, res) __os_warn_unused(__extension__({ \ + __typeof(*(res)) _tmp; \ + bool _s, _t; \ _s = os_add_overflow((a), (b), &_tmp); \ _t = os_add_overflow((c), _tmp, (res)); \ _s | _t; \ })) -#define os_sub_overflow(a, b, res) __os_warn_unused(({ \ - __OS_TYPE_CHECK((a), (b)); \ - __OS_TYPE_CHECK((b), *(res)); \ - __os_sub_overflow_func((a), (b), (res)); \ +/* os_mul3_overflow(a, b, c) -> (a * b * c) */ +#define os_mul3_overflow(a, b, c, res) __os_warn_unused(__extension__({ \ + __typeof(*(res)) _tmp; \ + bool _s, _t; \ + _s = os_mul_overflow((a), (b), &_tmp); \ + _t = os_mul_overflow((c), _tmp, (res)); \ + _s | _t; \ })) -#define os_mul_overflow(a, b, res) __os_warn_unused(({ \ - __OS_TYPE_CHECK((a), (b)); \ - __OS_TYPE_CHECK((b), *(res)); \ - __os_mul_overflow_func((a), (b), (res)); \ +/* os_add_and_mul_overflow(a, b, x) -> (a + b)*x */ +#define os_add_and_mul_overflow(a, b, x, res) __os_warn_unused(__extension__({ \ + __typeof(*(res)) _tmp; \ + bool _s, _t; \ + _s = os_add_overflow((a), (b), &_tmp); \ + _t = os_mul_overflow((x), _tmp, (res)); \ + _s | _t; \ })) +/* os_mul_and_add_overflow(a, x, b) -> a*x + b */ +#define os_mul_and_add_overflow(a, x, b, res) __os_warn_unused(__extension__({ \ + __typeof(*(res)) _tmp; \ + bool _s, _t; \ + _s = os_mul_overflow((a), (x), &_tmp); \ + _t = os_add_overflow((b), _tmp, (res)); \ + _s | _t; \ +})) + +/* os_convert_overflow(a) -> a [converted to the result type] */ +#define os_convert_overflow(a, res) os_add_overflow((a), 0, (res)) + +/* os_inc_overflow(res) -> *res += 1 */ +#define os_inc_overflow(res) __os_warn_unused(__extension__({ \ + __typeof((res)) _tmp = (res); \ + os_add_overflow(*_tmp, 1, _tmp); \ +})) + +/* os_dec_overflow(res) -> *res -= 1 */ +#define os_dec_overflow(res) __os_warn_unused(__extension__({ \ + __typeof((res)) _tmp = (res); \ + os_sub_overflow(*_tmp, 1, _tmp); \ +})) + + #endif /* _OS_OVERFLOW_H */