From e29c9d77f128e7ef9b2b5f8f09fb06b01a9dad3a Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 1 Oct 2020 09:50:48 -0700 Subject: [PATCH] [flang] Fix WRITE after BACKSPACE A WRITE to an unformatted sequential variable-length unit after a BACKSPACE needs to forget its previous knowledge of the length of the record that's about to be overwritten, and a BACKSPACE after an ENDFILE or at the start of the file needs to be a no-op. Differential revision: https://reviews.llvm.org/D88675 --- flang/runtime/io-api.cpp | 1 + flang/runtime/unit.cpp | 44 +++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp index 304c40e871f46..edd338af0fa77 100644 --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -235,6 +235,7 @@ Cookie BeginUnformattedIO( if (unit.access == Access::Sequential && !unit.isFixedRecordLength) { // Create space for (sub)record header to be completed by // UnformattedIoStatementState::EndIoStatement() + unit.recordLength.reset(); // in case of prior BACKSPACE io.Emit("\0\0\0\0", 4); // placeholder for record length header } } diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index bcb8a478ad59f..77b7a74551d8f 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -132,16 +132,17 @@ void ExternalFileUnit::OpenUnit(OpenStatus status, std::optional action, static_cast(*totalBytes)); } } + endfileRecordNumber.reset(); + currentRecordNumber = 1; + if (totalBytes && recordLength && *recordLength) { + endfileRecordNumber = 1 + (*totalBytes / *recordLength); + } if (position == Position::Append) { - if (totalBytes && recordLength && *recordLength) { - endfileRecordNumber = 1 + (*totalBytes / *recordLength); - } else { + if (!endfileRecordNumber) { // Fake it so that we can backspace relative from the end - endfileRecordNumber = std::numeric_limits::max() - 1; + endfileRecordNumber = std::numeric_limits::max() - 2; } currentRecordNumber = *endfileRecordNumber; - } else { - currentRecordNumber = 1; } } @@ -374,7 +375,9 @@ void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) { void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) { RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_); beganReadingRecord_ = false; - if (access == Access::Sequential) { + if (handler.GetIoStat() != IostatOk) { + // avoid bogus crashes in END/ERR circumstances + } else if (access == Access::Sequential) { RUNTIME_CHECK(handler, recordLength.has_value()); if (isFixedRecordLength) { frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; @@ -430,16 +433,22 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) { handler.SignalError(IostatBackspaceNonSequential, "BACKSPACE(UNIT=%d) on non-sequential file", unitNumber()); } else { - DoImpliedEndfile(handler); - --currentRecordNumber; - BeginRecord(); - if (isFixedRecordLength) { - BackspaceFixedRecord(handler); - } else if (isUnformatted) { - BackspaceVariableUnformattedRecord(handler); + if (endfileRecordNumber && currentRecordNumber > *endfileRecordNumber) { + // BACKSPACE after ENDFILE } else { - BackspaceVariableFormattedRecord(handler); + DoImpliedEndfile(handler); + if (frameOffsetInFile_ + recordOffsetInFrame_ > 0) { + --currentRecordNumber; + if (isFixedRecordLength) { + BackspaceFixedRecord(handler); + } else if (isUnformatted) { + BackspaceVariableUnformattedRecord(handler); + } else { + BackspaceVariableFormattedRecord(handler); + } + } } + BeginRecord(); } } @@ -456,8 +465,12 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) { } else if (!mayWrite()) { handler.SignalError(IostatEndfileUnwritable, "ENDFILE(UNIT=%d) on read-only file", unitNumber()); + } else if (endfileRecordNumber && + currentRecordNumber > *endfileRecordNumber) { + // ENDFILE after ENDFILE } else { DoEndfile(handler); + ++currentRecordNumber; } } @@ -469,7 +482,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) { DoImpliedEndfile(handler); SetPosition(0); currentRecordNumber = 1; - // TODO: reset endfileRecordNumber? } }