diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h index 06d6fe7ae3dd4..0c0b3f4b3f7f3 100644 --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -63,6 +63,9 @@ enum Iostat { IostatFormattedChildOnUnformattedParent, IostatChildInputFromOutputParent, IostatChildOutputToInputParent, + IostatShortRead, + IostatMissingTerminator, + IostatBadUnformattedRecord, }; const char *IostatErrorString(int); diff --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp index 994af4f2a4f78..f6305eaca6559 100644 --- a/flang/runtime/iostat.cpp +++ b/flang/runtime/iostat.cpp @@ -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; } diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index 87b11820609a3..23e5b6292621b 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -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(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( 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(frameOffsetInFile_, 1024); auto need{static_cast(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;