-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang][runtime] Resilient opening of anonymous unit #93876
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-flang-runtime Author: Peter Klausler (klausler) ChangesWhen 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. Full diff: https://github.com/llvm/llvm-project/pull/93876.diff 5 Files Affected:
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 &);
|
flang/runtime/external-unit.cpp
Outdated
// Make sure that the returned anonymous unit has been opened | ||
// not just created in the unitMap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment punctuation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't change those lines, but I've cleaned them up.
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.
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.