[flang-commits] [flang] [flang][runtime] Handle end of internal output correctly (PR #84994)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Wed Mar 13 13:05:19 PDT 2024


https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/84994

>From 76b941a2e3c438c2ff3b0b4bad8b892be9e2df23 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Tue, 12 Mar 2024 16:22:47 -0700
Subject: [PATCH] [flang][runtime] Correct handling of intentional I/O errors
 in pFLogger

At the end of an internal output statement, be sure to finish
any following control edit descriptors in the format (if any),
and (for output) advance to the next record.  Return the right
I/O error status code if output overruns the buffer.

Further, a signed integer in a format must have a digit, and can appear
only as the scale factor before a P control edit descriptor.
---
 flang/runtime/format-implementation.h | 27 +++++++++++++++++----------
 flang/runtime/internal-unit.cpp       | 16 +++++-----------
 flang/runtime/internal-unit.h         |  1 -
 flang/runtime/io-stmt.cpp             | 19 +++++++++++++++----
 flang/runtime/io-stmt.h               |  1 +
 5 files changed, 38 insertions(+), 26 deletions(-)

diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index 9c342db2e19a24..f554f740573f18 100644
--- a/flang/runtime/format-implementation.h
+++ b/flang/runtime/format-implementation.h
@@ -66,15 +66,6 @@ template <typename CONTEXT>
 int FormatControl<CONTEXT>::GetIntField(
     IoErrorHandler &handler, CharType firstCh, bool *hadError) {
   CharType ch{firstCh ? firstCh : PeekNext()};
-  if (ch != '-' && ch != '+' && (ch < '0' || ch > '9')) {
-    handler.SignalError(IostatErrorInFormat,
-        "Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
-    if (hadError) {
-      *hadError = true;
-    }
-    return 0;
-  }
-  int result{0};
   bool negate{ch == '-'};
   if (negate || ch == '+') {
     if (firstCh) {
@@ -84,6 +75,15 @@ int FormatControl<CONTEXT>::GetIntField(
     }
     ch = PeekNext();
   }
+  if (ch < '0' || ch > '9') {
+    handler.SignalError(IostatErrorInFormat,
+        "Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
+    if (hadError) {
+      *hadError = true;
+    }
+    return 0;
+  }
+  int result{0};
   while (ch >= '0' && ch <= '9') {
     constexpr int tenth{std::numeric_limits<int>::max() / 10};
     if (result > tenth ||
@@ -246,8 +246,15 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
       ch = GetNextChar(context);
     }
     if (ch == '-' || ch == '+' || (ch >= '0' && ch <= '9')) {
+      bool hadSign{ch == '-' || ch == '+'};
       repeat = GetIntField(context, ch);
       ch = GetNextChar(context);
+      if (hadSign && ch != 'p' && ch != 'P') {
+        ReportBadFormat(context,
+            "Invalid FORMAT: signed integer may appear only before 'P",
+            maybeReversionPoint);
+        return 0;
+      }
     } else if (ch == '*') {
       unlimited = true;
       ch = GetNextChar(context);
@@ -297,11 +304,11 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
       return 0;
     } else if (ch == ')') {
       if (height_ == 1) {
+        hitEnd_ = true;
         if (stop) {
           return 0; // end of FORMAT and no data items remain
         }
         context.AdvanceRecord(); // implied / before rightmost )
-        hitEnd_ = true;
       }
       auto restart{stack_[height_ - 1].start};
       if (format_[restart] == '(') {
diff --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp
index e3fffaa6f378ff..66140e00588723 100644
--- a/flang/runtime/internal-unit.cpp
+++ b/flang/runtime/internal-unit.cpp
@@ -41,16 +41,6 @@ InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
   endfileRecordNumber = d.Elements() + 1;
 }
 
-template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
-  if constexpr (DIR == Direction::Output) {
-    // Clear the remainder of the current record.
-    auto end{endfileRecordNumber.value_or(0)};
-    if (currentRecordNumber < end) {
-      BlankFillOutputRecord();
-    }
-  }
-}
-
 template <Direction DIR>
 bool InternalDescriptorUnit<DIR>::Emit(
     const char *data, std::size_t bytes, IoErrorHandler &handler) {
@@ -109,7 +99,11 @@ std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
 template <Direction DIR>
 bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
   if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
-    handler.SignalEnd();
+    if constexpr (DIR == Direction::Input) {
+      handler.SignalEnd();
+    } else {
+      handler.SignalError(IostatInternalWriteOverrun);
+    }
     return false;
   }
   if constexpr (DIR == Direction::Output) {
diff --git a/flang/runtime/internal-unit.h b/flang/runtime/internal-unit.h
index f0c50aac98878f..b536ffb831d550 100644
--- a/flang/runtime/internal-unit.h
+++ b/flang/runtime/internal-unit.h
@@ -28,7 +28,6 @@ template <Direction DIR> class InternalDescriptorUnit : public ConnectionState {
       std::conditional_t<DIR == Direction::Input, const char *, char *>;
   InternalDescriptorUnit(Scalar, std::size_t chars, int kind);
   InternalDescriptorUnit(const Descriptor &, const Terminator &);
-  void EndIoStatement();
 
   bool Emit(const char *, std::size_t, IoErrorHandler &);
   std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 3ec01ffba9bf06..153195fd965624 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -119,9 +119,6 @@ template <Direction DIR> void InternalIoStatementState<DIR>::BackspaceRecord() {
 }
 
 template <Direction DIR> int InternalIoStatementState<DIR>::EndIoStatement() {
-  if constexpr (DIR == Direction::Output) {
-    unit_.EndIoStatement(); // fill
-  }
   auto result{IoStatementBase::EndIoStatement()};
   if (free_) {
     FreeMemory(this);
@@ -165,7 +162,8 @@ template <Direction DIR, typename CHAR>
 void InternalFormattedIoStatementState<DIR, CHAR>::CompleteOperation() {
   if (!this->completedOperation()) {
     if constexpr (DIR == Direction::Output) {
-      format_.Finish(*this); // ignore any remaining input positioning actions
+      format_.Finish(*this);
+      unit_.AdvanceRecord(*this);
     }
     IoStatementBase::CompleteOperation();
   }
@@ -189,8 +187,21 @@ InternalListIoStatementState<DIR>::InternalListIoStatementState(
     : InternalIoStatementState<DIR>{d, sourceFile, sourceLine},
       ioStatementState_{*this} {}
 
+template <Direction DIR>
+void InternalListIoStatementState<DIR>::CompleteOperation() {
+  if (!this->completedOperation()) {
+    if constexpr (DIR == Direction::Output) {
+      if (unit_.furthestPositionInRecord > 0) {
+        unit_.AdvanceRecord(*this);
+      }
+    }
+    IoStatementBase::CompleteOperation();
+  }
+}
+
 template <Direction DIR>
 int InternalListIoStatementState<DIR>::EndIoStatement() {
+  CompleteOperation();
   if constexpr (DIR == Direction::Input) {
     if (int status{ListDirectedStatementState<DIR>::EndIoStatement()};
         status != IostatOk) {
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 0b6bcbd9af025a..dcee7f9365692a 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -403,6 +403,7 @@ class InternalListIoStatementState : public InternalIoStatementState<DIR>,
       const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
   IoStatementState &ioStatementState() { return ioStatementState_; }
   using ListDirectedStatementState<DIR>::GetNextDataEdit;
+  void CompleteOperation();
   int EndIoStatement();
 
 private:



More information about the flang-commits mailing list