integer overflow: use compiler intrinsics if supported gcc and clang support __builtin_add_overflow, use it whenever possible, falling back to our naive routines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
diff --git a/src/common.h b/src/common.h
index 8d1e890..98109ae 100644
--- a/src/common.h
+++ b/src/common.h
@@ -17,6 +17,11 @@
# define GIT_INLINE(type) static inline type
#endif
+/** Support for gcc/clang __has_builtin intrinsic */
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
#include <assert.h>
#include <errno.h>
#include <limits.h>
diff --git a/src/integer.h b/src/integer.h
index a4abe2b..8e86a48 100644
--- a/src/integer.h
+++ b/src/integer.h
@@ -54,6 +54,19 @@ GIT_INLINE(bool) git__add_uint64_overflow(uint64_t *out, uint64_t one, uint64_t
return false;
}
+/* Use clang/gcc compiler intrinsics whenever possible */
+#if (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow)
+# define git__add_sizet_overflow(out, one, two) \
+ __builtin_uadd_overflow(one, two, out)
+# define git__multiply_sizet_overflow(out, one, two)
+ __builtin_umul_overflow(one, two, out)
+#elif (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow)
+# define git__add_sizet_overflow(out, one, two) \
+ __builtin_uaddl_overflow(one, two, out)
+# define git__multiply_sizet_overflow(out, one, two) \
+ __builtin_umull_overflow(one, two, out)
+#else
+
/**
* Sets `one + two` into `out`, unless the arithmetic would overflow.
* @return true if the result fits in a `size_t`, false on overflow.
@@ -78,4 +91,6 @@ GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t tw
return false;
}
+#endif
+
#endif /* INCLUDE_integer_h__ */