Blame SOURCES/ICU-13634-Adding-integer-overflow-logic-to-ICU4C-num.patch

2d07e8
From 23d76d88630ecee02515e2c8f5c8769cc795ae23 Mon Sep 17 00:00:00 2001
2d07e8
From: Shane Carr <shane@unicode.org>
2d07e8
Date: Fri, 23 Mar 2018 00:56:16 +0000
2d07e8
Subject: [PATCH] ICU-13634 Adding integer overflow logic to ICU4C number
2d07e8
 pipeline in places where it is in ICU4J.
2d07e8
2d07e8
X-SVN-Rev: 41136
2d07e8
2d07e8
diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp
2d07e8
index 83f08ac070..452e2fd79c 100644
2d07e8
--- a/icu4c/source/common/putil.cpp
2d07e8
+++ b/icu4c/source/common/putil.cpp
2d07e8
@@ -533,6 +533,30 @@ uprv_fmin(double x, double y)
2d07e8
     return (x > y ? y : x);
2d07e8
 }
2d07e8
 
2d07e8
+#include <iostream>
2d07e8
+
2d07e8
+U_CAPI UBool U_EXPORT2
2d07e8
+uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) {
2d07e8
+    // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow.
2d07e8
+    // This function could be optimized by calling one of those primitives.
2d07e8
+    auto a64 = static_cast<int64_t>(a);
2d07e8
+    auto b64 = static_cast<int64_t>(b);
2d07e8
+    int64_t res64 = a64 + b64;
2d07e8
+    *res = static_cast<int32_t>(res64);
2d07e8
+    return res64 != *res;
2d07e8
+}
2d07e8
+
2d07e8
+U_CAPI UBool U_EXPORT2
2d07e8
+uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res) {
2d07e8
+    // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_mul_overflow.
2d07e8
+    // This function could be optimized by calling one of those primitives.
2d07e8
+    auto a64 = static_cast<int64_t>(a);
2d07e8
+    auto b64 = static_cast<int64_t>(b);
2d07e8
+    int64_t res64 = a64 * b64;
2d07e8
+    *res = static_cast<int32_t>(res64);
2d07e8
+    return res64 != *res;
2d07e8
+}
2d07e8
+
2d07e8
 /**
2d07e8
  * Truncates the given double.
2d07e8
  * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
2d07e8
diff --git a/icu4c/source/common/putilimp.h b/icu4c/source/common/putilimp.h
2d07e8
index eb9b5380f1..8b858df9e3 100644
2d07e8
--- a/icu4c/source/common/putilimp.h
2d07e8
+++ b/icu4c/source/common/putilimp.h
2d07e8
@@ -391,6 +391,32 @@ U_INTERNAL double  U_EXPORT2 uprv_log(double d);
2d07e8
  */
2d07e8
 U_INTERNAL double  U_EXPORT2 uprv_round(double x);
2d07e8
 
2d07e8
+/**
2d07e8
+ * Adds the signed integers a and b, storing the result in res.
2d07e8
+ * Checks for signed integer overflow.
2d07e8
+ * Similar to the GCC/Clang extension __builtin_add_overflow
2d07e8
+ *
2d07e8
+ * @param a The first operand.
2d07e8
+ * @param b The second operand.
2d07e8
+ * @param res a + b
2d07e8
+ * @return true if overflow occurred; false if no overflow occurred.
2d07e8
+ * @internal
2d07e8
+ */
2d07e8
+U_INTERNAL UBool U_EXPORT2 uprv_add32_overflow(int32_t a, int32_t b, int32_t* res);
2d07e8
+
2d07e8
+/**
2d07e8
+ * Multiplies the signed integers a and b, storing the result in res.
2d07e8
+ * Checks for signed integer overflow.
2d07e8
+ * Similar to the GCC/Clang extension __builtin_mul_overflow
2d07e8
+ *
2d07e8
+ * @param a The first multiplicand.
2d07e8
+ * @param b The second multiplicand.
2d07e8
+ * @param res a * b
2d07e8
+ * @return true if overflow occurred; false if no overflow occurred.
2d07e8
+ * @internal
2d07e8
+ */
2d07e8
+U_INTERNAL UBool U_EXPORT2 uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res);
2d07e8
+
2d07e8
 #if 0
2d07e8
 /**
2d07e8
  * Returns the number of digits after the decimal point in a double number x.
2d07e8
diff --git a/icu4c/source/test/cintltst/putiltst.c b/icu4c/source/test/cintltst/putiltst.c
2d07e8
index b99d9fca9c..1c3e073041 100644
2d07e8
--- a/icu4c/source/test/cintltst/putiltst.c
2d07e8
+++ b/icu4c/source/test/cintltst/putiltst.c
2d07e8
@@ -128,6 +128,20 @@ static void TestPUtilAPI(void){
2d07e8
         log_err("ERROR: uprv_isInfinite failed.\n");
2d07e8
     }
2d07e8
 
2d07e8
+    log_verbose("Testing the APIs uprv_add32_overflow and uprv_mul32_overflow\n");
2d07e8
+    int32_t overflow_result;
2d07e8
+    doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 1, &overflow_result), "should not overflow");
2d07e8
+    doAssert(INT32_MAX - 1, overflow_result, "should equal INT32_MAX - 1");
2d07e8
+    doAssert(FALSE, uprv_add32_overflow(INT32_MAX - 2, 2, &overflow_result), "should not overflow");
2d07e8
+    doAssert(INT32_MAX, overflow_result, "should equal exactly INT32_MAX");
2d07e8
+    doAssert(TRUE, uprv_add32_overflow(INT32_MAX - 2, 3, &overflow_result), "should overflow");
2d07e8
+    doAssert(FALSE, uprv_mul32_overflow(INT32_MAX / 5, 4, &overflow_result), "should not overflow");
2d07e8
+    doAssert(INT32_MAX / 5 * 4, overflow_result, "should equal INT32_MAX / 5 * 4");
2d07e8
+    doAssert(TRUE, uprv_mul32_overflow(INT32_MAX / 5, 6, &overflow_result), "should overflow");
2d07e8
+    // Test on negative numbers:
2d07e8
+    doAssert(FALSE, uprv_add32_overflow(-3, -2, &overflow_result), "should not overflow");
2d07e8
+    doAssert(-5, overflow_result, "should equal -5");
2d07e8
+
2d07e8
 #if 0
2d07e8
     log_verbose("Testing the API uprv_digitsAfterDecimal()....\n");
2d07e8
     doAssert(uprv_digitsAfterDecimal(value1), 3, "uprv_digitsAfterDecimal() failed.");
2d07e8
-- 
2d07e8
2.24.1
2d07e8