Skip to content

Commit 03c066a

Browse files
committed
[flang][runtime] Catch OPEN of connected file
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
1 parent 562fd2c commit 03c066a

File tree

9 files changed

+32
-11
lines changed

9 files changed

+32
-11
lines changed

flang/include/flang/Runtime/iostat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ enum Iostat {
7575
IostatBOZInputOverflow,
7676
IostatIntegerInputOverflow,
7777
IostatRealInputOverflow,
78+
IostatOpenAlreadyConnected,
79+
IostatCannotReposition,
7880
};
7981

8082
const char *IostatErrorString(int);

flang/runtime/file.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ bool OpenFile::Seek(FileOffset at, IoErrorHandler &handler) {
377377
SetPosition(at);
378378
return true;
379379
} else {
380-
handler.SignalErrno();
380+
handler.SignalError(IostatCannotReposition);
381381
return false;
382382
}
383383
}

flang/runtime/file.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class OpenFile {
2828
using FileOffset = std::int64_t;
2929

3030
const char *path() const { return path_.get(); }
31-
void set_path(OwningPtr<char> &&, std::size_t bytes);
3231
std::size_t pathLength() const { return pathLength_; }
32+
void set_path(OwningPtr<char> &&, std::size_t bytes);
3333
bool mayRead() const { return mayRead_; }
3434
bool mayWrite() const { return mayWrite_; }
3535
bool mayPosition() const { return mayPosition_; }

flang/runtime/io-api.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,9 @@ Cookie IONAME(BeginInquireFile)(const char *path, std::size_t pathLength,
431431
Terminator oom{sourceFile, sourceLine};
432432
auto trimmed{
433433
SaveDefaultCharacter(path, TrimTrailingSpaces(path, pathLength), oom)};
434-
if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(trimmed.get())}) {
434+
if (ExternalFileUnit *
435+
unit{ExternalFileUnit::LookUp(
436+
trimmed.get(), std::strlen(trimmed.get()))}) {
435437
// INQUIRE(FILE=) to a connected unit
436438
return &unit->BeginIoStatement<InquireUnitState>(
437439
*unit, sourceFile, sourceLine);

flang/runtime/iostat.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ const char *IostatErrorString(int iostat) {
9494
return "Integer input value overflows variable";
9595
case IostatRealInputOverflow:
9696
return "Real or complex input value overflows type";
97+
case IostatCannotReposition:
98+
return "Attempt to reposition a unit which is connected to a file that can "
99+
"only be processed sequentially";
100+
case IostatOpenAlreadyConnected:
101+
return "OPEN of file already connected to another unit";
97102
default:
98103
return nullptr;
99104
}

flang/runtime/unit-map.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,13 @@ void UnitMap::FlushAll(IoErrorHandler &handler) {
111111
}
112112
}
113113

114-
ExternalFileUnit *UnitMap::Find(const char *path) {
114+
ExternalFileUnit *UnitMap::Find(const char *path, std::size_t pathLen) {
115115
if (path) {
116116
// TODO: Faster data structure
117117
for (int j{0}; j < buckets_; ++j) {
118118
for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
119-
if (p->unit.path() && std::strcmp(p->unit.path(), path) == 0) {
119+
if (p->unit.path() && p->unit.pathLength() == pathLen &&
120+
std::memcmp(p->unit.path(), path, pathLen) == 0) {
120121
return &p->unit;
121122
}
122123
}

flang/runtime/unit-map.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ class UnitMap {
3737
}
3838

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

4545
ExternalFileUnit &NewUnit(const Terminator &);
@@ -84,7 +84,7 @@ class UnitMap {
8484
}
8585
return nullptr;
8686
}
87-
ExternalFileUnit *Find(const char *path);
87+
ExternalFileUnit *Find(const char *path, std::size_t pathLen);
8888

8989
ExternalFileUnit &Create(int, const Terminator &);
9090

flang/runtime/unit.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
7373
return result;
7474
}
7575

76-
ExternalFileUnit *ExternalFileUnit::LookUp(const char *path) {
77-
return GetUnitMap().LookUp(path);
76+
ExternalFileUnit *ExternalFileUnit::LookUp(
77+
const char *path, std::size_t pathLen) {
78+
return GetUnitMap().LookUp(path, pathLen);
7879
}
7980

8081
ExternalFileUnit &ExternalFileUnit::CreateNew(
@@ -124,6 +125,16 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
124125
FlushOutput(handler);
125126
Close(CloseStatus::Keep, handler);
126127
}
128+
if (newPath.get() && newPathLength > 0) {
129+
if (const auto *already{
130+
GetUnitMap().LookUp(newPath.get(), newPathLength)}) {
131+
handler.SignalError(IostatOpenAlreadyConnected,
132+
"OPEN(UNIT=%d,FILE='%.*s'): file is already connected to unit %d",
133+
unitNumber_, static_cast<int>(newPathLength), newPath.get(),
134+
already->unitNumber_);
135+
return;
136+
}
137+
}
127138
set_path(std::move(newPath), newPathLength);
128139
Open(status.value_or(OpenStatus::Unknown), action, position, handler);
129140
auto totalBytes{knownSize()};

flang/runtime/unit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ExternalFileUnit : public ConnectionState,
5050
int unit, const Terminator &, bool &wasExtant);
5151
static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction,
5252
std::optional<bool> isUnformatted, const Terminator &);
53-
static ExternalFileUnit *LookUp(const char *path);
53+
static ExternalFileUnit *LookUp(const char *path, std::size_t pathLen);
5454
static ExternalFileUnit &CreateNew(int unit, const Terminator &);
5555
static ExternalFileUnit *LookUpForClose(int unit);
5656
static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo);

0 commit comments

Comments
 (0)