Skip to content

Commit

Permalink
[flang][runtime] Catch OPEN of connected file
Browse files Browse the repository at this point in the history
Diagnose OPEN(FILE=f) when f is already connected by the same name to
a distinct external I/O unit.

Differential Revision: https://reviews.llvm.org/D127035
  • Loading branch information
klausler committed Jun 4, 2022
1 parent 562fd2c commit 03c066a
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 11 deletions.
2 changes: 2 additions & 0 deletions flang/include/flang/Runtime/iostat.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ enum Iostat {
IostatBOZInputOverflow,
IostatIntegerInputOverflow,
IostatRealInputOverflow,
IostatOpenAlreadyConnected,
IostatCannotReposition,
};

const char *IostatErrorString(int);
Expand Down
2 changes: 1 addition & 1 deletion flang/runtime/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ bool OpenFile::Seek(FileOffset at, IoErrorHandler &handler) {
SetPosition(at);
return true;
} else {
handler.SignalErrno();
handler.SignalError(IostatCannotReposition);
return false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion flang/runtime/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class OpenFile {
using FileOffset = std::int64_t;

const char *path() const { return path_.get(); }
void set_path(OwningPtr<char> &&, std::size_t bytes);
std::size_t pathLength() const { return pathLength_; }
void set_path(OwningPtr<char> &&, std::size_t bytes);
bool mayRead() const { return mayRead_; }
bool mayWrite() const { return mayWrite_; }
bool mayPosition() const { return mayPosition_; }
Expand Down
4 changes: 3 additions & 1 deletion flang/runtime/io-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,9 @@ Cookie IONAME(BeginInquireFile)(const char *path, std::size_t pathLength,
Terminator oom{sourceFile, sourceLine};
auto trimmed{
SaveDefaultCharacter(path, TrimTrailingSpaces(path, pathLength), oom)};
if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(trimmed.get())}) {
if (ExternalFileUnit *
unit{ExternalFileUnit::LookUp(
trimmed.get(), std::strlen(trimmed.get()))}) {
// INQUIRE(FILE=) to a connected unit
return &unit->BeginIoStatement<InquireUnitState>(
*unit, sourceFile, sourceLine);
Expand Down
5 changes: 5 additions & 0 deletions flang/runtime/iostat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ const char *IostatErrorString(int iostat) {
return "Integer input value overflows variable";
case IostatRealInputOverflow:
return "Real or complex input value overflows type";
case IostatCannotReposition:
return "Attempt to reposition a unit which is connected to a file that can "
"only be processed sequentially";
case IostatOpenAlreadyConnected:
return "OPEN of file already connected to another unit";
default:
return nullptr;
}
Expand Down
5 changes: 3 additions & 2 deletions flang/runtime/unit-map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,13 @@ void UnitMap::FlushAll(IoErrorHandler &handler) {
}
}

ExternalFileUnit *UnitMap::Find(const char *path) {
ExternalFileUnit *UnitMap::Find(const char *path, std::size_t pathLen) {
if (path) {
// TODO: Faster data structure
for (int j{0}; j < buckets_; ++j) {
for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
if (p->unit.path() && std::strcmp(p->unit.path(), path) == 0) {
if (p->unit.path() && p->unit.pathLength() == pathLen &&
std::memcmp(p->unit.path(), path, pathLen) == 0) {
return &p->unit;
}
}
Expand Down
6 changes: 3 additions & 3 deletions flang/runtime/unit-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ class UnitMap {
}

// Unit look-up by name is needed for INQUIRE(FILE="...")
ExternalFileUnit *LookUp(const char *path) {
ExternalFileUnit *LookUp(const char *path, std::size_t pathLen) {
CriticalSection critical{lock_};
return Find(path);
return Find(path, pathLen);
}

ExternalFileUnit &NewUnit(const Terminator &);
Expand Down Expand Up @@ -84,7 +84,7 @@ class UnitMap {
}
return nullptr;
}
ExternalFileUnit *Find(const char *path);
ExternalFileUnit *Find(const char *path, std::size_t pathLen);

ExternalFileUnit &Create(int, const Terminator &);

Expand Down
15 changes: 13 additions & 2 deletions flang/runtime/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
return result;
}

ExternalFileUnit *ExternalFileUnit::LookUp(const char *path) {
return GetUnitMap().LookUp(path);
ExternalFileUnit *ExternalFileUnit::LookUp(
const char *path, std::size_t pathLen) {
return GetUnitMap().LookUp(path, pathLen);
}

ExternalFileUnit &ExternalFileUnit::CreateNew(
Expand Down Expand Up @@ -124,6 +125,16 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
FlushOutput(handler);
Close(CloseStatus::Keep, handler);
}
if (newPath.get() && newPathLength > 0) {
if (const auto *already{
GetUnitMap().LookUp(newPath.get(), newPathLength)}) {
handler.SignalError(IostatOpenAlreadyConnected,
"OPEN(UNIT=%d,FILE='%.*s'): file is already connected to unit %d",
unitNumber_, static_cast<int>(newPathLength), newPath.get(),
already->unitNumber_);
return;
}
}
set_path(std::move(newPath), newPathLength);
Open(status.value_or(OpenStatus::Unknown), action, position, handler);
auto totalBytes{knownSize()};
Expand Down
2 changes: 1 addition & 1 deletion flang/runtime/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ExternalFileUnit : public ConnectionState,
int unit, const Terminator &, bool &wasExtant);
static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction,
std::optional<bool> isUnformatted, const Terminator &);
static ExternalFileUnit *LookUp(const char *path);
static ExternalFileUnit *LookUp(const char *path, std::size_t pathLen);
static ExternalFileUnit &CreateNew(int unit, const Terminator &);
static ExternalFileUnit *LookUpForClose(int unit);
static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo);
Expand Down

0 comments on commit 03c066a

Please sign in to comment.