forked from OSchip/llvm-project
[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
This commit is contained in:
parent
a54c42df9a
commit
a560910211
|
@ -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 @@ public:
|
|||
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);
|
||||
|
|
|
@ -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 &&);
|
||||
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;
|
||||
T *release() const;
|
||||
void reset(T *p = nullptr) const;
|
||||
void swap(unique_ptr<T> &p) const;
|
||||
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;
|
||||
operator bool() 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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue