[clang] [clang][dataflow] Ignore assignment where base class's operator is used (PR #66364)

Kinuko Yasuda via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 05:25:16 PDT 2023


https://github.com/kinu created https://github.com/llvm/llvm-project/pull/66364:

In C++ it seems it is legit to use base class's operator (e.g. `using Base::operator=`) to perform copy if the base class is the common ancestor of the source and destination object. In such a case we shouldn't try to access fields beyond that of the base class, however such a case seems to be very rare (typical code would implement a copy constructor instead), and could add complexities, so in this patch we simply bail if the method operator's parent class is different from the type of the destination object that this framework recognizes.

>From 0dd55ed61a14b01ea0c62c2a4ca2c50317587cb3 Mon Sep 17 00:00:00 2001
From: Kinuko Yasuda <kinuko at chromium.org>
Date: Thu, 14 Sep 2023 12:20:27 +0000
Subject: [PATCH] [clang][dataflow] Ignore weird assignment case where base
 class's operator is used

In C++ it seems it is legit to use base class's operator (e.g. `using
Base::operator=`) to perform copy if the base class is the common
ancestor of the source and destination object. In such a case we
shouldn't try to access fields beyond that of the base class, however
such a case seems to be very rare (typical code would implement a copy
constructor instead), and could add complexities, so in this patch we
simply bail if the method operator's parent class is different from the
type of the destination object that this framework recognizes.
---
 clang/lib/Analysis/FlowSensitive/Transfer.cpp |  7 ++++++
 .../Analysis/FlowSensitive/TransferTest.cpp   | 24 +++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index b46c947c691b9b9..b510114a7a355eb 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -531,6 +531,13 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
       auto *LocDst =
           cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg0));
 
+      // The assignment operators are different from the type of the destination
+      // in this model (i.e. in one of their base classes). This must be very rare
+      // and we just bail.
+      if (Method->getThisObjectType().getCanonicalType().getUnqualifiedType() !=
+          LocDst->getType().getCanonicalType().getUnqualifiedType())
+        return;
+
       if (LocSrc != nullptr && LocDst != nullptr) {
         copyRecord(*LocSrc, *LocDst, Env);
         Env.setStorageLocation(*S, *LocDst);
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 0abd171f1d0b7cb..e0e3b71503d2176 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -2124,6 +2124,30 @@ TEST(TransferTest, AssignmentOperator) {
       });
 }
 
+TEST(TransferTest, AssignmentOperatorFromBase) {
+  // This is a crash repro. We don't model the copy this case, so no
+  // expectations on the copied field of the base class are checked.
+  std::string Code = R"(
+    struct Base {
+      int base;
+    };
+    struct Derived : public Base {
+      using Base::operator=;
+      int derived;
+    };
+    void target(Base B, Derived D) {
+      D.base = 1;
+      D.derived = 1;
+      D = B;
+      // [[p]]
+    }
+  )";
+  runDataflow(
+      Code,
+      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+         ASTContext &ASTCtx) {});
+}
+
 TEST(TransferTest, AssignmentOperatorFromCallResult) {
   std::string Code = R"(
     struct A {};



More information about the cfe-commits mailing list