mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[analyzer] Bind return value for assigment and copies of trivial empty classes
We now properly bind return value of the trivial copy constructor and assignments of the empty objects. Such operations do not perform any loads from the source, however they preserve identity of the assigned object: ``` Empty e; auto& x = (e = Empty()); clang_analyzer_dump(x); // &e, was Unknown ``` Reviewed By: xazax.hun Differential Revision: https://reviews.llvm.org/D155442
This commit is contained in:
parent
ef7d53731b
commit
61760bb98c
@ -61,30 +61,30 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
|
||||
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();
|
||||
const Expr *CallExpr = Call.getOriginExpr();
|
||||
|
||||
ExplodedNodeSet Dst;
|
||||
Bldr.takeNodes(Pred);
|
||||
|
||||
SVal V = Call.getArgSVal(0);
|
||||
assert(ThisRD);
|
||||
if (!ThisRD->isEmpty()) {
|
||||
// Load the source value only for non-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.
|
||||
SVal V = Call.getArgSVal(0);
|
||||
|
||||
// If the value being copied is not unknown, load from its location to get
|
||||
// an aggregate rvalue.
|
||||
if (std::optional<Loc> L = V.getAs<Loc>())
|
||||
V = Pred->getState()->getSVal(*L);
|
||||
else
|
||||
assert(V.isUnknownOrUndef());
|
||||
|
||||
const Expr *CallExpr = Call.getOriginExpr();
|
||||
evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
|
||||
// If the value being copied is not unknown, load from its location to get
|
||||
// an aggregate rvalue.
|
||||
if (std::optional<Loc> L = V.getAs<Loc>())
|
||||
V = Pred->getState()->getSVal(*L);
|
||||
else
|
||||
assert(V.isUnknownOrUndef());
|
||||
evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
|
||||
} else {
|
||||
Dst.Add(Pred);
|
||||
}
|
||||
|
||||
PostStmt PS(CallExpr, LCtx);
|
||||
for (ExplodedNode *N : Dst) {
|
||||
|
34
clang/test/Analysis/ctor-trivial-copy.cpp
Normal file
34
clang/test/Analysis/ctor-trivial-copy.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
|
||||
|
||||
|
||||
template<typename T>
|
||||
void clang_analyzer_dump(T&);
|
||||
|
||||
struct aggr {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct empty {
|
||||
};
|
||||
|
||||
void test_copy_return() {
|
||||
aggr s1 = {1, 2};
|
||||
aggr const& cr1 = aggr(s1);
|
||||
clang_analyzer_dump(cr1); // expected-warning-re {{&lifetime_extended_object{aggr, cr1, S{{[0-9]+}}} }}
|
||||
|
||||
empty s2;
|
||||
empty const& cr2 = empty{s2};
|
||||
clang_analyzer_dump(cr2); // expected-warning-re {{&lifetime_extended_object{empty, cr2, S{{[0-9]+}}} }}
|
||||
}
|
||||
|
||||
void test_assign_return() {
|
||||
aggr s1 = {1, 2};
|
||||
aggr d1;
|
||||
clang_analyzer_dump(d1 = s1); // expected-warning {{&d1 }}
|
||||
|
||||
empty s2;
|
||||
empty d2;
|
||||
clang_analyzer_dump(d2 = s2); // expected-warning {{&d2 }} was Unknown
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user