Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linuxkpi/common/include/linux/overflow.h
| Show All 27 Lines | |||||
| * _Bools. Besides, the gcc builtins don't allow _Bool* as third | * _Bools. Besides, the gcc builtins don't allow _Bool* as third | ||||
| * argument.] | * argument.] | ||||
| * | * | ||||
| * Idea stolen from | * Idea stolen from | ||||
| * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - | * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - | ||||
| * credit to Christian Biere. | * credit to Christian Biere. | ||||
| */ | */ | ||||
| #define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) | #define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) | ||||
| #define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) | #define __type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) | ||||
| #define type_min(T) ((T)((T)-type_max(T)-(T)1)) | #define type_max(t) __type_max(typeof(t)) | ||||
| #define __type_min(T) ((T)((T)-type_max(T)-(T)1)) | |||||
| #define type_min(t) __type_min(typeof(t)) | |||||
| /* | /* | ||||
| * Avoids triggering -Wtype-limits compilation warning, | * Avoids triggering -Wtype-limits compilation warning, | ||||
| * while using unsigned data types to check a < 0. | * while using unsigned data types to check a < 0. | ||||
| */ | */ | ||||
| #define is_non_negative(a) ((a) > 0 || (a) == 0) | #define is_non_negative(a) ((a) > 0 || (a) == 0) | ||||
| #define is_negative(a) (!(is_non_negative(a))) | #define is_negative(a) (!(is_non_negative(a))) | ||||
| /* | /* | ||||
| * Allows for effectively applying __must_check to a macro so we can have | * Allows for effectively applying __must_check to a macro so we can have | ||||
| * both the type-agnostic benefits of the macros while also being able to | * both the type-agnostic benefits of the macros while also being able to | ||||
| * enforce that the return value is, in fact, checked. | * enforce that the return value is, in fact, checked. | ||||
| */ | */ | ||||
| static inline bool __must_check __must_check_overflow(bool overflow) | static inline bool __must_check __must_check_overflow(bool overflow) | ||||
| { | { | ||||
| return unlikely(overflow); | return unlikely(overflow); | ||||
| } | } | ||||
| /** | /** | ||||
| * check_add_overflow() - Calculate addition with overflow checking | * check_add_overflow() - Calculate addition with overflow checking | ||||
| * @a: first addend | * @a: first addend | ||||
| * @b: second addend | * @b: second addend | ||||
| * @d: pointer to store sum | * @d: pointer to store sum | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns true on wrap-around, false otherwise. | ||||
| * | * | ||||
| * *@d holds the results of the attempted addition, but is not considered | * *@d holds the results of the attempted addition, regardless of whether | ||||
| * "safe for use" on a non-zero return value, which indicates that the | * wrap-around occurred. | ||||
| * sum has overflowed or been truncated. | |||||
| */ | */ | ||||
| #define check_add_overflow(a, b, d) \ | #define check_add_overflow(a, b, d) \ | ||||
| __must_check_overflow(__builtin_add_overflow(a, b, d)) | __must_check_overflow(__builtin_add_overflow(a, b, d)) | ||||
| /** | /** | ||||
| * wrapping_add() - Intentionally perform a wrapping addition | |||||
| * @type: type for result of calculation | |||||
| * @a: first addend | |||||
| * @b: second addend | |||||
| * | |||||
| * Return the potentially wrapped-around addition without | |||||
| * tripping any wrap-around sanitizers that may be enabled. | |||||
| */ | |||||
| #define wrapping_add(type, a, b) \ | |||||
| ({ \ | |||||
| type __val; \ | |||||
| __builtin_add_overflow(a, b, &__val); \ | |||||
| __val; \ | |||||
| }) | |||||
| /** | |||||
| * wrapping_assign_add() - Intentionally perform a wrapping increment assignment | |||||
| * @var: variable to be incremented | |||||
| * @offset: amount to add | |||||
| * | |||||
| * Increments @var by @offset with wrap-around. Returns the resulting | |||||
| * value of @var. Will not trip any wrap-around sanitizers. | |||||
| * | |||||
| * Returns the new value of @var. | |||||
| */ | |||||
| #define wrapping_assign_add(var, offset) \ | |||||
| ({ \ | |||||
| typeof(var) *__ptr = &(var); \ | |||||
| *__ptr = wrapping_add(typeof(var), *__ptr, offset); \ | |||||
| }) | |||||
| /** | |||||
| * check_sub_overflow() - Calculate subtraction with overflow checking | * check_sub_overflow() - Calculate subtraction with overflow checking | ||||
| * @a: minuend; value to subtract from | * @a: minuend; value to subtract from | ||||
| * @b: subtrahend; value to subtract from @a | * @b: subtrahend; value to subtract from @a | ||||
| * @d: pointer to store difference | * @d: pointer to store difference | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns true on wrap-around, false otherwise. | ||||
| * | * | ||||
| * *@d holds the results of the attempted subtraction, but is not considered | * *@d holds the results of the attempted subtraction, regardless of whether | ||||
| * "safe for use" on a non-zero return value, which indicates that the | * wrap-around occurred. | ||||
| * difference has underflowed or been truncated. | |||||
| */ | */ | ||||
| #define check_sub_overflow(a, b, d) \ | #define check_sub_overflow(a, b, d) \ | ||||
| __must_check_overflow(__builtin_sub_overflow(a, b, d)) | __must_check_overflow(__builtin_sub_overflow(a, b, d)) | ||||
| /** | /** | ||||
| * wrapping_sub() - Intentionally perform a wrapping subtraction | |||||
| * @type: type for result of calculation | |||||
| * @a: minuend; value to subtract from | |||||
| * @b: subtrahend; value to subtract from @a | |||||
| * | |||||
| * Return the potentially wrapped-around subtraction without | |||||
| * tripping any wrap-around sanitizers that may be enabled. | |||||
| */ | |||||
| #define wrapping_sub(type, a, b) \ | |||||
| ({ \ | |||||
| type __val; \ | |||||
| __builtin_sub_overflow(a, b, &__val); \ | |||||
| __val; \ | |||||
| }) | |||||
| /** | |||||
| * wrapping_assign_sub() - Intentionally perform a wrapping decrement assign | |||||
| * @var: variable to be decremented | |||||
| * @offset: amount to subtract | |||||
| * | |||||
| * Decrements @var by @offset with wrap-around. Returns the resulting | |||||
| * value of @var. Will not trip any wrap-around sanitizers. | |||||
| * | |||||
| * Returns the new value of @var. | |||||
| */ | |||||
| #define wrapping_assign_sub(var, offset) \ | |||||
| ({ \ | |||||
| typeof(var) *__ptr = &(var); \ | |||||
| *__ptr = wrapping_sub(typeof(var), *__ptr, offset); \ | |||||
| }) | |||||
| /** | |||||
| * check_mul_overflow() - Calculate multiplication with overflow checking | * check_mul_overflow() - Calculate multiplication with overflow checking | ||||
| * @a: first factor | * @a: first factor | ||||
| * @b: second factor | * @b: second factor | ||||
| * @d: pointer to store product | * @d: pointer to store product | ||||
| * | * | ||||
| * Returns 0 on success. | * Returns true on wrap-around, false otherwise. | ||||
| * | * | ||||
| * *@d holds the results of the attempted multiplication, but is not | * *@d holds the results of the attempted multiplication, regardless of whether | ||||
| * considered "safe for use" on a non-zero return value, which indicates | * wrap-around occurred. | ||||
| * that the product has overflowed or been truncated. | |||||
| */ | */ | ||||
| #define check_mul_overflow(a, b, d) \ | #define check_mul_overflow(a, b, d) \ | ||||
| __must_check_overflow(__builtin_mul_overflow(a, b, d)) | __must_check_overflow(__builtin_mul_overflow(a, b, d)) | ||||
| /** | /** | ||||
| * wrapping_mul() - Intentionally perform a wrapping multiplication | |||||
| * @type: type for result of calculation | |||||
| * @a: first factor | |||||
| * @b: second factor | |||||
| * | |||||
| * Return the potentially wrapped-around multiplication without | |||||
| * tripping any wrap-around sanitizers that may be enabled. | |||||
| */ | |||||
| #define wrapping_mul(type, a, b) \ | |||||
| ({ \ | |||||
| type __val; \ | |||||
| __builtin_mul_overflow(a, b, &__val); \ | |||||
| __val; \ | |||||
| }) | |||||
| /** | |||||
| * check_shl_overflow() - Calculate a left-shifted value and check overflow | * check_shl_overflow() - Calculate a left-shifted value and check overflow | ||||
| * @a: Value to be shifted | * @a: Value to be shifted | ||||
| * @s: How many bits left to shift | * @s: How many bits left to shift | ||||
| * @d: Pointer to where to store the result | * @d: Pointer to where to store the result | ||||
| * | * | ||||
| * Computes *@d = (@a << @s) | * Computes *@d = (@a << @s) | ||||
| * | * | ||||
| * Returns true if '*@d' cannot hold the result or when '@a << @s' doesn't | * Returns true if '*@d' cannot hold the result or when '@a << @s' doesn't | ||||
| * make sense. Example conditions: | * make sense. Example conditions: | ||||
| * | * | ||||
| * - '@a << @s' causes bits to be lost when stored in *@d. | * - '@a << @s' causes bits to be lost when stored in *@d. | ||||
| * - '@s' is garbage (e.g. negative) or so large that the result of | * - '@s' is garbage (e.g. negative) or so large that the result of | ||||
| * '@a << @s' is guaranteed to be 0. | * '@a << @s' is guaranteed to be 0. | ||||
| * - '@a' is negative. | * - '@a' is negative. | ||||
| * - '@a << @s' sets the sign bit, if any, in '*@d'. | * - '@a << @s' sets the sign bit, if any, in '*@d'. | ||||
| * | * | ||||
| * '*@d' will hold the results of the attempted shift, but is not | * '*@d' will hold the results of the attempted shift, but is not | ||||
| * considered "safe for use" if true is returned. | * considered "safe for use" if true is returned. | ||||
| */ | */ | ||||
| #define check_shl_overflow(a, s, d) __must_check_overflow(({ \ | #define check_shl_overflow(a, s, d) __must_check_overflow(({ \ | ||||
| typeof(a) _a = a; \ | typeof(a) _a = a; \ | ||||
| typeof(s) _s = s; \ | typeof(s) _s = s; \ | ||||
| typeof(d) _d = d; \ | typeof(d) _d = d; \ | ||||
| u64 _a_full = _a; \ | unsigned long long _a_full = _a; \ | ||||
| unsigned int _to_shift = \ | unsigned int _to_shift = \ | ||||
| is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \ | is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \ | ||||
| *_d = (_a_full << _to_shift); \ | *_d = (_a_full << _to_shift); \ | ||||
| (_to_shift != _s || is_negative(*_d) || is_negative(_a) || \ | (_to_shift != _s || is_negative(*_d) || is_negative(_a) || \ | ||||
| (*_d >> _to_shift) != _a); \ | (*_d >> _to_shift) != _a); \ | ||||
| })) | })) | ||||
| #define __overflows_type_constexpr(x, T) ( \ | #define __overflows_type_constexpr(x, T) ( \ | ||||
| is_unsigned_type(typeof(x)) ? \ | is_unsigned_type(typeof(x)) ? \ | ||||
| (x) > type_max(typeof(T)) : \ | (x) > type_max(T) : \ | ||||
| is_unsigned_type(typeof(T)) ? \ | is_unsigned_type(typeof(T)) ? \ | ||||
| (x) < 0 || (x) > type_max(typeof(T)) : \ | (x) < 0 || (x) > type_max(T) : \ | ||||
| (x) < type_min(typeof(T)) || (x) > type_max(typeof(T))) | (x) < type_min(T) || (x) > type_max(T)) | ||||
| #define __overflows_type(x, T) ({ \ | #define __overflows_type(x, T) ({ \ | ||||
| typeof(T) v = 0; \ | typeof(T) v = 0; \ | ||||
| check_add_overflow((x), v, &v); \ | check_add_overflow((x), v, &v); \ | ||||
| }) | }) | ||||
| /** | /** | ||||
| * overflows_type - helper for checking the overflows between value, variables, | * overflows_type - helper for checking the overflows between value, variables, | ||||
| ▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | |||||
| * instance variable of type @type. | * instance variable of type @type. | ||||
| * | * | ||||
| * Return: number of bytes needed or SIZE_MAX on overflow. | * Return: number of bytes needed or SIZE_MAX on overflow. | ||||
| */ | */ | ||||
| #define struct_size_t(type, member, count) \ | #define struct_size_t(type, member, count) \ | ||||
| struct_size((type *)NULL, member, count) | struct_size((type *)NULL, member, count) | ||||
| /** | /** | ||||
| * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. | * __DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. | ||||
| * Enables caller macro to pass (different) initializer. | * Enables caller macro to pass arbitrary trailing expressions | ||||
| * | * | ||||
| * @type: structure type name, including "struct" keyword. | * @type: structure type name, including "struct" keyword. | ||||
| * @name: Name for a variable to define. | * @name: Name for a variable to define. | ||||
| * @member: Name of the array member. | * @member: Name of the array member. | ||||
| * @count: Number of elements in the array; must be compile-time const. | * @count: Number of elements in the array; must be compile-time const. | ||||
| * @initializer: initializer expression (could be empty for no init). | * @trailer: Trailing expressions for attributes and/or initializers. | ||||
| */ | */ | ||||
| #define _DEFINE_FLEX(type, name, member, count, initializer) \ | #define __DEFINE_FLEX(type, name, member, count, trailer...) \ | ||||
| _Static_assert(__builtin_constant_p(count), \ | _Static_assert(__builtin_constant_p(count), \ | ||||
| "onstack flex array members require compile-time const count"); \ | "onstack flex array members require compile-time const count"); \ | ||||
| union { \ | union { \ | ||||
| u8 bytes[struct_size_t(type, member, count)]; \ | u8 bytes[struct_size_t(type, member, count)]; \ | ||||
| type obj; \ | type obj; \ | ||||
| } name##_u initializer; \ | } name##_u trailer; \ | ||||
| type *name = (type *)&name##_u | type *name = (type *)&name##_u | ||||
| /** | /** | ||||
| * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing | * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. | ||||
| * flexible array member. | * Enables caller macro to pass (different) initializer. | ||||
| * | * | ||||
| * @type: structure type name, including "struct" keyword. | * @type: structure type name, including "struct" keyword. | ||||
| * @name: Name for a variable to define. | * @name: Name for a variable to define. | ||||
| * @member: Name of the array member. | * @member: Name of the array member. | ||||
| * @count: Number of elements in the array; must be compile-time const. | * @count: Number of elements in the array; must be compile-time const. | ||||
| * @initializer: Initializer expression (e.g., pass `= { }` at minimum). | |||||
| */ | |||||
| #define _DEFINE_FLEX(type, name, member, count, initializer...) \ | |||||
| __DEFINE_FLEX(type, name, member, count, = { .obj initializer }) | |||||
| /** | |||||
| * DEFINE_RAW_FLEX() - Define an on-stack instance of structure with a trailing | |||||
| * flexible array member, when it does not have a __counted_by annotation. | |||||
| * | * | ||||
| * @type: structure type name, including "struct" keyword. | |||||
| * @name: Name for a variable to define. | |||||
| * @member: Name of the array member. | |||||
| * @count: Number of elements in the array; must be compile-time const. | |||||
| * | |||||
| * Define a zeroed, on-stack, instance of @type structure with a trailing | * Define a zeroed, on-stack, instance of @type structure with a trailing | ||||
| * flexible array member. | * flexible array member. | ||||
| * Use __struct_size(@name) to get compile-time size of it afterwards. | * Use __struct_size(@name) to get compile-time size of it afterwards. | ||||
| * Use __member_size(@name->member) to get compile-time size of @name members. | |||||
| * Use STACK_FLEX_ARRAY_SIZE(@name, @member) to get compile-time number of | |||||
| * elements in array @member. | |||||
| */ | */ | ||||
| #define DEFINE_FLEX(type, name, member, count) \ | #define DEFINE_RAW_FLEX(type, name, member, count) \ | ||||
| _DEFINE_FLEX(type, name, member, count, = {}) | __DEFINE_FLEX(type, name, member, count, = { }) | ||||
| /** | |||||
| * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing | |||||
| * flexible array member. | |||||
| * | |||||
| * @TYPE: structure type name, including "struct" keyword. | |||||
| * @NAME: Name for a variable to define. | |||||
| * @MEMBER: Name of the array member. | |||||
| * @COUNTER: Name of the __counted_by member. | |||||
| * @COUNT: Number of elements in the array; must be compile-time const. | |||||
| * | |||||
| * Define a zeroed, on-stack, instance of @TYPE structure with a trailing | |||||
| * flexible array member. | |||||
| * Use __struct_size(@NAME) to get compile-time size of it afterwards. | |||||
| * Use __member_size(@NAME->member) to get compile-time size of @NAME members. | |||||
| * Use STACK_FLEX_ARRAY_SIZE(@name, @member) to get compile-time number of | |||||
| * elements in array @member. | |||||
| */ | |||||
| #define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT) \ | |||||
| _DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .COUNTER = COUNT, }) | |||||
| /** | |||||
| * STACK_FLEX_ARRAY_SIZE() - helper macro for DEFINE_FLEX() family. | |||||
| * Returns the number of elements in @array. | |||||
| * | |||||
| * @name: Name for a variable defined in DEFINE_RAW_FLEX()/DEFINE_FLEX(). | |||||
| * @array: Name of the array member. | |||||
| */ | |||||
| #define STACK_FLEX_ARRAY_SIZE(name, array) \ | |||||
| (__member_size((name)->array) / sizeof(*(name)->array) + \ | |||||
| __must_be_array((name)->array)) | |||||
| #endif /* _LINUXKPI_LINUX_OVERFLOW_H */ | #endif /* _LINUXKPI_LINUX_OVERFLOW_H */ | ||||