aboutsummaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorMichael Jones <michaelrj@google.com>2023-04-12 11:26:18 -0700
committerMichael Jones <michaelrj@google.com>2023-04-12 15:27:03 -0700
commit3d953234fede3cb0532c876fd4ba9ea4d89fbd7c (patch)
tree11e2b3ff82698bb6eb1d6e8a62766291bbe9068d /libc
parentefc8b52cbd942f4bd5ffe8f64da5fb8a3b7adc32 (diff)
downloadllvm-3d953234fede3cb0532c876fd4ba9ea4d89fbd7c.zip
llvm-3d953234fede3cb0532c876fd4ba9ea4d89fbd7c.tar.gz
llvm-3d953234fede3cb0532c876fd4ba9ea4d89fbd7c.tar.bz2
[libc] Fix strtod exponent overflow bug
String to float has a condition to prevent overflowing the exponent with the E notation. To do this it checks if adding that exponent to the exponent found by parsing the number is greater than the maximum exponent for the given size of float. The if statements had a gap on exactly the maximum exponent value that caused it to be treated as the minimum exponent value. This patch fixes those conditions. Reviewed By: lntue Differential Revision: https://reviews.llvm.org/D148152
Diffstat (limited to 'libc')
-rw-r--r--libc/src/__support/str_to_float.h9
-rw-r--r--libc/test/src/stdlib/strtod_test.cpp29
2 files changed, 33 insertions, 5 deletions
diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index 9ba0602..6c298d4 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -943,13 +943,12 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
// If the result is in the valid range, then we use it. The valid range is
// also within the int32 range, so this prevents overflow issues.
- if (temp_exponent < fputil::FPBits<T>::MAX_EXPONENT &&
- temp_exponent > -fputil::FPBits<T>::MAX_EXPONENT) {
- exponent = static_cast<int32_t>(temp_exponent);
- } else if (temp_exponent > fputil::FPBits<T>::MAX_EXPONENT) {
+ if (temp_exponent > fputil::FPBits<T>::MAX_EXPONENT) {
exponent = fputil::FPBits<T>::MAX_EXPONENT;
- } else {
+ } else if (temp_exponent < -fputil::FPBits<T>::MAX_EXPONENT) {
exponent = -fputil::FPBits<T>::MAX_EXPONENT;
+ } else {
+ exponent = static_cast<int32_t>(temp_exponent);
}
}
}
diff --git a/libc/test/src/stdlib/strtod_test.cpp b/libc/test/src/stdlib/strtod_test.cpp
index 4eb1f49..3b1458a 100644
--- a/libc/test/src/stdlib/strtod_test.cpp
+++ b/libc/test/src/stdlib/strtod_test.cpp
@@ -197,6 +197,35 @@ TEST_F(LlvmLibcStrToDTest, FuzzFailures) {
// this bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30220
run_test("0x30000002222225p-1077", 22, uint64_t(0x0006000000444445), ERANGE);
+ // This value triggered a bug by having an exponent exactly equal to the
+ // maximum. The overflow checks would accept a value less than the max value
+ // as valid and greater than the max value as invalid (and set it to the max),
+ // but an exponent of exactly max value hit the else condition which is
+ // intended for underflow and set the exponent to the min exponent.
+ run_test(
+ "184774460000000000000000000000000000052300000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000009351662015430037656316837118788423"
+ "887774460000000000004300376000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000052385811247017194600000000"
+ "000000000171946000000000000000000700460000000000000000000000001000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000020000000000000000"
+ "000000000000563168371187884238877744600000000000000000000000000000523858"
+ "112470171946000000000000000001719460000000000000000007004600000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000020000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000005238581124701719460000000"
+ "000000000017194600000000000000000070046000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "200000000000000000E608",
+ 1462, uint64_t(0x7ff0000000000000), ERANGE);
+
// This bug was in the handling of very large exponents in the exponent
// marker. Previously anything greater than 10,000 would be set to 10,000.
// This caused incorrect behavior if there were more than 10,000 '0's in the