-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][dataflow] Copy records relative to the destination type for c… #160557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…opy/move assignments. This mirrors the handling of copy/move constructors.
@llvm/pr-subscribers-clang Author: Samira Bakon (bazuzi) Changes…opy/move assignments. This mirrors the handling of copy/move constructors. Also fix a couple capitalizations of variables in an adjacent and related test. Full diff: https://github.com/llvm/llvm-project/pull/160557.diff 2 Files Affected:
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 60371d9498c25..f59bd6555aff5 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -657,7 +657,12 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
if (LocSrc == nullptr || LocDst == nullptr)
return;
- copyRecord(*LocSrc, *LocDst, Env);
+ // If the destination object here is of a derived class, `Arg0` may be a
+ // cast of that object to a base class, and the destination object may be
+ // of a sibling derived class. To handle these cases, ensure we are
+ // copying only the fields for `Arg0`'s type, not the type of the
+ // underlying `RecordStorageLocation`.
+ copyRecord(*LocSrc, *LocDst, Env, Arg0->getType());
// The assignment operator can have an arbitrary return type. We model the
// return value only if the return type is the same as or a base class of
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index d97e2b0c2425a..cbd55966a3d88 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1554,8 +1554,8 @@ TEST(TransferTest, BaseClassInitializerFromSiblingDerivedInstance) {
struct DerivedTwo : public Base {
int DerivedTwoField;
- DerivedTwo(const DerivedOne& d1)
- : Base(d1), DerivedTwoField(d1.DerivedOneField) {
+ DerivedTwo(const DerivedOne& D1)
+ : Base(D1), DerivedTwoField(D1.DerivedOneField) {
(void)BaseField;
}
};
@@ -1565,7 +1565,34 @@ TEST(TransferTest, BaseClassInitializerFromSiblingDerivedInstance) {
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
// Regression test only; we used to crash when transferring the base
- // class initializer from the DerivedToBase-cast `d1`.
+ // class initializer from the DerivedToBase-cast `D1`.
+ },
+ LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");
+}
+
+TEST(TransferTest, CopyAssignmentToDerivedToBase) {
+ std::string Code = R"cc(
+ struct Base {};
+
+struct DerivedOne : public Base {
+ int DerivedOneField;
+};
+
+struct DerivedTwo : public Base {
+ int DerivedTwoField;
+
+ explicit DerivedTwo(const DerivedOne& D1) {
+ *static_cast<Base*>(this) = D1;
+ }
+};
+)cc";
+
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ // Regression test only; we used to crash when transferring the copy
+ // assignment operator in the constructor for `DerivedTwo`.
},
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");
}
|
@llvm/pr-subscribers-clang-analysis Author: Samira Bakon (bazuzi) Changes…opy/move assignments. This mirrors the handling of copy/move constructors. Also fix a couple capitalizations of variables in an adjacent and related test. Full diff: https://github.com/llvm/llvm-project/pull/160557.diff 2 Files Affected:
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 60371d9498c25..f59bd6555aff5 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -657,7 +657,12 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
if (LocSrc == nullptr || LocDst == nullptr)
return;
- copyRecord(*LocSrc, *LocDst, Env);
+ // If the destination object here is of a derived class, `Arg0` may be a
+ // cast of that object to a base class, and the destination object may be
+ // of a sibling derived class. To handle these cases, ensure we are
+ // copying only the fields for `Arg0`'s type, not the type of the
+ // underlying `RecordStorageLocation`.
+ copyRecord(*LocSrc, *LocDst, Env, Arg0->getType());
// The assignment operator can have an arbitrary return type. We model the
// return value only if the return type is the same as or a base class of
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index d97e2b0c2425a..cbd55966a3d88 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1554,8 +1554,8 @@ TEST(TransferTest, BaseClassInitializerFromSiblingDerivedInstance) {
struct DerivedTwo : public Base {
int DerivedTwoField;
- DerivedTwo(const DerivedOne& d1)
- : Base(d1), DerivedTwoField(d1.DerivedOneField) {
+ DerivedTwo(const DerivedOne& D1)
+ : Base(D1), DerivedTwoField(D1.DerivedOneField) {
(void)BaseField;
}
};
@@ -1565,7 +1565,34 @@ TEST(TransferTest, BaseClassInitializerFromSiblingDerivedInstance) {
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
ASTContext &ASTCtx) {
// Regression test only; we used to crash when transferring the base
- // class initializer from the DerivedToBase-cast `d1`.
+ // class initializer from the DerivedToBase-cast `D1`.
+ },
+ LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");
+}
+
+TEST(TransferTest, CopyAssignmentToDerivedToBase) {
+ std::string Code = R"cc(
+ struct Base {};
+
+struct DerivedOne : public Base {
+ int DerivedOneField;
+};
+
+struct DerivedTwo : public Base {
+ int DerivedTwoField;
+
+ explicit DerivedTwo(const DerivedOne& D1) {
+ *static_cast<Base*>(this) = D1;
+ }
+};
+)cc";
+
+ runDataflow(
+ Code,
+ [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+ ASTContext &ASTCtx) {
+ // Regression test only; we used to crash when transferring the copy
+ // assignment operator in the constructor for `DerivedTwo`.
},
LangStandard::lang_cxx17, /*ApplyBuiltinTransfer=*/true, "DerivedTwo");
}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
And the other copyRecord further down "copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env)" is safe because there is a stricter check "DstDecl->isDerivedFrom(ReturnDecl)"?
Yes, the types there are already more restricted than the CompatibleTypes check inside of copyRecord. There may be some complex inheritance patterns that are compatible but not modeled because that check is more strict than necessary, but it is sufficient to make the copyRecord call safe, as far as I can tell. Unrelated, I noticed a mistake in the comment before the copyRecord call I modified. I'll correct "destination object may be of a sibling derived class" to "source object may be of a sibling derived class" before merging. |
llvm#160557) …opy/move assignments. This mirrors the handling of copy/move constructors. Also fix a couple capitalizations of variables in an adjacent and related test.
…opy/move assignments.
This mirrors the handling of copy/move constructors.
Also fix a couple capitalizations of variables in an adjacent and related test.