Message ID | 20211111204436.1560365-5-vishal.l.verma@intel.com |
---|---|
State | New, archived |
Headers | show |
Series | Initial CXL support | expand |
Hey Vishal, On 11/11/21 20:44, Vishal Verma wrote: > Add struct_size() from include/linux/overflow.h which calculates the > size of a struct with a trailing variable length array. [...] > +/* > + * Helpers for struct_size() copied from include/linux/overflow.h (GPL-2.0) > + * > + * For simplicity and code hygiene, the fallback code below insists on > + * a, b and *d having the same type (similar to the min() and max() > + * macros), whereas gcc's type-generic overflow checkers accept > + * different types. Hence we don't just make check_add_overflow an > + * alias for __builtin_add_overflow, but add type checks similar to > + * below. > + */ > +#define check_add_overflow(a, b, d) (({ \ > + typeof(a) __a = (a); \ > + typeof(b) __b = (b); \ > + typeof(d) __d = (d); \ > + (void) (&__a == &__b); \ > + (void) (&__a == __d); \ > + __builtin_add_overflow(__a, __b, __d); \ > +})) > + > +#define check_mul_overflow(a, b, d) (({ \ > + typeof(a) __a = (a); \ > + typeof(b) __b = (b); \ > + typeof(d) __d = (d); \ > + (void) (&__a == &__b); \ > + (void) (&__a == __d); \ > + __builtin_mul_overflow(__a, __b, __d); \ > +})) > + The introduction of this two macro helpers broke compilation against < gcc 5.1.0 (think CentOS/OL/RHEL 7 or anything resembling that) and clang 3.4. Particularly because of the lack of these overflow builtins __builtin_mul_overflow() / __buitin_add_overflow() giving errors like: BUILDSTDERR: lib/.libs/libcxl.so: undefined reference to `__builtin_mul_overflow' BUILDSTDERR: lib/.libs/libcxl.so: undefined reference to `__builtin_add_overflow' Since you pulled this helper from the kernel, you might wanna pull the compat code too that was there in commit f0907827a8a9 ("compiler.h: enable builtin overflow checkers and add fallback code"), particularly something like below. #if GCC_VERSION >= 50100 #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 #endif #if __clang__ && \ __has_builtin(__builtin_mul_overflow) && \ __has_builtin(__builtin_add_overflow) #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 #endif #if COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW #define check_add_overflow(a, b, d) (({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ __builtin_add_overflow(__a, __b, __d); \ })) #define check_mul_overflow(a, b, d) (({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ __builtin_mul_overflow(__a, __b, __d); \ })) #else /* !COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ /* Checking for unsigned overflow is relatively easy without causing UB. */ #define __unsigned_add_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = __a + __b; \ *__d < __a; \ }) #define __unsigned_sub_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = __a - __b; \ __a < __b; \ }) /* * If one of a or b is a compile-time constant, this avoids a division. */ #define __unsigned_mul_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = __a * __b; \ __builtin_constant_p(__b) ? \ __b > 0 && __a > type_max(typeof(__a)) / __b : \ __a > 0 && __b > type_max(typeof(__b)) / __a; \ }) /* * For signed types, detecting overflow is much harder, especially if * we want to avoid UB. But the interface of these macros is such that * we must provide a result in *d, and in fact we must produce the * result promised by gcc's builtins, which is simply the possibly * wrapped-around value. Fortunately, we can just formally do the * operations in the widest relevant unsigned type (u64) and then * truncate the result - gcc is smart enough to generate the same code * with and without the (u64) casts. */ /* * Adding two signed integers can overflow only if they have the same * sign, and overflow has happened iff the result has the opposite * sign. */ #define __signed_add_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = (u64)__a + (u64)__b; \ (((~(__a ^ __b)) & (*__d ^ __a)) \ & type_min(typeof(__a))) != 0; \ }) /* * Subtraction is similar, except that overflow can now happen only * when the signs are opposite. In this case, overflow has happened if * the result has the opposite sign of a. */ #define __signed_sub_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = (u64)__a - (u64)__b; \ ((((__a ^ __b)) & (*__d ^ __a)) \ & type_min(typeof(__a))) != 0; \ }) /* * Signed multiplication is rather hard. gcc always follows C99, so * division is truncated towards 0. This means that we can write the * overflow check like this: * * (a > 0 && (b > MAX/a || b < MIN/a)) || * (a < -1 && (b > MIN/a || b < MAX/a) || * (a == -1 && b == MIN) * * The redundant casts of -1 are to silence an annoying -Wtype-limits * (included in -Wextra) warning: When the type is u8 or u16, the * __b_c_e in check_mul_overflow obviously selects * __unsigned_mul_overflow, but unfortunately gcc still parses this * code and warns about the limited range of __b. */ #define __signed_mul_overflow(a, b, d) ({ \ typeof(a) __a = (a); \ typeof(b) __b = (b); \ typeof(d) __d = (d); \ typeof(a) __tmax = type_max(typeof(a)); \ typeof(a) __tmin = type_min(typeof(a)); \ (void) (&__a == &__b); \ (void) (&__a == __d); \ *__d = (u64)__a * (u64)__b; \ (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ (__b == (typeof(__b))-1 && __a == __tmin); \ }) #define check_add_overflow(a, b, d) \ __builtin_choose_expr(is_signed_type(typeof(a)), \ __signed_add_overflow(a, b, d), \ __unsigned_add_overflow(a, b, d)) #define check_sub_overflow(a, b, d) \ __builtin_choose_expr(is_signed_type(typeof(a)), \ __signed_sub_overflow(a, b, d), \ __unsigned_sub_overflow(a, b, d)) #define check_mul_overflow(a, b, d) \ __builtin_choose_expr(is_signed_type(typeof(a)), \ __signed_mul_overflow(a, b, d), \ __unsigned_mul_overflow(a, b, d)) #endif
diff --git a/util/size.h b/util/size.h index 646edae..a0f3593 100644 --- a/util/size.h +++ b/util/size.h @@ -4,6 +4,8 @@ #ifndef _NDCTL_SIZE_H_ #define _NDCTL_SIZE_H_ #include <stdbool.h> +#include <stdint.h> +#include <util/util.h> #define SZ_1K 0x00000400 #define SZ_4K 0x00001000 @@ -30,4 +32,64 @@ static inline bool is_power_of_2(unsigned long long v) #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define HPAGE_SIZE (2 << 20) +/* + * Helpers for struct_size() copied from include/linux/overflow.h (GPL-2.0) + * + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) (({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +})) + +#define check_mul_overflow(a, b, d) (({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_mul_overflow(__a, __b, __d); \ +})) + +/* + * Compute a*b+c, returning SIZE_MAX on overflow. Internal helper for + * struct_size() below. + */ +static inline size_t __ab_c_size(size_t a, size_t b, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + if (check_add_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * struct_size() - Calculate size of structure with trailing array. + * @p: Pointer to the structure. + * @member: Name of the array member. + * @count: Number of elements in the array. + * + * Calculates size of memory needed for structure @p followed by an + * array of @count number of @member elements. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size(p, member, count) \ + __ab_c_size(count, \ + sizeof(*(p)->member) + __must_be_array((p)->member),\ + sizeof(*(p))) + #endif /* _NDCTL_SIZE_H_ */ diff --git a/util/util.h b/util/util.h index ae0e4e1..b2b4ae6 100644 --- a/util/util.h +++ b/util/util.h @@ -63,6 +63,12 @@ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) +/* Are two types/vars the same type (ignoring qualifiers)? */ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) + +/* &a[0] degrades to a pointer: a different type from an array */ +#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) + enum { READ, WRITE, };