forked from OSchip/llvm-project
[analyzer] Add modeling for unique_ptr move constructor
Summary: Add support for handling move contructor of std::unique_ptr. Reviewers: NoQ, Szelethus, vsavchenko, xazax.hun Reviewed By: NoQ Subscribers: martong, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D86373
This commit is contained in:
parent
db464a2753
commit
1b743a9efa
|
@ -58,6 +58,10 @@ private:
|
|||
void handleSwap(const CallEvent &Call, CheckerContext &C) const;
|
||||
void handleGet(const CallEvent &Call, CheckerContext &C) const;
|
||||
bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;
|
||||
bool handleMoveCtr(const CallEvent &Call, CheckerContext &C,
|
||||
const MemRegion *ThisRegion) const;
|
||||
bool updateMovedSmartPointers(CheckerContext &C, const MemRegion *ThisRegion,
|
||||
const MemRegion *OtherSmartPtrRegion) const;
|
||||
|
||||
using SmartPtrMethodHandlerFn =
|
||||
void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
|
||||
|
@ -160,13 +164,16 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
|
|||
return false;
|
||||
|
||||
if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
|
||||
if (CC->getDecl()->isCopyOrMoveConstructor())
|
||||
if (CC->getDecl()->isCopyConstructor())
|
||||
return false;
|
||||
|
||||
const MemRegion *ThisRegion = CC->getCXXThisVal().getAsRegion();
|
||||
if (!ThisRegion)
|
||||
return false;
|
||||
|
||||
if (CC->getDecl()->isMoveConstructor())
|
||||
return handleMoveCtr(Call, C, ThisRegion);
|
||||
|
||||
if (Call.getNumArgs() == 0) {
|
||||
auto NullVal = C.getSValBuilder().makeNull();
|
||||
State = State->set<TrackedRegionMap>(ThisRegion, NullVal);
|
||||
|
@ -410,6 +417,22 @@ bool SmartPtrModeling::handleAssignOp(const CallEvent &Call,
|
|||
return true;
|
||||
}
|
||||
|
||||
return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion);
|
||||
}
|
||||
|
||||
bool SmartPtrModeling::handleMoveCtr(const CallEvent &Call, CheckerContext &C,
|
||||
const MemRegion *ThisRegion) const {
|
||||
const auto *OtherSmartPtrRegion = Call.getArgSVal(0).getAsRegion();
|
||||
if (!OtherSmartPtrRegion)
|
||||
return false;
|
||||
|
||||
return updateMovedSmartPointers(C, ThisRegion, OtherSmartPtrRegion);
|
||||
}
|
||||
|
||||
bool SmartPtrModeling::updateMovedSmartPointers(
|
||||
CheckerContext &C, const MemRegion *ThisRegion,
|
||||
const MemRegion *OtherSmartPtrRegion) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
const auto *OtherInnerPtr = State->get<TrackedRegionMap>(OtherSmartPtrRegion);
|
||||
if (OtherInnerPtr) {
|
||||
State = State->set<TrackedRegionMap>(ThisRegion, *OtherInnerPtr);
|
||||
|
@ -430,7 +453,7 @@ bool SmartPtrModeling::handleAssignOp(const CallEvent &Call,
|
|||
ThisRegion->printPretty(OS);
|
||||
}
|
||||
if (BR.isInteresting(ThisRegion) && IsArgValNull) {
|
||||
OS << "Null pointer value move-assigned to ";
|
||||
OS << "A null pointer value is moved to ";
|
||||
ThisRegion->printPretty(OS);
|
||||
BR.markInteresting(OtherSmartPtrRegion);
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ void derefOnNullPtrGotMovedFromValidPtr() {
|
|||
std::unique_ptr<A> P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
|
||||
// FIXME: above note should go away once we fix marking region not interested.
|
||||
std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
|
||||
P = std::move(PToMove); // expected-note {{Null pointer value move-assigned to 'P'}}
|
||||
P = std::move(PToMove); // expected-note {{A null pointer value is moved to 'P'}}
|
||||
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1 {{Dereference of null smart pointer 'P'}}
|
||||
}
|
||||
|
@ -170,3 +170,32 @@ void derefOnAssignedZeroToNullSmartPtr() {
|
|||
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1 {{Dereference of null smart pointer 'P'}}
|
||||
}
|
||||
|
||||
void derefMoveConstructedWithNullPtr() {
|
||||
std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
|
||||
std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}}
|
||||
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1{{Dereference of null smart pointer 'P'}}
|
||||
}
|
||||
|
||||
void derefValidPtrMovedToConstruct() {
|
||||
std::unique_ptr<A> PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
|
||||
// FIXME: above note should go away once we fix marking region not interested.
|
||||
std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
|
||||
}
|
||||
|
||||
void derefNullPtrMovedToConstruct() {
|
||||
std::unique_ptr<A> PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
|
||||
// FIXME: above note should go away once we fix marking region not interested.
|
||||
std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
|
||||
}
|
||||
|
||||
void derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove) {
|
||||
std::unique_ptr<A> P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after; previous value moved to 'P'}}
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
// expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ void derefAfterMove(std::unique_ptr<int> P) {
|
|||
if (P)
|
||||
clang_analyzer_warnIfReached(); // no-warning
|
||||
// TODO: Report a null dereference (instead).
|
||||
*P.get() = 1; // expected-warning {{Method called on moved-from object 'P'}}
|
||||
*P.get() = 1; // expected-warning {{Method called on moved-from object 'P' [cplusplus.Move]}}
|
||||
// expected-warning@-1 {{Dereference of null pointer [core.NullDereference]}}
|
||||
}
|
||||
|
||||
// Don't crash when attempting to model a call with unknown callee.
|
||||
|
@ -333,3 +334,44 @@ void drefOnAssignedNullFromMethodPtrValidSmartPtr() {
|
|||
P = returnRValRefOfUniquePtr();
|
||||
P->foo(); // No warning.
|
||||
}
|
||||
|
||||
void derefMoveConstructedWithValidPtr() {
|
||||
std::unique_ptr<A> PToMove(new A());
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
P->foo(); // No warning.
|
||||
}
|
||||
|
||||
void derefMoveConstructedWithNullPtr() {
|
||||
std::unique_ptr<A> PToMove;
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
|
||||
}
|
||||
|
||||
void derefMoveConstructedWithUnknownPtr(std::unique_ptr<A> PToMove) {
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
P->foo(); // No warning.
|
||||
}
|
||||
|
||||
void derefValidPtrMovedToConstruct() {
|
||||
std::unique_ptr<A> PToMove(new A());
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
}
|
||||
|
||||
void derefNullPtrMovedToConstruct() {
|
||||
std::unique_ptr<A> PToMove;
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
}
|
||||
|
||||
void derefUnknownPtrMovedToConstruct(std::unique_ptr<A> PToMove) {
|
||||
std::unique_ptr<A> P(std::move(PToMove));
|
||||
PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
|
||||
}
|
||||
|
||||
std::unique_ptr<A> &&functionReturnsRValueRef();
|
||||
|
||||
void derefMoveConstructedWithRValueRefReturn() {
|
||||
std::unique_ptr<A> P(functionReturnsRValueRef());
|
||||
P->foo(); // No warning.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue