* [PATCH] git-compat-util.h: implement a different ARRAY_SIZE macro for for safely deriving the size of array
@ 2014-10-30 10:56 Elia Pinto
0 siblings, 0 replies; only message in thread
From: Elia Pinto @ 2014-10-30 10:56 UTC (permalink / raw)
To: git; +Cc: Elia Pinto
To get number of elements in an array git use the ARRAY_SIZE macro defined as:
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
The problem with it is a possibility of mistakenly passing to it a
pointer instead an array.
Use instead a different but compatible ARRAY_SIZE() macro,
which (given a good compiler) will also break compile if you try to
use it on a pointer.
This can ensure your code is robust to changes, without
needing a gratuitous macro or constant. A similar
ARRAY_SIZE implementation also exists in the linux kernel.
Credits to Rusty Russell and his ccan library.
Signed-off-by: Elia Pinto <gitter.spiros@gmail.com>
---
Makefile | 7 +++++++
configure.ac | 24 ++++++++++++++++++++++++
git-compat-util.h | 36 +++++++++++++++++++++++++++++++++++-
3 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 827006b..37eb1e1 100644
--- a/Makefile
+++ b/Makefile
@@ -339,6 +339,9 @@ all::
# return NULL when it receives a bogus time_t.
#
# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
+#
+# Define SUPPORT__BUILTIN_TYPES_COMPATIBLE_P if your compiler support
+# the builtin function __builtin_types_compatible_
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -1382,6 +1385,10 @@ ifdef HAVE_CLOCK_GETTIME
EXTLIBS += -lrt
endif
+ifdef SUPPORT__BUILTIN_TYPES_COMPATIBLE_P
+ BASIC_CFLAGS += -DSUPPORT__BUILTIN_TYPES_COMPATIBLE_P
+endif
+
ifeq ($(TCLTK_PATH),)
NO_TCLTK = NoThanks
endif
diff --git a/configure.ac b/configure.ac
index 6af9647..9d489c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,6 +139,28 @@ if test -n "$1"; then
fi
])
+AC_DEFUN([GIT_FUNC_TYPES_COMPATIBLE_P], [
+ AC_CACHE_CHECK([if compiler has __builtin_types_compatible_p function],
+ [cc_cv_func_types_compatible_p],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ [int some_function();
+ int some_function() {
+ return __builtin_types_compatible_p(char *, int) ? 1 : 0;
+ }])],
+ [cc_cv_func_types_compatible_p=yes],
+ [cc_cv_func_types_compatible_p=no])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([test "x$cc_cv_func_types_compatible_p" = "xyes"],
+ [GIT_CONF_SUBST([SUPPORT__BUILTIN_TYPES_COMPATIBLE_P], [YesPlease])],
+ [$2])
+])
+
+
+
## Configure body starts here.
AC_PREREQ(2.59)
@@ -874,6 +896,8 @@ else
fi
GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
+GIT_FUNC_TYPES_COMPATIBLE_P
+
## Checks for library functions.
## (in default C library and libraries checked by AC_CHECK_LIB)
diff --git a/git-compat-util.h b/git-compat-util.h
index 400e921..cb45886 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -25,7 +25,41 @@
#endif
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+/*
+ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can be used in an expression: its value is "0".
+ *
+ * Example:
+ * #define foo_to_char(foo) \
+ * ((char *)(foo) \
+ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
+ */
+#define BUILD_ASSERT_OR_ZERO(cond) \
+ (sizeof(char [1 - 2*!(cond)]) - 1)
+
+
+#if SUPPORT__BUILTIN_TYPES_COMPATIBLE_P
+/* &arr[0] degrades to a pointer: a different type from an array */
+#define _array_size_chk(arr) \
+ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \
+ typeof(&(arr)[0])))
+#else
+#define _array_size_chk(arr) 0
+#endif
+
+/*
+ * ARRAY_SIZE - get the number of elements in a visible array
+ * <at> x: the array whose size you want.
+ *
+ * This does not work on pointers, or arrays declared as [], or
+ * function parameters. With correct compiler support, such usage
+ * will cause a build error (see build_assert).
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]) + _array_size_chk(x))
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
#define maximum_signed_value_of_type(a) \
--
1.7.10.4
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2014-10-30 10:56 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-30 10:56 [PATCH] git-compat-util.h: implement a different ARRAY_SIZE macro for for safely deriving the size of array Elia Pinto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).