[clang] 1b743a9 - [analyzer] Add modeling for unique_ptr move constructor
Nithin Vadukkumchery Rajendrakumar via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 31 05:36:23 PDT 2020
Author: Nithin Vadukkumchery Rajendrakumar
Date: 2020-08-31T14:36:11+02:00
New Revision: 1b743a9efa0884ed3a48ebea97b6ef6cb7d73164
URL: https://github.com/llvm/llvm-project/commit/1b743a9efa0884ed3a48ebea97b6ef6cb7d73164
DIFF: https://github.com/llvm/llvm-project/commit/1b743a9efa0884ed3a48ebea97b6ef6cb7d73164.diff
LOG: [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
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
clang/test/Analysis/smart-ptr-text-output.cpp
clang/test/Analysis/smart-ptr.cpp
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index c405ef12433a..391d038c8766 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -58,6 +58,10 @@ class SmartPtrModeling
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);
}
diff --git a/clang/test/Analysis/smart-ptr-text-output.cpp b/clang/test/Analysis/smart-ptr-text-output.cpp
index d63cd9b805f8..602a5e94c23a 100644
--- a/clang/test/Analysis/smart-ptr-text-output.cpp
+++ b/clang/test/Analysis/smart-ptr-text-output.cpp
@@ -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 at -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 at -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 at -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 at -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 at -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 at -1{{Dereference of null smart pointer 'PToMove'}}
+}
diff --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp
index 1403cd6492b2..b169f9c5c2f2 100644
--- a/clang/test/Analysis/smart-ptr.cpp
+++ b/clang/test/Analysis/smart-ptr.cpp
@@ -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 at -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.
+}
More information about the cfe-commits
mailing list