[clang] a560910 - [Analyzer] Add checkRegionChanges for SmartPtrModeling
Nithin Vadukkumchery Rajendrakumar via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 20 16:13:51 PDT 2020
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
+ }
+}
More information about the cfe-commits
mailing list