Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…l?id=51241

Fix bounds checking bug.
  • Loading branch information
kevinbackhouse authored and neheb committed Sep 29, 2022
1 parent b1e2cc6 commit a8a3534
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,24 +611,22 @@ Rational parseRational(const std::string& s, bool& ok) {
}

Rational floatToRationalCast(float f) {
// 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.)
// Convert f to double because it simplifies the range checks
// below. (All int values can be losslessly converted to double, but
// sometimes get rounded when converted to float.)
const double d = f;
// Don't allow INT_MIN (0x80000000) because it can cause a UBSAN failure in std::gcd().
const bool in_range = std::numeric_limits<int32_t>::min() < d && d <= std::numeric_limits<int32_t>::max();
if (!in_range) {
return {d > 0 ? 1 : -1, 0};
}
// Beware: primitive conversion algorithm
int32_t den = 1000000;
const auto d_as_int32_t = static_cast<int32_t>(d);
if (Safe::abs(d_as_int32_t) > 21474836) {
den = 1;
} else if (Safe::abs(d_as_int32_t) > 214748) {
den = 100;
} else if (Safe::abs(d_as_int32_t) > 2147) {
int32_t den;
if (std::fabs(d) <= std::numeric_limits<int32_t>::max() / 1000000) {
den = 1000000;
} else if (std::fabs(d) <= std::numeric_limits<int32_t>::max() / 10000) {
den = 10000;
} else if (std::fabs(d) <= std::numeric_limits<int32_t>::max() / 100) {
den = 100;
} else if (std::fabs(d) <= std::numeric_limits<int32_t>::max()) {
den = 1;
} else {
return {d > 0 ? 1 : -1, 0};
}
const auto nom = static_cast<int32_t>(std::round(d * den));
const int32_t g = std::gcd(nom, den);
Expand Down

0 comments on commit a8a3534

Please sign in to comment.