[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.
This commit is contained in:
parent
ea2c88f512
commit
a8f2d185b2
@ -58,15 +58,13 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
|
||||
|
||||
ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
|
||||
Direction dir, Fortran::common::optional<bool> isUnformatted,
|
||||
const Terminator &terminator) {
|
||||
// Make sure that the returned anonymous unit has been opened
|
||||
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) {
|
||||
|
@ -131,17 +131,17 @@ void OpenFile::Open(OpenStatus status, Fortran::common::optional<Action> action,
|
||||
}
|
||||
RUNTIME_CHECK(handler, action.has_value());
|
||||
pending_.reset();
|
||||
if (position == Position::Append && !RawSeekToEnd()) {
|
||||
if (fd_ >= 0 && position == Position::Append && !RawSeekToEnd()) {
|
||||
handler.SignalError(IostatOpenBadAppend);
|
||||
}
|
||||
isTerminal_ = IsATerminal(fd_) == 1;
|
||||
isTerminal_ = fd_ >= 0 && IsATerminal(fd_) == 1;
|
||||
mayRead_ = *action != Action::Write;
|
||||
mayWrite_ = *action != Action::Read;
|
||||
if (status == OpenStatus::Old || status == OpenStatus::Unknown) {
|
||||
knownSize_.reset();
|
||||
#ifndef _WIN32
|
||||
struct stat buf;
|
||||
if (::fstat(fd_, &buf) == 0) {
|
||||
if (fd_ >= 0 && ::fstat(fd_, &buf) == 0) {
|
||||
mayPosition_ = S_ISREG(buf.st_mode);
|
||||
knownSize_ = buf.st_size;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -120,7 +120,7 @@ public:
|
||||
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 &);
|
||||
|
Loading…
x
Reference in New Issue
Block a user