[flang-commits] [flang] 27cf6ba - [flang][runtime] Initialize uninitialized pointer components

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon May 8 15:24:58 PDT 2023


Author: Peter Klausler
Date: 2023-05-08T15:08:37-07:00
New Revision: 27cf6ba1d7bc623a5dca5c0ae82af98d0cdfc390

URL: https://github.com/llvm/llvm-project/commit/27cf6ba1d7bc623a5dca5c0ae82af98d0cdfc390
DIFF: https://github.com/llvm/llvm-project/commit/27cf6ba1d7bc623a5dca5c0ae82af98d0cdfc390.diff

LOG: [flang][runtime] Initialize uninitialized pointer components

Pointer components without default initialization pose some
difficult (or impossible) problems when they appear as right-hand
side targets in pointer assignment statements; they may contain
garbage or stale data that looks enough like a valid descriptor
to cause a crash.  Solve the problem by avoiding it -- ensure
that pointers' descriptors are at least minimally established.

Differential Revision: https://reviews.llvm.org/D149979

Added: 
    flang/test/Semantics/structconst07.f90
    flang/test/Semantics/typeinfo03.f90

Modified: 
    flang/include/flang/Semantics/tools.h
    flang/include/flang/Semantics/type.h
    flang/lib/Semantics/check-data.cpp
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/runtime-type-info.cpp
    flang/lib/Semantics/tools.cpp
    flang/lib/Semantics/type.cpp
    flang/runtime/derived.cpp
    flang/runtime/type-info.cpp
    flang/test/Semantics/canondo01.f90

Removed: 
    flang/test/Semantics/structconst07.f90#


################################################################################
diff  --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 4a78b31c5a792..ee62b66d54b0f 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -117,7 +117,7 @@ bool CanBeTypeBoundProc(const Symbol &);
 bool HasDeclarationInitializer(const Symbol &);
 // Is the symbol explicitly or implicitly initialized in any way?
 bool IsInitialized(const Symbol &, bool ignoreDATAstatements = false,
-    bool ignoreAllocatable = false);
+    bool ignoreAllocatable = false, bool ignorePointer = true);
 // Is the symbol a component subject to deallocation or finalization?
 bool IsDestructible(const Symbol &, const Symbol *derivedType = nullptr);
 bool HasIntrinsicTypeName(const Symbol &);

diff  --git a/flang/include/flang/Semantics/type.h b/flang/include/flang/Semantics/type.h
index 76866c8e994b0..3fcd438eaf134 100644
--- a/flang/include/flang/Semantics/type.h
+++ b/flang/include/flang/Semantics/type.h
@@ -266,7 +266,8 @@ class DerivedTypeSpec {
 
   bool MightBeParameterized() const;
   bool IsForwardReferenced() const;
-  bool HasDefaultInitialization(bool ignoreAllocatable = false) const;
+  bool HasDefaultInitialization(
+      bool ignoreAllocatable = false, bool ignorePointer = true) const;
   bool HasDestruction() const;
 
   // The "raw" type parameter list is a simple transcription from the

diff  --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp
index f33258ea7c19a..6916870907a63 100644
--- a/flang/lib/Semantics/check-data.cpp
+++ b/flang/lib/Semantics/check-data.cpp
@@ -63,7 +63,8 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
                 : IsFunctionResult(symbol)     ? "Function result"
                 : IsAllocatable(symbol)        ? "Allocatable"
                 : IsInitialized(symbol, true /*ignore DATA*/,
-                      true /*ignore allocatable components*/)
+                      true /*ignore allocatable components*/,
+                      true /*ignore uninitialized pointer components*/)
                 ? "Default-initialized"
                 : IsProcedure(symbol) && !IsPointer(symbol) ? "Procedure"
                 // remaining checks don't apply to components

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index cec936c8f5e42..5ec83344d03d0 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2066,13 +2066,15 @@ MaybeExpr ExpressionAnalyzer::Analyze(
     if (!symbol.test(Symbol::Flag::ParentComp) &&
         unavailable.find(symbol.name()) == unavailable.cend()) {
       if (IsAllocatable(symbol)) {
-        // Set all remaining allocatables to explicit NULL()
+        // Set all remaining allocatables to explicit NULL().
         result.Add(symbol, Expr<SomeType>{NullPointer{}});
-      } else if (const auto *details{
-                     symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
-        if (details->init()) {
-          result.Add(symbol, common::Clone(*details->init()));
-        } else { // C799
+      } else {
+        const auto *object{symbol.detailsIf<semantics::ObjectEntityDetails>()};
+        if (object && object->init()) {
+          result.Add(symbol, common::Clone(*object->init()));
+        } else if (IsPointer(symbol)) {
+          result.Add(symbol, Expr<SomeType>{NullPointer{}});
+        } else if (object) { // C799
           AttachDeclaration(Say(typeName,
                                 "Structure constructor lacks a value for "
                                 "component '%s'"_err_en_US,

diff  --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 15a2a67103236..acd3c49b39098 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -626,8 +626,8 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
     // instances without any initialized components, analyze the type
     // and set a flag if there's nothing to do for it at run time.
     AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
-        IntExpr<1>(
-            derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization()));
+        IntExpr<1>(derivedTypeSpec &&
+            !derivedTypeSpec->HasDefaultInitialization(false, false)));
     // Similarly, a flag to short-circuit destruction when not needed.
     AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
         IntExpr<1>(isAbstractType ||

diff  --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index fb2710b54284c..711537ec4947b 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -642,21 +642,23 @@ bool HasDeclarationInitializer(const Symbol &symbol) {
   }
 }
 
-bool IsInitialized(
-    const Symbol &symbol, bool ignoreDataStatements, bool ignoreAllocatable) {
+bool IsInitialized(const Symbol &symbol, bool ignoreDataStatements,
+    bool ignoreAllocatable, bool ignorePointer) {
   if (!ignoreAllocatable && IsAllocatable(symbol)) {
     return true;
   } else if (!ignoreDataStatements && symbol.test(Symbol::Flag::InDataStmt)) {
     return true;
   } else if (HasDeclarationInitializer(symbol)) {
     return true;
-  } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol) ||
-      IsPointer(symbol)) {
+  } else if (IsPointer(symbol)) {
+    return !ignorePointer;
+  } else if (IsNamedConstant(symbol) || IsFunctionResult(symbol)) {
     return false;
   } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
     if (!object->isDummy() && object->type()) {
       if (const auto *derived{object->type()->AsDerived()}) {
-        return derived->HasDefaultInitialization(ignoreAllocatable);
+        return derived->HasDefaultInitialization(
+            ignoreAllocatable, ignorePointer);
       }
     }
   }

diff  --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index d895f01dba2ea..667fdc453687a 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -179,11 +179,13 @@ bool DerivedTypeSpec::IsForwardReferenced() const {
   return typeSymbol_.get<DerivedTypeDetails>().isForwardReferenced();
 }
 
-bool DerivedTypeSpec::HasDefaultInitialization(bool ignoreAllocatable) const {
+bool DerivedTypeSpec::HasDefaultInitialization(
+    bool ignoreAllocatable, bool ignorePointer) const {
   DirectComponentIterator components{*this};
   return bool{std::find_if(
       components.begin(), components.end(), [&](const Symbol &component) {
-        return IsInitialized(component, true, ignoreAllocatable);
+        return IsInitialized(component, /*ignoreDataStatements=*/true,
+            ignoreAllocatable, ignorePointer);
       })};
 }
 

diff  --git a/flang/runtime/derived.cpp b/flang/runtime/derived.cpp
index 981ddb2a6e9d4..814fcfa1e1e7d 100644
--- a/flang/runtime/derived.cpp
+++ b/flang/runtime/derived.cpp
@@ -58,6 +58,16 @@ int Initialize(const Descriptor &instance, const typeInfo::DerivedType &derived,
         char *ptr{instance.ZeroBasedIndexedElement<char>(j) + comp.offset()};
         std::memcpy(ptr, init, bytes);
       }
+    } else if (comp.genre() == typeInfo::Component::Genre::Pointer) {
+      // Data pointers without explicit initialization are established
+      // so that they are valid right-hand side targets of pointer
+      // assignment statements.
+      for (std::size_t j{0}; j < elements; ++j) {
+        Descriptor &ptrDesc{*instance.OffsetElement<Descriptor>(
+            j * byteStride + comp.offset())};
+        comp.EstablishDescriptor(ptrDesc, instance, terminator);
+        ptrDesc.raw().attribute = CFI_attribute_pointer;
+      }
     } else if (comp.genre() == typeInfo::Component::Genre::Data &&
         comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) {
       // Default initialization of non-pointer non-allocatable/automatic

diff  --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp
index 84ec05d02705f..9b624a664a2f5 100644
--- a/flang/runtime/type-info.cpp
+++ b/flang/runtime/type-info.cpp
@@ -112,7 +112,7 @@ void Component::EstablishDescriptor(Descriptor &descriptor,
   } else {
     descriptor.Establish(cat, kind_, nullptr, rank_, nullptr, attribute);
   }
-  if (rank_ && genre_ != Genre::Allocatable) {
+  if (rank_ && genre_ != Genre::Allocatable && genre_ != Genre::Pointer) {
     const typeInfo::Value *boundValues{bounds()};
     RUNTIME_CHECK(terminator, boundValues != nullptr);
     auto byteStride{static_cast<SubscriptValue>(descriptor.ElementBytes())};

diff  --git a/flang/test/Semantics/canondo01.f90 b/flang/test/Semantics/canondo01.f90
index 50ffa489019e2..7a48db346e9a7 100644
--- a/flang/test/Semantics/canondo01.f90
+++ b/flang/test/Semantics/canondo01.f90
@@ -1,4 +1,3 @@
-
 ! RUN: %flang_fc1 -fdebug-unparse-with-symbols %s 2>&1 | FileCheck %s
 ! CHECK: end do
 

diff  --git a/flang/test/Semantics/structconst07.f90 b/flang/test/Semantics/structconst07.f90
new file mode 100644
index 0000000000000..a34289a817af4
--- /dev/null
+++ b/flang/test/Semantics/structconst07.f90
@@ -0,0 +1,9 @@
+! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+type :: hasPointer
+  class(*), pointer :: sp
+end type
+type(hasPointer) hp
+!CHECK: hp=haspointer(sp=NULL())
+hp = hasPointer()
+end
+

diff  --git a/flang/test/Semantics/structconst07.f90# b/flang/test/Semantics/structconst07.f90#
deleted file mode 100644
index af75b43658d32..0000000000000
--- a/flang/test/Semantics/structconst07.f90#
+++ /dev/null
@@ -1,5 +0,0 @@
-! RUN: %python %S/test_errors.py %s %flang_fc1
-! C1594(4)
-module m
-  type t1
-    

diff  --git a/flang/test/Semantics/typeinfo03.f90 b/flang/test/Semantics/typeinfo03.f90
new file mode 100644
index 0000000000000..f0c0a817da4a4
--- /dev/null
+++ b/flang/test/Semantics/typeinfo03.f90
@@ -0,0 +1,9 @@
+!RUN: bbc --dump-symbols %s | FileCheck %s
+!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s
+!Ensure that type with pointer component(s) has "noinitializationneeded=0"
+module m
+  type hasPointer
+    class(*), pointer :: sp, ap(:)
+  end type
+end module
+!CHECK: .dt.haspointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.haspointer,sizeinbytes=104_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=.c.haspointer,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)


        


More information about the flang-commits mailing list