https://github.com/bazuzi created 
https://github.com/llvm/llvm-project/pull/157148

Reverts llvm/llvm-project#153066

copyRecord crashes if copying from the RecordStorageLocation shared by the 
base/derived objects after a DerivedToBase cast because the source type is 
still `Derived` but the copy destination could be of a sibling type derived 
from Base that has children not present in `Derived`.

For example, running the dataflow analysis over the following produces UB by 
nullptr deref, or fails asserts if enabled:

```cc
struct Base {};

struct DerivedOne : public Base {
  int DerivedOneField;
};

struct DerivedTwo : public Base {
  int DerivedTwoField;

  DerivedTwo(const DerivedOne& d1)
      : Base(d1), DerivedTwoField(d1.DerivedOneField) {}
};
```

The constructor initializer for `DerivedTwoField` serves the purpose of forcing 
`DerivedOneField` to be modeled, which is necessary to trigger the crash but 
not the assert failure.

>From 24f6f18e9cfbd4705340cfdf36311afc22fb3544 Mon Sep 17 00:00:00 2001
From: Samira Bakon <baz...@google.com>
Date: Fri, 5 Sep 2025 13:40:11 -0400
Subject: [PATCH] Revert "[clang][dataflow] Transfer more cast expressions.
 (#153066)"

This reverts commit ffe21f1cd7ddc0a8f5e8f1a4ed137398d3bf0d83.
---
 .../Analysis/FlowSensitive/StorageLocation.h  |  11 -
 clang/lib/Analysis/FlowSensitive/Transfer.cpp |  71 +----
 .../Analysis/FlowSensitive/TransferTest.cpp   | 280 +-----------------
 3 files changed, 13 insertions(+), 349 deletions(-)

diff --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h 
b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
index 534b9a017d8f0..8fcc6a44027a0 100644
--- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
+++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
@@ -17,7 +17,6 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Debug.h"
 #include <cassert>
 
@@ -153,11 +152,6 @@ class RecordStorageLocation final : public StorageLocation 
{
     return {SyntheticFields.begin(), SyntheticFields.end()};
   }
 
-  /// Add a synthetic field, if none by that name is already present.
-  void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
-    SyntheticFields.insert({Name, &Loc});
-  }
-
   /// Changes the child storage location for a field `D` of reference type.
   /// All other fields cannot change their storage location and always retain
   /// the storage location passed to the `RecordStorageLocation` constructor.
@@ -170,11 +164,6 @@ class RecordStorageLocation final : public StorageLocation 
{
     Children[&D] = Loc;
   }
 
-  /// Add a child storage location for a field `D`, if not already present.
-  void addChild(const ValueDecl &D, StorageLocation *Loc) {
-    Children.insert({&D, Loc});
-  }
-
   llvm::iterator_range<FieldToLoc::const_iterator> children() const {
     return {Children.begin(), Children.end()};
   }
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp 
b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 23a6de45e18b1..86a816e2e406c 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -20,17 +20,14 @@
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtVisitor.h"
-#include "clang/AST/Type.h"
 #include "clang/Analysis/FlowSensitive/ASTOps.h"
 #include "clang/Analysis/FlowSensitive/AdornedCFG.h"
 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
 #include "clang/Analysis/FlowSensitive/RecordOps.h"
-#include "clang/Analysis/FlowSensitive/StorageLocation.h"
 #include "clang/Analysis/FlowSensitive/Value.h"
 #include "clang/Basic/Builtins.h"
-#include "clang/Basic/LLVM.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "llvm/Support/Casting.h"
 #include <assert.h>
@@ -290,7 +287,7 @@ class TransferVisitor : public 
ConstStmtVisitor<TransferVisitor> {
     }
   }
 
-  void VisitCastExpr(const CastExpr *S) {
+  void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
     const Expr *SubExpr = S->getSubExpr();
     assert(SubExpr != nullptr);
 
@@ -320,60 +317,6 @@ class TransferVisitor : public 
ConstStmtVisitor<TransferVisitor> {
       break;
     }
 
-    case CK_BaseToDerived: {
-      // This is a cast of (single-layer) pointer or reference to a record 
type.
-      // We should now model the fields for the derived type.
-
-      // Get the RecordStorageLocation for the record object underneath.
-      RecordStorageLocation *Loc = nullptr;
-      if (S->getType()->isPointerType()) {
-        auto *PV = Env.get<PointerValue>(*SubExpr);
-        assert(PV != nullptr);
-        if (PV == nullptr)
-          break;
-        Loc = cast<RecordStorageLocation>(&PV->getPointeeLoc());
-      } else {
-        assert(S->getType()->isRecordType());
-        if (SubExpr->isGLValue()) {
-          Loc = Env.get<RecordStorageLocation>(*SubExpr);
-        } else {
-          Loc = &Env.getResultObjectLocation(*SubExpr);
-        }
-      }
-      if (!Loc) {
-        // Nowhere to add children or propagate from, so we're done.
-        break;
-      }
-
-      // Get the derived record type underneath the reference or pointer.
-      QualType Derived = S->getType().getNonReferenceType();
-      if (Derived->isPointerType()) {
-        Derived = Derived->getPointeeType();
-      }
-
-      // Add children to the storage location for fields (including synthetic
-      // fields) of the derived type and initialize their values.
-      for (const FieldDecl *Field :
-           Env.getDataflowAnalysisContext().getModeledFields(Derived)) {
-        assert(Field != nullptr);
-        QualType FieldType = Field->getType();
-        if (FieldType->isReferenceType()) {
-          Loc->addChild(*Field, nullptr);
-        } else {
-          Loc->addChild(*Field, &Env.createStorageLocation(FieldType));
-        }
-
-        for (const auto &Entry :
-             Env.getDataflowAnalysisContext().getSyntheticFields(Derived)) {
-          Loc->addSyntheticField(Entry.getKey(),
-                                 Env.createStorageLocation(Entry.getValue()));
-        }
-      }
-      Env.initializeFieldsWithValues(*Loc, Derived);
-
-      // Fall through to propagate SubExpr's StorageLocation to the CastExpr.
-      [[fallthrough]];
-    }
     case CK_IntegralCast:
       // FIXME: This cast creates a new integral value from the
       // subexpression. But, because we don't model integers, we don't
@@ -381,9 +324,10 @@ class TransferVisitor : public 
ConstStmtVisitor<TransferVisitor> {
       // modeling is added, then update this code to create a fresh location 
and
       // value.
     case CK_UncheckedDerivedToBase:
-    case CK_DerivedToBase:
     case CK_ConstructorConversion:
     case CK_UserDefinedConversion:
+      // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
+      // CK_ConstructorConversion, and CK_UserDefinedConversion.
     case CK_NoOp: {
       // FIXME: Consider making `Environment::getStorageLocation` skip noop
       // expressions (this and other similar expressions in the file) instead
@@ -740,6 +684,15 @@ class TransferVisitor : public 
ConstStmtVisitor<TransferVisitor> {
     propagateValue(*SubExpr, *S, Env);
   }
 
+  void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
+    if (S->getCastKind() == CK_NoOp) {
+      const Expr *SubExpr = S->getSubExpr();
+      assert(SubExpr != nullptr);
+
+      propagateValueOrStorageLocation(*SubExpr, *S, Env);
+    }
+  }
+
   void VisitConditionalOperator(const ConditionalOperator *S) {
     const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
     const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 96e759e73c154..214aaee9f97f6 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -9,25 +9,17 @@
 #include "TestingSupport.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/OperationKinds.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
-#include "clang/Analysis/FlowSensitive/NoopLattice.h"
 #include "clang/Analysis/FlowSensitive/RecordOps.h"
 #include "clang/Analysis/FlowSensitive/StorageLocation.h"
 #include "clang/Analysis/FlowSensitive/Value.h"
 #include "clang/Basic/LangStandard.h"
 #include "clang/Testing/TestAST.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Casting.h"
 #include "llvm/Testing/Support/Error.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -35,7 +27,6 @@
 #include <string>
 #include <string_view>
 #include <utility>
-#include <vector>
 
 namespace clang {
 namespace dataflow {
@@ -3550,7 +3541,7 @@ TEST(TransferTest, 
ResultObjectLocationDontVisitUnevaluatedContexts) {
   testFunction(Code, "noexceptTarget");
 }
 
-TEST(TransferTest, StaticCastNoOp) {
+TEST(TransferTest, StaticCast) {
   std::string Code = R"(
     void target(int Foo) {
       int Bar = static_cast<int>(Foo);
@@ -3570,13 +3561,6 @@ TEST(TransferTest, StaticCastNoOp) {
         const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
         ASSERT_THAT(BarDecl, NotNull());
 
-        const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(
-            "cast",
-            ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),
-                                ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_NoOp);
-
         const auto *FooVal = Env.getValue(*FooDecl);
         const auto *BarVal = Env.getValue(*BarDecl);
         EXPECT_TRUE(isa<IntegerValue>(FooVal));
@@ -3585,268 +3569,6 @@ TEST(TransferTest, StaticCastNoOp) {
       });
 }
 
-TEST(TransferTest, StaticCastBaseToDerived) {
-  std::string Code = R"cc(
-    struct Base {
-      char C;
-    };
-    struct Intermediate : public Base {
-      bool B;
-    };
-    struct Derived : public Intermediate {
-      int I;
-    };
-    Base& getBaseRef();
-    void target(Base* BPtr) {
-      Derived* DPtr = static_cast<Derived*>(BPtr);
-      DPtr->C;
-      DPtr->B;
-      DPtr->I;
-      Derived& DRef = static_cast<Derived&>(*BPtr);
-      DRef.C;
-      DRef.B;
-      DRef.I;
-      Derived& DRefFromFunc = static_cast<Derived&>(getBaseRef());
-      DRefFromFunc.C;
-      DRefFromFunc.B;
-      DRefFromFunc.I;
-      // [[p]]
-    }
-  )cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        const ValueDecl *BPtrDecl = findValueDecl(ASTCtx, "BPtr");
-        ASSERT_THAT(BPtrDecl, NotNull());
-
-        const ValueDecl *DPtrDecl = findValueDecl(ASTCtx, "DPtr");
-        ASSERT_THAT(DPtrDecl, NotNull());
-
-        const ValueDecl *DRefDecl = findValueDecl(ASTCtx, "DRef");
-        ASSERT_THAT(DRefDecl, NotNull());
-
-        const ValueDecl *DRefFromFuncDecl =
-            findValueDecl(ASTCtx, "DRefFromFunc");
-        ASSERT_THAT(DRefFromFuncDecl, NotNull());
-
-        const auto *Cast = ast_matchers::selectFirst<CXXStaticCastExpr>(
-            "cast",
-            ast_matchers::match(ast_matchers::cxxStaticCastExpr().bind("cast"),
-                                ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_BaseToDerived);
-
-        EXPECT_EQ(Env.getValue(*BPtrDecl), Env.getValue(*DPtrDecl));
-        EXPECT_EQ(&Env.get<PointerValue>(*BPtrDecl)->getPointeeLoc(),
-                  Env.getStorageLocation(*DRefDecl));
-        // For DRefFromFunc, not crashing when analyzing the field accesses is
-        // enough.
-      });
-}
-
-TEST(TransferTest, ExplicitDerivedToBaseCast) {
-  std::string Code = R"cc(
-    struct Base {};
-    struct Derived : public Base {};
-    void target(Derived D) {
-      (Base*)&D;
-      // [[p]]
-    }
-)cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
-            "cast", ast_matchers::match(
-                        ast_matchers::implicitCastExpr().bind("cast"), 
ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);
-
-        auto *AddressOf = ast_matchers::selectFirst<UnaryOperator>(
-            "addressof",
-            
ast_matchers::match(ast_matchers::unaryOperator().bind("addressof"),
-                                ASTCtx));
-        ASSERT_THAT(AddressOf, NotNull());
-        ASSERT_EQ(AddressOf->getOpcode(), UO_AddrOf);
-
-        EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*AddressOf));
-      });
-}
-
-TEST(TransferTest, ConstructorConversion) {
-  std::string Code = R"cc(
-    struct Base {};
-    struct Derived : public Base {};
-    void target(Derived D) {
-      Base B = (Base)D;
-      // [[p]]
-    }
-)cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        auto *Cast = ast_matchers::selectFirst<CStyleCastExpr>(
-            "cast", ast_matchers::match(
-                        ast_matchers::cStyleCastExpr().bind("cast"), ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_ConstructorConversion);
-
-        auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");
-        auto &BLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "B");
-        EXPECT_NE(&BLoc, &DLoc);
-      });
-}
-
-TEST(TransferTest, UserDefinedConversion) {
-  std::string Code = R"cc(
-    struct To {};
-    struct From {
-        operator To();
-    };
-    void target(From F) {
-        To T = (To)F;
-        // [[p]]
-    }
-)cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
-            "cast", ast_matchers::match(
-                        ast_matchers::implicitCastExpr().bind("cast"), 
ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_UserDefinedConversion);
-
-        auto &FLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "F");
-        auto &TLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "T");
-        EXPECT_NE(&TLoc, &FLoc);
-      });
-}
-
-TEST(TransferTest, ImplicitUncheckedDerivedToBaseCast) {
-  std::string Code = R"cc(
-    struct Base {
-      void method();
-    };
-    struct Derived : public Base {};
-    void target(Derived D) {
-      D.method();
-      // [[p]]
-    }
-)cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
-            "cast", ast_matchers::match(
-                        ast_matchers::implicitCastExpr().bind("cast"), 
ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_UncheckedDerivedToBase);
-
-        auto &DLoc = getLocForDecl<StorageLocation>(ASTCtx, Env, "D");
-        EXPECT_EQ(Env.getStorageLocation(*Cast), &DLoc);
-      });
-}
-
-TEST(TransferTest, ImplicitDerivedToBaseCast) {
-  std::string Code = R"cc(
-    struct Base {};
-    struct Derived : public Base {};
-    void target() {
-      Base* B = new Derived();
-      // [[p]]
-    }
-)cc";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-
-        auto *Cast = ast_matchers::selectFirst<ImplicitCastExpr>(
-            "cast", ast_matchers::match(
-                        ast_matchers::implicitCastExpr().bind("cast"), 
ASTCtx));
-        ASSERT_THAT(Cast, NotNull());
-        ASSERT_EQ(Cast->getCastKind(), CK_DerivedToBase);
-
-        auto *New = ast_matchers::selectFirst<CXXNewExpr>(
-            "new", ast_matchers::match(ast_matchers::cxxNewExpr().bind("new"),
-                                       ASTCtx));
-        ASSERT_THAT(New, NotNull());
-
-        EXPECT_EQ(Env.getValue(*Cast), Env.getValue(*New));
-      });
-}
-
-TEST(TransferTest, ReinterpretCast) {
-  std::string Code = R"cc(
-    struct S {
-        int I;
-    };
-
-    void target(unsigned char* Bytes) {
-        S& SRef = reinterpret_cast<S&>(Bytes);
-        SRef.I;
-        S* SPtr = reinterpret_cast<S*>(Bytes);
-        SPtr->I;
-        // [[p]]
-    }
-  )cc";
-  runDataflow(Code, [](const 
llvm::StringMap<DataflowAnalysisState<NoopLattice>>
-                           &Results,
-                       ASTContext &ASTCtx) {
-    ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
-    const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-    const ValueDecl *I = findValueDecl(ASTCtx, "I");
-    ASSERT_THAT(I, NotNull());
-
-    // No particular knowledge of I's value is modeled, but for both casts,
-    // the fields of S are modeled.
-
-    {
-      auto &Loc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "SRef");
-      std::vector<const ValueDecl *> Children;
-      for (const auto &Entry : Loc.children()) {
-        Children.push_back(Entry.getFirst());
-      }
-
-      EXPECT_THAT(Children, UnorderedElementsAre(I));
-    }
-
-    {
-      auto &Loc = cast<RecordStorageLocation>(
-          getValueForDecl<PointerValue>(ASTCtx, Env, "SPtr").getPointeeLoc());
-      std::vector<const ValueDecl *> Children;
-      for (const auto &Entry : Loc.children()) {
-        Children.push_back(Entry.getFirst());
-      }
-
-      EXPECT_THAT(Children, UnorderedElementsAre(I));
-    }
-  });
-}
-
 TEST(TransferTest, IntegralCast) {
   std::string Code = R"(
     void target(int Foo) {

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to