[flang] Expose error recovery cases in external I/O

Some I/O error situations are current handled with fatal
runtime asserts, but should be exposed for user program
error recovery.

Differential Revision: https://reviews.llvm.org/D122049
This commit is contained in:
Peter Klausler 2022-03-15 12:17:17 -07:00
parent 240e06dfe7
commit 461b6fe470
3 changed files with 33 additions and 6 deletions

View File

@ -63,6 +63,9 @@ enum Iostat {
IostatFormattedChildOnUnformattedParent,
IostatChildInputFromOutputParent,
IostatChildOutputToInputParent,
IostatShortRead,
IostatMissingTerminator,
IostatBadUnformattedRecord,
};
const char *IostatErrorString(int);

View File

@ -69,6 +69,12 @@ const char *IostatErrorString(int iostat) {
return "Child input from output parent unit";
case IostatChildOutputToInputParent:
return "Child output to input parent unit";
case IostatShortRead:
return "Read from external unit returned insufficient data";
case IostatMissingTerminator:
return "Sequential record missing its terminator";
case IostatBadUnformattedRecord:
return "Erroneous unformatted sequential file record structure";
default:
return nullptr;
}

View File

@ -762,10 +762,16 @@ void ExternalFileUnit::BackspaceVariableUnformattedRecord(
// checked informatively in NextSequentialVariableUnformattedInputRecord().
std::size_t got{
ReadFrame(frameOffsetInFile_ - headerBytes, headerBytes, handler)};
RUNTIME_CHECK(handler, got >= sizeof footer);
if (static_cast<std::int64_t>(got) < headerBytes) {
handler.SignalError(IostatShortRead);
return;
}
std::memcpy(&footer, Frame(), sizeof footer);
recordLength = footer;
RUNTIME_CHECK(handler, frameOffsetInFile_ >= *recordLength + 2 * headerBytes);
if (frameOffsetInFile_ < *recordLength + 2 * headerBytes) {
handler.SignalError(IostatBadUnformattedRecord);
return;
}
frameOffsetInFile_ -= *recordLength + 2 * headerBytes;
if (frameOffsetInFile_ >= headerBytes) {
frameOffsetInFile_ -= headerBytes;
@ -774,9 +780,15 @@ void ExternalFileUnit::BackspaceVariableUnformattedRecord(
auto need{static_cast<std::size_t>(
recordOffsetInFrame_ + sizeof header + *recordLength)};
got = ReadFrame(frameOffsetInFile_, need, handler);
RUNTIME_CHECK(handler, got >= need);
if (got < need) {
handler.SignalError(IostatShortRead);
return;
}
std::memcpy(&header, Frame() + recordOffsetInFrame_, sizeof header);
RUNTIME_CHECK(handler, header == *recordLength);
if (header != *recordLength) {
handler.SignalError(IostatBadUnformattedRecord);
return;
}
}
// There's no portable memrchr(), unfortunately, and strrchr() would
@ -816,9 +828,15 @@ void ExternalFileUnit::BackspaceVariableFormattedRecord(
frameOffsetInFile_ -= std::min<std::int64_t>(frameOffsetInFile_, 1024);
auto need{static_cast<std::size_t>(prevNL + 1 - frameOffsetInFile_)};
auto got{ReadFrame(frameOffsetInFile_, need, handler)};
RUNTIME_CHECK(handler, got >= need);
if (got < need) {
handler.SignalError(IostatShortRead);
return;
}
}
if (Frame()[recordOffsetInFrame_ + *recordLength] != '\n') {
handler.SignalError(IostatMissingTerminator);
return;
}
RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ + *recordLength] == '\n');
if (*recordLength > 0 &&
Frame()[recordOffsetInFrame_ + *recordLength - 1] == '\r') {
--*recordLength;