[flang-commits] [flang] f1dbf8e - [flang][runtime] Fix edge-case FP input bugs
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Fri Apr 22 16:12:13 PDT 2022
Author: Peter Klausler
Date: 2022-04-22T16:12:04-07:00
New Revision: f1dbf8e4ada7761ba296400acbf0190e6e203dc6
URL: https://github.com/llvm/llvm-project/commit/f1dbf8e4ada7761ba296400acbf0190e6e203dc6
DIFF: https://github.com/llvm/llvm-project/commit/f1dbf8e4ada7761ba296400acbf0190e6e203dc6.diff
LOG: [flang][runtime] Fix edge-case FP input bugs
Blanks are allowed in more places than I allowed for, and
"NAN(foobar)" is allowed to have any parenthesis-balanced
characters in parentheses.
Update: Fix up old sanity test, then avoid usage of "limit" when null.
Differential Revision: https://reviews.llvm.org/D124294
Added:
Modified:
flang/lib/Decimal/decimal-to-binary.cpp
flang/runtime/edit-input.cpp
flang/unittests/Decimal/quick-sanity-test.cpp
Removed:
################################################################################
diff --git a/flang/lib/Decimal/decimal-to-binary.cpp b/flang/lib/Decimal/decimal-to-binary.cpp
index 9e3fc5f882f00..313788809bc13 100644
--- a/flang/lib/Decimal/decimal-to-binary.cpp
+++ b/flang/lib/Decimal/decimal-to-binary.cpp
@@ -408,19 +408,37 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary(
} else {
// Could not parse a decimal floating-point number. p has been
// advanced over any leading spaces.
- if (toupper(p[0]) == 'N' && toupper(p[1]) == 'A' && toupper(p[2]) == 'N') {
+ if ((!limit || limit >= p + 3) && toupper(p[0]) == 'N' &&
+ toupper(p[1]) == 'A' && toupper(p[2]) == 'N') {
// NaN
p += 3;
+ if ((!limit || p < limit) && *p == '(') {
+ int depth{1};
+ do {
+ ++p;
+ if (limit && p >= limit) {
+ // Invalid input
+ return {Real{NaN()}, Invalid};
+ } else if (*p == '(') {
+ ++depth;
+ } else if (*p == ')') {
+ --depth;
+ }
+ } while (depth > 0);
+ ++p;
+ }
return {Real{NaN()}};
} else {
// Try to parse Inf, maybe with a sign
const char *q{p};
- isNegative_ = *q == '-';
- if (*q == '-' || *q == '+') {
- ++q;
+ if (!limit || q < limit) {
+ isNegative_ = *q == '-';
+ if (isNegative_ || *q == '+') {
+ ++q;
+ }
}
- if (toupper(q[0]) == 'I' && toupper(q[1]) == 'N' &&
- toupper(q[2]) == 'F') {
+ if ((!limit || limit >= q + 3) && toupper(q[0]) == 'I' &&
+ toupper(q[1]) == 'N' && toupper(q[2]) == 'F') {
p = q + 3;
return {Real{Infinity()}};
} else {
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index fc5ee379e5df7..439f49b2fc964 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -176,9 +176,19 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
}
}
if (next && *next == '(') { // NaN(...)
- while (next && *next != ')') {
+ Put('(');
+ int depth{1};
+ do {
next = io.NextInField(remaining, edit);
- }
+ if (!next) {
+ break;
+ } else if (*next == '(') {
+ ++depth;
+ } else if (*next == ')') {
+ --depth;
+ }
+ Put(*next);
+ } while (depth > 0);
}
exponent = 0;
} else if (first == decimal || (first >= '0' && first <= '9') ||
@@ -225,7 +235,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
exponent = -edit.modes.scale;
if (next &&
(*next == '-' || *next == '+' || (*next >= '0' && *next <= '9') ||
- (bzMode && (*next == ' ' || *next == '\t')))) {
+ *next == ' ' || *next == '\t')) {
bool negExpo{*next == '-'};
if (negExpo || *next == '+') {
next = io.NextInField(remaining, edit);
@@ -233,8 +243,10 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
for (exponent = 0; next; next = io.NextInField(remaining, edit)) {
if (*next >= '0' && *next <= '9') {
exponent = 10 * exponent + *next - '0';
- } else if (bzMode && (*next == ' ' || *next == '\t')) {
- exponent = 10 * exponent;
+ } else if (*next == ' ' || *next == '\t') {
+ if (bzMode) {
+ exponent = 10 * exponent;
+ }
} else {
break;
}
@@ -328,11 +340,19 @@ static bool TryFastPathRealInput(
if (converted.flags & decimal::Invalid) {
return false;
}
- if (edit.digits.value_or(0) != 0 &&
- std::memchr(str, '.', p - str) == nullptr) {
- // No explicit decimal point, and edit descriptor is Fw.d (or other)
- // with d != 0, which implies scaling.
- return false;
+ if (edit.digits.value_or(0) != 0) {
+ // Edit descriptor is Fw.d (or other) with d != 0, which
+ // implies scaling
+ const char *q{str};
+ for (; q < limit; ++q) {
+ if (*q == '.' || *q == 'n' || *q == 'N') {
+ break;
+ }
+ }
+ if (q == limit) {
+ // No explicit decimal point, and not NaN/Inf.
+ return false;
+ }
}
for (; p < limit && (*p == ' ' || *p == '\t'); ++p) {
}
@@ -422,6 +442,10 @@ bool EditCommonRealInput(IoStatementState &io, const DataEdit &edit, void *n) {
converted.flags = static_cast<enum decimal::ConversionResultFlags>(
converted.flags | decimal::Inexact);
}
+ if (*p) { // unprocessed junk after value
+ io.GetIoErrorHandler().SignalError(IostatBadRealInput);
+ return false;
+ }
*reinterpret_cast<decimal::BinaryFloatingPointNumber<binaryPrecision> *>(n) =
converted.binary;
// Set FP exception flags
diff --git a/flang/unittests/Decimal/quick-sanity-test.cpp b/flang/unittests/Decimal/quick-sanity-test.cpp
index 476d2c64bafcb..ef745df850d39 100644
--- a/flang/unittests/Decimal/quick-sanity-test.cpp
+++ b/flang/unittests/Decimal/quick-sanity-test.cpp
@@ -61,13 +61,15 @@ void testReadback(float x, int flags) {
if (!(x == x)) {
if (y == y || *p != '\0' || (rflags & Invalid)) {
u.x = y;
- failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x";
- failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
+ (failed(x) << " (NaN) " << flags << ": -> '" << result.str << "' -> 0x")
+ .write_hex(u.u)
+ << " '" << p << "' " << rflags << '\n';
}
} else if (x != y || *p != '\0' || (rflags & Invalid)) {
- u.x = y;
- failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x";
- failed(x).write_hex(u.u) << " '" << p << "' " << rflags << '\n';
+ u.x = x;
+ (failed(x) << ' ' << flags << ": -> '" << result.str << "' -> 0x")
+ .write_hex(u.u)
+ << " '" << p << "' " << rflags << '\n';
}
}
}
More information about the flang-commits
mailing list