[clang] 76c0577 - [Analyzer] Handle unique_ptr::swap() in SmartPtrModeling

Nithin Vadukkumchery Rajendrakumar via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 21 03:05:39 PDT 2020


Author: Nithin Vadukkumchery Rajendrakumar
Date: 2020-07-21T12:05:27+02:00
New Revision: 76c0577763505ea3db1017a9aab579c1c2f135d0

URL: https://github.com/llvm/llvm-project/commit/76c0577763505ea3db1017a9aab579c1c2f135d0
DIFF: https://github.com/llvm/llvm-project/commit/76c0577763505ea3db1017a9aab579c1c2f135d0.diff

LOG:     [Analyzer] Handle unique_ptr::swap() in SmartPtrModeling

    Summary:
    Implemented modeling for unique_ptr::swap() SmartPtrModeling

    Subscribers: xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, Charusso, martong, ASDenysPetrov, cfe-commits

    Reviewers: NoQ, Szelethus, vsavchenko, xazax.hun
    Reviewed By: NoQ, vsavchenko, xazax.hun

    Tags: #clang

    Differential Revision: https://reviews.llvm.org/D8387

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 1b2174501d6e..c36e89c3e3a9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -108,6 +108,17 @@ removeTrackedSubregions(TrackedRegionMapTy RegionMap,
   return RegionMap;
 }
 
+static ProgramStateRef updateSwappedRegion(ProgramStateRef State,
+                                           const MemRegion *Region,
+                                           const SVal *RegionInnerPointerVal) {
+  if (RegionInnerPointerVal) {
+    State = State->set<TrackedRegionMap>(Region, *RegionInnerPointerVal);
+  } else {
+    State = State->remove<TrackedRegionMap>(Region);
+  }
+  return State;
+}
+
 bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
   // TODO: Update CallDescription to support anonymous calls?
   // TODO: Handle other methods, such as .get() or .release().
@@ -129,7 +140,8 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
         cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
 
     if (!move::isMovedFrom(State, ThisR)) {
-      // TODO: Model this case as well. At least, avoid invalidation of globals.
+      // TODO: Model this case as well. At least, avoid invalidation of
+      // globals.
       return false;
     }
 
@@ -204,7 +216,7 @@ void SmartPtrModeling::handleReset(const CallEvent &Call,
     return;
   auto State = updateTrackedRegion(Call, C, ThisValRegion);
   C.addTransition(State);
-  // TODO: Make sure to ivalidate the the region in the Store if we don't have
+  // TODO: Make sure to ivalidate the region in the Store if we don't have
   // time to model all methods.
 }
 
@@ -232,7 +244,30 @@ void SmartPtrModeling::handleRelease(const CallEvent &Call,
 
 void SmartPtrModeling::handleSwap(const CallEvent &Call,
                                   CheckerContext &C) const {
-  // TODO: Add support to handle swap method.
+  // To model unique_ptr::swap() method.
+  const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
+  if (!IC)
+    return;
+
+  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+  if (!ThisRegion)
+    return;
+
+  const auto *ArgRegion = Call.getArgSVal(0).getAsRegion();
+  if (!ArgRegion)
+    return;
+
+  auto State = C.getState();
+  const auto *ThisRegionInnerPointerVal =
+      State->get<TrackedRegionMap>(ThisRegion);
+  const auto *ArgRegionInnerPointerVal =
+      State->get<TrackedRegionMap>(ArgRegion);
+
+  // Swap the tracked region values.
+  State = updateSwappedRegion(State, ThisRegion, ArgRegionInnerPointerVal);
+  State = updateSwappedRegion(State, ArgRegion, ThisRegionInnerPointerVal);
+
+  C.addTransition(State);
 }
 
 ProgramStateRef

diff  --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
index d5e7c4c9218d..9010ce2bb9b6 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -971,6 +971,12 @@ class unique_ptr {
   operator bool() const noexcept;
   unique_ptr<T> &operator=(unique_ptr<T> &&p) noexcept;
 };
+
+// TODO :: Once the deleter parameter is added update with additional template parameter.
+template <typename T>
+void swap(unique_ptr<T> &x, unique_ptr<T> &y) noexcept {
+  x.swap(y);
+}
 } // namespace std
 #endif
 

diff  --git a/clang/test/Analysis/smart-ptr.cpp b/clang/test/Analysis/smart-ptr.cpp
index 5645afc9b657..168682ba758f 100644
--- a/clang/test/Analysis/smart-ptr.cpp
+++ b/clang/test/Analysis/smart-ptr.cpp
@@ -201,3 +201,30 @@ void derefAfterAssignment() {
     Q->foo(); // no-warning
   }
 }
+
+void derefOnSwappedNullPtr() {
+  std::unique_ptr<A> P(new A());
+  std::unique_ptr<A> PNull;
+  P.swap(PNull);
+  PNull->foo(); // No warning.
+  (*P).foo();   // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnStdSwappedNullPtr() {
+  std::unique_ptr<A> P;
+  std::unique_ptr<A> PNull;
+  std::swap(P, PNull);
+  PNull->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo();     // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnSwappedValidPtr() {
+  std::unique_ptr<A> P(new A());
+  std::unique_ptr<A> PValid(new A());
+  P.swap(PValid);
+  (*P).foo();    // No warning.
+  PValid->foo(); // No warning.
+  std::swap(P, PValid);
+  P->foo();      // No warning.
+  PValid->foo(); // No warning.
+}


        


More information about the cfe-commits mailing list