[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