Credit to OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=51241
Fix bounds checking bug.
This commit is contained in:
parent
b1e2cc6129
commit
a8a35345c8
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user