Skip to content

Commit 6b70aed

Browse files
committed
git-compat-util: add signed_mult_overflows and mult_overflows macros
The existing unsigned_mult_overflows macro detects multiplication overflow for unsigned types by checking b > MAX / a. Add the signed counterpart and a type-generic wrapper. signed_mult_overflows handles all four sign combinations: positive*positive, negative*negative, positive*negative, and negative*positive. Each case checks against maximum_signed_value_of_type to detect both overflow (result > MAX) and underflow (result < MIN, via the negation trick). mult_overflows dispatches to the unsigned or signed variant based on the type's signedness, using a new is_unsigned_type macro. This is useful for types like time_t whose signedness is implementation-defined: POSIX does not mandate whether time_t is signed or unsigned, and platforms differ. is_unsigned_type uses the GCC typeof extension, which is available on all compilers git targets (GCC, Clang, MSVC's C11 mode). The existing codebase already depends on GCC extensions in other places (e.g., __attribute__). Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 94f0577 commit 6b70aed

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

git-compat-util.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ struct strbuf;
8585

8686
#define bitsizeof(x) (CHAR_BIT * sizeof(x))
8787

88+
#define is_unsigned_type(a) ((typeof(a))-1 >= 0)
89+
8890
#define maximum_signed_value_of_type(a) \
8991
(INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a)))
9092

@@ -111,6 +113,28 @@ struct strbuf;
111113
#define unsigned_mult_overflows(a, b) \
112114
((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
113115

116+
/*
117+
* Returns true if the multiplication of "a" and "b" will
118+
* overflow or underflow a signed type. The types of "a" and "b"
119+
* must match and must be signed. Note that this macro evaluates
120+
* both "a" and "b" twice!
121+
*/
122+
#define signed_mult_overflows(a, b) \
123+
(((a) > 0 && (b) > 0 && (a) > maximum_signed_value_of_type(a) / (b)) || \
124+
((a) < 0 && (b) < 0 && (a) < maximum_signed_value_of_type(a) / (b)) || \
125+
((a) > 0 && (b) < 0 && (b) < -(maximum_signed_value_of_type(a) / (a))) || \
126+
((a) < 0 && (b) > 0 && (a) < -(maximum_signed_value_of_type(b) / (b))))
127+
128+
/*
129+
* Returns true if the multiplication of "a" and "b" will overflow,
130+
* regardless of whether the type is signed or unsigned. Note that
131+
* this macro evaluates both "a" and "b" twice!
132+
*/
133+
#define mult_overflows(a, b) \
134+
(is_unsigned_type(a) \
135+
? unsigned_mult_overflows(a, b) \
136+
: signed_mult_overflows(a, b))
137+
114138
/*
115139
* Returns true if the left shift of "a" by "shift" bits will
116140
* overflow. The type of "a" must be unsigned.

0 commit comments

Comments
 (0)