From 2f0321135da916142afcb606d05d951b46472497 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Fri, 21 Jun 2024 11:28:27 -0700 Subject: [PATCH] [flang][runtime] Better handling of "fort.N" opening errors When a data transfer statement references a unit number that hasn't been explicitly OPENed, the runtime I/O support library opens a local "fort.N" file where N is the unit number. If that name exists in the current working directory but is not a readable or writable file (as appropriate), the runtime needs to catch the error at the point of the READ or WRITE statement rather than leaving an open unit in the unit map without a valid file descriptor. --- flang/runtime/external-unit.cpp | 18 +++++++++++++----- flang/runtime/pseudo-unit.cpp | 2 +- flang/runtime/unit.h | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/flang/runtime/external-unit.cpp b/flang/runtime/external-unit.cpp index 328c994a180b1..8009151a8a370 100644 --- a/flang/runtime/external-unit.cpp +++ b/flang/runtime/external-unit.cpp @@ -65,10 +65,17 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit, bool exists{false}; ExternalFileUnit *result{GetUnitMap().LookUpOrCreate(unit, handler, exists)}; if (result && !exists) { - result->OpenAnonymousUnit( - dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace, - Action::ReadWrite, Position::Rewind, Convert::Unknown, handler); - result->isUnformatted = isUnformatted; + if (!result->OpenAnonymousUnit( + dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace, + Action::ReadWrite, Position::Rewind, Convert::Unknown, handler)) { + // fort.N isn't a writable file + if (ExternalFileUnit * closed{LookUpForClose(result->unitNumber())}) { + closed->DestroyClosed(); + } + result = nullptr; + } else { + result->isUnformatted = isUnformatted; + } } return result; } @@ -183,7 +190,7 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional status, return impliedClose; } -void ExternalFileUnit::OpenAnonymousUnit( +bool ExternalFileUnit::OpenAnonymousUnit( Fortran::common::optional status, Fortran::common::optional action, Position position, Convert convert, IoErrorHandler &handler) { @@ -193,6 +200,7 @@ void ExternalFileUnit::OpenAnonymousUnit( std::snprintf(path.get(), pathMaxLen, "fort.%d", unitNumber_); OpenUnit(status, action, position, std::move(path), std::strlen(path.get()), convert, handler); + return IsConnected(); } void ExternalFileUnit::CloseUnit(CloseStatus status, IoErrorHandler &handler) { diff --git a/flang/runtime/pseudo-unit.cpp b/flang/runtime/pseudo-unit.cpp index 70e70eec6a77e..526afd11d916e 100644 --- a/flang/runtime/pseudo-unit.cpp +++ b/flang/runtime/pseudo-unit.cpp @@ -65,7 +65,7 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional status, handler.Crash("%s: unsupported", RT_PRETTY_FUNCTION); } -void ExternalFileUnit::OpenAnonymousUnit(Fortran::common::optional, +bool ExternalFileUnit::OpenAnonymousUnit(Fortran::common::optional, Fortran::common::optional, Position, Convert convert, IoErrorHandler &handler) { handler.Crash("%s: unsupported", RT_PRETTY_FUNCTION); diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h index abd535fd0381d..83f839e205a48 100644 --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -134,7 +134,7 @@ class ExternalFileUnit : public ConnectionState, RT_API_ATTRS bool OpenUnit(Fortran::common::optional, Fortran::common::optional, Position, OwningPtr &&path, std::size_t pathLength, Convert, IoErrorHandler &); - RT_API_ATTRS void OpenAnonymousUnit(Fortran::common::optional, + RT_API_ATTRS bool OpenAnonymousUnit(Fortran::common::optional, Fortran::common::optional, Position, Convert, IoErrorHandler &); RT_API_ATTRS void CloseUnit(CloseStatus, IoErrorHandler &); RT_API_ATTRS void DestroyClosed();