[clang] 7f6c3a9 - [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`.

Martin Braenne via cfe-commits cfe-commits at lists.llvm.org
Thu May 25 07:47:13 PDT 2023


Author: Martin Braenne
Date: 2023-05-25T14:47:03Z
New Revision: 7f6c3a9033b6409ada46609f5f4b650e8556f56d

URL: https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d
DIFF: https://github.com/llvm/llvm-project/commit/7f6c3a9033b6409ada46609f5f4b650e8556f56d.diff

LOG: [clang][dataflow] Fix a crash in `getLogicOperatorSubExprValue()`.

This patch adds a test that crashes without the fix.

Reviewed By: ymandel

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

Added: 
    

Modified: 
    clang/lib/Analysis/FlowSensitive/Transfer.cpp
    clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index a67f9ceed82e..8547e5049261 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -194,24 +194,13 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
       auto &Loc = Env.createStorageLocation(*S);
       Env.setStorageLocation(*S, Loc);
 
-      BoolValue *LHSVal = getLogicOperatorSubExprValue(*LHS);
-      // If the LHS was not reachable, this BinaryOperator would also not be
-      // reachable, and we would never get here.
-      assert(LHSVal != nullptr);
-      BoolValue *RHSVal = getLogicOperatorSubExprValue(*RHS);
-      if (RHSVal == nullptr) {
-        // If the RHS isn't reachable and we evaluate this BinaryOperator,
-        // then the value of the LHS must have triggered the short-circuit
-        // logic. This implies that the value of the entire expression must be
-        // equal to the value of the LHS.
-        Env.setValue(Loc, *LHSVal);
-        break;
-      }
+      BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
+      BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
 
       if (S->getOpcode() == BO_LAnd)
-        Env.setValue(Loc, Env.makeAnd(*LHSVal, *RHSVal));
+        Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
       else
-        Env.setValue(Loc, Env.makeOr(*LHSVal, *RHSVal));
+        Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
       break;
     }
     case BO_NE:
@@ -805,35 +794,29 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
   }
 
 private:
-  /// If `SubExpr` is reachable, returns a non-null pointer to the value for
-  /// `SubExpr`. If `SubExpr` is not reachable, returns nullptr.
-  BoolValue *getLogicOperatorSubExprValue(const Expr &SubExpr) {
+  /// Returns the value for the sub-expression `SubExpr` of a logic operator.
+  BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
     // `SubExpr` and its parent logic operator might be part of 
diff erent basic
     // blocks. We try to access the value that is assigned to `SubExpr` in the
     // corresponding environment.
-    const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr);
-    if (!SubExprEnv)
-      return nullptr;
-
-    if (auto *Val =
-            dyn_cast_or_null<BoolValue>(SubExprEnv->getValueStrict(SubExpr)))
-      return Val;
-
-    if (Env.getValueStrict(SubExpr) == nullptr) {
-      // Sub-expressions that are logic operators are not added in basic blocks
-      // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
-      // operator, it may not have been evaluated and assigned a value yet. In
-      // that case, we need to first visit `SubExpr` and then try to get the
-      // value that gets assigned to it.
+    if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
+      if (auto *Val =
+              dyn_cast_or_null<BoolValue>(SubExprEnv->getValueStrict(SubExpr)))
+        return *Val;
+
+    // The sub-expression may lie within a basic block that isn't reachable,
+    // even if we need it to evaluate the current (reachable) expression
+    // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
+    // within the current environment and then try to get the value that gets
+    // assigned to it.
+    if (Env.getValueStrict(SubExpr) == nullptr)
       Visit(&SubExpr);
-    }
-
     if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValueStrict(SubExpr)))
-      return Val;
+      return *Val;
 
     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
     // boolean value for it.
-    return &Env.makeAtomicBoolValue();
+    return Env.makeAtomicBoolValue();
   }
 
   // If context sensitivity is enabled, try to analyze the body of the callee

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 726f2b7bbdcc..1a2442f0b12d 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -5140,6 +5140,26 @@ TEST(TransferTest, UnnamedBitfieldInitializer) {
       });
 }
 
+// Repro for a crash that used to occur with chained short-circuiting logical
+// operators.
+TEST(TransferTest, ChainedLogicalOps) {
+  std::string Code = R"(
+    bool target() {
+      bool b = true || false || false || false;
+      // [[p]]
+      return b;
+    }
+  )";
+  runDataflow(
+      Code,
+      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+         ASTContext &ASTCtx) {
+        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+        auto &B = getValueForDecl<BoolValue>(ASTCtx, Env, "b");
+        EXPECT_TRUE(Env.flowConditionImplies(B));
+      });
+}
+
 // Repro for a crash that used to occur when we call a `noreturn` function
 // within one of the operands of a `&&` or `||` operator.
 TEST(TransferTest, NoReturnFunctionInsideShortCircuitedBooleanOp) {


        


More information about the cfe-commits mailing list