[flang-commits] [flang] 2a07db4 - [flang][runtime] Don't crash after reporting I/O statement errors

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Jun 13 11:25:11 PDT 2022


Author: Peter Klausler
Date: 2022-06-13T11:24:59-07:00
New Revision: 2a07db4cf60f961ae05b9febf8bcd2948ace93e3

URL: https://github.com/llvm/llvm-project/commit/2a07db4cf60f961ae05b9febf8bcd2948ace93e3
DIFF: https://github.com/llvm/llvm-project/commit/2a07db4cf60f961ae05b9febf8bcd2948ace93e3.diff

LOG: [flang][runtime] Don't crash after reporting I/O statement errors

When an I/O statement is known to be in a recoverable error state,
it shouldn't cause a crash later in execution because it's not in
an expected non-erroneous processing state.  Add checking for the
ErroneousIoStatementState variant on paths that might otherwise
lead to runtime crashes.

Differential Revision: https://reviews.llvm.org/D127423

Added: 
    

Modified: 
    flang/runtime/io-api.cpp
    flang/runtime/io-stmt.h

Removed: 
    


################################################################################
diff  --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index 4373dcde29b4..42f4c2bcc760 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -591,8 +591,9 @@ bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) {
   if (auto *unit{io.GetExternalFileUnit()}) {
     unit->SetPosition(pos - 1, handler);
     return true;
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    io.GetIoErrorHandler().Crash("SetPos() called on internal unit");
   }
-  io.GetIoErrorHandler().Crash("SetPos() called on internal unit");
   return false;
 }
 
@@ -672,8 +673,11 @@ bool IONAME(SetAccess)(Cookie cookie, const char *keyword, std::size_t length) {
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetAccess() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetAccess() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetAccess() called after GetNewUnit() for an OPEN statement");
@@ -704,8 +708,11 @@ bool IONAME(SetAction)(Cookie cookie, const char *keyword, std::size_t length) {
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetAction() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetAction() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetAction() called after GetNewUnit() for an OPEN statement");
@@ -757,7 +764,7 @@ bool IONAME(SetAsynchronous)(
         handler.SignalError(IostatBadAsynchronous);
       }
     }
-  } else {
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
     handler.Crash("SetAsynchronous() called when not in an OPEN or external "
                   "I/O statement");
   }
@@ -769,8 +776,11 @@ bool IONAME(SetCarriagecontrol)(
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetCarriageControl() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetCarriageControl() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetCarriageControl() called after GetNewUnit() for an OPEN statement");
@@ -797,8 +807,11 @@ bool IONAME(SetConvert)(
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetConvert() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetConvert() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetConvert() called after GetNewUnit() for an OPEN statement");
@@ -818,8 +831,11 @@ bool IONAME(SetEncoding)(
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetEncoding() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetEncoding() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetEncoding() called after GetNewUnit() for an OPEN statement");
@@ -850,8 +866,10 @@ bool IONAME(SetForm)(Cookie cookie, const char *keyword, std::size_t length) {
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetForm() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetForm() called when not in an OPEN statement");
+    }
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetForm() called after GetNewUnit() for an OPEN statement");
@@ -876,8 +894,11 @@ bool IONAME(SetPosition)(
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetPosition() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetPosition() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetPosition() called after GetNewUnit() for an OPEN statement");
@@ -904,8 +925,11 @@ bool IONAME(SetRecl)(Cookie cookie, std::size_t n) {
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "SetRecl() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "SetRecl() called when not in an OPEN statement");
+    }
+    return false;
   } else if (open->completedOperation()) {
     io.GetIoErrorHandler().Crash(
         "SetRecl() called after GetNewUnit() for an OPEN statement");
@@ -969,7 +993,8 @@ bool IONAME(SetStatus)(Cookie cookie, const char *keyword, std::size_t length) {
     }
     return false;
   }
-  if (io.get_if<NoopStatementState>()) {
+  if (io.get_if<NoopStatementState>() ||
+      io.get_if<ErroneousIoStatementState>()) {
     return true; // don't bother validating STATUS= in a no-op CLOSE
   }
   io.GetIoErrorHandler().Crash(
@@ -985,9 +1010,10 @@ bool IONAME(SetFile)(Cookie cookie, const char *path, std::size_t chars) {
     }
     open->set_path(path, chars);
     return true;
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    io.GetIoErrorHandler().Crash(
+        "SetFile() called when not in an OPEN statement");
   }
-  io.GetIoErrorHandler().Crash(
-      "SetFile() called when not in an OPEN statement");
   return false;
 }
 
@@ -995,8 +1021,11 @@ bool IONAME(GetNewUnit)(Cookie cookie, int &unit, int kind) {
   IoStatementState &io{*cookie};
   auto *open{io.get_if<OpenStatementState>()};
   if (!open) {
-    io.GetIoErrorHandler().Crash(
-        "GetNewUnit() called when not in an OPEN statement");
+    if (!io.get_if<ErroneousIoStatementState>()) {
+      io.GetIoErrorHandler().Crash(
+          "GetNewUnit() called when not in an OPEN statement");
+    }
+    return false;
   } else if (!open->InError()) {
     open->CompleteOperation();
   }
@@ -1031,9 +1060,10 @@ bool IONAME(OutputUnformattedBlock)(Cookie cookie, const char *x,
     return unf->Emit(x, length, elementBytes);
   } else if (auto *inq{io.get_if<InquireIOLengthState>()}) {
     return inq->Emit(x, length, elementBytes);
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    io.GetIoErrorHandler().Crash("OutputUnformattedBlock() called for an I/O "
+                                 "statement that is not unformatted output");
   }
-  io.GetIoErrorHandler().Crash("OutputUnformattedBlock() called for an I/O "
-                               "statement that is not unformatted output");
   return false;
 }
 
@@ -1048,14 +1078,17 @@ bool IONAME(InputUnformattedBlock)(
   if (auto *unf{
           io.get_if<ExternalUnformattedIoStatementState<Direction::Input>>()}) {
     return unf->Receive(x, length, elementBytes);
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    handler.Crash("InputUnformattedBlock() called for an I/O statement that is "
+                  "not unformatted input");
   }
-  handler.Crash("InputUnformattedBlock() called for an I/O statement that is "
-                "not unformatted input");
   return false;
 }
 
 bool IONAME(OutputInteger8)(Cookie cookie, std::int8_t n) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger8");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger8")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1064,7 +1097,9 @@ bool IONAME(OutputInteger8)(Cookie cookie, std::int8_t n) {
 }
 
 bool IONAME(OutputInteger16)(Cookie cookie, std::int16_t n) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger16");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger16")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1073,7 +1108,9 @@ bool IONAME(OutputInteger16)(Cookie cookie, std::int16_t n) {
 }
 
 bool IONAME(OutputInteger32)(Cookie cookie, std::int32_t n) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger32");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger32")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1082,7 +1119,9 @@ bool IONAME(OutputInteger32)(Cookie cookie, std::int32_t n) {
 }
 
 bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1092,7 +1131,9 @@ bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
 
 #ifdef __SIZEOF_INT128__
 bool IONAME(OutputInteger128)(Cookie cookie, common::int128_t n) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger128");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger128")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1102,7 +1143,9 @@ bool IONAME(OutputInteger128)(Cookie cookie, common::int128_t n) {
 #endif
 
 bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputInteger");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputInteger")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1111,7 +1154,9 @@ bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
 }
 
 bool IONAME(OutputReal32)(Cookie cookie, float x) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputReal32");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal32")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
@@ -1119,7 +1164,9 @@ bool IONAME(OutputReal32)(Cookie cookie, float x) {
 }
 
 bool IONAME(OutputReal64)(Cookie cookie, double x) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputReal64");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputReal64")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
@@ -1127,7 +1174,9 @@ bool IONAME(OutputReal64)(Cookie cookie, double x) {
 }
 
 bool IONAME(InputReal32)(Cookie cookie, float &x) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputReal32");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal32")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
@@ -1135,7 +1184,9 @@ bool IONAME(InputReal32)(Cookie cookie, float &x) {
 }
 
 bool IONAME(InputReal64)(Cookie cookie, double &x) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputReal64");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputReal64")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
@@ -1143,7 +1194,9 @@ bool IONAME(InputReal64)(Cookie cookie, double &x) {
 }
 
 bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex32");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex32")) {
+    return false;
+  }
   float z[2]{r, i};
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
@@ -1153,7 +1206,9 @@ bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
 }
 
 bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex64");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex64")) {
+    return false;
+  }
   double z[2]{r, i};
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
@@ -1163,7 +1218,9 @@ bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
 }
 
 bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1172,7 +1229,9 @@ bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
 }
 
 bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1182,7 +1241,9 @@ bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
 
 bool IONAME(OutputCharacter)(
     Cookie cookie, const char *x, std::size_t length, int kind) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1196,7 +1257,9 @@ bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
 
 bool IONAME(InputCharacter)(
     Cookie cookie, char *x, std::size_t length, int kind) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0);
@@ -1208,7 +1271,9 @@ bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
 }
 
 bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
-  cookie->CheckFormattedStmtType<Direction::Output>("OutputLogical");
+  if (!cookie->CheckFormattedStmtType<Direction::Output>("OutputLogical")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1217,7 +1282,9 @@ bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
 }
 
 bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
-  cookie->CheckFormattedStmtType<Direction::Input>("InputLogical");
+  if (!cookie->CheckFormattedStmtType<Direction::Input>("InputLogical")) {
+    return false;
+  }
   StaticDescriptor staticDescriptor;
   Descriptor &descriptor{staticDescriptor.descriptor()};
   descriptor.Establish(
@@ -1234,9 +1301,10 @@ std::size_t IONAME(GetSize)(Cookie cookie) {
   if (const auto *formatted{
           io.get_if<FormattedIoStatementState<Direction::Input>>()}) {
     return formatted->GetEditDescriptorChars();
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    handler.Crash("GetIoSize() called for an I/O statement that is not a "
+                  "formatted READ()");
   }
-  handler.Crash(
-      "GetIoSize() called for an I/O statement that is not a formatted READ()");
   return 0;
 }
 
@@ -1248,9 +1316,10 @@ std::size_t IONAME(GetIoLength)(Cookie cookie) {
   }
   if (const auto *inq{io.get_if<InquireIOLengthState>()}) {
     return inq->bytes();
+  } else if (!io.get_if<ErroneousIoStatementState>()) {
+    handler.Crash("GetIoLength() called for an I/O statement that is not "
+                  "INQUIRE(IOLENGTH=)");
   }
-  handler.Crash("GetIoLength() called for an I/O statement that is not "
-                "INQUIRE(IOLENGTH=)");
   return 0;
 }
 

diff  --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 5b5b60e4a97f..aa9f018dafbc 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -194,11 +194,16 @@ class IoStatementState {
     return ch;
   }
 
-  template <Direction D> void CheckFormattedStmtType(const char *name) {
-    if (!get_if<FormattedIoStatementState<D>>()) {
-      GetIoErrorHandler().Crash(
-          "%s called for I/O statement that is not formatted %s", name,
-          D == Direction::Output ? "output" : "input");
+  template <Direction D> bool CheckFormattedStmtType(const char *name) {
+    if (get_if<FormattedIoStatementState<D>>()) {
+      return true;
+    } else {
+      if (!get_if<ErroneousIoStatementState>()) {
+        GetIoErrorHandler().Crash(
+            "%s called for I/O statement that is not formatted %s", name,
+            D == Direction::Output ? "output" : "input");
+      }
+      return false;
     }
   }
 


        


More information about the flang-commits mailing list