diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-06-16 14:33:41 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-06-16 14:33:41 -0700 |
commit | 335f1a7eb2a08218301deae92244591a0ee9710c (patch) | |
tree | 88267494e0615c43d9849f8efd23c62b091228e3 /git-compat-util.h | |
parent | 2c185f0476bbbd3a49dee54f3b67a76d90c59091 (diff) | |
parent | 89c855ed3cbe64bea93ea081d0e96077e9ee8517 (diff) | |
download | git-335f1a7eb2a08218301deae92244591a0ee9710c.tar.gz |
Merge branch 'ep/do-not-feed-a-pointer-to-array-size' into maint
Catch a programmer mistake to feed a pointer not an array to
ARRAY_SIZE() macro, by using a couple of GCC extensions.
* ep/do-not-feed-a-pointer-to-array-size:
git-compat-util.h: implement a different ARRAY_SIZE macro for for safely deriving the size of array
Diffstat (limited to 'git-compat-util.h')
-rw-r--r-- | git-compat-util.h | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/git-compat-util.h b/git-compat-util.h index bc8fc8cf85..b45c75fc7a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -3,6 +3,23 @@ #define _FILE_OFFSET_BITS 64 + +/* Derived from Linux "Features Test Macro" header + * Convenience macros to test the versions of gcc (or + * a compatible compiler). + * Use them like this: + * #if GIT_GNUC_PREREQ (2,8) + * ... code requiring gcc 2.8 or later ... + * #endif +*/ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define GIT_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else + #define GIT_GNUC_PREREQ(maj, min) 0 +#endif + + #ifndef FLEX_ARRAY /* * See if our compiler is known to support flexible array members. @@ -25,7 +42,42 @@ #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 defined(__GNUC__) && (__GNUC__ >= 3) +# if GIT_GNUC_PREREQ(3, 1) + /* &arr[0] degrades to a pointer: a different type from an array */ +# define BARF_UNLESS_AN_ARRAY(arr) \ + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \ + __typeof__(&(arr)[0]))) +# else +# define BARF_UNLESS_AN_ARRAY(arr) 0 +# endif +#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 the build_assert_or_zero macro). + */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]) + BARF_UNLESS_AN_ARRAY(x)) + #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define maximum_signed_value_of_type(a) \ |