[flang-commits] [flang] [flang][runtime] Handle end of internal output correctly (PR #84994)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Tue Mar 12 17:05:41 PDT 2024
https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/84994
>From 18ef785cc00cb87396f19ae20bee4894a1efbfc9 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Tue, 12 Mar 2024 16:22:47 -0700
Subject: [PATCH] [flang][runtime] Correct handling of intentional I/O errors
in pFUnit
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.
---
flang/runtime/format-implementation.h | 25 ++++++++++++-------
flang/runtime/internal-unit.cpp | 6 ++++-
flang/runtime/io-stmt.cpp | 16 +++++++++---
flang/runtime/io-stmt.h | 1 +
.../unittests/Runtime/NumericalFormatTest.cpp | 3 ++-
5 files changed, 36 insertions(+), 15 deletions(-)
diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index 9c342db2e19a24..f644845ce477d2 100644
--- a/flang/runtime/format-implementation.h
+++ b/flang/runtime/format-implementation.h
@@ -66,15 +66,6 @@ template <typename CONTEXT>
int FormatControl<CONTEXT>::GetIntField(
IoErrorHandler &handler, CharType firstCh, bool *hadError) {
CharType ch{firstCh ? firstCh : PeekNext()};
- if (ch != '-' && ch != '+' && (ch < '0' || ch > '9')) {
- handler.SignalError(IostatErrorInFormat,
- "Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
- if (hadError) {
- *hadError = true;
- }
- return 0;
- }
- int result{0};
bool negate{ch == '-'};
if (negate || ch == '+') {
if (firstCh) {
@@ -84,6 +75,15 @@ int FormatControl<CONTEXT>::GetIntField(
}
ch = PeekNext();
}
+ if (ch < '0' || ch > '9') {
+ handler.SignalError(IostatErrorInFormat,
+ "Invalid FORMAT: integer expected at '%c'", static_cast<char>(ch));
+ if (hadError) {
+ *hadError = true;
+ }
+ return 0;
+ }
+ int result{0};
while (ch >= '0' && ch <= '9') {
constexpr int tenth{std::numeric_limits<int>::max() / 10};
if (result > tenth ||
@@ -246,8 +246,15 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
ch = GetNextChar(context);
}
if (ch == '-' || ch == '+' || (ch >= '0' && ch <= '9')) {
+ bool hadSign{ch == '-' || ch == '+'};
repeat = GetIntField(context, ch);
ch = GetNextChar(context);
+ if (hadSign && ch != 'p' && ch != 'P') {
+ ReportBadFormat(context,
+ "Invalid FORMAT: signed integer may appear only before 'P",
+ maybeReversionPoint);
+ return 0;
+ }
} else if (ch == '*') {
unlimited = true;
ch = GetNextChar(context);
diff --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp
index e3fffaa6f378ff..46d442a7cdd726 100644
--- a/flang/runtime/internal-unit.cpp
+++ b/flang/runtime/internal-unit.cpp
@@ -109,7 +109,11 @@ std::size_t InternalDescriptorUnit<DIR>::GetNextInputBytes(
template <Direction DIR>
bool InternalDescriptorUnit<DIR>::AdvanceRecord(IoErrorHandler &handler) {
if (currentRecordNumber >= endfileRecordNumber.value_or(0)) {
- handler.SignalEnd();
+ if constexpr (DIR == Direction::Input) {
+ handler.SignalEnd();
+ } else {
+ handler.SignalError(IostatInternalWriteOverrun);
+ }
return false;
}
if constexpr (DIR == Direction::Output) {
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 3ec01ffba9bf06..bdee947481bf98 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -118,6 +118,16 @@ template <Direction DIR> void InternalIoStatementState<DIR>::BackspaceRecord() {
unit_.BackspaceRecord(*this);
}
+template <Direction DIR>
+void InternalIoStatementState<DIR>::CompleteOperation() {
+ if (!this->completedOperation()) {
+ if constexpr (DIR == Direction::Output) {
+ unit_.AdvanceRecord(*this);
+ }
+ IoStatementBase::CompleteOperation();
+ }
+}
+
template <Direction DIR> int InternalIoStatementState<DIR>::EndIoStatement() {
if constexpr (DIR == Direction::Output) {
unit_.EndIoStatement(); // fill
@@ -164,10 +174,8 @@ InternalFormattedIoStatementState<DIR, CHAR>::InternalFormattedIoStatementState(
template <Direction DIR, typename CHAR>
void InternalFormattedIoStatementState<DIR, CHAR>::CompleteOperation() {
if (!this->completedOperation()) {
- if constexpr (DIR == Direction::Output) {
- format_.Finish(*this); // ignore any remaining input positioning actions
- }
- IoStatementBase::CompleteOperation();
+ format_.Finish(*this);
+ InternalIoStatementState<DIR>::CompleteOperation();
}
}
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 0b6bcbd9af025a..2deef950d7f63e 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -346,6 +346,7 @@ class InternalIoStatementState : public IoStatementBase,
const char *sourceFile = nullptr, int sourceLine = 0);
InternalIoStatementState(
const Descriptor &, const char *sourceFile = nullptr, int sourceLine = 0);
+ void CompleteOperation();
int EndIoStatement();
bool Emit(const char *data, std::size_t bytes, std::size_t elementBytes = 0);
diff --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp
index 37eecd7708a1eb..ffde461fd82324 100644
--- a/flang/unittests/Runtime/NumericalFormatTest.cpp
+++ b/flang/unittests/Runtime/NumericalFormatTest.cpp
@@ -104,7 +104,7 @@ TEST(IOApiTests, HelloWorldOutputTest) {
TEST(IOApiTests, MultilineOutputTest) {
// Allocate buffer for multiline output
- static constexpr int numLines{5};
+ static constexpr int numLines{6};
static constexpr int lineLength{32};
char buffer[numLines][lineLength];
@@ -159,6 +159,7 @@ TEST(IOApiTests, MultilineOutputTest) {
" "
"789 abcd 666 777"
" 888 999 "
+ " "
"................................"};
// Ensure formatted string matches expected output
EXPECT_TRUE(
More information about the flang-commits
mailing list