Skip to content

Commit b6aeb77

Browse files
committed
[flang][runtime] Correct handling of intentional I/O errors in pFLogger
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. Further, a signed integer in a format must have a digit, and can appear only as the scale factor before a P control edit descriptor.
1 parent 83ca78d commit b6aeb77

File tree

5 files changed

+36
-15
lines changed

5 files changed

+36
-15
lines changed

flang/runtime/format-implementation.h

Lines changed: 16 additions & 9 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);

flang/runtime/internal-unit.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
109109
template <Direction DIR>
110110
bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
111111
if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
112-
handler.SignalEnd();
112+
if constexpr (DIR == Direction::Input) {
113+
handler.SignalEnd();
114+
} else {
115+
handler.SignalError(IostatInternalWriteOverrun);
116+
}
113117
return false;
114118
}
115119
if constexpr (DIR == Direction::Output) {

flang/runtime/io-stmt.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ template <Direction DIR> void InternalIoStatementState<DIR>::BackspaceRecord() {
118118
unit_.BackspaceRecord(*this);
119119
}
120120

121+
template <Direction DIR>
122+
void InternalIoStatementState<DIR>::CompleteOperation() {
123+
if (!this->completedOperation()) {
124+
if constexpr (DIR == Direction::Output) {
125+
unit_.AdvanceRecord(*this);
126+
}
127+
IoStatementBase::CompleteOperation();
128+
}
129+
}
130+
121131
template <Direction DIR> int InternalIoStatementState<DIR>::EndIoStatement() {
122132
if constexpr (DIR == Direction::Output) {
123133
unit_.EndIoStatement(); // fill
@@ -164,10 +174,8 @@ InternalFormattedIoStatementState<DIR, CHAR>::InternalFormattedIoStatementState(
164174
template <Direction DIR, typename CHAR>
165175
void InternalFormattedIoStatementState<DIR, CHAR>::CompleteOperation() {
166176
if (!this->completedOperation()) {
167-
if constexpr (DIR == Direction::Output) {
168-
format_.Finish(*this); // ignore any remaining input positioning actions
169-
}
170-
IoStatementBase::CompleteOperation();
177+
format_.Finish(*this);
178+
InternalIoStatementState<DIR>::CompleteOperation();
171179
}
172180
}
173181

flang/runtime/io-stmt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ class InternalIoStatementState : public IoStatementBase,
346346
const char *sourceFile = nullptr, int sourceLine = 0);
347347
InternalIoStatementState(
348348
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
349+
void CompleteOperation();
349350
int EndIoStatement();
350351

351352
bool Emit(const char *data, std::size_t bytes, std::size_t elementBytes = 0);

flang/unittests/Runtime/NumericalFormatTest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ TEST(IOApiTests, HelloWorldOutputTest) {
104104

105105
TEST(IOApiTests, MultilineOutputTest) {
106106
// Allocate buffer for multiline output
107-
static constexpr int numLines{5};
107+
static constexpr int numLines{6};
108108
static constexpr int lineLength{32};
109109
char buffer[numLines][lineLength];
110110

@@ -159,6 +159,7 @@ TEST(IOApiTests, MultilineOutputTest) {
159159
" "
160160
"789 abcd 666 777"
161161
" 888 999 "
162+
" "
162163
"................................"};
163164
// Ensure formatted string matches expected output
164165
EXPECT_TRUE(

0 commit comments

Comments
 (0)