vrnithinkumar created this revision.
Herald added subscribers: cfe-commits, steakhal, ASDenysPetrov, martong, 
Charusso, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, 
baloghadamsoftware, xazax.hun.
Herald added a project: clang.
vrnithinkumar requested review of this revision.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D86027

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/smart-ptr.cpp

Index: clang/test/Analysis/smart-ptr.cpp
===================================================================
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -87,6 +87,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr<A> P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -117,36 +118,39 @@
 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 'P' [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 'P' [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 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationTest1() {
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_const_ref(P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationTest2() {
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationTest3() {
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_const_rvalue_ref(std::move(P));
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationTest4() {
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationTest5() {
+  std::unique_ptr<A> P;
+  pass_smart_ptr_by_const_ptr(&P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 struct StructWithSmartPtr {
@@ -161,36 +165,39 @@
 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 'S.P' [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 'S.P' [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 'S.P' [alpha.cplusplus.SmartPtr]}}
-  }
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_ref(S);
+  S.P->foo(); // no-warning
+}
+
+void regioninvalidationTestWithinStruct2() {
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_const_ref(S);
+  S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationTestWithinStruct3() {
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_rvalue_ref(std::move(S));
+  S.P->foo(); // no-warning
+}
+
+void regioninvalidationTestWithinStruct4() {
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_const_rvalue_ref(std::move(S));
+  S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationTestWithinStruct5() {
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_ptr(&S);
+  S.P->foo(); // no-warning
+}
+
+void regioninvalidationTestWithinStruct6() {
+  StructWithSmartPtr S;
+  pass_struct_with_smart_ptr_by_const_ptr(&S);
+  S.P->foo(); // expected-warning {{Dereference of null smart pointer 'S.P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterAssignment() {
@@ -217,14 +224,20 @@
   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefOnStdSwappedNullPtr() {
+void derefOnFirstStdSwappedNullPtr() {
   std::unique_ptr<A> P;
   std::unique_ptr<A> PNull;
   std::swap(P, PNull);
-  PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
+void derefOnSecondStdSwappedNullPtr() {
+  std::unique_ptr<A> P;
+  std::unique_ptr<A> PNull;
+  std::swap(P, PNull);
+  PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
 void derefOnSwappedValidPtr() {
   std::unique_ptr<A> P(new A());
   std::unique_ptr<A> PValid(new A());
@@ -235,3 +248,45 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr<A> P;
+  if (P)
+    P->foo(); // No warning.
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr<A> P;
+  if (!P)
+    P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr<A> P(new A());
+  std::unique_ptr<A> PNull;
+  if (P)
+    PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr<A> P(new A());
+  std::unique_ptr<A> PNull;
+  if (!P)
+    PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+    // FIXME: This should go away once we fix the splitting bug with ctr evalCall
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr<A> P) {
+  if (P)
+    P->foo(); // No warning.
+  else
+    P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnValidPtrAfterReset(std::unique_ptr<A> P) {
+  P.reset(new A());
+  if (!P)
+    P->foo(); // No warning.
+  else
+    P->foo(); // No warning.
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -51,11 +51,14 @@
                      ArrayRef<const MemRegion *> ExplicitRegions,
                      ArrayRef<const MemRegion *> Regions,
                      const LocationContext *LCtx, const CallEvent *Call) const;
+  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+                  const char *Sep) const;
 
 private:
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
   void handleSwap(const CallEvent &Call, CheckerContext &C) const;
+  void handleBoolOperation(const CallEvent &Call, CheckerContext &C) const;
 
   using SmartPtrMethodHandlerFn =
       void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
@@ -141,17 +144,23 @@
     const MemRegion *ThisR =
         cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
 
-    if (!move::isMovedFrom(State, ThisR)) {
-      // TODO: Model this case as well. At least, avoid invalidation of
-      // globals.
-      return false;
+    if (ModelSmartPtrDereference) {
+      handleBoolOperation(Call, C);
+      return true;
+    } else {
+      if (!move::isMovedFrom(State, ThisR)) {
+        // TODO: Model this case as well. At least, avoid invalidation of
+        // globals.
+        return false;
+      }
+
+      // TODO: Add a note to bug reports describing this decision.
+      C.addTransition(State->BindExpr(
+          Call.getOriginExpr(), C.getLocationContext(),
+          C.getSValBuilder().makeZeroVal(Call.getResultType())));
+
+      return true;
     }
-
-    // TODO: Add a note to bug reports describing this decision.
-    C.addTransition(
-        State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
-                        C.getSValBuilder().makeZeroVal(Call.getResultType())));
-    return true;
   }
 
   if (!ModelSmartPtrDereference)
@@ -227,6 +236,23 @@
   C.addTransition(State);
 }
 
+void SmartPtrModeling::printState(raw_ostream &Out, ProgramStateRef State,
+                                  const char *NL, const char *Sep) const {
+  TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
+
+  if (!RS.isEmpty()) {
+    Out << Sep << "Smart ptr regions :" << NL;
+    for (auto I : RS) {
+      I.first->dumpToStream(Out);
+      if (smartptr::isNullSmartPtr(State, I.first))
+        Out << ": Null";
+      else
+        Out << ": Non Null";
+      Out << NL;
+    }
+  }
+}
+
 ProgramStateRef SmartPtrModeling::checkRegionChanges(
     ProgramStateRef State, const InvalidatedSymbols *Invalidated,
     ArrayRef<const MemRegion *> ExplicitRegions,
@@ -345,6 +371,55 @@
       }));
 }
 
+void SmartPtrModeling::handleBoolOperation(const CallEvent &Call,
+                                           CheckerContext &C) const {
+  // To model unique_ptr::operator bool
+  ProgramStateRef State = C.getState();
+  const MemRegion *ThisRegion =
+      cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
+  const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisRegion);
+  if (InnerPointVal) {
+    if (InnerPointVal->isZeroConstant()) {
+      State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                              C.getSValBuilder().makeTruthVal(false));
+    } else {
+      State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                              C.getSValBuilder().makeTruthVal(true));
+    }
+    C.addTransition(State);
+  } else if (move::isMovedFrom(State, ThisRegion)) {
+    C.addTransition(
+        State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                        C.getSValBuilder().makeZeroVal(Call.getResultType())));
+  } else {
+    const Expr *CallExpr = Call.getOriginExpr();
+    auto CallExprVal = State->getSVal(CallExpr, Call.getLocationContext())
+                           .getAs<DefinedOrUnknownSVal>();
+    if (CallExprVal) {
+      ProgramStateRef NotNullState, NullState;
+      std::tie(NotNullState, NullState) = State->assume(CallExprVal.getValue());
+
+      if (NullState) {
+        auto NullVal = C.getSValBuilder().makeNull();
+        NullState = NullState->set<TrackedRegionMap>(ThisRegion, NullVal);
+        NullState =
+            NullState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                                C.getSValBuilder().makeTruthVal(false));
+        C.addTransition(NullState);
+      }
+      if (NotNullState) {
+        auto NonNullVal = C.getSValBuilder().makeTruthVal(true);
+        NotNullState =
+            NotNullState->set<TrackedRegionMap>(ThisRegion, NonNullVal);
+        NotNullState =
+            NotNullState->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+                                   C.getSValBuilder().makeTruthVal(true));
+        C.addTransition(NotNullState);
+      }
+    }
+  }
+}
+
 void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
   auto *Checker = Mgr.registerChecker<SmartPtrModeling>();
   Checker->ModelSmartPtrDereference =
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to