Index: base/numerics/safe_math_impl.h |
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h |
index 71fc278b297c26f7bf51ec695a3baacdb977e961..0e21b6b130b5ae1df5075fd82871a77d2646868c 100644 |
--- a/base/numerics/safe_math_impl.h |
+++ b/base/numerics/safe_math_impl.h |
@@ -256,6 +256,15 @@ struct IsIntegerArithmeticSafe { |
sizeof(T) >= (2 * sizeof(Rhs)); |
}; |
+// Probe for builtin math overflow support on Clang and version check on GCC. |
+#if defined(__has_builtin) |
+#define USE_OVERFLOW_BUILTINS (__has_builtin(__builtin_add_overflow)) |
+#elif defined(__GNUC__) |
+#define USE_OVERFLOW_BUILTINS (__GNUC__ >= 5) |
+#else |
+#define USE_OVERFLOW_BUILTINS (0) |
+#endif |
+ |
// Here are the actual portable checked integer math implementations. |
// TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
// way to coalesce things into the CheckedNumericState specializations below. |
@@ -285,6 +294,9 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
std::numeric_limits<V>::is_integer, |
bool>::type |
CheckedAdd(T x, U y, V* result) { |
+#if USE_OVERFLOW_BUILTINS |
+ return !__builtin_add_overflow(x, y, result); |
+#else |
using Promotion = |
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
Promotion presult; |
@@ -301,6 +313,7 @@ CheckedAdd(T x, U y, V* result) { |
} |
*result = static_cast<V>(presult); |
return is_valid && IsValueInRangeForNumericType<V>(presult); |
+#endif |
} |
template <typename T> |
@@ -327,6 +340,9 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
std::numeric_limits<V>::is_integer, |
bool>::type |
CheckedSub(T x, U y, V* result) { |
+#if USE_OVERFLOW_BUILTINS |
+ return !__builtin_sub_overflow(x, y, result); |
+#else |
using Promotion = |
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
Promotion presult; |
@@ -343,6 +359,7 @@ CheckedSub(T x, U y, V* result) { |
} |
*result = static_cast<V>(presult); |
return is_valid && IsValueInRangeForNumericType<V>(presult); |
+#endif |
} |
// Integer multiplication is a bit complicated. In the fast case we just |
@@ -406,6 +423,20 @@ typename std::enable_if<std::numeric_limits<T>::is_integer && |
std::numeric_limits<V>::is_integer, |
bool>::type |
CheckedMul(T x, U y, V* result) { |
+#if USE_OVERFLOW_BUILTINS |
+#if defined(__clang__) |
+ // TODO(jschuh): Get the Clang runtime library issues sorted out so we can |
+ // support full-width, mixed-sign multiply builtins. https://crbug.com/613003 |
+ static const bool kUseMaxInt = |
+ sizeof(__typeof__(x * y)) < sizeof(intptr_t) || |
+ (sizeof(__typeof__(x * y)) == sizeof(intptr_t) && |
+ std::is_signed<T>::value == std::is_signed<U>::value); |
+#else |
+ static const bool kUseMaxInt = true; |
+#endif |
+ if (kUseMaxInt) |
+ return !__builtin_mul_overflow(x, y, result); |
+#endif |
using Promotion = |
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type; |
Promotion presult; |
@@ -424,6 +455,9 @@ CheckedMul(T x, U y, V* result) { |
return is_valid && IsValueInRangeForNumericType<V>(presult); |
} |
+// Avoid poluting the namespace once we're done with the macro. |
+#undef USE_OVERFLOW_BUILTINS |
+ |
// Division just requires a check for a zero denominator or an invalid negation |
// on signed min/-1. |
template <typename T> |