Skip to content

Commit a8f2d18

Browse files
authored
[flang][runtime] Resilient opening of anonymous unit (#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.
1 parent ea2c88f commit a8f2d18

File tree

5 files changed

+18
-13
lines changed

5 files changed

+18
-13
lines changed

flang/runtime/external-unit.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,13 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
5858

5959
ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
6060
Direction dir, Fortran::common::optional<bool> isUnformatted,
61-
const Terminator &terminator) {
62-
// Make sure that the returned anonymous unit has been opened
61+
IoErrorHandler &handler) {
62+
// Make sure that the returned anonymous unit has been opened,
6363
// not just created in the unitMap.
6464
CriticalSection critical{createOpenLock};
6565
bool exists{false};
66-
ExternalFileUnit *result{
67-
GetUnitMap().LookUpOrCreate(unit, terminator, exists)};
66+
ExternalFileUnit *result{GetUnitMap().LookUpOrCreate(unit, handler, exists)};
6867
if (result && !exists) {
69-
IoErrorHandler handler{terminator};
7068
result->OpenAnonymousUnit(
7169
dir == Direction::Input ? OpenStatus::Unknown : OpenStatus::Replace,
7270
Action::ReadWrite, Position::Rewind, Convert::Unknown, handler);
@@ -143,6 +141,9 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional<OpenStatus> status,
143141
}
144142
set_path(std::move(newPath), newPathLength);
145143
Open(status.value_or(OpenStatus::Unknown), action, position, handler);
144+
if (handler.InError()) {
145+
return impliedClose;
146+
}
146147
auto totalBytes{knownSize()};
147148
if (access == Access::Direct) {
148149
if (!openRecl) {

flang/runtime/file.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,17 @@ void OpenFile::Open(OpenStatus status, Fortran::common::optional<Action> action,
131131
}
132132
RUNTIME_CHECK(handler, action.has_value());
133133
pending_.reset();
134-
if (position == Position::Append && !RawSeekToEnd()) {
134+
if (fd_ >= 0 && position == Position::Append && !RawSeekToEnd()) {
135135
handler.SignalError(IostatOpenBadAppend);
136136
}
137-
isTerminal_ = IsATerminal(fd_) == 1;
137+
isTerminal_ = fd_ >= 0 && IsATerminal(fd_) == 1;
138138
mayRead_ = *action != Action::Write;
139139
mayWrite_ = *action != Action::Read;
140140
if (status == OpenStatus::Old || status == OpenStatus::Unknown) {
141141
knownSize_.reset();
142142
#ifndef _WIN32
143143
struct stat buf;
144-
if (::fstat(fd_, &buf) == 0) {
144+
if (fd_ >= 0 && ::fstat(fd_, &buf) == 0) {
145145
mayPosition_ = S_ISREG(buf.st_mode);
146146
knownSize_ = buf.st_size;
147147
}

flang/runtime/io-api-common.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ static inline RT_API_ATTRS Cookie NoopUnit(const Terminator &terminator,
3333
static inline RT_API_ATTRS ExternalFileUnit *GetOrCreateUnit(int unitNumber,
3434
Direction direction, Fortran::common::optional<bool> isUnformatted,
3535
const Terminator &terminator, Cookie &errorCookie) {
36+
IoErrorHandler handler{terminator};
37+
handler.HasIoStat();
3638
if (ExternalFileUnit *
3739
unit{ExternalFileUnit::LookUpOrCreateAnonymous(
38-
unitNumber, direction, isUnformatted, terminator)}) {
40+
unitNumber, direction, isUnformatted, handler)}) {
3941
errorCookie = nullptr;
4042
return unit;
4143
} else {
42-
errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
44+
auto iostat{static_cast<enum Iostat>(handler.GetIoStat())};
45+
errorCookie = NoopUnit(terminator, unitNumber,
46+
iostat != IostatOk ? iostat : IostatBadUnitNumber);
4347
return nullptr;
4448
}
4549
}

flang/runtime/pseudo-unit.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
3636

3737
ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
3838
Direction direction, Fortran::common::optional<bool>,
39-
const Terminator &terminator) {
39+
IoErrorHandler &handler) {
4040
if (direction != Direction::Output) {
4141
terminator.Crash("ExternalFileUnit only supports output IO");
4242
}
43-
return New<ExternalFileUnit>{terminator}(unit).release();
43+
return New<ExternalFileUnit>{handler}(unit).release();
4444
}
4545

4646
ExternalFileUnit *ExternalFileUnit::LookUp(const char *, std::size_t) {

flang/runtime/unit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class ExternalFileUnit : public ConnectionState,
120120
int unit, const Terminator &, bool &wasExtant);
121121
static RT_API_ATTRS ExternalFileUnit *LookUpOrCreateAnonymous(int unit,
122122
Direction, Fortran::common::optional<bool> isUnformatted,
123-
const Terminator &);
123+
IoErrorHandler &);
124124
static RT_API_ATTRS ExternalFileUnit *LookUp(
125125
const char *path, std::size_t pathLen);
126126
static RT_API_ATTRS ExternalFileUnit &CreateNew(int unit, const Terminator &);

0 commit comments

Comments
 (0)