From 7c2ab1d7dea740fa30689d1fc2cecda85c07586f Mon Sep 17 00:00:00 2001 From: Kevin Backhouse Date: Wed, 4 Aug 2021 13:34:21 +0100 Subject: [PATCH] Check that the float is within the range of an int before casting. --- src/types.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/types.cpp b/src/types.cpp index 9a51d89b..a24ca8a3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -670,27 +671,28 @@ namespace Exiv2 { Rational floatToRationalCast(float f) { -#if defined(_MSC_VER) && _MSC_VER < 1800 - if (!_finite(f)) { -#else - if (!std::isfinite(f)) { -#endif - return {f > 0 ? 1 : -1, 0}; + + // Convert f to double because it simplifies the "in_range" check + // below. (INT_MAX can be represented accurately as a double, but + // gets rounded when it's converted to float.) + const double d = f; + const bool in_range = INT_MIN <= d && d <= INT_MAX; + if (!in_range) { + return {d > 0 ? 1 : -1, 0}; } // Beware: primitive conversion algorithm int32_t den = 1000000; - const long f_as_long = static_cast(f); - if (Safe::abs(f_as_long) > 2147) { + const long d_as_long = static_cast(d); + if (Safe::abs(d_as_long) > 2147) { den = 10000; } - if (Safe::abs(f_as_long) > 214748) { + if (Safe::abs(d_as_long) > 214748) { den = 100; } - if (Safe::abs(f_as_long) > 21474836) { + if (Safe::abs(d_as_long) > 21474836) { den = 1; } - const float rnd = f >= 0 ? 0.5F : -0.5F; - const auto nom = static_cast(f * den + rnd); + const auto nom = static_cast(std::round(d * den)); const int32_t g = gcd(nom, den); return {nom / g, den / g};