aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorVishal Verma <vishal.l.verma@intel.com>2021-10-07 02:21:26 -0600
committerVishal Verma <vishal.l.verma@intel.com>2021-12-09 14:06:43 -0700
commit7aa7c7be6e803de267a165237e23577ab496e792 (patch)
tree974729aaafec792c83b8cf20623578644fad0336
parent894fb9b2b59364f7f5683ea68c8bd765223a4ca8 (diff)
util: add the struct_size() helper from the kernel
Add struct_size() from include/linux/overflow.h which calculates the size of a struct with a trailing variable length array. Suggested-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
-rw-r--r--util/size.h62
-rw-r--r--util/util.h6
2 files changed, 68 insertions, 0 deletions
diff --git a/util/size.h b/util/size.h
index 646edae0..a0f3593d 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 ae0e4e1f..b2b4ae65 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,
};