summaryrefslogtreecommitdiff
path: root/include/compile_time_macros.h
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2020-01-10 17:25:12 -0700
committerCommit Bot <commit-bot@chromium.org>2020-01-14 03:29:50 +0000
commit284344b78731339c3c00eaf71754a071d3ff637c (patch)
tree251ff96296a7157116404efe17df5b81b7de79f8 /include/compile_time_macros.h
parentfc6070c975516b8cf8f01e00bda6bf32c74e9809 (diff)
downloadchrome-ec-284344b78731339c3c00eaf71754a071d3ff637c.tar.gz
common: make ARRAY_SIZE, ARRAY_BEGIN, ARRAY_END type safe
ARRAY_SIZE (and family) used to allow pointers to be passed to the macro, which would cause a value of one for the array size. This is a really easy accidental programming error. This change causes ARRAY_SIZE and ARRAY_END to divide by zero (using BUILD_CHECK_INLINE) if a pointer is passed. ARRAY_BEGIN will cause a BUILD_ASSSERT to fail if a pointer is passed. BUG=none BRANCH=none TEST=buildall Change-Id: Ibdd0efcc9fc46c43d46f2bd06529cc76df910f2e Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1993915 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-by: Scott Collyer <scollyer@chromium.org>
Diffstat (limited to 'include/compile_time_macros.h')
-rw-r--r--include/compile_time_macros.h21
1 files changed, 18 insertions, 3 deletions
diff --git a/include/compile_time_macros.h b/include/compile_time_macros.h
index e5c1242f4c..ae6ac267eb 100644
--- a/include/compile_time_macros.h
+++ b/include/compile_time_macros.h
@@ -21,11 +21,26 @@
*/
#define BUILD_CHECK_INLINE(value, cond_true) ((value) / (!!(cond_true)))
-/* Number of elements in an array */
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+/* Check that the value is an array (not a pointer) */
+#define _IS_ARRAY(arr) \
+ !__builtin_types_compatible_p(typeof(arr), typeof(&(arr)[0]))
+
+/**
+ * ARRAY_SIZE - Number of elements in an array.
+ *
+ * This version is type-safe and will not allow pointers, causing a
+ * compile-time divide by zero error if a pointer is passed.
+ */
+#define ARRAY_SIZE(arr) \
+ BUILD_CHECK_INLINE(sizeof(arr) / sizeof((arr)[0]), _IS_ARRAY(arr))
/* Make for loops that iterate over pointers to array entries more readable */
-#define ARRAY_BEGIN(array) (array)
+#define ARRAY_BEGIN(array) \
+ ({ \
+ BUILD_ASSERT(_IS_ARRAY(array), \
+ "ARRAY_BEGIN is only compatible with arrays."); \
+ (array); \
+ })
#define ARRAY_END(array) ((array) + ARRAY_SIZE(array))
/* Just in case - http://gcc.gnu.org/onlinedocs/gcc/Offsetof.html */