[flang-commits] [flang] [flang] Fix crash from fuzzy test. (PR #122364)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Jan 9 14:32:17 PST 2025


https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/122364

>From 92a08edead963ca91379ff1b4aded691109c8d23 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 9 Jan 2025 12:17:20 -0800
Subject: [PATCH] [flang] Fix crashes from fuzzy test.

Fixes https://github.com/llvm/llvm-project/issues/122002.
The compiler now survives both of the test cases in that bug report.
---
 flang/include/flang/Evaluate/shape.h     |  8 +++-
 flang/lib/Evaluate/fold-implementation.h |  6 ++-
 flang/lib/Evaluate/shape.cpp             | 52 ++++++++++++++++--------
 flang/test/Semantics/bug122002a.f90      |  5 +++
 flang/test/Semantics/bug122002b.f90      | 13 ++++++
 5 files changed, 63 insertions(+), 21 deletions(-)
 create mode 100644 flang/test/Semantics/bug122002a.f90
 create mode 100644 flang/test/Semantics/bug122002b.f90

diff --git a/flang/include/flang/Evaluate/shape.h b/flang/include/flang/Evaluate/shape.h
index e679a001235490..a498444b0dd2b1 100644
--- a/flang/include/flang/Evaluate/shape.h
+++ b/flang/include/flang/Evaluate/shape.h
@@ -183,8 +183,12 @@ class GetShapeHelper
   }
   template <typename D, typename R, typename LO, typename RO>
   Result operator()(const Operation<D, R, LO, RO> &operation) const {
-    if (operation.right().Rank() > 0) {
-      return (*this)(operation.right());
+    if (int rr{operation.right().Rank()}; rr > 0) {
+      if (int lr{operation.left().Rank()}; lr == 0 || lr == rr) {
+        return (*this)(operation.right());
+      } else {
+        return std::nullopt;
+      }
     } else {
       return (*this)(operation.left());
     }
diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h
index c82995c38f79f7..208188a4ffcc77 100644
--- a/flang/lib/Evaluate/fold-implementation.h
+++ b/flang/lib/Evaluate/fold-implementation.h
@@ -1643,8 +1643,12 @@ auto ApplyElementwise(FoldingContext &context,
     -> std::optional<Expr<RESULT>> {
   auto resultLength{ComputeResultLength(operation)};
   auto &leftExpr{operation.left()};
-  leftExpr = Fold(context, std::move(leftExpr));
   auto &rightExpr{operation.right()};
+  if (leftExpr.Rank() != rightExpr.Rank() && leftExpr.Rank() != 0 &&
+      rightExpr.Rank() != 0) {
+    return std::nullopt; // error recovery
+  }
+  leftExpr = Fold(context, std::move(leftExpr));
   rightExpr = Fold(context, std::move(rightExpr));
   if (leftExpr.Rank() > 0) {
     if (std::optional<Shape> leftShape{GetShape(context, leftExpr)}) {
diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index c7b2156a3de17a..e62a5fe0e131db 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -254,7 +254,8 @@ class GetLowerBoundHelper
       if (dimension_ < rank) {
         const semantics::ShapeSpec &shapeSpec{object->shape()[dimension_]};
         if (shapeSpec.lbound().isExplicit()) {
-          if (const auto &lbound{shapeSpec.lbound().GetExplicit()}) {
+          if (const auto &lbound{shapeSpec.lbound().GetExplicit()};
+              lbound && lbound->Rank() == 0) {
             if constexpr (LBOUND_SEMANTICS) {
               bool ok{false};
               auto lbValue{ToInt64(*lbound)};
@@ -266,7 +267,8 @@ class GetLowerBoundHelper
               } else if (lbValue.value_or(0) == 1) {
                 // Lower bound is 1, regardless of extent
                 ok = true;
-              } else if (const auto &ubound{shapeSpec.ubound().GetExplicit()}) {
+              } else if (const auto &ubound{shapeSpec.ubound().GetExplicit()};
+                  ubound && ubound->Rank() == 0) {
                 // If we can't prove that the dimension is nonempty,
                 // we must be conservative.
                 // TODO: simple symbolic math in expression rewriting to
@@ -459,7 +461,7 @@ static MaybeExtentExpr GetNonNegativeExtent(
     } else {
       return ExtentExpr{*uval - *lval + 1};
     }
-  } else if (lbound && ubound &&
+  } else if (lbound && ubound && lbound->Rank() == 0 && ubound->Rank() == 0 &&
       (!invariantOnly ||
           (IsScopeInvariantExpr(*lbound) && IsScopeInvariantExpr(*ubound)))) {
     // Apply effective IDIM (MAX calculation with 0) so thet the
@@ -608,7 +610,8 @@ MaybeExtentExpr GetRawUpperBound(
     int rank{details->shape().Rank()};
     if (dimension < rank) {
       const auto &bound{details->shape()[dimension].ubound().GetExplicit()};
-      if (bound && (!invariantOnly || IsScopeInvariantExpr(*bound))) {
+      if (bound && bound->Rank() == 0 &&
+          (!invariantOnly || IsScopeInvariantExpr(*bound))) {
         return *bound;
       } else if (semantics::IsAssumedSizeArray(symbol) &&
           dimension + 1 == symbol.Rank()) {
@@ -640,7 +643,8 @@ MaybeExtentExpr GetRawUpperBound(FoldingContext &context,
 static MaybeExtentExpr GetExplicitUBOUND(FoldingContext *context,
     const semantics::ShapeSpec &shapeSpec, bool invariantOnly) {
   const auto &ubound{shapeSpec.ubound().GetExplicit()};
-  if (ubound && (!invariantOnly || IsScopeInvariantExpr(*ubound))) {
+  if (ubound && ubound->Rank() == 0 &&
+      (!invariantOnly || IsScopeInvariantExpr(*ubound))) {
     if (auto extent{GetNonNegativeExtent(shapeSpec, invariantOnly)}) {
       if (auto cstExtent{ToInt64(
               context ? Fold(*context, std::move(*extent)) : *extent)}) {
@@ -731,7 +735,8 @@ MaybeExtentExpr GetLCOBOUND(
     if (dimension < corank) {
       const semantics::ShapeSpec &shapeSpec{object->coshape()[dimension]};
       if (const auto &lcobound{shapeSpec.lbound().GetExplicit()}) {
-        if (!invariantOnly || IsScopeInvariantExpr(*lcobound)) {
+        if (lcobound->Rank() == 0 &&
+            (!invariantOnly || IsScopeInvariantExpr(*lcobound))) {
           return *lcobound;
         }
       }
@@ -748,7 +753,8 @@ MaybeExtentExpr GetUCOBOUND(
     if (dimension < corank - 1) {
       const semantics::ShapeSpec &shapeSpec{object->coshape()[dimension]};
       if (const auto ucobound{shapeSpec.ubound().GetExplicit()}) {
-        if (!invariantOnly || IsScopeInvariantExpr(*ucobound)) {
+        if (ucobound->Rank() == 0 &&
+            (!invariantOnly || IsScopeInvariantExpr(*ucobound))) {
           return *ucobound;
         }
       }
@@ -822,7 +828,7 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
             if (subp.isFunction()) {
               auto resultShape{(*this)(subp.result())};
               if (resultShape && !useResultSymbolShape_) {
-                // Ensure the shape is constant. Otherwise, it may be referring
+                // Ensure the shape is constant. Otherwise, it may be reerring
                 // to symbols that belong to the function's scope and are
                 // meaningless on the caller side without the related call
                 // expression.
@@ -908,23 +914,33 @@ auto GetShapeHelper::operator()(const ProcedureRef &call) const -> Result {
       if (auto chars{characteristics::Procedure::FromActuals(
               call.proc(), call.arguments(), *context_)}) {
         std::size_t j{0};
-        std::size_t anyArrayArgRank{0};
+        const ActualArgument *nonOptionalArrayArg{nullptr};
+        int anyArrayArgRank{0};
         for (const auto &arg : call.arguments()) {
           if (arg && arg->Rank() > 0 && j < chars->dummyArguments.size()) {
-            anyArrayArgRank = arg->Rank();
-            if (!chars->dummyArguments[j].IsOptional()) {
-              return (*this)(*arg);
+            if (!anyArrayArgRank) {
+              anyArrayArgRank = arg->Rank();
+            } else if (arg->Rank() != anyArrayArgRank) {
+              return std::nullopt; // error recovery
+            }
+            if (!nonOptionalArrayArg &&
+                !chars->dummyArguments[j].IsOptional()) {
+              nonOptionalArrayArg = &*arg;
             }
           }
           ++j;
         }
         if (anyArrayArgRank) {
-          // All dummy array arguments of the procedure are OPTIONAL.
-          // We cannot take the shape from just any array argument,
-          // because all of them might be OPTIONAL dummy arguments
-          // of the caller. Return unknown shape ranked according
-          // to the last actual array argument.
-          return Shape(anyArrayArgRank, MaybeExtentExpr{});
+          if (nonOptionalArrayArg) {
+            return (*this)(*nonOptionalArrayArg);
+          } else {
+            // All dummy array arguments of the procedure are OPTIONAL.
+            // We cannot take the shape from just any array argument,
+            // because all of them might be OPTIONAL dummy arguments
+            // of the caller. Return unknown shape ranked according
+            // to the last actual array argument.
+            return Shape(anyArrayArgRank, MaybeExtentExpr{});
+          }
         }
       }
     }
diff --git a/flang/test/Semantics/bug122002a.f90 b/flang/test/Semantics/bug122002a.f90
new file mode 100644
index 00000000000000..18fbed92a05f50
--- /dev/null
+++ b/flang/test/Semantics/bug122002a.f90
@@ -0,0 +1,5 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! ERROR: Missing initialization for parameter 'n'
+! ERROR: Must be a scalar value, but is a rank-1 array
+integer, parameter :: n(n)
+end
diff --git a/flang/test/Semantics/bug122002b.f90 b/flang/test/Semantics/bug122002b.f90
new file mode 100644
index 00000000000000..1e4315d3afdb67
--- /dev/null
+++ b/flang/test/Semantics/bug122002b.f90
@@ -0,0 +1,13 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+SUBROUTINE sub00(a,b,n,m)
+  complex(2) n,m
+! ERROR: Must have INTEGER type, but is COMPLEX(2)
+! ERROR: Must have INTEGER type, but is COMPLEX(2)
+! ERROR: The type of 'b' has already been implicitly declared
+  complex(3) a(n,m), b(size((LOG ((x * (a) - a + b / a - a))+1 - x)))
+  a = a ** n
+! ERROR: DO controls should be INTEGER
+  DO 10 j = 1,m
+    a = n ** a
+    10   PRINT *, g
+END SUBROUTINE sub00



More information about the flang-commits mailing list