Skip to content

Commit 4449e7f

Browse files
committed
[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
1 parent 1e3dbd7 commit 4449e7f

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,30 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
4242
const CallEvent &Call) {
4343
SVal ThisVal;
4444
bool AlwaysReturnsLValue;
45+
const CXXRecordDecl *ThisRD = nullptr;
4546
if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
4647
assert(Ctor->getDecl()->isTrivial());
4748
assert(Ctor->getDecl()->isCopyOrMoveConstructor());
4849
ThisVal = Ctor->getCXXThisVal();
50+
ThisRD = Ctor->getDecl()->getParent();
4951
AlwaysReturnsLValue = false;
5052
} else {
5153
assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
5254
assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
5355
OO_Equal);
5456
ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
57+
ThisRD = cast<CXXMethodDecl>(Call.getDecl())->getParent();
5558
AlwaysReturnsLValue = true;
5659
}
5760

61+
assert(ThisRD);
62+
if (ThisRD->isEmpty()) {
63+
// Do nothing for empty classes. Otherwise it'd retrieve an UnknownVal
64+
// and bind it and RegionStore would think that the actual value
65+
// in this region at this offset is unknown.
66+
return;
67+
}
68+
5869
const LocationContext *LCtx = Pred->getLocationContext();
5970

6071
ExplodedNodeSet Dst;

clang/test/Analysis/ctor.mm

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,3 +729,23 @@ void testSCtorNoCrash() {
729729
S s;
730730
}
731731
}
732+
733+
namespace EmptyBaseAssign {
734+
struct B1 {};
735+
struct B2 { int x; };
736+
struct D: public B1, public B2 {
737+
const D &operator=(const D &d) {
738+
*((B2 *)this) = d;
739+
*((B1 *)this) = d;
740+
return *this;
741+
}
742+
};
743+
744+
void test() {
745+
D d1;
746+
d1.x = 1;
747+
D d2;
748+
d2 = d1;
749+
clang_analyzer_eval(d2.x == 1); // expected-warning{{TRUE}}
750+
}
751+
}

0 commit comments

Comments
 (0)