Skip to content

[flang] Fix variable unformatted I/O bug with output after input #92828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 23, 2024

Conversation

klausler
Copy link
Contributor

When reading variable-length unformatted records, the external I/O library frames the input buffer so that the footer of the previous record remains in frame. This is done so that a BACKSPACE doesn't have to do an extra read to get the length of the previous record before repositioning over it.

When switching from input to output to overwrite or append new records after reading any, it is necessary to undo this framing of the last word in the previous record, since the new output isn't going to define it in the buffer and it'll be overwritten in the filesystem with garbage.

When reading variable-length unformatted records, the external I/O
library frames the input buffer so that the footer of the previous
record remains in frame.  This is done so that a BACKSPACE doesn't
have to do an extra read to get the length of the previous record
before repositioning over it.

When switching from input to output to overwrite or append new
records after reading any, it is necessary to undo this framing of
the last word in the previous record, since the new output isn't
going to define it in the buffer and it'll be overwritten in the
filesystem with garbage.
@klausler klausler requested a review from vzakhari May 20, 2024 22:17
@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category labels May 20, 2024
@llvmbot
Copy link
Member

llvmbot commented May 20, 2024

@llvm/pr-subscribers-flang-runtime

Author: Peter Klausler (klausler)

Changes

When reading variable-length unformatted records, the external I/O library frames the input buffer so that the footer of the previous record remains in frame. This is done so that a BACKSPACE doesn't have to do an extra read to get the length of the previous record before repositioning over it.

When switching from input to output to overwrite or append new records after reading any, it is necessary to undo this framing of the last word in the previous record, since the new output isn't going to define it in the buffer and it'll be overwritten in the filesystem with garbage.


Full diff: https://github.com/llvm/llvm-project/pull/92828.diff

2 Files Affected:

  • (modified) flang/runtime/external-unit.cpp (+7-1)
  • (modified) flang/runtime/unit.cpp (+1)
diff --git a/flang/runtime/external-unit.cpp b/flang/runtime/external-unit.cpp
index b48549d54587e..4bfa218bb7769 100644
--- a/flang/runtime/external-unit.cpp
+++ b/flang/runtime/external-unit.cpp
@@ -214,6 +214,13 @@ Iostat ExternalFileUnit::SetDirection(Direction direction) {
     }
   } else {
     if (mayWrite()) {
+      if (direction_ == Direction::Input) {
+        // Don't retain any input data from previous record, like a
+        // variable-length unformatted record footer, in the frame,
+        // since we're going start writing frames.
+        frameOffsetInFile_ += recordOffsetInFrame_;
+        recordOffsetInFrame_ = 0;
+      }
       direction_ = Direction::Output;
       return IostatOk;
     } else {
@@ -332,5 +339,4 @@ bool ExternalFileUnit::Wait(int id) {
 }
 
 } // namespace Fortran::runtime::io
-
 #endif // !defined(RT_USE_PSEUDO_FILE_UNIT)
diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 3b42f45d55884..a11f444d8d754 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -265,6 +265,7 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
     furthestPositionInRecord =
         std::max(furthestPositionInRecord, positionInRecord);
     frameOffsetInFile_ += recordOffsetInFrame_ + furthestPositionInRecord;
+    recordOffsetInFrame_ = 0;
   }
   BeginRecord();
 }

if (direction_ == Direction::Input) {
// Don't retain any input data from previous record, like a
// variable-length unformatted record footer, in the frame,
// since we're going start writing frames.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// since we're going start writing frames.
// since we're going to start writing frames.

@klausler klausler merged commit 975579b into llvm:main May 23, 2024
7 checks passed
@klausler klausler deleted the gamess branch May 23, 2024 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants