From 461b6fe470f72637e226ee7ff2722c1d76ebc549 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Tue, 15 Mar 2022 12:17:17 -0700 Subject: [PATCH] [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 --- flang/include/flang/Runtime/iostat.h | 3 +++ flang/runtime/iostat.cpp | 6 ++++++ flang/runtime/unit.cpp | 30 ++++++++++++++++++++++++------ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h index 06d6fe7..0c0b3f4 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 994af4f..f6305ea 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 87b1182..23e5b62 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; -- 2.7.4