[flang-commits] [flang] 77a57f6 - [flang] Avoid crash in statement function error case

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Jun 22 13:25:54 PDT 2023


Author: Peter Klausler
Date: 2023-06-22T13:25:41-07:00
New Revision: 77a57f6b250faf78637a44e88006923476421385

URL: https://github.com/llvm/llvm-project/commit/77a57f6b250faf78637a44e88006923476421385
DIFF: https://github.com/llvm/llvm-project/commit/77a57f6b250faf78637a44e88006923476421385.diff

LOG: [flang] Avoid crash in statement function error case

The predicate IsPureProcedure() crashes with infinite
recursion when presented with mutually recursive statement
functions -- an error case that should be recoverable.
Fix by adding a visited set.

Fixes bug https://github.com/llvm/llvm-project/issues/63231

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

Added: 
    

Modified: 
    flang/lib/Evaluate/tools.cpp
    flang/test/Semantics/stmt-func01.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index befe286050559..4761407e4bcbd 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1272,16 +1272,21 @@ bool IsVariableName(const Symbol &original) {
           ultimate.has<AssocEntityDetails>());
 }
 
-bool IsPureProcedure(const Symbol &original) {
+static bool IsPureProcedureImpl(
+    const Symbol &original, semantics::UnorderedSymbolSet &set) {
   // An ENTRY is pure if its containing subprogram is
   const Symbol &symbol{DEREF(GetMainEntry(&original.GetUltimate()))};
+  if (set.find(symbol) != set.end()) {
+    return true;
+  }
+  set.emplace(symbol);
   if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) {
     if (procDetails->procInterface()) {
       // procedure with a pure interface
-      return IsPureProcedure(*procDetails->procInterface());
+      return IsPureProcedureImpl(*procDetails->procInterface(), set);
     }
   } else if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) {
-    return IsPureProcedure(details->symbol());
+    return IsPureProcedureImpl(details->symbol(), set);
   } else if (!IsProcedure(symbol)) {
     return false;
   }
@@ -1293,7 +1298,7 @@ bool IsPureProcedure(const Symbol &original) {
         if (&*ref == &symbol) {
           return false; // error recovery, recursion is caught elsewhere
         }
-        if (IsFunction(*ref) && !IsPureProcedure(*ref)) {
+        if (IsFunction(*ref) && !IsPureProcedureImpl(*ref, set)) {
           return false;
         }
         if (ref->GetUltimate().attrs().test(Attr::VOLATILE)) {
@@ -1308,6 +1313,11 @@ bool IsPureProcedure(const Symbol &original) {
           !symbol.attrs().test(Attr::IMPURE));
 }
 
+bool IsPureProcedure(const Symbol &original) {
+  semantics::UnorderedSymbolSet set;
+  return IsPureProcedureImpl(original, set);
+}
+
 bool IsPureProcedure(const Scope &scope) {
   const Symbol *symbol{scope.GetSymbol()};
   return symbol && IsPureProcedure(*symbol);

diff  --git a/flang/test/Semantics/stmt-func01.f90 b/flang/test/Semantics/stmt-func01.f90
index 0f4fed51c1184..1857143071808 100644
--- a/flang/test/Semantics/stmt-func01.f90
+++ b/flang/test/Semantics/stmt-func01.f90
@@ -34,7 +34,10 @@ pure integer function ifunc()
   integer :: sf9
   !ERROR: Defining expression of statement function 'sf9' cannot be converted to its result type INTEGER(4)
   sf9(n) = "bad"
-  sf10 = 1.
+  !ERROR: Statement function 'sf10' may not reference another statement function 'sf11' that is defined later
+  sf10(n) = sf11(n)
+  sf11(n) = sf10(n) ! mutual recursion, caused crash
+  sf13 = 1.
  contains
   real function explicit(x,y)
     integer, intent(in) :: x
@@ -47,6 +50,6 @@ pure function arr()
   end function
   subroutine foo
     !PORTABILITY: An implicitly typed statement function should not appear when the same symbol is available in its host scope
-    sf10(x) = 2.*x
+    sf13(x) = 2.*x
   end subroutine
 end


        


More information about the flang-commits mailing list