mirror of https://github.com/microsoft/clang.git
[analyzer] Do not invalidate the `this` pointer.
Summary: `this` pointer is not an l-value, although we have modeled `CXXThisRegion` for `this` pointer, we can only bind it once, which is when we start to inline method. And this patch fixes https://bugs.llvm.org/show_bug.cgi?id=35506. In addition, I didn't find any other cases other than loop-widen that could invalidate `this` pointer. Reviewers: NoQ, george.karpenkov, a.sidorin, seaneveson, szepet Reviewed By: NoQ Subscribers: xazax.hun, rnkovacs, cfe-commits, MTC Differential Revision: https://reviews.llvm.org/D45491 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@330095 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ea7b75a952
commit
ac7fbab9b4
|
@ -59,6 +59,18 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
|
|||
ITraits.setTrait(Region,
|
||||
RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
|
||||
}
|
||||
|
||||
// 'this' pointer is not an lvalue, we should not invalidate it. If the loop
|
||||
// is located in a method, constructor or destructor, the value of 'this'
|
||||
// pointer shoule remain unchanged.
|
||||
if (const CXXMethodDecl *CXXMD = dyn_cast<CXXMethodDecl>(STC->getDecl())) {
|
||||
const CXXThisRegion *ThisR = MRMgr.getCXXThisRegion(
|
||||
CXXMD->getThisType(STC->getAnalysisDeclContext()->getASTContext()),
|
||||
STC);
|
||||
ITraits.setTrait(ThisR,
|
||||
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
|
||||
}
|
||||
|
||||
return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt),
|
||||
BlockCount, LCtx, true, nullptr, nullptr,
|
||||
&ITraits);
|
||||
|
|
|
@ -2050,6 +2050,9 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
|
|||
R = GetElementZeroRegion(SR, T);
|
||||
}
|
||||
|
||||
assert((!isa<CXXThisRegion>(R) || !B.lookup(R)) &&
|
||||
"'this' pointer is not an l-value and is not assignable");
|
||||
|
||||
// Clear out bindings that may overlap with this binding.
|
||||
RegionBindingsRef NewB = removeSubRegionBindings(B, cast<SubRegion>(R));
|
||||
return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config widen-loops=true -analyzer-disable-retry-exhausted -verify %s
|
||||
|
||||
void clang_analyzer_eval(bool);
|
||||
void clang_analyzer_dump(int);
|
||||
|
||||
// 'this' pointer is not an lvalue, we should not invalidate it.
|
||||
namespace this_pointer_after_loop_widen {
|
||||
class A {
|
||||
public:
|
||||
A() {
|
||||
int count = 10;
|
||||
do {
|
||||
} while (count--);
|
||||
}
|
||||
};
|
||||
|
||||
void goo(A a);
|
||||
void test_temporary_object() {
|
||||
goo(A()); // no-crash
|
||||
}
|
||||
|
||||
struct B {
|
||||
int mem;
|
||||
B() : mem(0) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
mem = 0;
|
||||
}
|
||||
};
|
||||
|
||||
void test_ctor() {
|
||||
B b;
|
||||
clang_analyzer_eval(b.mem == 0); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
struct C {
|
||||
int mem;
|
||||
C() : mem(0) {}
|
||||
void set() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
mem = 10;
|
||||
}
|
||||
};
|
||||
|
||||
void test_method() {
|
||||
C c;
|
||||
clang_analyzer_eval(c.mem == 0); // expected-warning{{TRUE}}
|
||||
c.set();
|
||||
clang_analyzer_eval(c.mem == 10); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
struct D {
|
||||
int mem;
|
||||
D() : mem(0) {}
|
||||
void set() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
mem = 10;
|
||||
}
|
||||
};
|
||||
|
||||
void test_new() {
|
||||
D *d = new D;
|
||||
clang_analyzer_eval(d->mem == 0); // expected-warning{{TRUE}}
|
||||
d->set();
|
||||
clang_analyzer_eval(d->mem == 10); // expected-warning{{TRUE}}
|
||||
}
|
||||
|
||||
struct E {
|
||||
int mem;
|
||||
E() : mem(0) {}
|
||||
void set() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
}
|
||||
setAux();
|
||||
}
|
||||
void setAux() {
|
||||
this->mem = 10;
|
||||
}
|
||||
};
|
||||
|
||||
void test_chained_method_call() {
|
||||
E e;
|
||||
e.set();
|
||||
clang_analyzer_eval(e.mem == 10); // expected-warning{{TRUE}}
|
||||
}
|
||||
} // namespace this_pointer_after_loop_widen
|
Loading…
Reference in New Issue