[flang] Expose error recovery cases in external I/O
authorPeter Klausler <pklausler@nvidia.com>
Tue, 15 Mar 2022 19:17:17 +0000 (12:17 -0700)
committerPeter Klausler <pklausler@nvidia.com>
Mon, 21 Mar 2022 19:46:16 +0000 (12:46 -0700)
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
flang/runtime/iostat.cpp
flang/runtime/unit.cpp

index 06d6fe7..0c0b3f4 100644 (file)
@@ -63,6 +63,9 @@ enum Iostat {
   IostatFormattedChildOnUnformattedParent,
   IostatChildInputFromOutputParent,
   IostatChildOutputToInputParent,
+  IostatShortRead,
+  IostatMissingTerminator,
+  IostatBadUnformattedRecord,
 };
 
 const char *IostatErrorString(int);
index 994af4f..f6305ea 100644 (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;
   }
index 87b1182..23e5b62 100644 (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;