From: Peter Klausler Date: Tue, 26 Apr 2022 23:09:42 +0000 (-0700) Subject: [flang][runtime] Correct emission & reading of unterminated final records X-Git-Tag: upstream/15.0.7~9135 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=36771bbad1b2588b66f9033074f1f2155065dffb;p=platform%2Fupstream%2Fllvm.git [flang][runtime] Correct emission & reading of unterminated final records When the last operation on a foramtted sequential or stream file (prior to an implied or explicit ENDFILE) is a non-advancing WRITE, ensure that any partial record data is emitted to the file without a line terminator. Further, when that last record is read with a non-advancing READ, ensure that it won't raise an end-of-record condition after its data, but instead will signal an end-of-file. Differential Revision: https://reviews.llvm.org/D124546 --- diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h index 09b8425..a19c49f 100644 --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -54,6 +54,7 @@ struct ConnectionState : public ConnectionAttributes { void BeginRecord() { positionInRecord = 0; furthestPositionInRecord = 0; + unterminatedRecord = false; } std::optional EffectiveRecordLength() const { @@ -85,6 +86,10 @@ struct ConnectionState : public ConnectionAttributes { // so that backspacing to the beginning of the repeated item doesn't require // repositioning the external storage medium when that's impossible. bool pinnedFrame{false}; + + // Set when the last record of a file is not properly terminated + // so that a non-advancing READ will not signal EOR. + bool unterminatedRecord{false}; }; // Utility class for capturing and restoring a position in an input stream. diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp index ad0a4dc..8080263 100644 --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -327,7 +327,6 @@ void ExternalIoStatementState::CompleteOperation() { } unit().leftTabLimit = unit().furthestPositionInRecord; } else { - unit().leftTabLimit.reset(); unit().AdvanceRecord(*this); } unit().FlushIfTerminal(*this); @@ -673,7 +672,15 @@ bool IoStatementState::CheckForEndOfRecord() { if (connection.positionInRecord >= *length) { IoErrorHandler &handler{GetIoErrorHandler()}; if (mutableModes().nonAdvancing) { - handler.SignalEor(); + if (connection.access == Access::Stream && + connection.unterminatedRecord) { + // Reading final unterminated record left by a + // non-advancing WRITE on a stream file prior to + // positioning or ENDFILE. + handler.SignalEnd(); + } else { + handler.SignalEor(); + } } else if (!connection.modes.pad) { handler.SignalError(IostatRecordReadOverrun); } diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index e7d0fd5..31c350f 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -349,7 +349,7 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes, return true; } else { handler.SignalEnd(); - if (access == Access::Sequential) { + if (IsRecordFile() && access != Access::Direct) { endfileRecordNumber = currentRecordNumber; } return false; @@ -385,7 +385,7 @@ const char *ExternalFileUnit::FrameNextInput( return Frame() + at; } handler.SignalEnd(); - if (access == Access::Sequential) { + if (IsRecordFile() && access != Access::Direct) { endfileRecordNumber = currentRecordNumber; } } @@ -544,6 +544,7 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) { #endif ok = ok && Emit(lineEnding, lineEndingBytes, 1, handler); } + leftTabLimit.reset(); if (IsAfterEndfile()) { return false; } @@ -620,7 +621,7 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) { // ENDFILE after ENDFILE } else { DoEndfile(handler); - if (access == Access::Sequential) { + if (IsRecordFile() && access != Access::Direct) { // Explicit ENDFILE leaves position *after* the endfile record RUNTIME_CHECK(handler, endfileRecordNumber.has_value()); currentRecordNumber = *endfileRecordNumber + 1; @@ -716,6 +717,7 @@ void ExternalFileUnit::BeginVariableFormattedInputRecord( if (length > 0) { // final record w/o \n recordLength = length; + unterminatedRecord = true; } else { handler.SignalEnd(); } @@ -839,11 +841,17 @@ void ExternalFileUnit::DoImpliedEndfile(IoErrorHandler &handler) { } void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) { - if (IsRecordFile()) { + if (IsRecordFile() && access != Access::Direct) { + if (furthestPositionInRecord > 0) { + // Last write was non-advancing, so AdvanceRecord() was not called. + leftTabLimit.reset(); + ++currentRecordNumber; + } endfileRecordNumber = currentRecordNumber; } FlushOutput(handler); - Truncate(frameOffsetInFile_ + recordOffsetInFrame_, handler); + Truncate(frameOffsetInFile_ + recordOffsetInFrame_ + furthestPositionInRecord, + handler); BeginRecord(); impliedEndfile_ = false; }