From 01e8b07452eb691469c0a302fff64ecd5dadd3e3 Mon Sep 17 00:00:00 2001 From: Matthew Sloyan Date: Wed, 23 Sep 2020 09:51:04 +0100 Subject: IVGCVSW-5306 Add floating point type checks to NumericCast.hpp * Added Unit Tests to capture all combinations. Signed-off-by: Matthew Sloyan Change-Id: I04db920a5f5f485dc00b2f16582cf7e0bbef3ef2 --- include/armnn/utility/NumericCast.hpp | 166 ++++++++++++++++++++++++++++++---- 1 file changed, 146 insertions(+), 20 deletions(-) (limited to 'include/armnn/utility') diff --git a/include/armnn/utility/NumericCast.hpp b/include/armnn/utility/NumericCast.hpp index af34013c30..cdbfd89638 100644 --- a/include/armnn/utility/NumericCast.hpp +++ b/include/armnn/utility/NumericCast.hpp @@ -22,14 +22,16 @@ namespace armnn #if defined(ARMNN_NUMERIC_CAST_TESTABLE) # define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ConditionalThrow(cond) #else -# define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ARMNN_ASSERT_MSG(cond, msg) +#define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ARMNN_ASSERT_MSG(cond, msg) #endif +// Unsigned to Unsigned + template typename std::enable_if_t< std::is_unsigned::value && - std::is_unsigned::value - , Dest> + std::is_unsigned::value, + Dest> numeric_cast(Source source) { #if ENABLE_NUMERIC_CAST_CHECKS @@ -43,26 +45,53 @@ numeric_cast(Source source) return static_cast(source); } +// Signed to Signed + +// numeric cast from signed integral to signed integral types, checked for narrowing overflows template typename std::enable_if_t< std::is_signed::value && - std::is_signed::value - , Dest> + std::is_integral::value && + std::is_signed::value && + std::is_integral::value, + Dest> numeric_cast(Source source) { - static_assert(!std::is_floating_point::value && !std::is_floating_point::value, - "numeric_cast doesn't cast float."); +#if ENABLE_NUMERIC_CAST_CHECKS + if (source > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed integral type to narrower signed type. " + "Overflow detected."); + } + + if (source < std::numeric_limits::lowest()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed integral type to narrower signed type. " + "Underflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(source); +} +// numeric cast from floating point to floating point types, checked for narrowing overflows +template +typename std::enable_if_t< + std::is_floating_point::value && + std::is_floating_point::value, + Dest> +numeric_cast(Source source) +{ #if ENABLE_NUMERIC_CAST_CHECKS if (source > std::numeric_limits::max()) { - ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. " + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. " "Overflow detected."); } if (source < std::numeric_limits::lowest()) { - ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. " + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. " "Underflow detected."); } #endif // ENABLE_NUMERIC_CAST_CHECKS @@ -70,16 +99,71 @@ numeric_cast(Source source) return static_cast(source); } -// numeric cast from unsigned to signed checked for narrowing overflows +// numeric cast from floating point types (signed) to signed integral types, checked for narrowing overflows template typename std::enable_if_t< + std::is_floating_point::value && std::is_signed::value && - std::is_unsigned::value - , Dest> -numeric_cast(Source sValue) + std::is_integral::value, + Dest> +numeric_cast(Source source) { - static_assert(!std::is_floating_point::value, "numeric_cast doesn't cast to float."); +#if ENABLE_NUMERIC_CAST_CHECKS + if (source > static_cast(std::numeric_limits::max())) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. " + "Overflow detected."); + } + + if (source < static_cast(std::numeric_limits::lowest())) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. " + "Underflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(source); +} + +// numeric cast from signed integral types to floating point types (signed), checked for narrowing overflows +template +typename std::enable_if_t< + std::is_signed::value && + std::is_integral::value && + std::is_floating_point::value, + Dest> +numeric_cast(Source source) +{ +#if ENABLE_NUMERIC_CAST_CHECKS + Dest sourceConverted = static_cast(source); + + if (sourceConverted > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower floating point type. " + "Overflow detected."); + } + + if (sourceConverted < std::numeric_limits::lowest()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower floating point type. " + "Underflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(source); +} + +// Unsigned to Signed +// numeric cast from unsigned integral type to signed integral type, checked for narrowing overflows +template +typename std::enable_if_t< + std::is_signed::value && + std::is_integral::value && + std::is_unsigned::value, + Dest> +numeric_cast(Source sValue) +{ #if ENABLE_NUMERIC_CAST_CHECKS if (sValue > static_cast< typename std::make_unsigned::type >(std::numeric_limits::max())) { @@ -91,17 +175,36 @@ numeric_cast(Source sValue) return static_cast(sValue); } -// numeric cast from signed to unsigned checked for underflows and narrowing overflows +// numeric cast from unsigned integral type to floating point (signed), checked for narrowing overflows template typename std::enable_if_t< - std::is_unsigned::value && - std::is_signed::value - , Dest> + std::is_floating_point::value && + std::is_unsigned::value, + Dest> numeric_cast(Source sValue) { - static_assert(!std::is_floating_point::value && !std::is_floating_point::value, - "numeric_cast doesn't cast floats."); +#if ENABLE_NUMERIC_CAST_CHECKS + if (static_cast(sValue) > std::numeric_limits::max()) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to floating point type. " + "Overflow detected."); + } +#endif // ENABLE_NUMERIC_CAST_CHECKS + + return static_cast(sValue); +} + +// Signed to Unsigned +// numeric cast from signed integral types to unsigned integral type, checked for underflows and narrowing overflows +template +typename std::enable_if_t< + std::is_unsigned::value && + std::is_signed::value && + std::is_integral::value, + Dest> +numeric_cast(Source sValue) +{ #if ENABLE_NUMERIC_CAST_CHECKS if (sValue < 0) { @@ -114,7 +217,30 @@ numeric_cast(Source sValue) ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to unsigned type. " "Overflow detected."); } +#endif // ENABLE_NUMERIC_CAST_CHECKS + return static_cast(sValue); +} +// numeric cast from floating point (signed) to unsigned integral type, checked for underflows and narrowing overflows +template +typename std::enable_if_t< + std::is_unsigned::value && + std::is_floating_point::value, + Dest> +numeric_cast(Source sValue) +{ +#if ENABLE_NUMERIC_CAST_CHECKS + if (sValue < 0) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting negative value to unsigned type. " + "Underflow detected."); + } + + if (sValue > static_cast(std::numeric_limits::max())) + { + ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to unsigned type. " + "Overflow detected."); + } #endif // ENABLE_NUMERIC_CAST_CHECKS return static_cast(sValue); } -- cgit v1.2.1