Re: [PATCH 4/5] git-compat-util: add `signed_mult_overflows` and `mult_overflows` macros
Hi Johannes
On 14/10/2026 07:09, Johannes Schindelin via GitGitGadget wrote:
> From: Johannes Schindelin <johannes.schindelin@gmx.de>
> > `unsigned_mult_overflows()` does not cover signed arithmetic, but types
> such as `time_t` can be signed or unsigned. Add signed and type-generic
> guards so callers can check multiplication overflow in either case.
It would have been nice to mention that the type-generic macro is gcc only so we cannot rely on this for safety checks.
Show 5 quoted lines
> #define maximum_signed_value_of_type(a) \
> (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a)))
> > +/* Account for the extra negative value on two's-complement targets. */
> +#define minimum_signed_value_of_type(a) \
> + (-maximum_signed_value_of_type(a) - (INTMAX_MIN < -INTMAX_MAX))
Do we support any platforms that do not use two's complement arithmetic? C23 makes it mandatory so presumably there are not may contemporary platforms out there that do not use it.
Show 5 quoted lines
> +/*
> + * Returns true if the multiplication of "a" and "b" will
> + * overflow or underflow a signed type. The types of "a" and "b"
> + * must match and must be signed. Note that this macro evaluates
> + * both "a" and "b" twice!
> + */
> +#define signed_mult_overflows(a, b) \
As the macro relies on both operands being the same width, can we use BUILD_ASSERT_OR_ZERO() to ensure sizeof(a) == sizeof(b) here?
> + (((a) > 0 && (b) > 0 && (a) > maximum_signed_value_of_type(a) / (b)) || \
> + ((a) < 0 && (b) < 0 && (a) < maximum_signed_value_of_type(a) / (b)) || \
> + ((a) > 0 && (b) < 0 && (b) < minimum_signed_value_of_type(a) / (a)) || \
> + ((a) < 0 && (b) > 0 && (a) < minimum_signed_value_of_type(b) / (b)))
Show 24 quoted lines
> +
> +/*
> + * Returns true if the product of "a" and "b", after the usual arithmetic
> + * conversions, cannot be represented in the multiplication expression's
> + * type. The operands must be integers and may be evaluated more than once.
> + */
> +#if GIT_GNUC_PREREQ(3, 1)
> +#define mult_overflows(a, b) \
> + (is_unsigned_type((a) * (b)) \
> + ? unsigned_mult_overflows((__typeof__((a) * (b)))(a), \
> + (__typeof__((a) * (b)))(b)) \
> + : signed_mult_overflows((__typeof__((a) * (b)))(a), \
> + (__typeof__((a) * (b)))(b)))
> +#else
> +/*
> + * This implementation needs GNU `typeof` to convert both operands to the
> + * multiplication's type. Skip the check without that extension.
> + */
> +#define mult_overflows(a, b) 0
> +#endif
> +
> /*
> * Returns true if the left shift of "a" by "shift" bits will
> * overflow. The type of "a" must be unsigned.