[flang-commits] [flang] [flang][runtime] Resilient opening of anonymous unit (PR #93876)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu May 30 13:33:03 PDT 2024


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/93876

When an I/O statement references a unit number that has not been explicitly opened or predefined, the I/O runtime support library opens a local "fort.N" file.  If this fails, the program crashes, even when the I/O statement has IOSTAT= or IOMSG= or ERR= control list items.  Connect the dots to enable resilience in these cases.

>From 362364a6fef4f8e9a01587a442428163497829e3 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 30 May 2024 13:29:32 -0700
Subject: [PATCH] [flang][runtime] Resilient opening of anonymous unit

When an I/O statement references a unit number that has not been
explicitly opened or predefined, the I/O runtime support library
opens a local "fort.N" file.  If this fails, the program crashes,
even when the I/O statement has IOSTAT= or IOMSG= or ERR= control
list items.  Connect the dots to enable resilience in these cases.
---
 flang/runtime/external-unit.cpp | 9 +++++----
 flang/runtime/file.cpp          | 1 +
 flang/runtime/io-api-common.h   | 8 ++++++--
 flang/runtime/pseudo-unit.cpp   | 4 ++--
 flang/runtime/unit.h            | 2 +-
 5 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/flang/runtime/external-unit.cpp b/flang/runtime/external-unit.cpp
index 4bfa218bb7769..13926c2822205 100644
--- a/flang/runtime/external-unit.cpp
+++ b/flang/runtime/external-unit.cpp
@@ -58,15 +58,13 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
 
 ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
     Direction dir, Fortran::common::optional<bool> isUnformatted,
-    const Terminator &terminator) {
+    IoErrorHandler &handler) {
   // Make sure that the returned anonymous unit has been opened
   // not just created in the unitMap.
   CriticalSection critical{createOpenLock};
   bool exists{false};
-  ExternalFileUnit *result{
-      GetUnitMap().LookUpOrCreate(unit, terminator, exists)};
+  ExternalFileUnit *result{GetUnitMap().LookUpOrCreate(unit, handler, exists)};
   if (result && !exists) {
-    IoErrorHandler handler{terminator};
     result->OpenAnonymousUnit(
         dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace,
         Action::ReadWrite, Position::Rewind, Convert::Unknown, handler);
@@ -143,6 +141,9 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional<OpenStatus> status,
   }
   set_path(std::move(newPath), newPathLength);
   Open(status.value_or(OpenStatus::Unknown), action, position, handler);
+  if (handler.InError()) {
+    return impliedClose;
+  }
   auto totalBytes{knownSize()};
   if (access == Access::Direct) {
     if (!openRecl) {
diff --git a/flang/runtime/file.cpp b/flang/runtime/file.cpp
index 79db17e70acd9..67aa8d3cd13b0 100644
--- a/flang/runtime/file.cpp
+++ b/flang/runtime/file.cpp
@@ -126,6 +126,7 @@ void OpenFile::Open(OpenStatus status, Fortran::common::optional<Action> action,
       fd_ = ::open(path_.get(), flags, 0600);
       if (fd_ < 0) {
         handler.SignalErrno();
+        return;
       }
     }
   }
diff --git a/flang/runtime/io-api-common.h b/flang/runtime/io-api-common.h
index e9e050f6e7e61..c7b86cab73a52 100644
--- a/flang/runtime/io-api-common.h
+++ b/flang/runtime/io-api-common.h
@@ -33,13 +33,17 @@ static inline RT_API_ATTRS Cookie NoopUnit(const Terminator &terminator,
 static inline RT_API_ATTRS ExternalFileUnit *GetOrCreateUnit(int unitNumber,
     Direction direction, Fortran::common::optional<bool> isUnformatted,
     const Terminator &terminator, Cookie &errorCookie) {
+  IoErrorHandler handler{terminator};
+  handler.HasIoStat();
   if (ExternalFileUnit *
       unit{ExternalFileUnit::LookUpOrCreateAnonymous(
-          unitNumber, direction, isUnformatted, terminator)}) {
+          unitNumber, direction, isUnformatted, handler)}) {
     errorCookie = nullptr;
     return unit;
   } else {
-    errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
+    auto iostat{static_cast<enum Iostat>(handler.GetIoStat())};
+    errorCookie = NoopUnit(terminator, unitNumber,
+        iostat != IostatOk ? iostat : IostatBadUnitNumber);
     return nullptr;
   }
 }
diff --git a/flang/runtime/pseudo-unit.cpp b/flang/runtime/pseudo-unit.cpp
index a57e3a59efa5f..5a8696312d7ee 100644
--- a/flang/runtime/pseudo-unit.cpp
+++ b/flang/runtime/pseudo-unit.cpp
@@ -36,11 +36,11 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
 
 ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
     Direction direction, Fortran::common::optional<bool>,
-    const Terminator &terminator) {
+    IoErrorHandler &handler) {
   if (direction != Direction::Output) {
     terminator.Crash("ExternalFileUnit only supports output IO");
   }
-  return New<ExternalFileUnit>{terminator}(unit).release();
+  return New<ExternalFileUnit>{handler}(unit).release();
 }
 
 ExternalFileUnit *ExternalFileUnit::LookUp(const char *, std::size_t) {
diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index e59fbbce2b577..abd535fd0381d 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -120,7 +120,7 @@ class ExternalFileUnit : public ConnectionState,
       int unit, const Terminator &, bool &wasExtant);
   static RT_API_ATTRS ExternalFileUnit *LookUpOrCreateAnonymous(int unit,
       Direction, Fortran::common::optional<bool> isUnformatted,
-      const Terminator &);
+      IoErrorHandler &);
   static RT_API_ATTRS ExternalFileUnit *LookUp(
       const char *path, std::size_t pathLen);
   static RT_API_ATTRS ExternalFileUnit &CreateNew(int unit, const Terminator &);



More information about the flang-commits mailing list