[flang-commits] [flang] cdfb95a - [flang] Add checks for misuse of formatted I/O APIs in unformatted I/O statement
peter klausler via flang-commits
flang-commits at lists.llvm.org
Thu Oct 1 09:58:22 PDT 2020
Author: peter klausler
Date: 2020-10-01T09:58:04-07:00
New Revision: cdfb95ad580fbf366a9bffc5082df22e9d2b5fa3
URL: https://github.com/llvm/llvm-project/commit/cdfb95ad580fbf366a9bffc5082df22e9d2b5fa3
DIFF: https://github.com/llvm/llvm-project/commit/cdfb95ad580fbf366a9bffc5082df22e9d2b5fa3.diff
LOG: [flang] Add checks for misuse of formatted I/O APIs in unformatted I/O statement
Add checking to I/O statement APIs to catch cases where the formatted
I/O data item transfer routines like OutputInteger64 are being
incorrectly used for unformatted I/O, which should use the
unformatted block or descriptor-based data item interfaces.
Differential revision: https://reviews.llvm.org/D88672
Added:
Modified:
flang/runtime/io-api.cpp
flang/runtime/io-api.h
flang/runtime/io-stmt.h
flang/runtime/type-code.cpp
flang/runtime/unit.cpp
Removed:
################################################################################
diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index 18c3f8241f08..304c40e871f4 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -922,14 +922,16 @@ bool IONAME(InputUnformattedBlock)(
}
bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputInteger64");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
- TypeCategory::Integer, 8, reinterpret_cast<void *>(&n), 0);
+ TypeCategory::Integer, sizeof n, reinterpret_cast<void *>(&n), 0);
return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
}
bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputInteger");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
@@ -938,6 +940,7 @@ bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
}
bool IONAME(OutputReal32)(Cookie cookie, float x) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputReal32");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
@@ -945,6 +948,7 @@ bool IONAME(OutputReal32)(Cookie cookie, float x) {
}
bool IONAME(OutputReal64)(Cookie cookie, double x) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputReal64");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
@@ -952,6 +956,7 @@ bool IONAME(OutputReal64)(Cookie cookie, double x) {
}
bool IONAME(InputReal32)(Cookie cookie, float &x) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputReal32");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
@@ -959,6 +964,7 @@ bool IONAME(InputReal32)(Cookie cookie, float &x) {
}
bool IONAME(InputReal64)(Cookie cookie, double &x) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputReal64");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
@@ -966,6 +972,7 @@ bool IONAME(InputReal64)(Cookie cookie, double &x) {
}
bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex32");
float z[2]{r, i};
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
@@ -975,6 +982,7 @@ bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
}
bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputComplex64");
double z[2]{r, i};
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
@@ -984,6 +992,7 @@ bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
}
bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputComplex32");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
@@ -992,6 +1001,7 @@ bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
}
bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputComplex64");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
@@ -999,34 +1009,48 @@ bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
}
-bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
+bool IONAME(OutputCharacter)(
+ Cookie cookie, const char *x, std::size_t length, int kind) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputCharacter");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
- 1, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);
+ kind, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);
return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
}
-bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
+bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
+ return IONAME(OutputCharacter(cookie, x, length, 1));
+}
+
+bool IONAME(InputCharacter)(
+ Cookie cookie, char *x, std::size_t length, int kind) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputCharacter");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
- descriptor.Establish(1, length, reinterpret_cast<void *>(x), 0);
+ descriptor.Establish(kind, length, reinterpret_cast<void *>(x), 0);
return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
}
+bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
+ return IONAME(InputCharacter(cookie, x, length, 1));
+}
+
bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
+ cookie->CheckFormattedStmtType<Direction::Output>("OutputLogical");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
- TypeCategory::Logical, 1, reinterpret_cast<void *>(&truth), 0);
+ TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
}
bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
+ cookie->CheckFormattedStmtType<Direction::Input>("InputLogical");
StaticDescriptor staticDescriptor;
Descriptor &descriptor{staticDescriptor.descriptor()};
descriptor.Establish(
- TypeCategory::Logical, 1, reinterpret_cast<void *>(&truth), 0);
+ TypeCategory::Logical, sizeof truth, reinterpret_cast<void *>(&truth), 0);
return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
}
diff --git a/flang/runtime/io-api.h b/flang/runtime/io-api.h
index 369013fee8bc..80a6de95069c 100644
--- a/flang/runtime/io-api.h
+++ b/flang/runtime/io-api.h
@@ -231,10 +231,12 @@ bool IONAME(SetSign)(Cookie, const char *, std::size_t);
// and avoid the following items when they might crash.
bool IONAME(OutputDescriptor)(Cookie, const Descriptor &);
bool IONAME(InputDescriptor)(Cookie, const Descriptor &);
+// Contiguous transfers for unformatted I/O
bool IONAME(OutputUnformattedBlock)(
Cookie, const char *, std::size_t, std::size_t elementBytes);
bool IONAME(InputUnformattedBlock)(
Cookie, char *, std::size_t, std::size_t elementBytes);
+// Formatted (including list directed) I/O data items
bool IONAME(OutputInteger64)(Cookie, std::int64_t);
bool IONAME(InputInteger)(Cookie, std::int64_t &, int kind = 8);
bool IONAME(OutputReal32)(Cookie, float);
@@ -245,7 +247,9 @@ bool IONAME(OutputComplex32)(Cookie, float, float);
bool IONAME(InputComplex32)(Cookie, float[2]);
bool IONAME(OutputComplex64)(Cookie, double, double);
bool IONAME(InputComplex64)(Cookie, double[2]);
+bool IONAME(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1);
bool IONAME(OutputAscii)(Cookie, const char *, std::size_t);
+bool IONAME(InputCharacter)(Cookie, char *, std::size_t, int kind = 1);
bool IONAME(InputAscii)(Cookie, char *, std::size_t);
bool IONAME(OutputLogical)(Cookie, bool);
bool IONAME(InputLogical)(Cookie, bool &);
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 3c82dc8b1b0a..343619bc121c 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -43,6 +43,13 @@ class ExternalFormattedIoStatementState;
template <Direction> class ExternalListIoStatementState;
template <Direction> class UnformattedIoStatementState;
+struct InputStatementState {};
+struct OutputStatementState {};
+template <Direction D>
+using IoDirectionState = std::conditional_t<D == Direction::Input,
+ InputStatementState, OutputStatementState>;
+struct FormattedIoStatementState {};
+
// The Cookie type in the I/O API is a pointer (for C) to this class.
class IoStatementState {
public:
@@ -90,6 +97,15 @@ class IoStatementState {
std::optional<char32_t> NextInField(std::optional<int> &remaining);
std::optional<char32_t> GetNextNonBlank(); // can advance record
+ template <Direction D> void CheckFormattedStmtType(const char *name) {
+ if (!get_if<FormattedIoStatementState>() ||
+ !get_if<IoDirectionState<D>>()) {
+ GetIoErrorHandler().Crash(
+ "%s called for I/O statement that is not formatted %s", name,
+ D == Direction::Output ? "output" : "input");
+ }
+ }
+
private:
std::variant<std::reference_wrapper<OpenStatementState>,
std::reference_wrapper<CloseStatementState>,
@@ -132,17 +148,11 @@ struct IoStatementBase : public DefaultFormatControlCallbacks {
void BadInquiryKeywordHashCrash(InquiryKeywordHash);
};
-struct InputStatementState {};
-struct OutputStatementState {};
-template <Direction D>
-using IoDirectionState = std::conditional_t<D == Direction::Input,
- InputStatementState, OutputStatementState>;
-
-struct FormattedStatementState {};
-
// Common state for list-directed internal & external I/O
-template <Direction> struct ListDirectedStatementState {};
-template <> struct ListDirectedStatementState<Direction::Output> {
+template <Direction> struct ListDirectedStatementState;
+template <>
+struct ListDirectedStatementState<Direction::Output>
+ : public FormattedIoStatementState {
static std::size_t RemainingSpaceInRecord(const ConnectionState &);
bool NeedAdvance(const ConnectionState &, std::size_t) const;
bool EmitLeadingSpaceOrAdvance(
@@ -151,7 +161,9 @@ template <> struct ListDirectedStatementState<Direction::Output> {
IoStatementState &, int maxRepeat = 1);
bool lastWasUndelimitedCharacter{false};
};
-template <> class ListDirectedStatementState<Direction::Input> {
+template <>
+class ListDirectedStatementState<Direction::Input>
+ : public FormattedIoStatementState {
public:
// Skips value separators, handles repetition and null values.
// Vacant when '/' appears; present with descriptor == ListDirectedNullValue
@@ -199,7 +211,7 @@ class InternalIoStatementState : public IoStatementBase,
template <Direction DIR, typename CHAR>
class InternalFormattedIoStatementState
: public InternalIoStatementState<DIR, CHAR>,
- public FormattedStatementState {
+ public FormattedIoStatementState {
public:
using CharType = CHAR;
using typename InternalIoStatementState<DIR, CharType>::Buffer;
@@ -275,7 +287,7 @@ class ExternalIoStatementState : public ExternalIoStatementBase,
template <Direction DIR, typename CHAR>
class ExternalFormattedIoStatementState : public ExternalIoStatementState<DIR>,
- public FormattedStatementState {
+ public FormattedIoStatementState {
public:
using CharType = CHAR;
ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
diff --git a/flang/runtime/type-code.cpp b/flang/runtime/type-code.cpp
index 3fda906516ed..19de2ef2e58e 100644
--- a/flang/runtime/type-code.cpp
+++ b/flang/runtime/type-code.cpp
@@ -78,13 +78,13 @@ TypeCode::TypeCode(TypeCategory f, int kind) {
raw_ = CFI_type_Bool;
break;
case 2:
- raw_ = CFI_type_int16_t;
+ raw_ = CFI_type_int_fast16_t;
break;
case 4:
- raw_ = CFI_type_int32_t;
+ raw_ = CFI_type_int_fast32_t;
break;
case 8:
- raw_ = CFI_type_int64_t;
+ raw_ = CFI_type_int_fast64_t;
break;
}
break;
diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 8170fbc696c2..bcb8a478ad59 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -290,7 +290,7 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes,
furthestPositionInRecord = furthestAfter;
return true;
} else {
- handler.SignalEnd();
+ // EOF or error: can be handled & has been signaled
endfileRecordNumber = currentRecordNumber;
return false;
}
More information about the flang-commits
mailing list