r349190 - [analyzer] MoveChecker: Improve invalidation policies.
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 14 12:47:59 PST 2018
Author: dergachev
Date: Fri Dec 14 12:47:58 2018
New Revision: 349190
URL: http://llvm.org/viewvc/llvm-project?rev=349190&view=rev
Log:
[analyzer] MoveChecker: Improve invalidation policies.
If a moved-from object is passed into a conservatively evaluated function
by pointer or by reference, we assume that the function may reset its state.
Make sure it doesn't apply to const pointers and const references. Add a test
that demonstrates that it does apply to rvalue references.
Additionally, make sure that the object is invalidated when its contents change
for reasons other than invalidation caused by evaluating a call conservatively.
In particular, when the object's fields are manipulated directly, we should
assume that some sort of reset may be happening.
Differential Revision: https://reviews.llvm.org/D55289
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
cfe/trunk/test/Analysis/use-after-move.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp?rev=349190&r1=349189&r2=349190&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp Fri Dec 14 12:47:58 2018
@@ -53,8 +53,8 @@ public:
ProgramStateRef
checkRegionChanges(ProgramStateRef State,
const InvalidatedSymbols *Invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
+ ArrayRef<const MemRegion *> RequestedRegions,
+ ArrayRef<const MemRegion *> InvalidatedRegions,
const LocationContext *LCtx, const CallEvent *Call) const;
void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const override;
@@ -525,19 +525,35 @@ void MoveChecker::checkDeadSymbols(Symbo
ProgramStateRef MoveChecker::checkRegionChanges(
ProgramStateRef State, const InvalidatedSymbols *Invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
- const CallEvent *Call) const {
- // In case of an InstanceCall don't remove the ThisRegion from the GDM since
- // it is handled in checkPreCall and checkPostCall.
- const MemRegion *ThisRegion = nullptr;
- if (const auto *IC = dyn_cast_or_null<CXXInstanceCall>(Call)) {
- ThisRegion = IC->getCXXThisVal().getAsRegion();
- }
-
- for (const auto *Region : ExplicitRegions) {
- if (ThisRegion != Region)
- State = removeFromState(State, Region);
+ ArrayRef<const MemRegion *> RequestedRegions,
+ ArrayRef<const MemRegion *> InvalidatedRegions,
+ const LocationContext *LCtx, const CallEvent *Call) const {
+ if (Call) {
+ // Relax invalidation upon function calls: only invalidate parameters
+ // that are passed directly via non-const pointers or non-const references
+ // or rvalue references.
+ // In case of an InstanceCall don't invalidate the this-region since
+ // it is fully handled in checkPreCall and checkPostCall.
+ const MemRegion *ThisRegion = nullptr;
+ if (const auto *IC = dyn_cast<CXXInstanceCall>(Call))
+ ThisRegion = IC->getCXXThisVal().getAsRegion();
+
+ // Requested ("explicit") regions are the regions passed into the call
+ // directly, but not all of them end up being invalidated.
+ // But when they do, they appear in the InvalidatedRegions array as well.
+ for (const auto *Region : RequestedRegions) {
+ if (ThisRegion != Region) {
+ if (llvm::find(InvalidatedRegions, Region) !=
+ std::end(InvalidatedRegions)) {
+ State = removeFromState(State, Region);
+ }
+ }
+ }
+ } else {
+ // For invalidations that aren't caused by calls, assume nothing. In
+ // particular, direct write into an object's field invalidates the status.
+ for (const auto *Region : InvalidatedRegions)
+ State = removeFromState(State, Region->getBaseRegion());
}
return State;
Modified: cfe/trunk/test/Analysis/use-after-move.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/use-after-move.cpp?rev=349190&r1=349189&r2=349190&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/use-after-move.cpp (original)
+++ cfe/trunk/test/Analysis/use-after-move.cpp Fri Dec 14 12:47:58 2018
@@ -116,6 +116,19 @@ public:
bool empty() const;
bool isEmpty() const;
operator bool() const;
+
+ void testUpdateField() {
+ A a;
+ A b = std::move(a);
+ a.i = 1;
+ a.foo(); // no-warning
+ }
+ void testUpdateFieldDouble() {
+ A a;
+ A b = std::move(a);
+ a.d = 1.0;
+ a.foo(); // no-warning
+ }
};
int bignum();
@@ -594,24 +607,50 @@ void paramEvaluateOrderTest() {
foobar(a.getI(), std::move(a)); //no-warning
}
-void not_known(A &a);
-void not_known(A *a);
+void not_known_pass_by_ref(A &a);
+void not_known_pass_by_const_ref(const A &a);
+void not_known_pass_by_rvalue_ref(A &&a);
+void not_known_pass_by_ptr(A *a);
+void not_known_pass_by_const_ptr(const A *a);
void regionAndPointerEscapeTest() {
{
A a;
A b;
b = std::move(a);
- not_known(a);
- a.foo(); //no-warning
+ not_known_pass_by_ref(a);
+ a.foo(); // no-warning
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note{{Object 'a' is moved}}
+ not_known_pass_by_const_ref(a);
+ a.foo(); // expected-warning{{Method called on moved-from object 'a'}}
+ // expected-note at -1{{Method called on moved-from object 'a'}}
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ not_known_pass_by_rvalue_ref(std::move(a));
+ a.foo(); // no-warning
}
{
A a;
A b;
b = std::move(a);
- not_known(&a);
+ not_known_pass_by_ptr(&a);
a.foo(); // no-warning
}
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note{{Object 'a' is moved}}
+ not_known_pass_by_const_ptr(&a);
+ a.foo(); // expected-warning{{Method called on moved-from object 'a'}}
+ // expected-note at -1{{Method called on moved-from object 'a'}}
+ }
}
// A declaration statement containing multiple declarations sequences the
More information about the cfe-commits
mailing list