Skip to content

Commit 89c855e

Browse files
devzero2000gitster
authored andcommitted
git-compat-util.h: implement a different ARRAY_SIZE macro for for safely deriving the size of array
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. The ARRAY_SIZE macro as conventionally defined does not provide good type-safety and the open-coded approach is more fragile, more verbose and provides no improvement in type-safety. Use instead a different but compatible ARRAY_SIZE() macro, which will also break compile if you try to use it on a pointer. This implemention revert to the original code if the compiler doesn't know the typeof and __builtin_types_compatible_p GCC extensions. This can ensure our 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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fdf96a2 commit 89c855e

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

git-compat-util.h

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,23 @@
33

44
#define _FILE_OFFSET_BITS 64
55

6+
7+
/* Derived from Linux "Features Test Macro" header
8+
* Convenience macros to test the versions of gcc (or
9+
* a compatible compiler).
10+
* Use them like this:
11+
* #if GIT_GNUC_PREREQ (2,8)
12+
* ... code requiring gcc 2.8 or later ...
13+
* #endif
14+
*/
15+
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
16+
# define GIT_GNUC_PREREQ(maj, min) \
17+
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
18+
#else
19+
#define GIT_GNUC_PREREQ(maj, min) 0
20+
#endif
21+
22+
623
#ifndef FLEX_ARRAY
724
/*
825
* See if our compiler is known to support flexible array members.
@@ -25,7 +42,42 @@
2542
#endif
2643
#endif
2744

28-
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
45+
46+
/*
47+
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
48+
* @cond: the compile-time condition which must be true.
49+
*
50+
* Your compile will fail if the condition isn't true, or can't be evaluated
51+
* by the compiler. This can be used in an expression: its value is "0".
52+
*
53+
* Example:
54+
* #define foo_to_char(foo) \
55+
* ((char *)(foo) \
56+
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
57+
*/
58+
#define BUILD_ASSERT_OR_ZERO(cond) \
59+
(sizeof(char [1 - 2*!(cond)]) - 1)
60+
61+
#if defined(__GNUC__) && (__GNUC__ >= 3)
62+
# if GIT_GNUC_PREREQ(3, 1)
63+
/* &arr[0] degrades to a pointer: a different type from an array */
64+
# define BARF_UNLESS_AN_ARRAY(arr) \
65+
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
66+
__typeof__(&(arr)[0])))
67+
# else
68+
# define BARF_UNLESS_AN_ARRAY(arr) 0
69+
# endif
70+
#endif
71+
/*
72+
* ARRAY_SIZE - get the number of elements in a visible array
73+
* <at> x: the array whose size you want.
74+
*
75+
* This does not work on pointers, or arrays declared as [], or
76+
* function parameters. With correct compiler support, such usage
77+
* will cause a build error (see the build_assert_or_zero macro).
78+
*/
79+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]) + BARF_UNLESS_AN_ARRAY(x))
80+
2981
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
3082

3183
#define maximum_signed_value_of_type(a) \

0 commit comments

Comments
 (0)