[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