Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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 llvm-svn: 330095
- Loading branch information
1 parent
6be1f01
commit 525d412
Showing
3 changed files
with
103 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |