summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 21:10:08 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-02-27 21:10:08 +0000
commit4449e7f008cbb6da6dbe8a93fdf4cfd89851f7b1 (patch)
treed58380501c5ce67ea2ee090718898425ed3faa07
parent1e3dbd7a17b3cfbda5a0b83812020122a82a9e0e (diff)
downloadbcm5719-llvm-4449e7f008cbb6da6dbe8a93fdf4cfd89851f7b1.tar.gz
bcm5719-llvm-4449e7f008cbb6da6dbe8a93fdf4cfd89851f7b1.zip
[analyzer] Fix trivial copy for empty objects.
The SVal for any empty C++ object is an UnknownVal. Because RegionStore does not have binding extents, binding an empty object to an UnknownVal may potentially overwrite existing bindings at the same offset. Therefore, when performing a trivial copy of an empty object, don't try to take the value of the object and bind it to the copy. Doing nothing is accurate enough, and it doesn't screw any existing bindings. Differential Revision: https://reviews.llvm.org/D43714 llvm-svn: 326247
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp11
-rw-r--r--clang/test/Analysis/ctor.mm20
2 files changed, 31 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 6502af74a33..f4aa56f2750 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -42,19 +42,30 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &Call) {
SVal ThisVal;
bool AlwaysReturnsLValue;
+ const CXXRecordDecl *ThisRD = nullptr;
if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
assert(Ctor->getDecl()->isTrivial());
assert(Ctor->getDecl()->isCopyOrMoveConstructor());
ThisVal = Ctor->getCXXThisVal();
+ ThisRD = Ctor->getDecl()->getParent();
AlwaysReturnsLValue = false;
} else {
assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
OO_Equal);
ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
+ ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
AlwaysReturnsLValue = true;
}
+ assert(ThisRD);
+ if (ThisRD->isEmpty()) {
+ // Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal
+ // and bind it and RegionStore would think that the actual value
+ // in this region at this offset is unknown.
+ return;
+ }
+
const LocationContext *LCtx = Pred->getLocationContext();
ExplodedNodeSet Dst;
diff --git a/clang/test/Analysis/ctor.mm b/clang/test/Analysis/ctor.mm
index 5ef2beea496..cfae8ed4ed0 100644
--- a/clang/test/Analysis/ctor.mm
+++ b/clang/test/Analysis/ctor.mm
@@ -729,3 +729,23 @@ namespace NoCrashOnEmptyBaseOptimization {
S s;
}
}
+
+namespace EmptyBaseAssign {
+struct B1 {};
+struct B2 { int x; };
+struct D: public B1, public B2 {
+const D &operator=(const D &d) {
+ *((B2 *)this) = d;
+ *((B1 *)this) = d;
+ return *this;
+}
+};
+
+void test() {
+ D d1;
+ d1.x = 1;
+ D d2;
+ d2 = d1;
+ clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}}
+}
+}
OpenPOWER on IntegriCloud