Author: Nithin Vadukkumchery Rajendrakumar Date: 2020-07-21T01:13:40+02:00 New Revision: a5609102117d2384fb73a14f37d24a0c844e3864
URL: https://github.com/llvm/llvm-project/commit/a5609102117d2384fb73a14f37d24a0c844e3864 DIFF: https://github.com/llvm/llvm-project/commit/a5609102117d2384fb73a14f37d24a0c844e3864.diff LOG: [Analyzer] Add checkRegionChanges for SmartPtrModeling Summary: Implemented checkRegionChanges for SmartPtrModeling Reviewers: NoQ, Szelethus, vsavchenko, xazax.hun Reviewed By: NoQ, vsavchenko, xazax.hun Subscribers: martong, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D83836 Added: Modified: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp clang/test/Analysis/Inputs/system-header-simulator-cxx.h clang/test/Analysis/smart-ptr.cpp Removed: ################################################################################ diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index bcc7d4103c1c..1b2174501d6e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -30,7 +30,8 @@ using namespace clang; using namespace ento; namespace { -class SmartPtrModeling : public Checker<eval::Call, check::DeadSymbols> { +class SmartPtrModeling + : public Checker<eval::Call, check::DeadSymbols, check::RegionChanges> { bool isNullAfterMoveMethod(const CallEvent &Call) const; @@ -40,6 +41,12 @@ class SmartPtrModeling : public Checker<eval::Call, check::DeadSymbols> { bool evalCall(const CallEvent &Call, CheckerContext &C) const; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + ProgramStateRef + checkRegionChanges(ProgramStateRef State, + const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const LocationContext *LCtx, const CallEvent *Call) const; private: ProgramStateRef updateTrackedRegion(const CallEvent &Call, CheckerContext &C, @@ -87,6 +94,20 @@ bool isNullSmartPtr(const ProgramStateRef State, const MemRegion *ThisRegion) { } // namespace ento } // namespace clang +// If a region is removed all of the subregions need to be removed too. +static TrackedRegionMapTy +removeTrackedSubregions(TrackedRegionMapTy RegionMap, + TrackedRegionMapTy::Factory &RegionMapFactory, + const MemRegion *Region) { + if (!Region) + return RegionMap; + for (const auto &E : RegionMap) { + if (E.first->isSubRegionOf(Region)) + RegionMap = RegionMapFactory.remove(RegionMap, E.first); + } + return RegionMap; +} + bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const { // TODO: Update CallDescription to support anonymous calls? // TODO: Handle other methods, such as .get() or .release(). @@ -158,6 +179,20 @@ void SmartPtrModeling::checkDeadSymbols(SymbolReaper &SymReaper, C.addTransition(State); } +ProgramStateRef SmartPtrModeling::checkRegionChanges( + ProgramStateRef State, const InvalidatedSymbols *Invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, + const CallEvent *Call) const { + TrackedRegionMapTy RegionMap = State->get<TrackedRegionMap>(); + TrackedRegionMapTy::Factory &RegionMapFactory = + State->get_context<TrackedRegionMap>(); + for (const auto *Region : Regions) + RegionMap = removeTrackedSubregions(RegionMap, RegionMapFactory, + Region->getBaseRegion()); + return State->set<TrackedRegionMap>(RegionMap); +} + void SmartPtrModeling::handleReset(const CallEvent &Call, CheckerContext &C) const { const auto *IC = dyn_cast<CXXInstanceCall>(&Call); diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h index 1dee3294d732..d5e7c4c9218d 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -953,24 +953,25 @@ next(ForwardIterator it, #if __cplusplus >= 201103L namespace std { - template <typename T> // TODO: Implement the stub for deleter. - class unique_ptr { - public: - unique_ptr() {} - unique_ptr(T *) {} - unique_ptr(const unique_ptr &) = delete; - unique_ptr(unique_ptr &&); - - T *get() const; - T *release() const; - void reset(T *p = nullptr) const; - void swap(unique_ptr<T> &p) const; - - typename std::add_lvalue_reference<T>::type operator*() const; - T *operator->() const; - operator bool() const; - }; -} +template <typename T> // TODO: Implement the stub for deleter. +class unique_ptr { +public: + unique_ptr() noexcept {} + unique_ptr(T *) noexcept {} + unique_ptr(const unique_ptr &) noexcept = delete; + unique_ptr(unique_ptr &&) noexcept; + + T *get() const noexcept; + T *release() noexcept; + void reset(T *p = nullptr) noexcept; + void swap(unique_ptr<T> &p) noexcept; + + typename std::add_lvalue_reference<T>::type operator*() const; + T *operator->() const noexcept; + operator bool() const noexcept; + unique_ptr<T> &operator=(unique_ptr<T> &&p) noexcept; +}; +} // namespace std #endif #ifdef TEST_INLINABLE_ALLOCATORS diff --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp index 4ab7e2bbd3bf..5645afc9b657 100644 --- a/clang/test/Analysis/smart-ptr.cpp +++ b/clang/test/Analysis/smart-ptr.cpp @@ -67,14 +67,14 @@ void derefAfterRelease() { std::unique_ptr<A> P(new A()); P.release(); clang_analyzer_numTimesReached(); // expected-warning {{1}} - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} } void derefAfterReset() { std::unique_ptr<A> P(new A()); P.reset(); clang_analyzer_numTimesReached(); // expected-warning {{1}} - P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} } void derefAfterResetWithNull() { @@ -101,3 +101,103 @@ void derefOnReleasedNullRawPtr() { A *AP = P.release(); AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}} } + +void pass_smart_ptr_by_ref(std::unique_ptr<A> &a); +void pass_smart_ptr_by_const_ref(const std::unique_ptr<A> &a); +void pass_smart_ptr_by_rvalue_ref(std::unique_ptr<A> &&a); +void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr<A> &&a); +void pass_smart_ptr_by_ptr(std::unique_ptr<A> *a); +void pass_smart_ptr_by_const_ptr(const std::unique_ptr<A> *a); + +void regioninvalidationTest() { + { + std::unique_ptr<A> P; + pass_smart_ptr_by_ref(P); + P->foo(); // no-warning + } + { + std::unique_ptr<A> P; + pass_smart_ptr_by_const_ref(P); + P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } + { + std::unique_ptr<A> P; + pass_smart_ptr_by_rvalue_ref(std::move(P)); + P->foo(); // no-warning + } + { + std::unique_ptr<A> P; + pass_smart_ptr_by_const_rvalue_ref(std::move(P)); + P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } + { + std::unique_ptr<A> P; + pass_smart_ptr_by_ptr(&P); + P->foo(); + } + { + std::unique_ptr<A> P; + pass_smart_ptr_by_const_ptr(&P); + P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } +} + +struct StructWithSmartPtr { + std::unique_ptr<A> P; +}; + +void pass_struct_with_smart_ptr_by_ref(StructWithSmartPtr &a); +void pass_struct_with_smart_ptr_by_const_ref(const StructWithSmartPtr &a); +void pass_struct_with_smart_ptr_by_rvalue_ref(StructWithSmartPtr &&a); +void pass_struct_with_smart_ptr_by_const_rvalue_ref(const StructWithSmartPtr &&a); +void pass_struct_with_smart_ptr_by_ptr(StructWithSmartPtr *a); +void pass_struct_with_smart_ptr_by_const_ptr(const StructWithSmartPtr *a); + +void regioninvalidationTestWithinStruct() { + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_ref(S); + S.P->foo(); // no-warning + } + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_const_ref(S); + S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_rvalue_ref(std::move(S)); + S.P->foo(); // no-warning + } + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S)); + S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_ptr(&S); + S.P->foo(); + } + { + StructWithSmartPtr S; + pass_struct_with_smart_ptr_by_const_ptr(&S); + S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}} + } +} + +void derefAfterAssignment() { + { + std::unique_ptr<A> P(new A()); + std::unique_ptr<A> Q; + Q = std::move(P); + Q->foo(); // no-warning + } + { + std::unique_ptr<A> P; + std::unique_ptr<A> Q; + Q = std::move(P); + // TODO: Fix test with expecting warning after '=' operator overloading modeling. + Q->foo(); // no-warning + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits