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