Skip to content

Commit fc71a49

Browse files
authored
[flang][runtime] Handle end of internal output correctly (#84994)
At the end of an internal output statement, be sure to finish any following control edit descriptors in the format (if any), and (for output) advance to the next record. Return the right I/O error status code if output overruns the buffer.
1 parent 7bdba95 commit fc71a49

File tree

5 files changed

+38
-26
lines changed

5 files changed

+38
-26
lines changed

flang/runtime/format-implementation.h

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,6 @@ template <typename CONTEXT>
6666
int FormatControl<CONTEXT>::GetIntField(
6767
IoErrorHandler &handler, CharType firstCh, bool *hadError) {
6868
CharType ch{firstCh ? firstCh : PeekNext()};
69-
if (ch != '-' && ch != '+' && (ch < '0' || ch > '9')) {
70-
handler.SignalError(IostatErrorInFormat,
71-
"Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
72-
if (hadError) {
73-
*hadError = true;
74-
}
75-
return 0;
76-
}
77-
int result{0};
7869
bool negate{ch == '-'};
7970
if (negate || ch == '+') {
8071
if (firstCh) {
@@ -84,6 +75,15 @@ int FormatControl<CONTEXT>::GetIntField(
8475
}
8576
ch = PeekNext();
8677
}
78+
if (ch < '0' || ch > '9') {
79+
handler.SignalError(IostatErrorInFormat,
80+
"Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
81+
if (hadError) {
82+
*hadError = true;
83+
}
84+
return 0;
85+
}
86+
int result{0};
8787
while (ch >= '0' && ch <= '9') {
8888
constexpr int tenth{std::numeric_limits<int>::max() / 10};
8989
if (result > tenth ||
@@ -246,8 +246,15 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
246246
ch = GetNextChar(context);
247247
}
248248
if (ch == '-' || ch == '+' || (ch >= '0' && ch <= '9')) {
249+
bool hadSign{ch == '-' || ch == '+'};
249250
repeat = GetIntField(context, ch);
250251
ch = GetNextChar(context);
252+
if (hadSign && ch != 'p' && ch != 'P') {
253+
ReportBadFormat(context,
254+
"Invalid FORMAT: signed integer may appear only before 'P",
255+
maybeReversionPoint);
256+
return 0;
257+
}
251258
} else if (ch == '*') {
252259
unlimited = true;
253260
ch = GetNextChar(context);
@@ -297,11 +304,11 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
297304
return 0;
298305
} else if (ch == ')') {
299306
if (height_ == 1) {
307+
hitEnd_ = true;
300308
if (stop) {
301309
return 0; // end of FORMAT and no data items remain
302310
}
303311
context.AdvanceRecord(); // implied / before rightmost )
304-
hitEnd_ = true;
305312
}
306313
auto restart{stack_[height_ - 1].start};
307314
if (format_[restart] == '(') {

flang/runtime/internal-unit.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,6 @@ InternalDescriptorUnit<DIR>::InternalDescriptorUnit(
4141
endfileRecordNumber = d.Elements() + 1;
4242
}
4343

44-
template <Direction DIR> void InternalDescriptorUnit<DIR>::EndIoStatement() {
45-
if constexpr (DIR == Direction::Output) {
46-
// Clear the remainder of the current record.
47-
auto end{endfileRecordNumber.value_or(0)};
48-
if (currentRecordNumber < end) {
49-
BlankFillOutputRecord();
50-
}
51-
}
52-
}
53-
5444
template <Direction DIR>
5545
bool InternalDescriptorUnit<DIR>::Emit(
5646
const char *data, std::size_t bytes, IoErrorHandler &handler) {
@@ -109,7 +99,11 @@ std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
10999
template <Direction DIR>
110100
bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
111101
if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
112-
handler.SignalEnd();
102+
if constexpr (DIR == Direction::Input) {
103+
handler.SignalEnd();
104+
} else {
105+
handler.SignalError(IostatInternalWriteOverrun);
106+
}
113107
return false;
114108
}
115109
if constexpr (DIR == Direction::Output) {

flang/runtime/internal-unit.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ template <Direction DIR> class InternalDescriptorUnit : public ConnectionState {
2828
std::conditional_t<DIR == Direction::Input, const char *, char *>;
2929
InternalDescriptorUnit(Scalar, std::size_t chars, int kind);
3030
InternalDescriptorUnit(const Descriptor &, const Terminator &);
31-
void EndIoStatement();
3231

3332
bool Emit(const char *, std::size_t, IoErrorHandler &);
3433
std::size_t GetNextInputBytes(const char *&, IoErrorHandler &);

flang/runtime/io-stmt.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,6 @@ template <Direction DIR> void InternalIoStatementState<DIR>::BackspaceRecord() {
119119
}
120120

121121
template <Direction DIR> int InternalIoStatementState<DIR>::EndIoStatement() {
122-
if constexpr (DIR == Direction::Output) {
123-
unit_.EndIoStatement(); // fill
124-
}
125122
auto result{IoStatementBase::EndIoStatement()};
126123
if (free_) {
127124
FreeMemory(this);
@@ -165,7 +162,8 @@ template <Direction DIR, typename CHAR>
165162
void InternalFormattedIoStatementState<DIR, CHAR>::CompleteOperation() {
166163
if (!this->completedOperation()) {
167164
if constexpr (DIR == Direction::Output) {
168-
format_.Finish(*this); // ignore any remaining input positioning actions
165+
format_.Finish(*this);
166+
unit_.AdvanceRecord(*this);
169167
}
170168
IoStatementBase::CompleteOperation();
171169
}
@@ -189,8 +187,21 @@ InternalListIoStatementState<DIR>::InternalListIoStatementState(
189187
: InternalIoStatementState<DIR>{d, sourceFile, sourceLine},
190188
ioStatementState_{*this} {}
191189

190+
template <Direction DIR>
191+
void InternalListIoStatementState<DIR>::CompleteOperation() {
192+
if (!this->completedOperation()) {
193+
if constexpr (DIR == Direction::Output) {
194+
if (unit_.furthestPositionInRecord > 0) {
195+
unit_.AdvanceRecord(*this);
196+
}
197+
}
198+
IoStatementBase::CompleteOperation();
199+
}
200+
}
201+
192202
template <Direction DIR>
193203
int InternalListIoStatementState<DIR>::EndIoStatement() {
204+
CompleteOperation();
194205
if constexpr (DIR == Direction::Input) {
195206
if (int status{ListDirectedStatementState<DIR>::EndIoStatement()};
196207
status != IostatOk) {

flang/runtime/io-stmt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ class InternalListIoStatementState : public InternalIoStatementState<DIR>,
403403
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
404404
IoStatementState &ioStatementState() { return ioStatementState_; }
405405
using ListDirectedStatementState<DIR>::GetNextDataEdit;
406+
void CompleteOperation();
406407
int EndIoStatement();
407408

408409
private:

0 commit comments

Comments
 (0)