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@-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'}} +} 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@-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. +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits