Skip to content

Commit

Permalink
[flang] Fix WRITE after BACKSPACE
Browse files Browse the repository at this point in the history
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
  • Loading branch information
klausler committed Oct 1, 2020
1 parent 8654a0f commit e29c9d7
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 16 deletions.
1 change: 1 addition & 0 deletions flang/runtime/io-api.cpp
Expand Up @@ -235,6 +235,7 @@ Cookie BeginUnformattedIO(
if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
// Create space for (sub)record header to be completed by
// UnformattedIoStatementState<Direction::Output>::EndIoStatement()
unit.recordLength.reset(); // in case of prior BACKSPACE
io.Emit("\0\0\0\0", 4); // placeholder for record length header
}
}
Expand Down
44 changes: 28 additions & 16 deletions flang/runtime/unit.cpp
Expand Up @@ -132,16 +132,17 @@ void ExternalFileUnit::OpenUnit(OpenStatus status, std::optional<Action> action,
static_cast<std::intmax_t>(*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<std::int64_t>::max() - 1;
endfileRecordNumber = std::numeric_limits<std::int64_t>::max() - 2;
}
currentRecordNumber = *endfileRecordNumber;
} else {
currentRecordNumber = 1;
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}

Expand All @@ -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;
}
}

Expand All @@ -469,7 +482,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
DoImpliedEndfile(handler);
SetPosition(0);
currentRecordNumber = 1;
// TODO: reset endfileRecordNumber?
}
}

Expand Down

0 comments on commit e29c9d7

Please sign in to comment.