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

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D84600

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/smart-ptr-text-output.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
@@ -12,7 +12,7 @@
   std::unique_ptr<int> Q = std::move(P);
   if (Q)
     clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-  *Q.get() = 1;                     // no-warning
+  *Q.get() = 1; // no-warning
   if (P)
     clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
@@ -50,37 +50,38 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr<A> P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr<A> P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr<A> P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr<A> P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
 }
 
 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 'P' of type 'std::unique_ptr' [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 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr<A> P(new A());
   P.reset(nullptr);
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNonNull() {
@@ -102,6 +103,12 @@
   AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
 }
 
+void derefOnReleasedValidRawPtr() {
+  std::unique_ptr<A> P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 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);
@@ -118,7 +125,7 @@
   {
     std::unique_ptr<A> P;
     pass_smart_ptr_by_const_ref(P);
-    P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+    P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
   {
     std::unique_ptr<A> P;
@@ -128,7 +135,7 @@
   {
     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]}}
+    P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
   {
     std::unique_ptr<A> P;
@@ -138,7 +145,7 @@
   {
     std::unique_ptr<A> P;
     pass_smart_ptr_by_const_ptr(&P);
-    P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+    P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -162,7 +169,7 @@
   {
     StructWithSmartPtr S;
     pass_struct_with_smart_ptr_by_const_ref(S);
-    S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+    S.P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
   {
     StructWithSmartPtr S;
@@ -172,7 +179,7 @@
   {
     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]}}
+    S.P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
   {
     StructWithSmartPtr S;
@@ -182,7 +189,7 @@
   {
     StructWithSmartPtr S;
     pass_struct_with_smart_ptr_by_const_ptr(&S);
-    S.P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+    S.P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -207,24 +214,24 @@
   std::unique_ptr<A> PNull;
   P.swap(PNull);
   PNull->foo(); // No warning.
-  (*P).foo();   // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [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]}}
+  PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [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.
+  (*P).foo(); // No warning.
   PValid->foo(); // No warning.
   std::swap(P, PValid);
-  P->foo();      // No warning.
+  P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.SmartPtr\
+// RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:  -analyzer-output=text -std=c++11 %s -verify=expected
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+class A {
+public:
+  A(){};
+  void foo();
+};
+
+A *return_null() {
+  return nullptr;
+}
+
+void derefAfterDefaultCtr() {
+  std::unique_ptr<A> P; // expected-note {{Default constructed unique_ptr, 'P' is null}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefAfterCtrWithNull() {
+  A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
+  std::unique_ptr<A> P(NullInnerPtr); // expected-note {{unique_ptr, 'P' constructed using a null value}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefAfterCtrWithNullVariable() {
+  A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
+  std::unique_ptr<A> P(NullInnerPtr); // expected-note {{unique_ptr, 'P' constructed using a null value}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefAfterRelease() {
+  std::unique_ptr<A> P(new A());
+  P.release(); // expected-note {{unique_ptr, 'P' is released and set to null}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefAfterReset() {
+  std::unique_ptr<A> P(new A());
+  P.reset(); // expected-note {{unique_ptr, 'P' reset using a null value}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefAfterResetWithNull() {
+  A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
+  std::unique_ptr<A> P(new A());
+  P.reset(NullInnerPtr); // expected-note {{unique_ptr, 'P' reset using a null value}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+void derefOnReleasedNullRawPtr() {
+  std::unique_ptr<A> P; // expected-note {{Default constructed unique_ptr, 'P' is null}}
+  A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer value}}
+  // expected-note@-1 {{unique_ptr, 'P' is released and set to null}}
+  AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+  // expected-note@-1{{Called C++ object pointer is null}}
+}
+
+void derefOnSwappedNullPtr() {
+  std::unique_ptr<A> P(new A());
+  std::unique_ptr<A> PNull; // expected-note {{Default constructed unique_ptr, 'PNull' is null}}
+  P.swap(PNull); // expected-note {{Swapped null unique_ptr, 'PNull' with unique_ptr, 'P'}}
+  PNull->foo(); // No warning.
+  (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
+
+// TODO: Enabale this test when "std::swap" is modeled seperately.
+void derefOnStdSwappedNullPtr() {
+  std::unique_ptr<A> P;
+  std::unique_ptr<A> PNull;
+  // std::swap(P, PNull);
+  // PNull->foo();
+  // P->foo();
+}
+
+struct StructWithSmartPtr { // expected-note {{Default constructed unique_ptr, 'P' is null}}
+  std::unique_ptr<A> P;
+};
+
+void derefAfterDefaultCtrInsideStruct() {
+  StructWithSmartPtr S; // expected-note {{Calling implicit default constructor for 'StructWithSmartPtr'}}
+  // expected-note@-1 {{Returning from default constructor for 'StructWithSmartPtr'}}
+  S.P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -23,12 +23,43 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include <string>
 
 using namespace clang;
 using namespace ento;
 
+namespace {
+// Helper struct for adding smart pointer note tags.
+struct SmartPtrTagDetails {
+  enum SmartPtrKind { UniquePtr, SharedPtr, WeakPtr };
+  enum SmartPtrMethodKind { Constructor, Reset, Release, Swap, Get };
+  SmartPtrTagDetails(SmartPtrKind SmartPtr, SmartPtrMethodKind SmartPtrMethod,
+                     const MemRegion *TrackingRegion, const Expr *E = nullptr,
+                     StringRef ArgName = "")
+      : SmartPtr(SmartPtr), SmartPtrMethod(SmartPtrMethod),
+        TrackingRegion(TrackingRegion), TrackingExpr(E),
+        SwappedArgName(ArgName) {}
+
+private:
+  SmartPtrKind SmartPtr;
+  SmartPtrMethodKind SmartPtrMethod;
+  const MemRegion *TrackingRegion;
+  const Expr *TrackingExpr;
+  const StringRef SwappedArgName;
+
+public:
+  void explainSmartPtrAction(llvm::raw_ostream &OS) const;
+  void trackValidExpr(PathSensitiveBugReport &BR) const {
+    if (TrackingExpr) {
+      bugreporter::trackExpressionValue(BR.getErrorNode(), TrackingExpr, BR);
+    }
+  }
+};
+} // end of anonymous namespace
+
 namespace {
 class SmartPtrModeling
     : public Checker<eval::Call, check::DeadSymbols, check::RegionChanges> {
@@ -49,8 +80,9 @@
                      const LocationContext *LCtx, const CallEvent *Call) const;
 
 private:
-  ProgramStateRef updateTrackedRegion(const CallEvent &Call, CheckerContext &C,
-                                      const MemRegion *ThisValRegion) const;
+  SVal getSValForRegion(const CallEvent &Call, CheckerContext &C) const;
+  const NoteTag *createTag(SmartPtrTagDetails TagDetails,
+                           CheckerContext &C) const;
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
   void handleSwap(const CallEvent &Call, CheckerContext &C) const;
@@ -119,6 +151,62 @@
   return State;
 }
 
+// Get first argument expression if exist else nullptr
+static const Expr *getFirstArgExpr(const CallEvent &Call) {
+  if (Call.getNumArgs() > 0) {
+    return Call.getArgExpr(0);
+  }
+  return nullptr;
+}
+
+void SmartPtrTagDetails::explainSmartPtrAction(llvm::raw_ostream &OS) const {
+  StringRef SmartPtrName, SmartPtrTypeName;
+
+  if (const auto *DR = dyn_cast<DeclRegion>(TrackingRegion)) {
+    SmartPtrName = DR->getDecl()->getName();
+  }
+  switch (SmartPtr) {
+  case UniquePtr:
+    SmartPtrTypeName = "unique_ptr";
+    break;
+  case SharedPtr:
+    SmartPtrTypeName = "shared_ptr";
+    break;
+  case WeakPtr:
+    SmartPtrTypeName = "weak_ptr";
+  }
+
+  switch (SmartPtrMethod) {
+  case Constructor: {
+    if (TrackingExpr) {
+      OS << SmartPtrTypeName << ", '" << SmartPtrName << "'"
+         << " constructed using a null value";
+    } else {
+      OS << "Default constructed " << SmartPtrTypeName << ", '" << SmartPtrName
+         << "'"
+         << " is null";
+    }
+    break;
+  }
+  case Reset:
+    OS << SmartPtrTypeName << ", '" << SmartPtrName << "'"
+       << " reset using a null value";
+    break;
+  case Release:
+    OS << SmartPtrTypeName << ", '" << SmartPtrName << "'"
+       << " is released and set to null";
+    break;
+  case Swap:
+    OS << "Swapped null " << SmartPtrTypeName << ", '" << SwappedArgName << "'"
+       << " with " << SmartPtrTypeName << ", '" << SmartPtrName << "'";
+    break;
+  case Get:
+    OS << "Accessed inner pointer from " << SmartPtrTypeName << ", '"
+       << SmartPtrName << "'";
+    break;
+  }
+}
+
 bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
   // TODO: Update CallDescription to support anonymous calls?
   // TODO: Handle other methods, such as .get() or .release().
@@ -131,11 +219,11 @@
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
                                 CheckerContext &C) const {
 
+  ProgramStateRef State = C.getState();
   if (!smartptr::isStdSmartPtrCall(Call))
     return false;
 
   if (isNullAfterMoveMethod(Call)) {
-    ProgramStateRef State = C.getState();
     const MemRegion *ThisR =
         cast<CXXInstanceCall>(&Call)->getCXXThisVal().getAsRegion();
 
@@ -163,8 +251,15 @@
     if (!ThisValRegion)
       return false;
 
-    auto State = updateTrackedRegion(Call, C, ThisValRegion);
-    C.addTransition(State);
+    auto ArgVal = getSValForRegion(Call, C);
+    State = State->set<TrackedRegionMap>(ThisValRegion, ArgVal);
+    const auto *ArgExpr = getFirstArgExpr(Call);
+    SmartPtrTagDetails TagDetail(SmartPtrTagDetails::UniquePtr,
+                                 SmartPtrTagDetails::Constructor, ThisValRegion,
+                                 ArgExpr);
+    const NoteTag *CallTag = createTag(TagDetail, C);
+
+    C.addTransition(State, CallTag);
     return true;
   }
 
@@ -207,6 +302,7 @@
 
 void SmartPtrModeling::handleReset(const CallEvent &Call,
                                    CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
   if (!IC)
     return;
@@ -214,14 +310,22 @@
   const MemRegion *ThisValRegion = IC->getCXXThisVal().getAsRegion();
   if (!ThisValRegion)
     return;
-  auto State = updateTrackedRegion(Call, C, ThisValRegion);
-  C.addTransition(State);
+
+  auto ArgVal = getSValForRegion(Call, C);
+  State = State->set<TrackedRegionMap>(ThisValRegion, ArgVal);
+  const auto *ArgExpr = getFirstArgExpr(Call);
+  SmartPtrTagDetails TagDetail(SmartPtrTagDetails::UniquePtr,
+                               SmartPtrTagDetails::Reset, ThisValRegion,
+                               ArgExpr);
+  const NoteTag *CallTag = createTag(TagDetail, C);
+  C.addTransition(State, CallTag);
   // TODO: Make sure to ivalidate the region in the Store if we don't have
   // time to model all methods.
 }
 
 void SmartPtrModeling::handleRelease(const CallEvent &Call,
                                      CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
   const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
   if (!IC)
     return;
@@ -230,14 +334,19 @@
   if (!ThisValRegion)
     return;
 
-  auto State = updateTrackedRegion(Call, C, ThisValRegion);
-
   const auto *InnerPointVal = State->get<TrackedRegionMap>(ThisValRegion);
   if (InnerPointVal) {
     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
                             *InnerPointVal);
   }
-  C.addTransition(State);
+
+  auto ValueToUpdate = C.getSValBuilder().makeNull();
+  State = State->set<TrackedRegionMap>(ThisValRegion, ValueToUpdate);
+
+  SmartPtrTagDetails TagDetail(SmartPtrTagDetails::UniquePtr,
+                               SmartPtrTagDetails::Release, ThisValRegion);
+  const NoteTag *CallTag = createTag(TagDetail, C);
+  C.addTransition(State, CallTag);
   // TODO: Add support to enable MallocChecker to start tracking the raw
   // pointer.
 }
@@ -267,27 +376,42 @@
   State = updateSwappedRegion(State, ThisRegion, ArgRegionInnerPointerVal);
   State = updateSwappedRegion(State, ArgRegion, ThisRegionInnerPointerVal);
 
-  C.addTransition(State);
+  StringRef SwappedRegionName = "";
+  if (const auto *DR = dyn_cast<DeclRegion>(ArgRegion))
+    SwappedRegionName = DR->getDecl()->getName();
+  SmartPtrTagDetails TagDetail(SmartPtrTagDetails::UniquePtr,
+                               SmartPtrTagDetails::Swap, ThisRegion, nullptr,
+                               SwappedRegionName);
+  const NoteTag *CallTag = createTag(TagDetail, C);
+  C.addTransition(State, CallTag);
 }
 
-ProgramStateRef
-SmartPtrModeling::updateTrackedRegion(const CallEvent &Call, CheckerContext &C,
-                                      const MemRegion *ThisValRegion) const {
-  // TODO: Refactor and clean up handling too many things.
+// Gets the SVal to track for a smart pointer memory region
+SVal SmartPtrModeling::getSValForRegion(const CallEvent &Call,
+                                        CheckerContext &C) const {
   ProgramStateRef State = C.getState();
   auto NumArgs = Call.getNumArgs();
 
-  if (NumArgs == 0) {
-    auto NullSVal = C.getSValBuilder().makeNull();
-    State = State->set<TrackedRegionMap>(ThisValRegion, NullSVal);
-  } else if (NumArgs == 1) {
-    auto ArgVal = Call.getArgSVal(0);
-    assert(Call.getArgExpr(0)->getType()->isPointerType() &&
-           "Adding a non pointer value to TrackedRegionMap");
-    State = State->set<TrackedRegionMap>(ThisValRegion, ArgVal);
-  }
+  if (NumArgs == 0)
+    return C.getSValBuilder().makeNull();
 
-  return State;
+  auto ArgVal = Call.getArgSVal(0);
+  assert(Call.getArgExpr(0)->getType()->isPointerType() &&
+         "Adding a non pointer value to TrackedRegionMap");
+  return ArgVal;
+}
+
+const NoteTag *SmartPtrModeling::createTag(SmartPtrTagDetails TagDetails,
+                                           CheckerContext &C) const {
+  return C.getNoteTag(
+      [TagDetails](PathSensitiveBugReport &BR) -> std::string {
+        SmallString<128> Msg;
+        llvm::raw_svector_ostream Out(Msg);
+        TagDetails.trackValidExpr(BR);
+        TagDetails.explainSmartPtrAction(Out);
+        return std::string(Out.str());
+      },
+      false);
 }
 
 void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
@@ -23,6 +23,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/StringRef.h"
 
 using namespace clang;
 using namespace ento;
@@ -36,7 +37,10 @@
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
 
 private:
-  void reportBug(CheckerContext &C, const CallEvent &Call) const;
+  void reportBug(CheckerContext &C, const MemRegion *DerefRegion,
+                 const CallEvent &Call) const;
+  void explainDereference(llvm::raw_ostream &OS, const MemRegion *DerefRegion,
+                          const CallEvent &Call) const;
 };
 } // end of anonymous namespace
 
@@ -55,21 +59,45 @@
   OverloadedOperatorKind OOK = OC->getOverloadedOperator();
   if (OOK == OO_Star || OOK == OO_Arrow) {
     if (smartptr::isNullSmartPtr(State, ThisRegion))
-      reportBug(C, Call);
+      reportBug(C, ThisRegion, Call);
   }
 }
 
-void SmartPtrChecker::reportBug(CheckerContext &C,
+void SmartPtrChecker::reportBug(CheckerContext &C, const MemRegion *DerefRegion,
                                 const CallEvent &Call) const {
   ExplodedNode *ErrNode = C.generateErrorNode();
   if (!ErrNode)
     return;
-
-  auto R = std::make_unique<PathSensitiveBugReport>(
-      NullDereferenceBugType, "Dereference of null smart pointer", ErrNode);
+  llvm::SmallString<128> Str;
+  llvm::raw_svector_ostream OS(Str);
+  explainDereference(OS, DerefRegion, Call);
+  auto R = std::make_unique<PathSensitiveBugReport>(NullDereferenceBugType,
+                                                    OS.str(), ErrNode);
   C.emitReport(std::move(R));
 }
 
+void SmartPtrChecker::explainDereference(llvm::raw_ostream &OS,
+                                         const MemRegion *DerefRegion,
+                                         const CallEvent &Call) const {
+  OS << "Dereference of null smart pointer";
+
+  // Add smart pointer variable name
+  if (const auto *DR = dyn_cast<DeclRegion>(DerefRegion)) {
+    auto SmartPtrName = DR->getDecl()->getName();
+    OS << " '" << SmartPtrName << "'";
+  }
+
+  // Add smart pointer type info
+  const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
+  if (!MethodDecl || !MethodDecl->getParent())
+    return;
+
+  const auto *RecordDecl = MethodDecl->getParent();
+  if (RecordDecl && RecordDecl->getDeclName().isIdentifier()) {
+    OS << " of type '" << RecordDecl->getQualifiedNameAsString() << "'";
+  }
+}
+
 void ento::registerSmartPtrChecker(CheckerManager &Mgr) {
   Mgr.registerChecker<SmartPtrChecker>();
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to