Skip to content

Commit

Permalink
Check that the float is within the range of an int before casting.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinbackhouse committed Aug 3, 2021
1 parent 388f254 commit 48da0e9
Showing 1 changed file with 14 additions and 12 deletions.
26 changes: 14 additions & 12 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <sstream>
#include <utility>
#include <cctype>
#include <climits>
#include <ctime>
#include <cstdio>
#include <cstdlib>
Expand Down Expand Up @@ -687,27 +688,28 @@ namespace Exiv2 {

Rational floatToRationalCast(float f)
{
#if defined(_MSC_VER) && _MSC_VER < 1800
if (!_finite(f)) {
#else
if (!std::isfinite(f)) {
#endif
return Rational(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 flow.)
const double d = f;
const bool in_range = INT_MIN <= d && d <= INT_MAX;
if (!in_range) {
return Rational(d > 0 ? 1 : -1, 0);
}
// Beware: primitive conversion algorithm
int32_t den = 1000000;
const long f_as_long = static_cast<long>(f);
if (Safe::abs(f_as_long) > 2147) {
const long d_as_long = static_cast<long>(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 int32_t nom = static_cast<int32_t>(f * den + rnd);
const float rnd = d >= 0 ? 0.5f : -0.5f;
const int32_t nom = static_cast<int32_t>(d * den + rnd);
const int32_t g = gcd(nom, den);

return Rational(nom / g, den / g);
Expand Down

0 comments on commit 48da0e9

Please sign in to comment.