From bc04b57eedb057f60ac23b9da9cfa7e26ca1766a Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 17 Nov 2021 11:52:21 +0000 Subject: [PATCH] gtypes: Rework checked arithmetic handling Rather than using the fixed-type compiler builtins (`__builtin_uadd_overflow()`, etc.), use the generic versions (`__builtin_add_overflow()`). This avoids issues with matching the definition of GLib types (such as `guint` and particularly `gsize`) to basic C types (`int`, `long`, `long long`), as the mapping can vary between platforms. See https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html Adjust the fallback inline functions similarly. Signed-off-by: Philip Withnall Fixes: #2523 --- glib/gtypes.h | 66 ++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/glib/gtypes.h b/glib/gtypes.h index 2c4825582..ea2a49057 100644 --- a/glib/gtypes.h +++ b/glib/gtypes.h @@ -424,56 +424,62 @@ typedef const gchar * (*GTranslateFunc) (const gchar *str, /* https://bugzilla.gnome.org/show_bug.cgi?id=769104 */ #if __GNUC__ >= 5 && !defined(__INTEL_COMPILER) #define _GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS -#elif g_macro__has_builtin(__builtin_uadd_overflow) +#elif g_macro__has_builtin(__builtin_add_overflow) #define _GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS #endif #endif +#ifdef _GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS + #define g_uint_checked_add(dest, a, b) \ - _GLIB_CHECKED_ADD_U32(dest, a, b) + (!__builtin_add_overflow(a, b, dest)) #define g_uint_checked_mul(dest, a, b) \ - _GLIB_CHECKED_MUL_U32(dest, a, b) + (!__builtin_mul_overflow(a, b, dest)) #define g_uint64_checked_add(dest, a, b) \ - _GLIB_CHECKED_ADD_U64(dest, a, b) + (!__builtin_add_overflow(a, b, dest)) #define g_uint64_checked_mul(dest, a, b) \ - _GLIB_CHECKED_MUL_U64(dest, a, b) + (!__builtin_mul_overflow(a, b, dest)) -#if GLIB_SIZEOF_SIZE_T == 8 #define g_size_checked_add(dest, a, b) \ - _GLIB_CHECKED_ADD_U64(dest, a, b) + (!__builtin_add_overflow(a, b, dest)) #define g_size_checked_mul(dest, a, b) \ - _GLIB_CHECKED_MUL_U64(dest, a, b) -#else -#define g_size_checked_add(dest, a, b) \ - _GLIB_CHECKED_ADD_U32(dest, a, b) -#define g_size_checked_mul(dest, a, b) \ - _GLIB_CHECKED_MUL_U32(dest, a, b) -#endif + (!__builtin_mul_overflow(a, b, dest)) + +#else /* !_GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS */ /* The names of the following inlines are private. Use the macro * definitions above. */ -#ifdef _GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS -static inline gboolean _GLIB_CHECKED_ADD_U32 (guint32 *dest, guint32 a, guint32 b) { - return !__builtin_uadd_overflow(a, b, dest); } -static inline gboolean _GLIB_CHECKED_MUL_U32 (guint32 *dest, guint32 a, guint32 b) { - return !__builtin_umul_overflow(a, b, dest); } -static inline gboolean _GLIB_CHECKED_ADD_U64 (guint64 *dest, guint64 a, guint64 b) { - G_STATIC_ASSERT(sizeof (unsigned long long) == sizeof (guint64)); - return !__builtin_uaddll_overflow(a, b, (unsigned long long *) dest); } -static inline gboolean _GLIB_CHECKED_MUL_U64 (guint64 *dest, guint64 a, guint64 b) { - return !__builtin_umulll_overflow(a, b, (unsigned long long *) dest); } -#else -static inline gboolean _GLIB_CHECKED_ADD_U32 (guint32 *dest, guint32 a, guint32 b) { +static inline gboolean _GLIB_CHECKED_ADD_UINT (guint *dest, guint a, guint b) { *dest = a + b; return *dest >= a; } -static inline gboolean _GLIB_CHECKED_MUL_U32 (guint32 *dest, guint32 a, guint32 b) { +static inline gboolean _GLIB_CHECKED_MUL_UINT (guint *dest, guint a, guint b) { *dest = a * b; return !a || *dest / a == b; } -static inline gboolean _GLIB_CHECKED_ADD_U64 (guint64 *dest, guint64 a, guint64 b) { +static inline gboolean _GLIB_CHECKED_ADD_UINT64 (guint64 *dest, guint64 a, guint64 b) { *dest = a + b; return *dest >= a; } -static inline gboolean _GLIB_CHECKED_MUL_U64 (guint64 *dest, guint64 a, guint64 b) { +static inline gboolean _GLIB_CHECKED_MUL_UINT64 (guint64 *dest, guint64 a, guint64 b) { *dest = a * b; return !a || *dest / a == b; } -#endif +static inline gboolean _GLIB_CHECKED_ADD_SIZE (gsize *dest, gsize a, gsize b) { + *dest = a + b; return *dest >= a; } +static inline gboolean _GLIB_CHECKED_MUL_SIZE (gsize *dest, gsize a, gsize b) { + *dest = a * b; return !a || *dest / a == b; } + +#define g_uint_checked_add(dest, a, b) \ + _GLIB_CHECKED_ADD_UINT(dest, a, b) +#define g_uint_checked_mul(dest, a, b) \ + _GLIB_CHECKED_MUL_UINT(dest, a, b) + +#define g_uint64_checked_add(dest, a, b) \ + _GLIB_CHECKED_ADD_UINT64(dest, a, b) +#define g_uint64_checked_mul(dest, a, b) \ + _GLIB_CHECKED_MUL_UINT64(dest, a, b) + +#define g_size_checked_add(dest, a, b) \ + _GLIB_CHECKED_ADD_SIZE(dest, a, b) +#define g_size_checked_mul(dest, a, b) \ + _GLIB_CHECKED_MUL_SIZE(dest, a, b) + +#endif /* !_GLIB_HAVE_BUILTIN_OVERFLOW_CHECKS */ /* IEEE Standard 754 Single Precision Storage Format (gfloat): *