[PATCH] D80490: Check for rule of five and zero.

2020-05-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
vrnithinkumar added reviewers: aaron.ballman, alexfh, jbcoe, dblaikie, rsmith.
Herald added subscribers: cfe-commits, kbarton, mgorny, nemanjai.
Herald added a project: clang.

New check to check if a class defines all special members of none of them. This 
also known as rule of five and zero.
Specified in CppCoreGuidelines: 
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c21-if-you-define-or-delete-any-default-operation-define-or-delete-them-all.
In summary the check will

- Checks class defines all special members of none of them.
- It also see if the base class deletes the special members or not.
- Has two modes with the flag strict-check.
- Strict mode will check all or nothing strictly.

For some combination, compiler explicitly delete the special members or  does 
not declare implicitly. In that case don'nt have to define all the special 
members. 
For example, in case of defining all members except move constructor and move 
assignment compiler will not implicitly declare the move constructor and move 
assignment.
For non strict mode we will consider these combinations as safe.

I found one review https://reviews.llvm.org/D16376 already related to this. 
I modified my changes based on this. But I could not find out why this got 
abandoned.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80490

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-rule-of-five-and-zero %t
+
+class DefinesNothing {
+};
+
+class DefinesEverything {
+  DefinesEverything(const DefinesEverything &);
+  DefinesEverything &operator=(const DefinesEverything &);
+  DefinesEverything(DefinesEverything &&);
+  DefinesEverything &operator=(DefinesEverything &&);
+  ~DefinesEverything();
+};
+
+class DeletesEverything {
+  DeletesEverything(const DeletesEverything &);
+  DeletesEverything &operator=(const DeletesEverything &);
+  DeletesEverything(DeletesEverything &&);
+  DeletesEverything &operator=(DeletesEverything &&);
+  ~DeletesEverything();
+};
+
+// Safe cases
+class DefinesAllExceptMoves {
+  ~DefinesAllExceptMoves();
+  DefinesAllExceptMoves(DefinesAllExceptMoves &);
+  DefinesAllExceptMoves &operator=(DefinesAllExceptMoves &);
+};
+
+class DefinesAllExceptMoveConstructor {
+  ~DefinesAllExceptMoveConstructor();
+  DefinesAllExceptMoveConstructor(DefinesAllExceptMoveConstructor &);
+  DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &);
+  DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &&);
+};
+
+class DefinesAllExceptMoveAssignment {
+  ~DefinesAllExceptMoveAssignment();
+  DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &);
+  DefinesAllExceptMoveAssignment &operator=(DefinesAllExceptMoveAssignment &);
+  DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &&);
+};
+
+class DefinesDestructorAndMoveConstructor {
+  ~DefinesDestructorAndMoveConstructor();
+  DefinesDestructorAndMoveConstructor(DefinesDestructorAndMoveConstructor &&);
+};
+
+class DefinesDestructorAndMoveAssignment {
+  ~DefinesDestructorAndMoveAssignment();
+  DefinesDestructorAndMoveAssignment &operator=(DefinesDestructorAndMoveAssignment &&);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyDestructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyDestructor {
+  ~DefinesOnlyDestructor();
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyConstructor' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyCopyConstructor {
+  DefinesOnlyCopyConstructor(const DefinesOnlyCopyConstructor &);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveConstructor' defines a move constructor but does not define all other 5, define all other 5 or delet

[PATCH] D80490: Check for rule of five and zero.

2020-05-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 265921.
vrnithinkumar added a comment.

fixed the clang-tidy warnig


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D80490/new/

https://reviews.llvm.org/D80490

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.cpp
  clang-tools-extra/clang-tidy/cppcoreguidelines/RuleOfFiveAndZeroCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-rule-of-five-and-zero.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero-strict.cpp
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-rule-of-five-and-zero.cpp
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-rule-of-five-and-zero %t
+
+class DefinesNothing {
+};
+
+class DefinesEverything {
+  DefinesEverything(const DefinesEverything &);
+  DefinesEverything &operator=(const DefinesEverything &);
+  DefinesEverything(DefinesEverything &&);
+  DefinesEverything &operator=(DefinesEverything &&);
+  ~DefinesEverything();
+};
+
+class DeletesEverything {
+  DeletesEverything(const DeletesEverything &);
+  DeletesEverything &operator=(const DeletesEverything &);
+  DeletesEverything(DeletesEverything &&);
+  DeletesEverything &operator=(DeletesEverything &&);
+  ~DeletesEverything();
+};
+
+// Safe cases
+class DefinesAllExceptMoves {
+  ~DefinesAllExceptMoves();
+  DefinesAllExceptMoves(DefinesAllExceptMoves &);
+  DefinesAllExceptMoves &operator=(DefinesAllExceptMoves &);
+};
+
+class DefinesAllExceptMoveConstructor {
+  ~DefinesAllExceptMoveConstructor();
+  DefinesAllExceptMoveConstructor(DefinesAllExceptMoveConstructor &);
+  DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &);
+  DefinesAllExceptMoveConstructor &operator=(DefinesAllExceptMoveConstructor &&);
+};
+
+class DefinesAllExceptMoveAssignment {
+  ~DefinesAllExceptMoveAssignment();
+  DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &);
+  DefinesAllExceptMoveAssignment &operator=(DefinesAllExceptMoveAssignment &);
+  DefinesAllExceptMoveAssignment(DefinesAllExceptMoveAssignment &&);
+};
+
+class DefinesDestructorAndMoveConstructor {
+  ~DefinesDestructorAndMoveConstructor();
+  DefinesDestructorAndMoveConstructor(DefinesDestructorAndMoveConstructor &&);
+};
+
+class DefinesDestructorAndMoveAssignment {
+  ~DefinesDestructorAndMoveAssignment();
+  DefinesDestructorAndMoveAssignment &operator=(DefinesDestructorAndMoveAssignment &&);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyDestructor' defines a destructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyDestructor {
+  ~DefinesOnlyDestructor();
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyConstructor' defines a copy constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyCopyConstructor {
+  DefinesOnlyCopyConstructor(const DefinesOnlyCopyConstructor &);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveConstructor' defines a move constructor but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyMoveConstructor {
+  DefinesOnlyMoveConstructor(DefinesOnlyMoveConstructor &&);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyCopyAssignment' defines a copy assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyCopyAssignment {
+  DefinesOnlyCopyAssignment &operator=(const DefinesOnlyCopyAssignment &);
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: class 'DefinesOnlyMoveAssignment' defines a move assignment operator but does not define all other 5, define all other 5 or delete all other special member functions [cppcoreguidelines-rule-of-five-and-zero]
+class DefinesOnlyMoveAssignment {
+  DefinesOnlyMoveAssignment &operator=(DefinesOnlyMoveAssignment &&);
+};
+
+// check inheritance
+class NoCopyBase {
+public:
+  ~NoCopyBase();
+  NoCopyBase(NoCopyBase &&);
+  NoCopyBase &operator=(NoCopyBase &&);
+
+private:
+  NoCopyBase(const NoCopyBase &) = delete;
+  NoCopyBase &operator=(const NoCopyBase 

[PATCH] D83836: [Analyzer] Add checkRegionChanges for SmartPtrModeling

2020-07-16 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 278622.
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

- Addressing review comments
- Enabling commented out tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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,102 @@
   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);
+void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
+void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
+void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr &&a);
+void pass_smart_ptr_by_ptr(std::unique_ptr *a);
+void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
+
+void regioninvalidationTest() {
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_ref(P);
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_const_ref(P);
+P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_rvalue_ref(std::move(P));
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr 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 P;
+pass_smart_ptr_by_ptr(&P);
+P->foo();
+  }
+  {
+std::unique_ptr 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 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 P(new A());
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // no-warning
+  }
+}
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -943,24 +943,25 @@
 
 #if __cplusplus >= 201103L
 namespace std {
-  template  // TODO: Implement the stub for deleter.
-  class unique_ptr {
-  public:
-unique_ptr() {}
-unique_ptr(T *) {}
-unique_ptr(const unique_ptr &) = de

[PATCH] D83836: [Analyzer] Add checkRegionChanges for SmartPtrModeling

2020-07-16 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 278628.
vrnithinkumar marked 8 inline comments as done.
vrnithinkumar added a comment.

- Adding a missed todo


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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 @@
   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);
+void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
+void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
+void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr &&a);
+void pass_smart_ptr_by_ptr(std::unique_ptr *a);
+void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
+
+void regioninvalidationTest() {
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_ref(P);
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_const_ref(P);
+P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_rvalue_ref(std::move(P));
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr 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 P;
+pass_smart_ptr_by_ptr(&P);
+P->foo();
+  }
+  {
+std::unique_ptr 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 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 P(new A());
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+std::unique_ptr Q;
+Q = std::move(P);
+// TODO: Fix test with expecting warning after '=' operator overloading modeling.
+Q->foo(); // no-warning
+  }
+}
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -943,24 +943,25 @@
 
 #if __cplusplus >= 201103L
 namespace std {
-  template  // TODO: Implement the stub for deleter.
-  class unique_ptr {
-  public:
-unique_ptr() {}
-unique_pt

[PATCH] D83836: [Analyzer] Add checkRegionChanges for SmartPtrModeling

2020-07-16 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:97
 
+// If a region is removed all of the subregions needs to be removed too.
+static ProgramStateRef removeTrackedRegions(ProgramStateRef State,

vsavchenko wrote:
> nit: *need to be removed
fixed



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:98
+// If a region is removed all of the subregions needs to be removed too.
+static ProgramStateRef removeTrackedRegions(ProgramStateRef State,
+const MemRegion *Region) {

vsavchenko wrote:
> Maybe `Subregions` would fit better in this name then?
Changed to Subregions



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:186
+  for (const auto *Region : Regions)
+State = removeTrackedRegions(State, Region->getBaseRegion());
+  return State;

vsavchenko wrote:
> It is not critical, but potentially we can allocate/deallocate a whole bunch 
> of states here.  We can do the same sort of operation with the map itself 
> (`State->get()`), which still have similar problem but to a 
> lesser degree.  Additionally, this `get` method is not 
> compile-time, it searches for the corresponding map in runtime (also in a 
> map), so you repeat that as many times as you have `Regions`.
> 
> And super-duper over-optimization note on my part: making the loop over 
> `Regions` to be the inner-most is more cache-friendly.  It is not really 
> critical here, but it is overall good to have an eye for things like that.
Updated `removeTrackedSubregions` for passing `TrackedRegionMap`



Comment at: clang/test/Analysis/Inputs/system-header-simulator-cxx.h:962
+  operator bool() const;
+  unique_ptr &operator=(unique_ptr &&p);
+};

xazax.hun wrote:
> vrnithinkumar wrote:
> > added this to support  use case like `Q = std::move(P)`
> This operation should be `noexcept`: 
> https://en.cppreference.com/w/cpp/memory/unique_ptr/operator%3D
> 
> While it makes little difference for the analyzer at this point we should try 
> to be as close to the standard as possible. If you have some time feel free 
> to add `noexcept` to other methods that miss it :)
Added `noexcept` for all applicable methods



Comment at: clang/test/Analysis/smart-ptr.cpp:190
+/*
+// TODO: Enable this test after '=' operator overloading modeling.
+void derefAfterAssignment() {

vsavchenko wrote:
> Usually we simply add the test with expectations matching current state of 
> things, but add a TODO over those particular lines. This way when you fix the 
> issue the test will start failing and you won't forget to uncomment it.
Enabled the test and added the todo.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83877: [Analyzer] Handle unique_ptr::swap() in SmartPtrModeling

2020-07-17 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 278759.
vrnithinkumar marked 11 inline comments as done.
vrnithinkumar edited the summary of this revision.
vrnithinkumar added a comment.

- Changes from review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83877/new/

https://reviews.llvm.org/D83877

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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,30 @@
   A *AP = P.release();
   AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
 }
+
+void derefOnSwappedNullPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr 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 P;
+  std::unique_ptr 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 P(new A());
+  std::unique_ptr 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.
+}
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -960,7 +960,13 @@
 T *operator->() const;
 operator bool() const;
   };
-}
+
+  // TODO :: Once the deleter parameter is added update with additional template parameter.
+  template 
+  void swap(unique_ptr &x, unique_ptr &y) noexcept {
+x.swap(y);
+  }
+  } // namespace std
 #endif
 
 #ifdef TEST_INLINABLE_ALLOCATORS
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -87,6 +87,17 @@
 } // namespace ento
 } // namespace clang
 
+static ProgramStateRef updateSwappedRegion(ProgramStateRef State,
+   const MemRegion *Region,
+   const SVal *RegionInnerPointerVal) {
+  if (RegionInnerPointerVal) {
+State = State->set(Region, *RegionInnerPointerVal);
+  } else {
+State = State->remove(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().
@@ -169,7 +180,7 @@
 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.
 }
 
@@ -197,7 +208,30 @@
 
 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(&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(ThisRegion);
+  const auto *ArgRegionInnerPointerVal =
+  State->get(ArgRegion);
+
+  // Swap the tracked region values.
+  State = updateSwappedRegion(State, ThisRegion, ArgRe

[PATCH] D83877: [Analyzer] Handle unique_ptr::swap() in SmartPtrModeling

2020-07-17 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:198
 
 void SmartPtrModeling::handleSwap(const CallEvent &Call,
   CheckerContext &C) const {

vsavchenko wrote:
> I think it would be good to add some comments in the body of the function to 
> be more explicit about the situation you are handling.
Added comments



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:224-228
+  if (ThisRegionInnerPointerVal) {
+State = State->set(ArgRegion, 
*ThisRegionInnerPointerVal);
+  } else {
+State = State->remove(ArgRegion);
+  }

vsavchenko wrote:
> These two if's are clearly duplicates and it seems like a good candidate for 
> a separate function.
Thanks!
created a separate function `updateSwappedRegion()`



Comment at: clang/test/Analysis/Inputs/system-header-simulator-cxx.h:964-965
+
+  template 
+  void swap(unique_ptr &x, unique_ptr &y) noexcept {
+x.swap(y);

xazax.hun wrote:
> NoQ wrote:
> > You seem to be relying on the fact that global `std::swap` is implemented 
> > in terms of the member `std::swap`. That's an implementation detail of the 
> > standard library; i'm not sure that this is always the case. Ideally we 
> > should model the global `std::swap` separately.
> I am not sure how reliable cppreference is, but I think this overload might 
> actually be guaranteed by the standard: 
> https://en.cppreference.com/w/cpp/memory/unique_ptr/swap2
I also made the assumption based on this 
(https://en.cppreference.com/w/cpp/memory/unique_ptr/swap2).




Comment at: clang/test/Analysis/Inputs/system-header-simulator-cxx.h:965
+  template 
+  void swap(unique_ptr &x, unique_ptr &y) noexcept {
+x.swap(y);

xazax.hun wrote:
> Maybe it is worth to add a TODO to introduce an additional template parameter 
> once the deleter is added above.
> 
> https://en.cppreference.com/w/cpp/memory/unique_ptr/swap2
Added the TODO



Comment at: clang/test/Analysis/smart-ptr.cpp:124
+
+void derefOnStdSwappedNullPtr() {
+  std::unique_ptr P(new A());

vsavchenko wrote:
> xazax.hun wrote:
> > This test case is very similar to the first one. Maybe you could move them 
> > closer. And you could make both pointers invalid to make them more distinct.
> +1
Moved and made both pointers invalid in the test



Comment at: clang/test/Analysis/smart-ptr.cpp:131
+}
\ No newline at end of file


vrnithinkumar wrote:
> I will fix this.
Fixed


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83877/new/

https://reviews.llvm.org/D83877



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-07-26 Thread Nithin VR via Phabricator via cfe-commits
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 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 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 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 P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr 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 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 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 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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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 P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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 P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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;
@@ -

[PATCH] D81315: [Draft] [Prototype] warning for default constructed unique pointer dereferences

2020-06-05 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
vrnithinkumar added reviewers: vsavchenko, xazax.hun, NoQ.
Herald added subscribers: cfe-commits, martong, Charusso, rnkovacs.
Herald added a project: clang.

This is just a prototype review for my changes since I thought it will be 
easier to ask code related doubts here.

I just wanted to share how I prototyped the checker for default constructed 
unique pointer dereferences.
It is incomplete. Not added tests. Not all cases covered. Reporting part is not 
proper. **This may be a throw away code.**

I am sharing this so that if I am fundamentally wrong in any of my directions 
it will be much better to catch early and rectify.

- Added a two maps to track  mem region and corresponding states and Symbols to 
mem region
- Created a RegionState to track information about the state of memory region 
whether it is null or not or unknown
- Using PostCall to update the states of mem region
- Using PreCall to check the null pointer dereferences

**Few doubts:**
I am not sure about whether I should use `eval::Call` or both `check::PreCall` 
and `check::PostCall`.
In the `eval::Call` documentation I found this "Note, that only one checker can 
evaluate a call.". So I am little bit confused about using it.

Using one map for tracking the mem region and states then one more for Symbols 
to region to track which all Symbol has the inner pointer.
I am just looking is there any better approach for this.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81315

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp

Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -14,25 +14,75 @@
 #include "Move.h"
 
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #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/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 
 using namespace clang;
 using namespace ento;
 
 namespace {
-class SmartPtrModeling : public Checker {
+struct RegionState {
+private:
+  enum Kind { Null, NonNull, Unknown } K;
+  RegionState(Kind InK) : K(InK) {}
+
+public:
+  bool isNull() const { return K == Null; }
+
+  static RegionState getNull() { return RegionState(Null); }
+  static RegionState getNonNull() { return RegionState(NonNull); }
+  static RegionState getUnKnown() { return RegionState(Unknown); }
+
+  bool operator==(const RegionState &X) const { return K == X.K; }
+  void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
+};
+} // end of anonymous namespace
+
+namespace {
+class SmartPtrModeling : public Checker {
   bool isNullAfterMoveMethod(const CallEvent &Call) const;
 
 public:
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+
+private:
+  mutable std::unique_ptr BT;
+  void reportBug(CheckerContext &C, const CallEvent &Call) const;
+  bool isSmartPointer(const CXXRecordDecl *RD) const;
+  bool isResetMethod(const CXXMethodDecl *MethodDec) const;
+
+  // STL smart pointers which we are trying to model
+  const llvm::StringSet<> StdSmartPtrs = {
+  "shared_ptr",
+  "unique_ptr",
+  "weak_ptr",
+  };
+
+  // STL smart pointer methods which resets to null
+  const llvm::StringSet<> ResetMethods = {"reset", "release", "swap"};
+
+  // STL smart pointer methods which resets to null via null argument
+  const llvm::StringSet<> NullResetMethods = {"reset", "swap"};
 };
 } // end of anonymous namespace
 
+// to track the mem region and curresponding states
+REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, RegionState)
+// to track the Symbols which will get inner raw pointer via unique_ptr.get()
+// method
+REGISTER_MAP_WITH_PROGRAMSTATE(SymbolRegionMap, const SymbolRef, MemRegion)
+
 bool SmartPtrModeling::isNullAfterMoveMethod(const CallEvent &Call) const {
   // TODO: Update CallDescription to support anonymous calls?
   // TODO: Handle other methods, such as .get() or .release().
@@ -63,6 +113,129 @@
   return true;
 }
 
+void SmartPtrModeling::checkPreCall(const CallEvent &Call,
+CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  const auto OC = dyn_cast(&Call);
+  if (!OC)
+return;
+  const MemRegion *ThisRegion =

[PATCH] D81734: Initial smart pointer check

2020-06-12 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar abandoned this revision.
vrnithinkumar added a comment.

It was a mistake 
I was supposed to update an existing review.
first time use of arc


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81734/new/

https://reviews.llvm.org/D81734



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81734: Initial smart pointer check

2020-06-12 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
Herald added subscribers: cfe-commits, martong.
Herald added a project: clang.
vrnithinkumar abandoned this revision.
vrnithinkumar added a comment.

It was a mistake 
I was supposed to update an existing review.
first time use of arc


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81734

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -10,7 +10,7 @@
   std::unique_ptr 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).
@@ -26,3 +26,64 @@
   (s->*func)(); // no-crash
 }
 } // namespace testUnknownCallee
+
+class A {
+public:
+  A(){};
+  void foo();
+};
+
+A *return_null() {
+  return nullptr;
+}
+
+void derefAfterValidCtr() {
+  std::unique_ptr P(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterDefaultCtr() {
+  std::unique_ptr P;
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNull() {
+  std::unique_ptr P(nullptr);
+  *P; // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNullReturnMethod() {
+  std::unique_ptr P(return_null());
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterRelease() {
+  std::unique_ptr P(new A());
+  P.release();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterReset() {
+  std::unique_ptr P(new A());
+  P.reset();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNull() {
+  std::unique_ptr P(new A());
+  P.reset(nullptr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNonNull() {
+  std::unique_ptr P;
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterReleaseAndResetWithNonNull() {
+  std::unique_ptr P(new A());
+  P.release();
+  P.reset(new A());
+  P->foo(); // No warning.
+}
\ No newline at end of file
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -946,10 +946,15 @@
   template  // 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 &p) const;
 
 typename std::add_lvalue_reference::type operator*() const;
 T *operator->() const;
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -13,26 +13,60 @@
 
 #include "Move.h"
 
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #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/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 
 using namespace clang;
 using namespace ento;
 
 namespace {
-class SmartPtrModeling : public Checker {
+class SmartPtrModeling
+: public Checker {
   bool isNullAfterMoveMethod(const CallEvent &Call) const;
+  BugType NullDereferenceBugType{this, "Null-smartPtr-deref",
+ "C++ smart pointer"};
 
 public:
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkPostCall(const CallEvent &MC, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+
+private:
+  void reportBug(CheckerContext &C, const CallEvent &Call) const;
+  bool isStdSmartPointerClass(const CXXRecordDecl *RD) const;
+  void updateTrackedRegion(const CallEvent &Call, CheckerContext &C,
+   const MemRegion *Region) const;
+  void 

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-12 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 270391.
vrnithinkumar retitled this revision from "[analyzer][Draft] [Prototype] 
warning for default constructed unique pointer dereferences" to "[analyzer] 
Warning for default constructed unique pointer dereferences".
vrnithinkumar added a comment.

Addressing the review comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -10,7 +10,7 @@
   std::unique_ptr 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).
@@ -26,3 +26,64 @@
   (s->*func)(); // no-crash
 }
 } // namespace testUnknownCallee
+
+class A {
+public:
+  A(){};
+  void foo();
+};
+
+A *return_null() {
+  return nullptr;
+}
+
+void derefAfterValidCtr() {
+  std::unique_ptr P(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterDefaultCtr() {
+  std::unique_ptr P;
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNull() {
+  std::unique_ptr P(nullptr);
+  *P; // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNullReturnMethod() {
+  std::unique_ptr P(return_null());
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterRelease() {
+  std::unique_ptr P(new A());
+  P.release();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterReset() {
+  std::unique_ptr P(new A());
+  P.reset();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNull() {
+  std::unique_ptr P(new A());
+  P.reset(nullptr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNonNull() {
+  std::unique_ptr P;
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterReleaseAndResetWithNonNull() {
+  std::unique_ptr P(new A());
+  P.release();
+  P.reset(new A());
+  P->foo(); // No warning.
+}
\ No newline at end of file
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -946,10 +946,15 @@
   template  // 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 &p) const;
 
 typename std::add_lvalue_reference::type operator*() const;
 T *operator->() const;
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -13,26 +13,60 @@
 
 #include "Move.h"
 
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #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/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 
 using namespace clang;
 using namespace ento;
 
 namespace {
-class SmartPtrModeling : public Checker {
+class SmartPtrModeling
+: public Checker {
   bool isNullAfterMoveMethod(const CallEvent &Call) const;
+  BugType NullDereferenceBugType{this, "Null-smartPtr-deref",
+ "C++ smart pointer"};
 
 public:
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+  void checkPostCall(const CallEvent &MC, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+
+private:
+  void reportBug(CheckerContext &C, const CallEvent &Call) const;
+  bool isStdSmartPointerClass(const CXXRecordDecl *RD) const;
+  void updateTrackedRegion(const CallEvent &Call, Chec

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-12 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 38 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:31
 namespace {
-class SmartPtrModeling : public Checker {
+struct RegionState {
+private:

vsavchenko wrote:
> xazax.hun wrote:
> > I think `RegionState` is not very descriptive. I'd call it something like 
> > `RegionNullness`.
> linter: LLVM coding standards require to use `class` keyword in situations 
> like this 
> (https://llvm.org/docs/CodingStandards.html#use-of-class-and-struct-keywords).
>   I would even say that `struct` is good for POD types.
With the new changes, the struct is removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:31
 namespace {
-class SmartPtrModeling : public Checker {
+struct RegionState {
+private:

vrnithinkumar wrote:
> vsavchenko wrote:
> > xazax.hun wrote:
> > > I think `RegionState` is not very descriptive. I'd call it something like 
> > > `RegionNullness`.
> > linter: LLVM coding standards require to use `class` keyword in situations 
> > like this 
> > (https://llvm.org/docs/CodingStandards.html#use-of-class-and-struct-keywords).
> >   I would even say that `struct` is good for POD types.
> With the new changes, the struct is removed.
With the new changes, the struct is removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:33
+private:
+  enum Kind { Null, NonNull, Unknown } K;
+  RegionState(Kind InK) : K(InK) {}

vsavchenko wrote:
> I think that it would be better to put declarations for `enum` and for a 
> field separately.
> Additionally, I don't think that `K` is a very good name for a data member.  
> It should be evident from the name of the member what is it.  Shot names like 
> that can be fine only for iterators or for certain `clang`-specific 
> structures because of existing traditions (like `SM` for `SourceManager` and 
> `LO` for `LanguageOptions`).
With the new changes, the `enum`  is removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:46
+};
+} // end of anonymous namespace
+

Szelethus wrote:
> xazax.hun wrote:
> > You can merge the two anonymous namespaces, this and the one below.
> [[https://llvm.org/docs/CodingStandards.html#anonymous-namespaces | I prefer 
> them like this. ]]
with new change only one anonymous namespace is there



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:60
+private:
+  mutable std::unique_ptr BT;
+  void reportBug(CheckerContext &C, const CallEvent &Call) const;

xazax.hun wrote:
> This is how we used to do it, but we did not update all the checks yet. 
> Nowadays we can just initialize bugtypes immediately, see 
> https://github.com/llvm/llvm-project/blob/master/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp#L169
updated to initialize bugtype immediately



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:65
+
+  // STL smart pointers which we are trying to model
+  const llvm::StringSet<> StdSmartPtrs = {

xazax.hun wrote:
> In LLVM we aim for full sentences as comments with a period at the end.
Updated the comments as LLVM style



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:72-76
+  // STL smart pointer methods which resets to null
+  const llvm::StringSet<> ResetMethods = {"reset", "release", "swap"};
+
+  // STL smart pointer methods which resets to null via null argument
+  const llvm::StringSet<> NullResetMethods = {"reset", "swap"};

NoQ wrote:
> Please consider `CallDescription` and `CallDescriptionMap`!
Made changes to use `CallDescription` and `CallDescriptionMap`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:81
+// to track the mem region and curresponding states
+REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, 
RegionState)
+// to track the Symbols which will get inner raw pointer via unique_ptr.get()

NoQ wrote:
> I ultimately believe this map should go away. The only thing we really need 
> is the map from smart pointer region to the symbol for its current raw 
> pointer. As long as we have such data we can discover the nullness of that 
> symbol (which *is* the nullness of the smart pointer as well) from Range 
> Constraints.
Removed this map.
Now maping region to SVal



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:119
+  ProgramStateRef State = C.getState();
+  const auto OC = dyn_cast(&Call);
+  if (!OC)

vsavchenko wrote:
> xazax.hun wrote:
> > Here the const applies for the pointer, not the pointee. We usually do 
> > `const auto *OC` instead.
> As I said above, I think we should be really careful about abbreviated and 
> extremely short variable na

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 275076.
vrnithinkumar marked 14 inline comments as done.
vrnithinkumar added a comment.
Herald added a subscriber: mgorny.

- Created a new checker for smart point derference diagnostic
- Moved checking part to this checker
- Kept all the modeling in `SmartPtrModeling`
- Created a header file for shared API -calls


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/smart-ptr.cpp
  clang/test/Analysis/use-after-move.cpp

Index: clang/test/Analysis/use-after-move.cpp
===
--- clang/test/Analysis/use-after-move.cpp
+++ clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 
 // RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,23 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtrModeling,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartP

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td:574
 
-def SmartPtrModeling: Checker<"SmartPtr">,
+def SmartPtrModeling: Checker<"SmartPtrModeling">,
   HelpText<"Model behavior of C++ smart pointers">,

Changed the modeling to `SmartPtrModeling` and named checker to `SmartPtr`



Comment at: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td:579
+CmdLineOptionhttps://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td:577-583
+  CheckerOptions<[
+CmdLineOption,
+  ]>,

Szelethus wrote:
> NoQ wrote:
> > Szelethus wrote:
> > > This goes against D81750 -- Sorry for not bringing this up earlier, but 
> > > you can't emit diagnostics from a checker that is hidden :/
> > > 
> > > The proper solution would be to create a non-hidden checker, and emit a 
> > > diagnostic under its name. You can take inspiration from `MallocChecker`, 
> > > `NullabilityChecker`, and a variety of other sound in the stack of this 
> > > patch: D77845
> > Aha, ok, that's what i meant at the end of D81315#inline-760088. @Szelethus 
> > insists, so let's turn ourselves into a separate checker right away!
> > 
> > In fact, let's *not* take the inspiration from poor-man's solutions in 
> > `MallocChecker` etc., but instead let's try a full-on modular approach:
> > - Make a separate .cpp file and a separate Checker class for emitting 
> > diagnostics.
> >   - Remove the checker option and instead add a separate checker entry in 
> > Checkers.td.
> > - Subscribe the new checker on PreCall only and move all the bug reporting 
> > logic there.
> > - Keep all the modeling logic in the old checker (it's called 
> > SmartPtr//Modeling// for a reason!).
> > - Put common functionality into a header file shared between the two 
> > checkers.
> >   - In particular, the GDM trait should be only accessed through such 
> > getter.
> > - Take some inspiration from `Taint.h`.
> Sounds great! And of course, say the word if any help is needed! :)
Thanks...!

Created a new checker `alpha.cplusplus.SmartPtr` to emit the SmartPtr 
dereference diagnostic.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:139
+
+  const auto *MethodDecl = dyn_cast_or_null(OC->getDecl());
+

xazax.hun wrote:
> You should never get null here due to `isStdSmartPointerClass` guarding 
> above. I think the null check could be transformed into an assert.
Changed to dyn_cast.
Added assert 



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:141
+
+  if (!MethodDecl || !MethodDecl->isOverloadedOperator())
+return;

xazax.hun wrote:
> You have a `CXXMemberOperatorCall` which already represents an overloaded 
> operator. This check is either redundant or could be an assert instead.
Removed the redundant check



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:144
+
+  OverloadedOperatorKind OOK = MethodDecl->getOverloadedOperator();
+  if (OOK == OO_Star || OOK == OO_Arrow) {

xazax.hun wrote:
> In case `CXXMemberOperatorCall ` class does not have a way to query the 
> overloaded operator kind maybe it would be worth to add a helper method to 
> that class. So you can do most of the checking using one interface only.
Added `getOverloadedOperator()` in `CXXMemberOperatorCall` class



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:148
+if (InnerPointVal && InnerPointVal->isZeroConstant()) {
+  reportBug(C, Call);
+}

NoQ wrote:
> This doesn't seem to be guarded by `ShouldCheckSmartPtrDereference`.
> 
> Consider adding a LIT test for the flag to make sure we're not leaking our 
> project to the public until it's ready ^.^ Say, you could make two run-lines 
> in your test like this:
> ```
> // RUN: %clang_analyze_cc1 -verify=expected -analyzer-config 
> cplusplus.SmartPtr:CheckSmartPtrDereference=true \
> // RUN: ...
> // RUN: %clang_analyze_cc1 -verify=unexpected \
> // RUN: ...
> 
> // unexpected-no-diagnostics
> ```
> (see 
> https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html 
> for more fancy tricks with `-verify`)
Added one more run to verify it.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:198
+*InnerPointVal);
+C.addTransition(State);
+  }

xazax.hun wrote:
> It is possible that both `updateTrackedRegion` and this adds a transition. 
> Both transition will have the same predecessor, i.e. you introduce a split in 
> the exploded graph. Is this intended?
This was not intended.
- Fixed to avoid split in the exploded graph.
- Updated test to check with `clang_analyzer_numTimesReached`


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 4 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td:582
+  "false",
+  InAlpha>,
+  ]>,

Szelethus wrote:
> Let's `Hide` this in addition.
Added `Hide`



Comment at: clang/test/Analysis/smart-ptr.cpp:6
+// RUN: %clang_analyze_cc1 -analyzer-checker=core\
+// RUN:   -analyzer-checker 
cplusplus.SmartPtrModeling,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config 
cplusplus.SmartPtrModeling:ModelSmartPtrDereference=false\

Szelethus wrote:
> `alpha.cplusplus.SmartPtr` on its own should be sufficient, dependencies 
> ensure that `cplusplus.SmartPtrModeling` will be enabled and registered 
> beforehand.
Removed `cplusplus.SmartPtrModeling`


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 275254.
vrnithinkumar added a comment.

Addressing review comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/smart-ptr.cpp
  clang/test/Analysis/use-after-move.cpp

Index: clang/test/Analysis/use-after-move.cpp
===
--- clang/test/Analysis/use-after-move.cpp
+++ clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 
 // RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,23 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:   -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core\
+// RUN:   -analyzer-checker alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=false\
+// RUN

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-03 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 275434.
vrnithinkumar marked 11 inline comments as done.
vrnithinkumar added a comment.

addressing review comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/smart-ptr.cpp
  clang/test/Analysis/use-after-move.cpp

Index: clang/test/Analysis/use-after-move.cpp
===
--- clang/test/Analysis/use-after-move.cpp
+++ clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 
 // RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,18 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:   -std=c++11 -verify %s
 
 #include "Inputs/system-header-simulator-cxx.h"
 
 void clang_analyzer_warnIfReached();
+void clang_analyzer_numTimesReached();
 
 void derefAfterMov

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-03 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:41
+
+  bool checkDeferenceOps(const CallEvent &Call, CheckerContext &C) const;
+};

NoQ wrote:
> Looks like dead code.
Thanks!
removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:72
+  NullDereferenceBugType, "Dereference of null smart pointer", ErrNode);
+  R->addRange(Call.getSourceRange());
+  C.emitReport(std::move(R));

NoQ wrote:
> This is probably unnecessary. The default `SourceRange` highlighted in 
> path-sensitive report is the error node's statement and it should be exactly 
> the same.
Removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:67-80
+bool isStdSmartPtrCall(const CallEvent &Call) {
+  const auto *MethodDecl = dyn_cast_or_null(Call.getDecl());
+  if (!MethodDecl || !MethodDecl->getParent())
+return false;
+
+  const auto *RecordDecl = MethodDecl->getParent();
+  if (!RecordDecl || !RecordDecl->getDeclContext()->isStdNamespace())

NoQ wrote:
> Ok, so the normal solution to this problem is to make this logic a part of 
> your `CallDescriptionMap`:
> 
> ```lang=c++
>   CallDescriptionMap SmartPtrMethodHandlers{
> 
> {{"std", "unique_ptr", "reset"}, &SmartPtrModeling::handleReset},
> {{"std", "unique_ptr", "release"}, &SmartPtrModeling::handleRelease},
> {{"std", "unique_ptr", "swap", 1}, &SmartPtrModeling::handleSwap},
> 
> {{"std", "shared_ptr", "reset"}, &SmartPtrModeling::handleReset},
> {{"std", "shared_ptr", "release"}, &SmartPtrModeling::handleRelease},
> {{"std", "shared_ptr", "swap", 1}, &SmartPtrModeling::handleSwap},
> 
> {{"std", "weak_ptr", "reset"}, &SmartPtrModeling::handleReset},
> {{"std", "weak_ptr", "release"}, &SmartPtrModeling::handleRelease},
> {{"std", "weak_ptr", "swap", 1}, &SmartPtrModeling::handleSwap},
>   };
> ```
> 
> It looks like you're not doing this because `CallDescriptionMap` doesn't 
> support operator calls yet. In fact, it looks like it doesn't support them 
> because i'm not doing my homework by reviewing D81059. I just tried to catch 
> up on it.
> 
> The other potential reason not to use `CallDescriptionMap` would be that 
> you'll have to duplicate the list of methods for every smart pointer class 
> you want to support. I don't think it's necessarily bad though, because 
> different classes may in fact require different handling.
> 
> The downside of your solution, though, is that you're manually implementing 
> the name matching logic that has been already implemented for you in 
> `CallDescriptionMap`. And the reason we made `CallDescriptionMap` was because 
> we really really wanted to re-use this logic because it's surprisingly 
> difficult to implement correctly. One potential problem i see with your 
> implementation is that you don't account for inline namespaces such as [[ 
> https://github.com/llvm/llvm-project/blob/master/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp#L127
>  | libcxx's `__1` ]]. `CallDescriptionMap` knows about these things but 
> they're almost impossible to discover independently when you're matching 
> names by hand.
> 
> Let's leave this code as-is for now but try to get rid of this function as 
> soon as possible (i.e., when D81059 lands).
Thanks for the details.
If I recall correctly, I also found that  `CallDescriptionMap` was not 
supporting constructors also. 
I am not sure why.
Is it because constructor name is a special name?



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:50
+  void handleSwap(const CallEvent &Call, CheckerContext &C) const;
+  bool checkDeferenceOps(const CallEvent &Call, CheckerContext &C) const;
+

NoQ wrote:
> Looks like dead code.
Thanks!
removed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:81
 CheckerContext &C) const {
-  if (!isNullAfterMoveMethod(Call))
+  if (isNullAfterMoveMethod(Call)) {
+ProgramStateRef State = C.getState();

NoQ wrote:
> vrnithinkumar wrote:
> > xazax.hun wrote:
> > > Don't we want this to be also protected by the `isStdSmartPointerClass` 
> > > check?
> > added `isStdSmartPointerClass` check in the beginning.
> Uh-oh, i'm shocked this wasn't in place before. Maybe we should do some code 
> review or something. What idiot wrote this code anyway? Wait, it was me.
:)



Comment at: clang/test/Analysis/smart-ptr.cpp:5
 // RUN:   -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core\
+// RUN:   -analyzer-checker alpha.cplusplus.SmartPtr\

NoQ wrote:
> This second run-line no longer tests the option. The checker is disabled, of 
> course there won't be any diagnostics. I think we should remove the second 
> run-line now and i don't have much better tests in mind that 

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-07 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:202-219
+ProgramStateRef
+SmartPtrModeling::updateTrackedRegion(const CallEvent &Call, CheckerContext &C,
+  const MemRegion *ThisValRegion) const {
+  ProgramStateRef State = C.getState();
+  auto NumArgs = Call.getNumArgs();
+
+  if (NumArgs == 0) {

NoQ wrote:
> Szelethus wrote:
> > Hmm, this function feels clunky. So, if the call has no arguments, we set 
> > the smart pointer to null, otherwise if its a single-argument then we set 
> > it to whatever the argument is? 
> > 
> > How about `operator[]`, that also takes a single argument, but isn't a 
> > memory region? `get`, `get_deleter` don't take any arguments, but they 
> > don't set the internal pointee to null either. The name 
> > `updateTrackedRegion` however suggests that whatever operation was done, 
> > this is the one-tool-to-solve-it-all function to take care of it.
> > 
> > I think this function handles too many things as once, and the name and 
> > lack of documentation obfuscates its purpose. How about we put the relevant 
> > code to `handleRelease`, and repurpose the rest of the function like this:
> > 
> > `updateOwnedRegion(CallEvent, CheckerContext, MemRegion of the smart 
> > pointer, MemRegion to take ownership of)`
> > 
> > What do you think?
> Yup, I completely agree. I think this structure will naturally evolve into 
> something cleaner once more modeling gets added.
Thanks for the detailed comment.

I totally agree this method is handling many things. 
For methods like `get`, `get_deleter` this makes no sense at all.

I will add TODO there,  will address this  in a later patch once we get a clear 
picture after more modeling added.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-08 Thread Nithin VR via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG20e271a98de5: [analyzer] Warning for default constructed 
unique_ptr dereference (authored by vrnithinkumar).

Changed prior to commit:
  https://reviews.llvm.org/D81315?vs=275434&id=276327#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/smart-ptr.cpp
  clang/test/Analysis/use-after-move.cpp

Index: clang/test/Analysis/use-after-move.cpp
===
--- clang/test/Analysis/use-after-move.cpp
+++ clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 
 // RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,18 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:   -std=c++1

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-07-08 Thread Nithin VR via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rG20e271a98de5: [analyzer] Warning for default constructed 
unique_ptr dereference (authored by vrnithinkumar).

Changed prior to commit:
  https://reviews.llvm.org/D81315?vs=275434&id=275699#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/smart-ptr.cpp
  clang/test/Analysis/use-after-move.cpp

Index: clang/test/Analysis/use-after-move.cpp
===
--- clang/test/Analysis/use-after-move.cpp
+++ clang/test/Analysis/use-after-move.cpp
@@ -1,36 +1,36 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move -verify %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=KnownsOnly\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,non-aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=unexplored_first_queue\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 // RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.Move %s\
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive
 
 // RUN: not %clang_analyze_cc1 -verify %s \
@@ -49,7 +49,7 @@
 // RUN:  -std=c++11 -analyzer-output=text -analyzer-config eagerly-assume=false\
 // RUN:  -analyzer-config exploration_strategy=dfs -DDFS\
 // RUN:  -analyzer-config cplusplus.Move:WarnOn=All -DAGGRESSIVE_DFS\
-// RUN:  -analyzer-checker core,cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-checker core,cplusplus.SmartPtrModeling,debug.ExprInspection\
 // RUN:  -verify=expected,peaceful,aggressive %s 2>&1 | FileCheck %s
 
 #include "Inputs/system-header-simulator-cxx.h"
Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -1,16 +1,18 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
-// RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-co

[PATCH] D83836: Implementing checkRegionChanges

2020-07-14 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
Herald added subscribers: cfe-commits, martong.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D83836

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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,105 @@
   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);
+void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
+void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
+void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr &&a);
+void pass_smart_ptr_by_ptr(std::unique_ptr *a);
+void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
+
+void regioninvalidationTest() {
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_ref(P);
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_const_ref(P);
+P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_rvalue_ref(std::move(P));
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr 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 P;
+pass_smart_ptr_by_ptr(&P);
+P->foo();
+  }
+  {
+std::unique_ptr 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 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]}}
+  }
+}
+
+/*
+// TODO: Enable this test after '=' operator overloading modeling.
+void derefAfterAssignment() {
+  {
+std::unique_ptr P(new A());
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // warning
+  }
+}
+*/
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -943,24 +943,25 @@
 
 #if __cplusplus >= 201103L
 namespace std {
-  template  // 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 *r

[PATCH] D83836: [Analyzer] Implementing checkRegionChanges for SmartPtrModeling

2020-07-14 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 3 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:180
 
+ProgramStateRef SmartPtrModeling::checkRegionChanges(
+ProgramStateRef State, const InvalidatedSymbols *Invalidated,

I am using the same code from the  `MoveChecker` since the same logic applies 
here too.
But I am not completely sure whether this is the clean approach.



Comment at: clang/test/Analysis/Inputs/system-header-simulator-cxx.h:962
+  operator bool() const;
+  unique_ptr &operator=(unique_ptr &&p);
+};

added this to support  use case like `Q = std::move(P)`



Comment at: clang/test/Analysis/smart-ptr.cpp:145
+
+struct StructWithSmartPtr {
+  std::unique_ptr P;

@xazax.hun , Is this the type of test you were suggesting?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83877: [Analyzer] Changed in SmartPtrModeling to handle Swap

2020-07-15 Thread Nithin VR via Phabricator via cfe-commits
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/D83877

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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,30 @@
   A *AP = P.release();
   AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
 }
+
+void derefOnSwappedNullPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  P.swap(PNull);
+  PNull->foo(); // No warning.
+  (*P).foo();   // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnSwappedValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr 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.
+}
+
+void derefOnStdSwappedNullPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  std::swap(P, PNull);
+  PNull->foo(); // No warning.
+  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+}
\ No newline at end of file
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -960,7 +960,12 @@
 T *operator->() const;
 operator bool() const;
   };
-}
+
+  template 
+  void swap(unique_ptr &x, unique_ptr &y) noexcept {
+x.swap(y);
+  }
+  } // namespace std
 #endif
 
 #ifdef TEST_INLINABLE_ALLOCATORS
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -169,7 +169,7 @@
 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.
 }
 
@@ -197,7 +197,37 @@
 
 void SmartPtrModeling::handleSwap(const CallEvent &Call,
   CheckerContext &C) const {
-  // TODO: Add support to handle swap method.
+  const auto *IC = dyn_cast(&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(ThisRegion);
+  const auto *ArgRegionInnerPointerVal =
+  State->get(ArgRegion);
+
+  // Swap the tracked region values.
+  if (ArgRegionInnerPointerVal) {
+State = State->set(ThisRegion, *ArgRegionInnerPointerVal);
+  } else {
+State = State->remove(ThisRegion);
+  }
+  if (ThisRegionInnerPointerVal) {
+State = State->set(ArgRegion, *ThisRegionInnerPointerVal);
+  } else {
+State = State->remove(ArgRegion);
+  }
+
+  C.addTransition(State);
 }
 
 ProgramStateRef
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83877: [Analyzer] Changed in SmartPtrModeling to handle Swap

2020-07-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: clang/test/Analysis/smart-ptr.cpp:131
+}
\ No newline at end of file


I will fix this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83877/new/

https://reviews.llvm.org/D83877



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83836: [Analyzer] Implementing checkRegionChanges for SmartPtrModeling

2020-07-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 278207.
vrnithinkumar edited the summary of this revision.
vrnithinkumar added a comment.

Untrack all changing regions in checkRegionChanges


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -67,14 +67,14 @@
   std::unique_ptr 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 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,105 @@
   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);
+void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
+void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
+void pass_smart_ptr_by_const_rvalue_ref(const std::unique_ptr &&a);
+void pass_smart_ptr_by_ptr(std::unique_ptr *a);
+void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
+
+void regioninvalidationTest() {
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_ref(P);
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_const_ref(P);
+P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  }
+  {
+std::unique_ptr P;
+pass_smart_ptr_by_rvalue_ref(std::move(P));
+P->foo(); // no-warning
+  }
+  {
+std::unique_ptr 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 P;
+pass_smart_ptr_by_ptr(&P);
+P->foo();
+  }
+  {
+std::unique_ptr 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 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]}}
+  }
+}
+
+/*
+// TODO: Enable this test after '=' operator overloading modeling.
+void derefAfterAssignment() {
+  {
+std::unique_ptr P(new A());
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // no-warning
+  }
+  {
+std::unique_ptr P;
+std::unique_ptr Q;
+Q = std::move(P);
+Q->foo(); // warning
+  }
+}
+*/
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -943,24 +943,25 @@
 
 #if __cplusplus >= 201103L
 namespace std {
-  template  // TODO: Implement the stub for deleter.
-  class unique_ptr {
-  public:
-unique_ptr() 

[PATCH] D83836: [Analyzer] Implementing checkRegionChanges for SmartPtrModeling

2020-07-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:189-190
+// or rvalue references.
+// In case of an InstanceCall don't invalidate the this-region since
+// it is fully handled in checkPreCall and checkPostCall.
+const MemRegion *ThisRegion = nullptr;

NoQ wrote:
> The whole reason why we are making this patch first is because we *don't* 
> fully handle methods :)
> 
> Also, unlike the move checker, once we handle them, they'll probably stop 
> changing regions, so no exceptional code path would be necessary in most 
> cases.
> 
> So i'd rather start with fully wiping all the data on any sneeze and later 
> see if we can relax it.
I completely missed that point and jumped ahead.
Made changes to untrack all changing regions in `checkRegionChanges`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: Enabling ctr in evalCall event

2020-06-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
Herald added subscribers: cfe-commits, martong.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82256

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
  clang/test/Analysis/new-ctor-conservative.cpp

Index: clang/test/Analysis/new-ctor-conservative.cpp
===
--- clang/test/Analysis/new-ctor-conservative.cpp
+++ clang/test/Analysis/new-ctor-conservative.cpp
@@ -27,6 +27,7 @@
   S *s = new S[10];
   // FIXME: Should be true once we inline array constructors.
   clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}}
 }
 
 struct NullS {
Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- /dev/null
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:  -analyzer-checker=debug.AnalysisOrder \
+// RUN:  -analyzer-config debug.AnalysisOrder:EvalCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PreCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PostCall=true \
+// RUN:  2>&1 | FileCheck %s
+
+// This test ensures that eval::Call event will be triggered for constructors.
+
+class C {
+public:
+  C(){};
+  C(int x){};
+  C(int x, int y){};
+};
+
+void foo() {
+  C C0;
+  C C1(42);
+  C *C2 = new C{2, 3};
+}
+
+// CHECK:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {0} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {1} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {2} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
\ No newline at end of file
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -50,6 +50,7 @@
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
+// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false
 // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false
 // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false
 // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -583,8 +583,9 @@
   // to see if the can evaluate the function call, and get a callback at
   // defaultEvalCall if all of them fail.
   ExplodedNodeSet dstCallEvaluated;
+  EvalCallOptions CallOpts;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
- Call, *this);
+ Call, *this, CallOpts);
 
   // If there were other constructors called for object-type arguments
   // of this call, clean them up.
@@ -717,7 +718,7 @@
 ExprEngine::CallInlinePolicy
 ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
   AnalyzerOptions &Opts,
-  const ExprEngine::EvalCallOptions &CallOpts) {
+  const EvalCallOptions &CallOpts) {
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -615,7 +615,8 @@
   } else {
 for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
  I != E; ++I)
-  defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *

[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h:100
+/// Hints for figuring out of a call should be inlined during evalCall().
+struct EvalCallOptions {
+  /// This call is a constructor or a destructor for which we do not currently

Moved the  `struct EvalCallOptions` outside `ExprEngine` class.
Since CheckerManager.h using forward declaration of `ExprEngine` and inner type 
`EvalCallOptions` is needed for the `runCheckersForEvalCall` function 
declaration.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp:586
   ExplodedNodeSet dstCallEvaluated;
+  EvalCallOptions CallOpts;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,

NoQ wrote:
> If you want you can make it an optional argument of 
> `runCheckersForEvalCall()`, like it's done in `defaultEvalCall()`.
I tried to make it as default argument for `runCheckersForEvalCall()` but 
`struct EvalCallOptions` is forward declared in `CheckerManager.h`.



Comment at: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp:34
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
\ No newline at end of file


NoQ wrote:
> No NEwLiNE aT EnD Of FiLE
added new line


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 272275.
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

Addressing review comment adding miised new line


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256

Files:
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp


Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -30,4 +30,4 @@
 // CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
 // CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
 // CHECK-NEXT:  EvalCall (C::C) {2} [CXXConstructorCall]
-// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
\ No newline at end of file
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]


Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -30,4 +30,4 @@
 // CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
 // CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
 // CHECK-NEXT:  EvalCall (C::C) {2} [CXXConstructorCall]
-// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
\ No newline at end of file
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 272276.
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

Fixing wrongly deleted the old commit via arc


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
  clang/test/Analysis/new-ctor-conservative.cpp

Index: clang/test/Analysis/new-ctor-conservative.cpp
===
--- clang/test/Analysis/new-ctor-conservative.cpp
+++ clang/test/Analysis/new-ctor-conservative.cpp
@@ -27,6 +27,7 @@
   S *s = new S[10];
   // FIXME: Should be true once we inline array constructors.
   clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}}
 }
 
 struct NullS {
Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- /dev/null
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:  -analyzer-checker=debug.AnalysisOrder \
+// RUN:  -analyzer-config debug.AnalysisOrder:EvalCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PreCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PostCall=true \
+// RUN:  2>&1 | FileCheck %s
+
+// This test ensures that eval::Call event will be triggered for constructors.
+
+class C {
+public:
+  C(){};
+  C(int x){};
+  C(int x, int y){};
+};
+
+void foo() {
+  C C0;
+  C C1(42);
+  C *C2 = new C{2, 3};
+}
+
+// CHECK:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {0} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {1} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {2} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -50,6 +50,7 @@
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
+// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false
 // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false
 // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false
 // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -583,8 +583,9 @@
   // to see if the can evaluate the function call, and get a callback at
   // defaultEvalCall if all of them fail.
   ExplodedNodeSet dstCallEvaluated;
+  EvalCallOptions CallOpts;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
- Call, *this);
+ Call, *this, CallOpts);
 
   // If there were other constructors called for object-type arguments
   // of this call, clean them up.
@@ -717,7 +718,7 @@
 ExprEngine::CallInlinePolicy
 ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
   AnalyzerOptions &Opts,
-  const ExprEngine::EvalCallOptions &CallOpts) {
+  const EvalCallOptions &CallOpts) {
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -615,7 +615,8 @@
   } else {
 for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
  I != E; ++I)
-  defaultEvalC

[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-24 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 273117.
vrnithinkumar added a comment.

Fixing test failures


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
  clang/test/Analysis/new-ctor-conservative.cpp

Index: clang/test/Analysis/new-ctor-conservative.cpp
===
--- clang/test/Analysis/new-ctor-conservative.cpp
+++ clang/test/Analysis/new-ctor-conservative.cpp
@@ -27,6 +27,7 @@
   S *s = new S[10];
   // FIXME: Should be true once we inline array constructors.
   clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}}
 }
 
 struct NullS {
Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- /dev/null
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:  -analyzer-checker=debug.AnalysisOrder \
+// RUN:  -analyzer-config debug.AnalysisOrder:EvalCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PreCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PostCall=true \
+// RUN:  2>&1 | FileCheck %s
+
+// This test ensures that eval::Call event will be triggered for constructors.
+
+class C {
+public:
+  C(){};
+  C(int x){};
+  C(int x, int y){};
+};
+
+void foo() {
+  C C0;
+  C C1(42);
+  C *C2 = new C{2, 3};
+}
+
+// CHECK:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 0} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 1} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 2} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -50,6 +50,7 @@
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
+// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false
 // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false
 // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false
 // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -584,7 +584,7 @@
   // defaultEvalCall if all of them fail.
   ExplodedNodeSet dstCallEvaluated;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
- Call, *this);
+ Call, *this, EvalCallOptions());
 
   // If there were other constructors called for object-type arguments
   // of this call, clean them up.
@@ -717,7 +717,7 @@
 ExprEngine::CallInlinePolicy
 ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
   AnalyzerOptions &Opts,
-  const ExprEngine::EvalCallOptions &CallOpts) {
+  const EvalCallOptions &CallOpts) {
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -615,7 +615,8 @@
   } else {
 for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
  I != E; ++I)
-  defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this,
+   

[PATCH] D82256: [analyzer] Enabling ctr in evalCall event

2020-06-24 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 5 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp:130
+llvm::errs() << " (" << ND->getQualifiedNameAsString() << ')';
+  llvm::errs() << " {" << Call.getNumArgs() << '}';
+  llvm::errs() << " [" << Call.getKindAsString() << ']';

Szelethus wrote:
> This seems a bit cryptic, how about `{argno:`?
For more clarity, added "{argno:".



Comment at: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp:669
   ProgramPoint L = ProgramPoint::getProgramPoint(
-  cast(Call.getOriginExpr()),
+  Call.getOriginExpr(),
   ProgramPoint::PostStmtKind,

This is for fixing the unit test failures. 
Previously `assert` to check the type inside `cast`  was causing the 
unit test failures.
The reason was `CXXConstructExpr` was not inherited from `CallExpr` and the 
cast was causing the assert failure with `isa` check.

I am not sure removing the cast is the best solution.
And the TODO comment, I did not understood properly.

Alternative approach was to cast it to `CXXConstructExpr` if it is not 
`CallExpr` but not sure whether `runCheckersForEvalCall` should aware of  
`CXXConstructExpr`.



Comment at: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp:586
   ExplodedNodeSet dstCallEvaluated;
+  EvalCallOptions CallOpts;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,

NoQ wrote:
> vrnithinkumar wrote:
> > NoQ wrote:
> > > If you want you can make it an optional argument of 
> > > `runCheckersForEvalCall()`, like it's done in `defaultEvalCall()`.
> > I tried to make it as default argument for `runCheckersForEvalCall()` but 
> > `struct EvalCallOptions` is forward declared in `CheckerManager.h`.
> Oh well! You probably still don't need a separate local variable, can you try 
> `EvalCallOptions()` or even `{}`?
Updated to use `EvalCallOptions()`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: [analyzer] Enable constructor support in evalCall event

2020-06-24 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 273162.
vrnithinkumar added a comment.

clang-format fix


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
  clang/test/Analysis/new-ctor-conservative.cpp

Index: clang/test/Analysis/new-ctor-conservative.cpp
===
--- clang/test/Analysis/new-ctor-conservative.cpp
+++ clang/test/Analysis/new-ctor-conservative.cpp
@@ -27,6 +27,7 @@
   S *s = new S[10];
   // FIXME: Should be true once we inline array constructors.
   clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}}
 }
 
 struct NullS {
Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- /dev/null
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:  -analyzer-checker=debug.AnalysisOrder \
+// RUN:  -analyzer-config debug.AnalysisOrder:EvalCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PreCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PostCall=true \
+// RUN:  2>&1 | FileCheck %s
+
+// This test ensures that eval::Call event will be triggered for constructors.
+
+class C {
+public:
+  C(){};
+  C(int x){};
+  C(int x, int y){};
+};
+
+void foo() {
+  C C0;
+  C C1(42);
+  C *C2 = new C{2, 3};
+}
+
+// CHECK:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 0} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 1} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 2} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -50,6 +50,7 @@
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
+// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false
 // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false
 // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false
 // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -584,7 +584,7 @@
   // defaultEvalCall if all of them fail.
   ExplodedNodeSet dstCallEvaluated;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
- Call, *this);
+ Call, *this, EvalCallOptions());
 
   // If there were other constructors called for object-type arguments
   // of this call, clean them up.
@@ -717,7 +717,7 @@
 ExprEngine::CallInlinePolicy
 ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
   AnalyzerOptions &Opts,
-  const ExprEngine::EvalCallOptions &CallOpts) {
+  const EvalCallOptions &CallOpts) {
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -615,7 +615,8 @@
   } else {
 for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
  I != E; ++I)
-  defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, *this,
+   

[PATCH] D82256: [analyzer] Enable constructor support in evalCall event

2020-06-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added a comment.

In D82256#2113233 , @NoQ wrote:

> @vrnithinkumar what's your preferred `Full Name ` for llvm's git?


Nithin Vadukkumchery Rajendrakumar 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82256: [analyzer] Enable constructor support in evalCall event

2020-06-25 Thread Nithin VR via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG37c1bf21d1da: [analyzer] Enable constructor support in 
evalCall event. (authored by vrnithinkumar, committed by Artem Dergachev 
).

Changed prior to commit:
  https://reviews.llvm.org/D82256?vs=273162&id=273430#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D82256/new/

https://reviews.llvm.org/D82256

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
  clang/lib/StaticAnalyzer/Core/CallEvent.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
  clang/test/Analysis/new-ctor-conservative.cpp

Index: clang/test/Analysis/new-ctor-conservative.cpp
===
--- clang/test/Analysis/new-ctor-conservative.cpp
+++ clang/test/Analysis/new-ctor-conservative.cpp
@@ -27,6 +27,7 @@
   S *s = new S[10];
   // FIXME: Should be true once we inline array constructors.
   clang_analyzer_eval(s[0].x == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(s[1].x == 1); // expected-warning{{UNKNOWN}}
 }
 
 struct NullS {
Index: clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
===
--- /dev/null
+++ clang/test/Analysis/cxxctr-evalcall-analysis-order.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:  -analyzer-checker=debug.AnalysisOrder \
+// RUN:  -analyzer-config debug.AnalysisOrder:EvalCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PreCall=true \
+// RUN:  -analyzer-config debug.AnalysisOrder:PostCall=true \
+// RUN:  2>&1 | FileCheck %s
+
+// This test ensures that eval::Call event will be triggered for constructors.
+
+class C {
+public:
+  C(){};
+  C(int x){};
+  C(int x, int y){};
+};
+
+void foo() {
+  C C0;
+  C C1(42);
+  C *C2 = new C{2, 3};
+}
+
+// CHECK:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 0} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 1} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  PreCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PostCall (operator new) [CXXAllocatorCall]
+// CHECK-NEXT:  PreCall (C::C) [CXXConstructorCall]
+// CHECK-NEXT:  EvalCall (C::C) {argno: 2} [CXXConstructorCall]
+// CHECK-NEXT:  PostCall (C::C) [CXXConstructorCall]
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -50,6 +50,7 @@
 // CHECK-NEXT: debug.AnalysisOrder:Bind = false
 // CHECK-NEXT: debug.AnalysisOrder:EndAnalysis = false
 // CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
+// CHECK-NEXT: debug.AnalysisOrder:EvalCall = false
 // CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false
 // CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false
 // CHECK-NEXT: debug.AnalysisOrder:PointerEscape = false
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -584,7 +584,7 @@
   // defaultEvalCall if all of them fail.
   ExplodedNodeSet dstCallEvaluated;
   getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
- Call, *this);
+ Call, *this, EvalCallOptions());
 
   // If there were other constructors called for object-type arguments
   // of this call, clean them up.
@@ -717,7 +717,7 @@
 ExprEngine::CallInlinePolicy
 ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
   AnalyzerOptions &Opts,
-  const ExprEngine::EvalCallOptions &CallOpts) {
+  const EvalCallOptions &CallOpts) {
   const LocationContext *CurLC = Pred->getLocationContext();
   const StackFrameContext *CallerSFC = CurLC->getStackFrame();
   switch (Call.getKind()) {
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -615,7 +615,8 @@
   } else {
 for (ExplodedNodeSet::iterator I = DstP

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 273568.
vrnithinkumar marked 16 inline comments as done.
vrnithinkumar added a comment.

Addressing review comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  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
@@ -1,5 +1,6 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
 // RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtr:CheckSmartPtrDereference=true\
 // RUN:   -std=c++11 -verify %s
 
 #include "Inputs/system-header-simulator-cxx.h"
@@ -10,7 +11,7 @@
   std::unique_ptr 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).
@@ -26,3 +27,70 @@
   (s->*func)(); // no-crash
 }
 } // namespace testUnknownCallee
+
+class A {
+public:
+  A(){};
+  void foo();
+};
+
+A *return_null() {
+  return nullptr;
+}
+
+void derefAfterValidCtr() {
+  std::unique_ptr P(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterDefaultCtr() {
+  std::unique_ptr P;
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNull() {
+  std::unique_ptr P(nullptr);
+  *P; // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNullReturnMethod() {
+  std::unique_ptr P(return_null());
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterRelease() {
+  std::unique_ptr P(new A());
+  P.release();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterReset() {
+  std::unique_ptr P(new A());
+  P.reset();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNull() {
+  std::unique_ptr P(new A());
+  P.reset(nullptr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNonNull() {
+  std::unique_ptr P;
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterReleaseAndResetWithNonNull() {
+  std::unique_ptr P(new A());
+  P.release();
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefOnReleasedNullRawPtr() {
+  std::unique_ptr P;
+  A *AP = P.release();
+  AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -39,6 +39,7 @@
 // CHECK-NEXT: core.CallAndMessage:ParameterCount = true
 // CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
 // CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
+// CHECK-NEXT: cplusplus.SmartPtr:CheckSmartPtrDereference = false
 // CHECK-NEXT: crosscheck-with-z3 = false
 // CHECK-NEXT: ctu-dir = ""
 // CHECK-NEXT: ctu-import-threshold = 100
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -946,10 +946,15 @@
   template  // 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 &p) const;
 
 typename std::add_lvalue_reference::type operator*() const;
 T *operator->() const;
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -13,26 +13,60 @@
 
 #include "Move.h"
 
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/Path

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:35
   bool isNullAfterMoveMethod(const CallEvent &Call) const;
+  BugType NullDereferenceBugType{this, "Null-smartPtr-deref",
+ "C++ smart pointer"};

xazax.hun wrote:
> Nit: We do not use hypens/dashes in diagnostic names.
Fixed the format



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:53
+  // Set of STL smart pointer class which we are trying to model.
+  const llvm::StringSet<> StdSmartPtrs = {
+  "shared_ptr",

xazax.hun wrote:
> It might be just a personal preference but I tend to put these at the top of 
> the file for easier discoverability. Feel free to ignore this comment unless 
> other reviewers have the same preference as me.
Thanks!
Moved to top.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:81
 CheckerContext &C) const {
-  if (!isNullAfterMoveMethod(Call))
+  if (isNullAfterMoveMethod(Call)) {
+ProgramStateRef State = C.getState();

xazax.hun wrote:
> Don't we want this to be also protected by the `isStdSmartPointerClass` check?
added `isStdSmartPointerClass` check in the beginning.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:115
+  const auto *MethodDecl = dyn_cast(Call.getDecl());
+  if (!MethodDecl || !isStdSmartPointerClass(MethodDecl->getParent()))
+return;

xazax.hun wrote:
> I wonder if making `isStdSmartPointerClass` operate on `CallEvent` would 
> simllify the call sites of this function.
Yeah. Thanks!
That makes it better.
Made changes to pass `CallEvent` to `isStdSmartPointerClass`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:124
+return;
+  updateTrackedRegion(Call, C, ThisValRegion);
+}

NoQ wrote:
> NoQ wrote:
> > Not all constructors behave this way. In particular, if it's a copy/move 
> > constructor this function would track the value of the original smart 
> > pointer to this smart pointer, but what we need is to track the value of 
> > the raw pointer instead.
> Actually, let's add an assertion into `updateTrackedRegion` that the value 
> that's put into the map is of pointer type. This would give us an automatic 
> notification when we make such mistakes.
- Added check to filter out copy/move constructor
- Added  assert to check the value is of type pointer.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:137
+if (IsRegDead) {
+  State = State->remove(Region);
+}

NoQ wrote:
> xazax.hun wrote:
> > In LLVM we often omit braces for small single statement branches. Also, 
> > Artem mentioned that we could interact with the malloc checker. Maybe it is 
> > worth considering to notify the malloc checker to mark the appropriate 
> > region as deallocated? This would help find double release errors, avoid 
> > spurious leak errors and so on. 
> > Maybe it is worth considering to notify the malloc checker to mark the 
> > appropriate region as deallocated?
> 
> This happens in destructor.
removed the braces



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:155
+
+  if (MethodDecl && MethodDecl->isOverloadedOperator()) {
+OverloadedOperatorKind OOK = MethodDecl->getOverloadedOperator();

xazax.hun wrote:
> Early returns can decrease the indentation. 
Updated with early return. 
Thanks!



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:175
+return;
+  updateTrackedRegion(Call, C, ThisValRegion);
+}

NoQ wrote:
> When you're doing `evalCall`, you're responsible for all aspects of the call 
> - not just your private GDM map but also the Store and the Environment.
> 
> For `.reset()` the other important thing to do would be to invalidate the 
> region in the Store so that the Store did not think that it contains the old 
> value. We can't set the new value correctly but invalidating it would still 
> be better than doing nothing - simply because "not being sure" is not as bad 
> as "being confidently incorrect". That said, once you model *all* methods of 
> the smart pointers, you would probably no longer need to invalidate the 
> Store, because it will never be actually accessed during analysis. So my 
> conclusion here is:
> - For this first patch invalidating the Store is probably not worth it but 
> let's add a FIXME.
> - We should make sure that we eventually add the invalidation if we don't 
> have time to model all methods.
> 
> Now, you're calling this same function for `.release()` as well. And for 
> `.release()` there is another important thing that we're responsible for: 
> //model the return value//. The `.release()` method returns the raw pointer - 
> which i

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added a comment.

In D81315#2079457 , @Szelethus wrote:

> Best of luck on your GSoC! I don't have much else to add to your patch, but 
> you seem to have made good progress already!


Thanks!

> In D81315#2078043 , @xazax.hun wrote:
> 
>> some folks have automated scripts based on that tag to add themselves as 
>> subscriber/reviewer.
> 
> 
> Hope you don't mind my intrusion :)

Not at all.

>> I am not sure about whether I should use eval::Call or both check::PreCall 
>> and check::PostCall. In the eval::Call documentation I found this "Note, 
>> that only one checker can evaluate a call.". So I am little bit confused 
>> about using it.
> 
> Inlining (when we model a function call, https://youtu.be/yh2qdnJjizE?t=238) 
> is rather expensive. Creating a new stack frame, parameters, new 
> `ExplodedNode`s, running checkers, etc., eats memory for breakfast, is slow 
> and limits how deep the analysis can go. Worse still, the analysis could lose 
> precision if the called function's definition isn't available. `eval::Call` 
> serves to circumvent this by allowing the analyzer to give a precise summary 
> of the function. `StreamChecker`, for instance, uses this for functions such 
> as `clearerr()` -- the C standard defines how this function should behave, so 
> upon encountering a call to it, we don't need all the extra work regular 
> inlining demands, just ask `StreamChecker` to model it for us.
> 
> Use `eval::Call` if you can provide a precise model for a function. Only a 
> single checker is allowed to do that -- you can see that it returns with a 
> boolean value to sign whether the checker could provide an evaluation, and as 
> far as I know, the first checker that returns true will be doing it.
> 
> I think it would be appropriate in this instance, because we're modeling a 
> well established API. In general, I think we should use it when appropriate 
> more often, like in MallocChecker.

Thank you for the detailed help.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 273841.
vrnithinkumar added a comment.

Moving dereference precondition checks  into `checkPreCall`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315

Files:
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/analyzer-config.c
  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
@@ -1,5 +1,6 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
 // RUN:   -analyzer-checker cplusplus.Move,cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtr:CheckSmartPtrDereference=true\
 // RUN:   -std=c++11 -verify %s
 
 #include "Inputs/system-header-simulator-cxx.h"
@@ -10,7 +11,7 @@
   std::unique_ptr 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).
@@ -26,3 +27,70 @@
   (s->*func)(); // no-crash
 }
 } // namespace testUnknownCallee
+
+class A {
+public:
+  A(){};
+  void foo();
+};
+
+A *return_null() {
+  return nullptr;
+}
+
+void derefAfterValidCtr() {
+  std::unique_ptr P(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterDefaultCtr() {
+  std::unique_ptr P;
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNull() {
+  std::unique_ptr P(nullptr);
+  *P; // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterCtrWithNullReturnMethod() {
+  std::unique_ptr P(return_null());
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterRelease() {
+  std::unique_ptr P(new A());
+  P.release();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterReset() {
+  std::unique_ptr P(new A());
+  P.reset();
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNull() {
+  std::unique_ptr P(new A());
+  P.reset(nullptr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer [cplusplus.SmartPtr]}}
+}
+
+void derefAfterResetWithNonNull() {
+  std::unique_ptr P;
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefAfterReleaseAndResetWithNonNull() {
+  std::unique_ptr P(new A());
+  P.release();
+  P.reset(new A());
+  P->foo(); // No warning.
+}
+
+void derefOnReleasedNullRawPtr() {
+  std::unique_ptr P;
+  A *AP = P.release();
+  AP->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
Index: clang/test/Analysis/analyzer-config.c
===
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -39,6 +39,7 @@
 // CHECK-NEXT: core.CallAndMessage:ParameterCount = true
 // CHECK-NEXT: core.CallAndMessage:UndefReceiver = true
 // CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals
+// CHECK-NEXT: cplusplus.SmartPtr:CheckSmartPtrDereference = false
 // CHECK-NEXT: crosscheck-with-z3 = false
 // CHECK-NEXT: ctu-dir = ""
 // CHECK-NEXT: ctu-import-threshold = 100
Index: clang/test/Analysis/Inputs/system-header-simulator-cxx.h
===
--- clang/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ clang/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -946,10 +946,15 @@
   template  // 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 &p) const;
 
 typename std::add_lvalue_reference::type operator*() const;
 T *operator->() const;
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -13,26 +13,62 @@
 
 #include "Move.h"
 
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallE

[PATCH] D81315: [analyzer] Warning for default constructed unique pointer dereferences

2020-06-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:117-118
 
-  // TODO: Add a note to bug reports describing this decision.
-  C.addTransition(
-  State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
-  C.getSValBuilder().makeZeroVal(Call.getResultType(;
+  if (checkDeferenceOps(Call, C))
+return true;
+

NoQ wrote:
> By returning "true" here you're saying that operators `*` and `->` do 
> nothing. That's not quite right; they return a value. You should not return 
> `true` from `evalCall` unless you //fully// model the call.
> 
> I wouldn't mind moving //precondition// checks such as this one into 
> `checkPreCall`, even if you do `evalCall` later. That would clearly separate 
> concerns and avoid the need to figure out whether we still need to model the 
> call after the bug-reporting routine finishes (the engine will do that for 
> you automatically).
> 
> In fact i wouldn't mind moving all bug reporting functionality into a 
> separate //checker//. But that's a story for another time^^
> By returning "true" here you're saying that operators * and -> do nothing. 
> That's not quite right; they return a value. You should not return true from 
> evalCall unless you fully model the call.

Thanks!
I completely missed this point.

> I wouldn't mind moving precondition checks such as this one into 
> checkPreCall, even if you do evalCall later. That would clearly separate 
> concerns and avoid the need to figure out whether we still need to model the 
> call after the bug-reporting routine finishes (the engine will do that for 
> you automatically).
Made changes to move dereference precondition checks into `checkPreCall`

> In fact i wouldn't mind moving all bug reporting functionality into a 
> separate checker. But that's a story for another time^^
Cool!
I will keep this in mind.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D81315/new/

https://reviews.llvm.org/D81315



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-07-31 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:408-412
+SmallString<128> Msg;
+llvm::raw_svector_ostream Out(Msg);
+TagDetails.trackValidExpr(BR);
+TagDetails.explainSmartPtrAction(Out);
+return std::string(Out.str());

NoQ wrote:
> NoQ wrote:
> > Ok, note that note tags are attached to nodes independently of bug reports; 
> > when the report is thrown, only then we know what are the smart pointers 
> > that should be explained.
> > 
> > So there are two checks that you should do here:
> > 
> > 1. Check that the bug report is emitted by your checker (eg., by comparing 
> > bug types). If not, don't add notes.
> > 
> > 2. Check that the region about which the note speaks is related to your 
> > report (i.e., it's not a completely unrelated smart pointer). You can do 
> > that by marking the smart pointer as "interesting" (i.e., 
> > `PathSensitiveBugReport::markIntersting()`) when you emit the report, and 
> > then in the lambda you check whether the smart pointer is interesting 
> > before you emit a note. Additionally, you can carry over interestingness 
> > when smart pointers are copied.
> > 
> > This is what i was trying to accomplish with this code snippet that i 
> > included in the examples in the other comment:
> > ```lang=c++
> >   if (&BR.getBugType() != &NullDereferenceBugType || !R->isInteresting())
> > return "";
> > ```
> (i strongly recommend having test cases for both of these issues)
I was stuck on how to check the 2 cases from `SmartPtrModeling`.

1. I was not able to figure out how to access `NullDereferenceBugType` defined 
in the `SmartPtrChecker` in `SmartPtrModeling` to check `&BR.getBugType() != 
&NullDereferenceBugType`. Since `NullDereferenceBugType` is part of the 
`SmartPtrChecker` I could not access it from `PathSensitiveBugReport`.  One way 
I figured out is to use `getCheckerName()` on BugType and compare the string. I 
feel this one as little hacky.


2. I got stuck on how will we implement the `!R->isInteresting()` in case of 
the bug report is added by some other checker on some other region. For below 
test case, bug report is added on a raw pointer by `CallAndMessageChecker` and 
the `!R->isInteresting()` will not satisfy and we will not be adding note tags 
where `unique_ptr` is released. I tried getting the LHS region for `A *AP = 
P.release();` assignment operation and check if the region is interesting but 
not sure whether its gonna work for some complex assignment cases.

```
void derefOnReleasedNullRawPtr() {
  std::unique_ptr P;
  A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer 
value}}
  // expected-note@-1 {{Smart pointer '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}}
}
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-07-31 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:408-412
+SmallString<128> Msg;
+llvm::raw_svector_ostream Out(Msg);
+TagDetails.trackValidExpr(BR);
+TagDetails.explainSmartPtrAction(Out);
+return std::string(Out.str());

NoQ wrote:
> NoQ wrote:
> > vrnithinkumar wrote:
> > > NoQ wrote:
> > > > NoQ wrote:
> > > > > Ok, note that note tags are attached to nodes independently of bug 
> > > > > reports; when the report is thrown, only then we know what are the 
> > > > > smart pointers that should be explained.
> > > > > 
> > > > > So there are two checks that you should do here:
> > > > > 
> > > > > 1. Check that the bug report is emitted by your checker (eg., by 
> > > > > comparing bug types). If not, don't add notes.
> > > > > 
> > > > > 2. Check that the region about which the note speaks is related to 
> > > > > your report (i.e., it's not a completely unrelated smart pointer). 
> > > > > You can do that by marking the smart pointer as "interesting" (i.e., 
> > > > > `PathSensitiveBugReport::markIntersting()`) when you emit the report, 
> > > > > and then in the lambda you check whether the smart pointer is 
> > > > > interesting before you emit a note. Additionally, you can carry over 
> > > > > interestingness when smart pointers are copied.
> > > > > 
> > > > > This is what i was trying to accomplish with this code snippet that i 
> > > > > included in the examples in the other comment:
> > > > > ```lang=c++
> > > > >   if (&BR.getBugType() != &NullDereferenceBugType || 
> > > > > !R->isInteresting())
> > > > > return "";
> > > > > ```
> > > > (i strongly recommend having test cases for both of these issues)
> > > I was stuck on how to check the 2 cases from `SmartPtrModeling`.
> > > 
> > > 1. I was not able to figure out how to access `NullDereferenceBugType` 
> > > defined in the `SmartPtrChecker` in `SmartPtrModeling` to check 
> > > `&BR.getBugType() != &NullDereferenceBugType`. Since 
> > > `NullDereferenceBugType` is part of the `SmartPtrChecker` I could not 
> > > access it from `PathSensitiveBugReport`.  One way I figured out is to use 
> > > `getCheckerName()` on BugType and compare the string. I feel this one as 
> > > little hacky.
> > > 
> > > 
> > > 2. I got stuck on how will we implement the `!R->isInteresting()` in case 
> > > of the bug report is added by some other checker on some other region. 
> > > For below test case, bug report is added on a raw pointer by 
> > > `CallAndMessageChecker` and the `!R->isInteresting()` will not satisfy 
> > > and we will not be adding note tags where `unique_ptr` is released. I 
> > > tried getting the LHS region for `A *AP = P.release();` assignment 
> > > operation and check if the region is interesting but not sure whether its 
> > > gonna work for some complex assignment cases.
> > > 
> > > ```
> > > void derefOnReleasedNullRawPtr() {
> > >   std::unique_ptr P;
> > >   A *AP = P.release(); // expected-note {{'AP' initialized to a null 
> > > pointer value}}
> > >   // expected-note@-1 {{Smart pointer '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}}
> > > }
> > > ```
> > > Since `NullDereferenceBugType` is part of the `SmartPtrChecker` I could 
> > > not access it from `PathSensitiveBugReport`.
> > 
> > You shouldn't be accessing it from the bug report, you should be accessing 
> > it from the lambda. See the example code snippets in D84600#inline-779418
> > 
> > > For below test case, bug report is added on a raw pointer by 
> > > `CallAndMessageChecker` and the `!R->isInteresting()` will not satisfy 
> > > and we will not be adding note tags where `unique_ptr` is released.
> > 
> > That's an interesting question (no pun intended). The way i imagine this 
> > working is: the note tag for `.release()` should try to figure out whether 
> > the raw pointer is tracked and mark the smart pointer as interesting based 
> > on that. If the raw pointer was a symbol that would have been easy (either 
> > null dereference checker or `trackExpressionValue()` could mark it as 
> > interesting). But for concrete null pointer this won't work.
> > 
> > Maybe we should consider introducing interesting expressions. I.e., when 
> > `trackExpressionValue()` reaches the call-expression `P.release()`, it has 
> > to stop there. But if it also marked the call-expression as interesting, 
> > the note tag provided by the checker could read that interestingness 
> > information and act upon it by marking the smart pointer region as 
> > interesting.
> >  That's an interesting question
> 
> I'd rather make a separate commit for this endeavor because it sounds pretty 
> nasty.
> You shouldn't be accessing it from the bug report, you should be accessing it 
> from the lambda. See the exam

[PATCH] D83877: [Analyzer] Handle unique_ptr::swap() in SmartPtrModeling

2020-08-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

In D83877#2189637 , @NoQ wrote:

> These patches look like they're done, maybe let's land them?

I have already committed this changes.  
https://github.com/llvm/llvm-project/commit/76c0577763505ea3db1017a9aab579c1c2f135d0




Comment at: clang/test/Analysis/Inputs/system-header-simulator-cxx.h:964-965
+
+  template 
+  void swap(unique_ptr &x, unique_ptr &y) noexcept {
+x.swap(y);

NoQ wrote:
> vrnithinkumar wrote:
> > xazax.hun wrote:
> > > NoQ wrote:
> > > > You seem to be relying on the fact that global `std::swap` is 
> > > > implemented in terms of the member `std::swap`. That's an 
> > > > implementation detail of the standard library; i'm not sure that this 
> > > > is always the case. Ideally we should model the global `std::swap` 
> > > > separately.
> > > I am not sure how reliable cppreference is, but I think this overload 
> > > might actually be guaranteed by the standard: 
> > > https://en.cppreference.com/w/cpp/memory/unique_ptr/swap2
> > I also made the assumption based on this 
> > (https://en.cppreference.com/w/cpp/memory/unique_ptr/swap2).
> > 
> Aha, interesting. We still probably can't rely on it being always inlined 
> though, so we'll still probably have to model it separately.
Okay. We will add the separate modeling for `std::swap`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83877/new/

https://reviews.llvm.org/D83877

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D83836: [Analyzer] Add checkRegionChanges for SmartPtrModeling

2020-08-02 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

In D83836#2189636 , @NoQ wrote:

> These patches look like they're done, maybe let's land them?

This one also committed. 
(https://github.com/llvm/llvm-project/commit/a5609102117d2384fb73a14f37d24a0c844e3864)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83836/new/

https://reviews.llvm.org/D83836

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-03 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 282771.
vrnithinkumar marked 10 inline comments as done.
vrnithinkumar edited the summary of this revision.
vrnithinkumar added a comment.

- Addressing review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/NullDereference.h
  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 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 P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterRelease() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterReset() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr 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' [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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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' [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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 StructWithSmartPtr S;
@@ -172,7 +179,7 @@
   {
 StructWithSmartPtr S;
 pass_struct_with_smart_ptr_by_const_rvalu

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-03 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:86
+  if (const auto *DR = dyn_cast(DerefRegion)) {
+auto SmartPtrName = DR->getDecl()->getName();
+OS << " '" << SmartPtrName << "'";

NoQ wrote:
> Please `getNameAsString()` because `getName()` crashes on anonymous 
> declarations (eg., lambda captures, anonymous nested structs/unions, etc.).
Changed to use `getNameAsString()`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:95-96
+
+  const auto *RecordDecl = MethodDecl->getParent();
+  if (RecordDecl && RecordDecl->getDeclName().isIdentifier()) {
+OS << " of type '" << RecordDecl->getQualifiedNameAsString() << "'";

NoQ wrote:
> Aha, this time you checked for anonymous declarations! Good.
> 
> That said, i'm not sure type is actually useful for this warning, because 
> they're roughly all the same.
Okay. I was trying to be consistent with `MoveChecker`.
Just removed smart pointer type.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:179
+
+  switch (SmartPtrMethod) {
+  case Constructor: {

NoQ wrote:
> NoQ wrote:
> > I feel this is a bit over-engineered. There's no need to create an enum and 
> > later convert it into a string when you can capture a string directly. 
> > Like, this entire "details" structure of your, it should be just captures 
> > instead, and your strings would make it immediately obvious what kind of 
> > note is emitted:
> > ```lang=c++
> > C.addTransition(State, getNoteTag([R](PathSensitiveBugReport &BR) {
> >   if (&BR.getBugType() != &NullDereferenceBugType || !R->isInteresting())
> > return "";
> >  
> >   return Twine("Default constructed smart pointer '") + getSmartPtrName(R) 
> > + "' is null";
> > }));
> > ```
> > 
> > Hmm, maybe we should also provide an overload with lambdas of 
> > signature`void(PathSensitiveBugReport &BR, llvm::raw_ostream OS)` so that 
> > to make the same one-liners possible with streams? Something like this:
> > 
> > ```lang=c++
> > class CheckerContext {
> > // ...
> >   NoteTag *getNoteTag(std::function > llvm::raw_ostream OS)> f) {
> > return getNoteTag([](PathSensitiveBugReport &BR) -> std::string {
> >   llvm::SmallString<128> Str;
> >   llvm::raw_svector_ostream OS(Str);
> >   f(BR, OS);
> >   return OS.str();
> > });
> >   }
> > // ...
> > };
> > ```
> > 
> > Then you could do:
> > ```lang=c++
> > C.addTransition(State, getNoteTag([R](PathSensitiveBugReport &BR) {
> >   if (&BR.getBugType() != &NullDereferenceBugType || !R->isInteresting())
> > return;
> > 
> >   OS << "Default constructed smart pointer '" << getSmartPtrName(R) << "' 
> > is null";
> > }));
> > ```
> (forgot `, llvm::raw_ostream OS` in the last snippet; probably forgot a bunch 
> of other stuff because i didn't try to actually compile these snippets)
- Added overload for `getNoteTag` with lambda accepting a `llvm::raw_ostream`
- Used the overload instead of `SmartPtrTagDetails` structure to add tags.
- Removed the `SmartPtrTagDetails` and changed related code.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:408-412
+SmallString<128> Msg;
+llvm::raw_svector_ostream Out(Msg);
+TagDetails.trackValidExpr(BR);
+TagDetails.explainSmartPtrAction(Out);
+return std::string(Out.str());

NoQ wrote:
> NoQ wrote:
> > vrnithinkumar wrote:
> > > NoQ wrote:
> > > > NoQ wrote:
> > > > > vrnithinkumar wrote:
> > > > > > NoQ wrote:
> > > > > > > NoQ wrote:
> > > > > > > > Ok, note that note tags are attached to nodes independently of 
> > > > > > > > bug reports; when the report is thrown, only then we know what 
> > > > > > > > are the smart pointers that should be explained.
> > > > > > > > 
> > > > > > > > So there are two checks that you should do here:
> > > > > > > > 
> > > > > > > > 1. Check that the bug report is emitted by your checker (eg., 
> > > > > > > > by comparing bug types). If not, don't add notes.
> > > > > > > > 
> > > > > > > > 2. Check that the region about which the note speaks is related 
> > > > > > > > to your report (i.e., it's not a completely unrelated smart 
> > > > > > > > pointer). You can do that by marking the smart pointer as 
> > > > > > > > "interesting" (i.e., 
> > > > > > > > `PathSensitiveBugReport::markIntersting()`) when you emit the 
> > > > > > > > report, and then in the lambda you check whether the smart 
> > > > > > > > pointer is interesting before you emit a note. Additionally, 
> > > > > > > > you can carry over interestingness when smart pointers are 
> > > > > > > > copied.
> > > > > > > > 
> > > > > > > > This is what i was trying to accomplish with this code snippet 
> > > > > > > > that i included in the examples in the other comment:
> > > > > > > > ```lang=c++
> > > > > > > >   if (&BR.getBugType() != &NullDerefe

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-04 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:110
+  SmartPtrChecker *Checker = Mgr.registerChecker();
+  NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
 }

NoQ wrote:
> Wait, i don't understand again. You're taking the bug type from that checker 
> and using it in that checker. Why did you need to make it global? I thought 
> your problem was about capturing the bug type from the //raw// null 
> dereference checker?
> Wait, i don't understand again. You're taking the bug type from that checker 
> and using it in that checker. Why did you need to make it global? I thought 
> your problem was about capturing the bug type from the //raw// null 
> dereference checker?

The check for bug type is in `SmartPtrModeling` but the bug type is defined in 
`SmartPtrChecker`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:95-96
+
+  const auto *RecordDecl = MethodDecl->getParent();
+  if (RecordDecl && RecordDecl->getDeclName().isIdentifier()) {
+OS << " of type '" << RecordDecl->getQualifiedNameAsString() << "'";

NoQ wrote:
> vrnithinkumar wrote:
> > NoQ wrote:
> > > Aha, this time you checked for anonymous declarations! Good.
> > > 
> > > That said, i'm not sure type is actually useful for this warning, because 
> > > they're roughly all the same.
> > Okay. I was trying to be consistent with `MoveChecker`.
> > Just removed smart pointer type.
> These were important in `MoveChecker` because use-after-move rules for smart 
> pointers are different from use-after-move rules of any other class in the 
> standard library and the checker has to behave differently 
> (https://wiki.sei.cmu.edu/confluence/x/O3s-BQ).
Oh
That makes sense.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-05 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:110
+  SmartPtrChecker *Checker = Mgr.registerChecker();
+  NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
 }

xazax.hun wrote:
> NoQ wrote:
> > vrnithinkumar wrote:
> > > NoQ wrote:
> > > > Wait, i don't understand again. You're taking the bug type from that 
> > > > checker and using it in that checker. Why did you need to make it 
> > > > global? I thought your problem was about capturing the bug type from 
> > > > the //raw// null dereference checker?
> > > > Wait, i don't understand again. You're taking the bug type from that 
> > > > checker and using it in that checker. Why did you need to make it 
> > > > global? I thought your problem was about capturing the bug type from 
> > > > the //raw// null dereference checker?
> > > 
> > > The check for bug type is in `SmartPtrModeling` but the bug type is 
> > > defined in `SmartPtrChecker`
> > Aha, ok, i misunderstood again. So i guess we didn't need a new header 
> > then. That said, it's an interesting layering violation that we encounter 
> > in this design: it used to be up to the checker to attach a visitor and so 
> > should be activating a note tag, but note tags are part of modeling, not 
> > checking.
> > 
> > I guess that's just how it is and it's the responsibility of the checkers 
> > to inform the modeling about bug types. I guess the ultimate API could look 
> > like `BugReport->activateNoteTag(NoteTagTag TT)` (where `TT` is a crying 
> > smiley that cries about "tag tags" T_T). But that's a story for another 
> > time.
> I hope we will be able to figure out a nicer solution at some point. But I do 
> not have a better alternative now, so I am ok with committing as is.
> 
> The API Artem is suggesting looks good to me (although it is out of scope for 
> the GSoC). But I think that might not solve the problem of how multiple 
> checkers should share the information about those tags. (Or at least I do not 
> see how.)
> 
> Note that if we had both checks in the same file we might be able to work 
> this problem around using `CheckerManager::getChecker`. I am not suggesting 
> merging them, only wanted to point out.
>  So i guess we didn't need a new header then.
So we should remove the `NullDereference.h` and add the inter checker api to 
get the BugType to `SmartPtr.h`?

>  I guess the ultimate API could look like 
> `BugReport->activateNoteTag(NoteTagTag TT)`
Do we have to make these api changes on this review? Or some follow up changes?



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:352
+// Gets the SVal to track for a smart pointer memory region
+SVal SmartPtrModeling::getSValForRegion(const CallEvent &Call,
+CheckerContext &C) const {

xazax.hun wrote:
> I am a bit unhappy with this function.
> I feel like it does not really have a purpose. It returns the null constant 
> for default constructor calls, for every other case it just returns the first 
> argument. The branch we have in this function would completely go away if we 
> would inline this to all the call sites and the result would be a single line 
> each place. I'd rather just remove this function.
Also we have to assert that we are adding a pointer value to TrackedRegionMap.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-06 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 283602.
vrnithinkumar marked 13 inline comments as done.
vrnithinkumar added a comment.



- Changes from review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  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 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 P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterRelease() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterReset() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr 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' [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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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' [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 'S.P' [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-wa

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-06 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h:312
+  const NoteTag *getNoteTag(
+  std::function 
Cb,
+  bool IsPrunable = false) {

xazax.hun wrote:
> The callback is taken is an rvalue reference in other `getNoteTag` APIs. I 
> think these overloads should be consistent.
> Also, I wonder if the caller should be able to manipulate the buffer size of 
> the small string (as a template parameter), but I do not have strong feelings 
> about this. 
> 
> As a side note, since Clang is using C++14, maybe the lambda captures in the 
> `getNoteTag` overloads above should utilize it and capture the callback by 
> move. This is more of a note to ourselves independent of this patch. 
> 
> Side note 2: maybe a modernize tidy check would be useful to discover where 
> rvalue references are captured by value in lambdas?
Changed to rvalue reference.



Comment at: clang/lib/StaticAnalyzer/Checkers/NullDereference.h:21
+namespace ento {
+namespace nullDereference {
+

NoQ wrote:
> Namespaces are traditionally snake_case rather than camelCase.
removed the new namespace



Comment at: clang/lib/StaticAnalyzer/Checkers/NullDereference.h:23
+
+/// Returns NullDereferenceBugType.
+const BugType *getNullDereferenceBugType();

xazax.hun wrote:
> I think this comment does not really add much value.
Yeah.
removed it.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:110
+  SmartPtrChecker *Checker = Mgr.registerChecker();
+  NullDereferenceBugTypePtr = &Checker->NullDereferenceBugType;
 }

NoQ wrote:
> vrnithinkumar wrote:
> > xazax.hun wrote:
> > > NoQ wrote:
> > > > vrnithinkumar wrote:
> > > > > NoQ wrote:
> > > > > > Wait, i don't understand again. You're taking the bug type from 
> > > > > > that checker and using it in that checker. Why did you need to make 
> > > > > > it global? I thought your problem was about capturing the bug type 
> > > > > > from the //raw// null dereference checker?
> > > > > > Wait, i don't understand again. You're taking the bug type from 
> > > > > > that checker and using it in that checker. Why did you need to make 
> > > > > > it global? I thought your problem was about capturing the bug type 
> > > > > > from the //raw// null dereference checker?
> > > > > 
> > > > > The check for bug type is in `SmartPtrModeling` but the bug type is 
> > > > > defined in `SmartPtrChecker`
> > > > Aha, ok, i misunderstood again. So i guess we didn't need a new header 
> > > > then. That said, it's an interesting layering violation that we 
> > > > encounter in this design: it used to be up to the checker to attach a 
> > > > visitor and so should be activating a note tag, but note tags are part 
> > > > of modeling, not checking.
> > > > 
> > > > I guess that's just how it is and it's the responsibility of the 
> > > > checkers to inform the modeling about bug types. I guess the ultimate 
> > > > API could look like `BugReport->activateNoteTag(NoteTagTag TT)` (where 
> > > > `TT` is a crying smiley that cries about "tag tags" T_T). But that's a 
> > > > story for another time.
> > > I hope we will be able to figure out a nicer solution at some point. But 
> > > I do not have a better alternative now, so I am ok with committing as is.
> > > 
> > > The API Artem is suggesting looks good to me (although it is out of scope 
> > > for the GSoC). But I think that might not solve the problem of how 
> > > multiple checkers should share the information about those tags. (Or at 
> > > least I do not see how.)
> > > 
> > > Note that if we had both checks in the same file we might be able to work 
> > > this problem around using `CheckerManager::getChecker`. I am not 
> > > suggesting merging them, only wanted to point out.
> > >  So i guess we didn't need a new header then.
> > So we should remove the `NullDereference.h` and add the inter checker api 
> > to get the BugType to `SmartPtr.h`?
> > 
> > >  I guess the ultimate API could look like 
> > > `BugReport->activateNoteTag(NoteTagTag TT)`
> > Do we have to make these api changes on this review? Or some follow up 
> > changes?
> > So we should remove the `NullDereference.h` and add the inter checker api 
> > to get the BugType to `SmartPtr.h`?
> Yes.
> 
> > Do we have to make these api changes on this review? Or some follow up 
> > changes?
> You don't have to do this at all; i think you have enough stuff on your 
> plate. But if you like you can put up another patch later.
Removed the new header file and added to `SmartPtr.h`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:131
+  }
+  return nullptr;
+}

NoQ wrote:
> You never ever check for this case. Therefore this function entirely boils 
> down to `Call.getArgExpr(0)` which is shorter than `getFirstArgExpr(Call)` 
> anyway.
remov

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-08 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrChecker.cpp:33
 
+// Static global pointer to NullDereferenceBugType.
+static const BugType *NullDereferenceBugTypePtr;

xazax.hun wrote:
> I find this comment redundant as well. It just repeats what is already 
> evident from the code.
removed



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:63
+void derefOnReleasedNullRawPtr() {
+  std::unique_ptr P;
+  A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer 
value}}

NoQ wrote:
> Unlike the next line, this line deserves a note that `P` holds a null value.
Added a FIXEM to add note "Default constructed smart pointer 'P' is null"



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:65
+  A *AP = P.release(); // expected-note {{'AP' initialized to a null pointer 
value}}
+  //TODO add note "Smart pointer 'P' is released and set to null"
+  AP->foo(); // expected-warning {{Called C++ object pointer is null 
[core.CallAndMessage]}}

NoQ wrote:
> Such note is unnecessary. We don't care what happens to `P` after it's 
> released; we only care about its old value.
Removed this.



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:79
+
+// TODO: Enabale this test when "std::swap" is modeled seperately.
+void derefOnStdSwappedNullPtr() {

NoQ wrote:
> Instead of commenting out tests, i recommend testing the incorrect behavior 
> (with a FIXME comment telling us why it's incorrect). This way we'll be 
> notified when the test is fixed, accidentally or intentionally, and also 
> generally that's more testing for everybody.
I have commented out this since right now `std::swap` is using 
`unique_ptr.swap`.
So note tag for std::swap is added in header file  
`system-header-simulator-cxx.h`
eg:
`system-header-simulator-cxx.h Line 978: Swapped null smart pointer 'PNull' 
with smart pointer 'P'`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-08 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 284137.
vrnithinkumar marked 4 inline comments as done.
vrnithinkumar added a comment.

- Review comment changes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  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 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 P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterRelease() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterReset() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr 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' [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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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' [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 'S.P' [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 {{D

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-08 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added a comment.

In D84600#2203604 , @Szelethus wrote:

> Layering violations are a running theme in the analyzer -- CheckerRegistry 
> and the entire MallocChecker fiasco 
>  are two glaring examples. 
> Luckily, this isn't a severe case so I wouldn't worry about it much.
>
> I've been following your patches, but them mentors answer way ahead of me and 
> are very thorough :^) Best of luck with the finale!

Thanks for sharing checker dependency talk.
Also fo suggesting to separate checker and modeling from beginning.  :)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-08 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:79
+
+// TODO: Enabale this test when "std::swap" is modeled seperately.
+void derefOnStdSwappedNullPtr() {

vrnithinkumar wrote:
> NoQ wrote:
> > Instead of commenting out tests, i recommend testing the incorrect behavior 
> > (with a FIXME comment telling us why it's incorrect). This way we'll be 
> > notified when the test is fixed, accidentally or intentionally, and also 
> > generally that's more testing for everybody.
> I have commented out this since right now `std::swap` is using 
> `unique_ptr.swap`.
> So note tag for std::swap is added in header file  
> `system-header-simulator-cxx.h`
> eg:
> `system-header-simulator-cxx.h Line 978: Swapped null smart pointer 'PNull' 
> with smart pointer 'P'`
- Is it okay to add a expected-note on `system-header-simulator-cxx.h`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-09 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:79
+
+// TODO: Enabale this test when "std::swap" is modeled seperately.
+void derefOnStdSwappedNullPtr() {

NoQ wrote:
> vrnithinkumar wrote:
> > vrnithinkumar wrote:
> > > NoQ wrote:
> > > > Instead of commenting out tests, i recommend testing the incorrect 
> > > > behavior (with a FIXME comment telling us why it's incorrect). This way 
> > > > we'll be notified when the test is fixed, accidentally or 
> > > > intentionally, and also generally that's more testing for everybody.
> > > I have commented out this since right now `std::swap` is using 
> > > `unique_ptr.swap`.
> > > So note tag for std::swap is added in header file  
> > > `system-header-simulator-cxx.h`
> > > eg:
> > > `system-header-simulator-cxx.h Line 978: Swapped null smart pointer 
> > > 'PNull' with smart pointer 'P'`
> > - Is it okay to add a expected-note on `system-header-simulator-cxx.h`?
> Aha, i see.
> 
> It's obviously not ok because the header is included by multiple tests but 
> only some tests will have the note show up.
> 
> The usual solution is to put the expected-note comment in the current test 
> file but make it refer to the header. Here's doc from 
> https://clang.llvm.org/doxygen/classclang_1_1VerifyDiagnosticConsumer.html:
> > If the diagnostic is generated in a separate file, for example in a shared 
> > header file, it may be beneficial to be able to declare the file in which 
> > the diagnostic will appear, rather than placing the expected-* directive in 
> > the actual file itself. This can be done using the following syntax:
> > ```// expected-error@path/include.h:15 {{error message}}```
> 
> It still is a bit of a problem that you have to hardcode the line number (so 
> everybody who modifies the header above your note will have to update your 
> test) but that's not a big deal.
Thanks!
Added the tags for the line from header file.



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-09 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 284237.
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

- Updating test with tags from header file


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  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 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 P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterRelease() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterReset() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr 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' [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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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' [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 'S.P' [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(); // ex

[PATCH] D84600: [Analyzer] Support note tags for smart ptr checker

2020-08-11 Thread Nithin VR via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG06d100a69a08: [Analyzer] Support note tags for smart ptr 
checker (authored by vrnithinkumar).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84600/new/

https://reviews.llvm.org/D84600

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  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 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 P;
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
-  *P; // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+  *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefAfterCtrWithNullReturnMethod() {
-  std::unique_ptr P(return_null());
-  P->foo(); // expected-warning {{Dereference of null smart pointer [alpha.cplusplus.SmartPtr]}}
+void derefAfterCtrWithNullVariable() {
+  A *InnerPtr = nullptr;
+  std::unique_ptr P(InnerPtr);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterRelease() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterReset() {
   std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterResetWithNull() {
   std::unique_ptr 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' [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 P(new A());
+  A *AP = P.release();
+  AP->foo(); // No warning.
+}
+
 void pass_smart_ptr_by_ref(std::unique_ptr &a);
 void pass_smart_ptr_by_const_ref(const std::unique_ptr &a);
 void pass_smart_ptr_by_rvalue_ref(std::unique_ptr &&a);
@@ -118,7 +125,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -128,7 +135,7 @@
   {
 std::unique_ptr 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' [alpha.cplusplus.SmartPtr]}}
   }
   {
 std::unique_ptr P;
@@ -138,7 +145,7 @@
   {
 std::unique_ptr 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' [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 'S.P' [alpha.cplusplus.SmartPtr]}}
   }
   {
 StructWithSmartPtr S;
@@ -172,7 +179,7 @@
   {
 StructWithSmartPtr S;
 pass_struct_with

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-11 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar created this revision.
Herald added subscribers: cfe-commits, martong.
Herald added a project: clang.
vrnithinkumar requested review of this revision.

Fixing tests


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85796

Files:
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.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
@@ -41,6 +41,7 @@
 
 void derefAfterValidCtr() {
   std::unique_ptr P(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -50,17 +51,20 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr P;
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNullVariable() {
   A *InnerPtr = nullptr;
   std::unique_ptr P(InnerPtr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
@@ -87,6 +91,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -135,7 +140,7 @@
   {
 std::unique_ptr P;
 pass_smart_ptr_by_const_rvalue_ref(std::move(P));
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+P->foo(); // no-warning
   }
   {
 std::unique_ptr P;
@@ -145,7 +150,7 @@
   {
 std::unique_ptr P;
 pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+P->foo(); // no-warning
   }
 }
 
@@ -179,17 +184,17 @@
   {
 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]}}
+S.P->foo(); // no-warning
   }
   {
 StructWithSmartPtr S;
 pass_struct_with_smart_ptr_by_ptr(&S);
-S.P->foo();
+S.P->foo(); // no-warning
   }
   {
 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]}}
+S.P->foo(); // no-warning
   }
 }
 
@@ -217,14 +222,20 @@
   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
-void derefOnStdSwappedNullPtr() {
+void derefOnFirstStdSwappedNullPtr() {
   std::unique_ptr P;
   std::unique_ptr 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 P;
+  std::unique_ptr PNull;
+  std::swap(P, PNull);
+  PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
 void derefOnSwappedValidPtr() {
   std::unique_ptr P(new A());
   std::unique_ptr PValid(new A());
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -36,14 +36,14 @@
 }
 
 void derefAfterRelease() {
-  std::unique_ptr P(new A());
+  std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
   P.release(); // expected-note {{Smart pointer 'P' is released and set to null}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
 void derefAfterReset() {
-  std::unique_ptr P(new A());
+  std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
   P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
@@ -51,7 +51,7 @@
 
 void derefAfterResetWithNull() {
   A *NullInnerPtr = nullptr; // expected-note {{'NullInnerPtr' initialized to a null pointer value}}
-  s

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-12 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp:619
   getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, 
*this,
- CallOpts);
+ CallOpts, Bldr);
   }

NoQ wrote:
> We should probably delete the copy-constructor for node builders. I've no 
> idea what it's supposed to do anyway and the whole problem that we're having 
> here is due to there being //too many// of them already.
So we should disable the copying of `NodeBuilder` and create a heap allocated 
`NodeBuilder` and use pointer to pass around functions?



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:39
 void derefAfterRelease() {
-  std::unique_ptr P(new A());
+  std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is 
constructed}}
   P.release(); // expected-note {{Smart pointer 'P' is released and set to 
null}}

NoQ wrote:
> Ok, these notes shouldn't be there; a note on `.release()` is sufficient to 
> understand the warning and it looks like that's one more place where we 
> should mark the region as uninteresting.
> 
> Can you try to debug why did they suddenly show up?
I checked the exploded graph for this test case. 
Before the bug fix, there exists a path where the no Note Tag is added to the 
corresponding `CXXConstructExpr`. After the fix removed this branching theres 
always a Note Tag on Ctr. {F12591752}

Since the note on .release() is sufficient to understand the warning and I 
agree we should mark this region as uninteresting.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-13 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 285514.
vrnithinkumar added a comment.

- Addressing review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

Files:
  clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.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
@@ -41,6 +41,7 @@
 
 void derefAfterValidCtr() {
   std::unique_ptr P(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -50,17 +51,20 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr P;
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNullVariable() {
   A *InnerPtr = nullptr;
   std::unique_ptr P(InnerPtr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
@@ -87,6 +91,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -116,37 +121,40 @@
 void pass_smart_ptr_by_ptr(std::unique_ptr *a);
 void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
 
-void regioninvalidationTest() {
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_ref(P);
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ref(P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_rvalue_ref(std::move(P));
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr 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 P;
-pass_smart_ptr_by_ptr(&P);
-P->foo();
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+void regioninvalidationWithPassByRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByCostRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ref(P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationWithPassByRValueRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByConstRValueRef() {
+  std::unique_ptr 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 regioninvalidationWithPassByPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationWithPassByConstPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ptr(&P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 struct StructWithSmartPtr {
@@ -160,37 +168,40 @@
 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 '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-warni

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-13 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 5 inline comments as done.
vrnithinkumar added a comment.






Comment at: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp:619
   getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, 
*this,
- CallOpts);
+ CallOpts, Bldr);
   }

NoQ wrote:
> vrnithinkumar wrote:
> > NoQ wrote:
> > > We should probably delete the copy-constructor for node builders. I've no 
> > > idea what it's supposed to do anyway and the whole problem that we're 
> > > having here is due to there being //too many// of them already.
> > So we should disable the copying of `NodeBuilder` and create a heap 
> > allocated `NodeBuilder` and use pointer to pass around functions?
> No-no, keep it on the stack and don't pass it around *at all*.
Sorry, I am still little confused. 

Do we have to make the fix without passing around the `NodeBuilder`?
And delete copy-constructor for `NodeBuilder` in this patch? 



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:39
 void derefAfterRelease() {
-  std::unique_ptr P(new A());
+  std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is 
constructed}}
   P.release(); // expected-note {{Smart pointer 'P' is released and set to 
null}}

NoQ wrote:
> vrnithinkumar wrote:
> > NoQ wrote:
> > > Ok, these notes shouldn't be there; a note on `.release()` is sufficient 
> > > to understand the warning and it looks like that's one more place where 
> > > we should mark the region as uninteresting.
> > > 
> > > Can you try to debug why did they suddenly show up?
> > I checked the exploded graph for this test case. 
> > Before the bug fix, there exists a path where the no Note Tag is added to 
> > the corresponding `CXXConstructExpr`. After the fix removed this branching 
> > theres always a Note Tag on Ctr. {F12591752}
> > 
> > Since the note on .release() is sufficient to understand the warning and I 
> > agree we should mark this region as uninteresting.
> Ok, fair enough! Let's add a FIXME.
Added the FIXME



Comment at: clang/test/Analysis/smart-ptr.cpp:143
 pass_smart_ptr_by_const_rvalue_ref(std::move(P));
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' 
[alpha.cplusplus.SmartPtr]}}
+P->foo(); // no-warning
   }

NoQ wrote:
> That's indeed the intended consequence of your patch: we're no longer 
> exploring a bogus execution path that's parallel to the previous null 
> dereference on line 133, therefore we're no longer emitting this warning but 
> instead correctly interrupting the entire analysis after we've found that 
> other null dereference.
> 
> That said, we should preserve the test so that it was still testing whatever 
> it was testing previously. Can you split up this function into smaller 
> functions so that each test was running independently?
Separated the function into smaller functions.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-14 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 285763.
vrnithinkumar marked 3 inline comments as done.
vrnithinkumar added a comment.

- Fix without passing the NodeBuilder


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

Files:
  clang/lib/StaticAnalyzer/Core/CheckerManager.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
@@ -41,6 +41,7 @@
 
 void derefAfterValidCtr() {
   std::unique_ptr P(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -50,17 +51,20 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr P;
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNullVariable() {
   A *InnerPtr = nullptr;
   std::unique_ptr P(InnerPtr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
@@ -87,6 +91,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -116,37 +121,40 @@
 void pass_smart_ptr_by_ptr(std::unique_ptr *a);
 void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
 
-void regioninvalidationTest() {
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_ref(P);
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ref(P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_rvalue_ref(std::move(P));
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr 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 P;
-pass_smart_ptr_by_ptr(&P);
-P->foo();
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+void regioninvalidationWithPassByRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByCostRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ref(P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationWithPassByRValueRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByConstRValueRef() {
+  std::unique_ptr 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 regioninvalidationWithPassByPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationWithPassByConstPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ptr(&P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 struct StructWithSmartPtr {
@@ -160,37 +168,40 @@
 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 '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]}}
-  }
+void regioninvalidationWithinStr

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-14 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp:682
 anyEvaluated = true;
+Dst.clear();
 Dst.insert(checkDst);

> runCheckersForEvalCall() already has its own builder, you don't need another.

In that case is it okay to clear the  `ExplodedNodeSet DstEvaluated` passed as 
`Dst` which contains parent node [[ 
https://github.com/llvm/llvm-project/blob/master/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp#L604
 | contains parent node ]] ?

When the any of the evaluated checker is evaluated the node successfully we can 
clear the `Dst` which is part of the `StmtNodeBuilder Bldr(DstPreCall, 
DstEvaluated, *currBldrCtx);` before inserting new nodes.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-15 Thread Nithin VR via Phabricator via cfe-commits
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 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);
 
 void regioninvalidationTest() {
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_ref(P);
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ref(P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_rvalue_ref(std::move(P));
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr 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 P;
-pass_smart_ptr_by_ptr(&P);
-P->foo();
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+  std::unique_ptr P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationTest1() {
+  std::unique_ptr 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 P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationTest3() {
+  std::unique_ptr 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 P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationTest5() {
+  std::unique_ptr 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() {
@

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:147
 
-if (!move::isMovedFrom(State, ThisR)) {
-  // TODO: Model this case as well. At least, avoid invalidation of
-  // globals.
-  return false;
+if (ModelSmartPtrDereference) {
+  handleBoolOperation(Call, C);

This seems little messy here.
I guess once we model the `std::move` for smart ptr it will be less messy 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:411
+  if (NotNullState) {
+auto NonNullVal = C.getSValBuilder().makeTruthVal(true);
+NotNullState =

Since the inner pointer value can be any non-null value, I am not sure what 
should be the value to be added to the map for tracking.



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-15 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:400
+  ProgramStateRef NotNullState, NullState;
+  std::tie(NotNullState, NullState) = 
State->assume(CallExprVal.getValue());
+

NoQ wrote:
> It's always `UnknownVal` because the call has not been evaluated yet. This 
> `assume()` does nothing.
Okay.
So in that case the `NotNullState` and `NullState` will be same as the original 
state?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86029: [analyzer] Add modeling for unque_ptr::get()

2020-08-15 Thread Nithin VR via Phabricator via cfe-commits
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/D86029

Files:
  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
@@ -235,3 +235,17 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P;
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null 
[core.CallAndMessage]}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -117,3 +117,18 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of 
type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P' of type 
'std::unique_ptr'}}
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 
'P' is null"
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null 
[core.CallAndMessage]}}
+  // expected-note@-1 {{Called C++ object pointer is null}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -56,13 +56,15 @@
   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 handleGet(const CallEvent &Call, CheckerContext &C) const;
 
   using SmartPtrMethodHandlerFn =
   void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) 
const;
   CallDescriptionMap SmartPtrMethodHandlers{
   {{"reset"}, &SmartPtrModeling::handleReset},
   {{"release"}, &SmartPtrModeling::handleRelease},
-  {{"swap", 1}, &SmartPtrModeling::handleSwap}};
+  {{"swap", 1}, &SmartPtrModeling::handleSwap},
+  {{"get"}, &SmartPtrModeling::handleGet}};
 };
 } // end of anonymous namespace
 
@@ -345,6 +347,27 @@
   }));
 }
 
+void SmartPtrModeling::handleGet(const CallEvent &Call,
+ CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  const auto *IC = dyn_cast(&Call);
+  if (!IC)
+return;
+
+  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+  if (!ThisRegion)
+return;
+
+  const auto *InnerPointVal = State->get(ThisRegion);
+  if (!InnerPointVal)
+return;
+
+  State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+  *InnerPointVal);
+  //TODO: Add NoteTag, for how the raw pointer got using 'get' method.
+  C.addTransition(State);
+}
+
 void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
   auto *Checker = Mgr.registerChecker();
   Checker->ModelSmartPtrDereference =


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -235,3 +235,17 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P;
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -117,3 +117,18 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Der

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-17 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 285969.
vrnithinkumar added a comment.

- Make exactly single NodeBuilder exists at any given time


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.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
@@ -41,6 +41,7 @@
 
 void derefAfterValidCtr() {
   std::unique_ptr P(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -50,17 +51,20 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr P;
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNullVariable() {
   A *InnerPtr = nullptr;
   std::unique_ptr P(InnerPtr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
@@ -87,6 +91,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -116,37 +121,40 @@
 void pass_smart_ptr_by_ptr(std::unique_ptr *a);
 void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
 
-void regioninvalidationTest() {
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_ref(P);
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ref(P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_rvalue_ref(std::move(P));
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr 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 P;
-pass_smart_ptr_by_ptr(&P);
-P->foo();
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+void regioninvalidationWithPassByRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByCostRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ref(P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationWithPassByRValueRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByConstRValueRef() {
+  std::unique_ptr 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 regioninvalidationWithPassByPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationWithPassByConstPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ptr(&P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 struct StructWithSmartPtr {
@@ -160,37 +168,40 @@
 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 '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]}}
-  }
+void regioninvalidationWithinStructPassByRef() {
+  StructWi

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-17 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp:682
 anyEvaluated = true;
+Dst.clear();
 Dst.insert(checkDst);

NoQ wrote:
> vrnithinkumar wrote:
> > > runCheckersForEvalCall() already has its own builder, you don't need 
> > > another.
> > 
> > In that case is it okay to clear the  `ExplodedNodeSet DstEvaluated` passed 
> > as `Dst` which contains parent node [[ 
> > https://github.com/llvm/llvm-project/blob/master/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp#L604
> >  | contains parent node ]] ?
> > 
> > When the any of the evaluated checker is evaluated the node successfully we 
> > can clear the `Dst` which is part of the `StmtNodeBuilder Bldr(DstPreCall, 
> > DstEvaluated, *currBldrCtx);` before inserting new nodes.
> Hmm actually your code is now incorrect because `runCheckersForEvalCall()` is 
> in fact invoked multiple times in a loop (if there were state splits in 
> PreStmt/PreCall), therefore it's possible that `Dst` does in fact already 
> contain nodes.
> 
> That also means that i can't put in the assertions that i thought of; the 
> destination set is indeed potentially non-empty in many cases.
> 
> 
> Anyway, here's what i meant:
> ```lang=diff
>ExplodedNodeSet DstPreCall;
>getCheckerManager().runCheckersForPreCall(DstPreCall, PreInitialized,
>  *Call, *this);
> 
>ExplodedNodeSet DstEvaluated;
> -  StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
> 
>if (CE && CE->getConstructor()->isTrivial() &&
>CE->getConstructor()->isCopyOrMoveConstructor() &&
>!CallOpts.IsArrayCtorOrDtor) {
> +StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
>  // FIXME: Handle other kinds of trivial constructors as well.
>  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = 
> DstPreCall.end();
>   I != E; ++I)
>performTrivialCopy(Bldr, *I, *Call);
> 
>} else {
>  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = 
> DstPreCall.end();
>   I != E; ++I)
>getCheckerManager().runCheckersForEvalCall(DstEvaluated, *I, *Call, 
> *this,
>   CallOpts);
>}
> 
>// If the CFG was constructed without elements for temporary destructors
>// and the just-called constructor created a temporary object then
>// stop exploration if the temporary object has a noreturn constructor.
>// This can lose coverage because the destructor, if it were present
>// in the CFG, would be called at the end of the full expression or
>// later (for life-time extended temporaries) -- but avoids infeasible
>// paths when no-return temporary destructors are used for assertions.
> +  ExplodedNodeSet DstEvaluatedPostProcessed;
> +  StmtNodeBuilder Bldr(DstEvaluated, DstEvaluatedPostProcessed, 
> *currBldrCtx);
>const AnalysisDeclContext *ADC = LCtx->getAnalysisDeclContext();
>if (!ADC->getCFGBuildOptions().AddTemporaryDtors) {
>  if (llvm::isa_and_nonnull(TargetRegion) &&
>  cast(Call->getDecl())
>  ->getParent()
>  ->isAnyDestructorNoReturn()) {
> 
>// If we've inlined the constructor, then DstEvaluated would be empty.
>// In this case we still want a sink, which could be implemented
>// in processCallExit. But we don't have that implemented at the 
> moment,
>// so if you hit this assertion, see if you can avoid inlining
>// the respective constructor when analyzer-config cfg-temporary-dtors
>// is set to false.
>// Otherwise there's nothing wrong with inlining such constructor.
>assert(!DstEvaluated.empty() &&
>   "We should not have inlined this constructor!");
> 
>for (ExplodedNode *N : DstEvaluated) {
>  Bldr.generateSink(E, N, N->getState());
>}
> 
>// There is no need to run the PostCall and PostStmt checker
>// callbacks because we just generated sinks on all nodes in th
>// frontier.
>return;
>  }
>}
> 
>ExplodedNodeSet DstPostArgumentCleanup;
> -  for (ExplodedNode *I : DstEvaluated)
> +  for (ExplodedNode *I : DstEvaluatedPostProcessed)
>  finishArgumentConstruction(DstPostArgumentCleanup, I, *Call);
> ```
> This way exactly one builder exists at any given moment of time and exactly 
> one builder operates on each pair of source-destination sets.
> 
> Also this entire `AddTemporaryDtors` option could probably be banned already 
> which would make things a whole lot easier; i'll look into that.
> Hmm actually your code is now incorrect because runCheckersForEvalCall() is 
> in fact invoked multiple times in a loop (if there were state splits in 
> PreStmt/PreCall), therefore it's possible that Dst does in fact already 
> contain nodes.
Oh, I missed that point.

[PATCH] D85796: [Analysis] Bug fix for exploded graph branching in evalCall for constructor

2020-08-18 Thread Nithin VR via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGb34b1e38381f: [Analysis] Bug fix for exploded graph 
branching in evalCall for constructor (authored by vrnithinkumar).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85796/new/

https://reviews.llvm.org/D85796

Files:
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.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
@@ -41,6 +41,7 @@
 
 void derefAfterValidCtr() {
   std::unique_ptr P(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -50,17 +51,20 @@
 
 void derefAfterDefaultCtr() {
   std::unique_ptr P;
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNull() {
   std::unique_ptr P(nullptr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 void derefAfterCtrWithNullVariable() {
   A *InnerPtr = nullptr;
   std::unique_ptr P(InnerPtr);
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
@@ -87,6 +91,7 @@
 void derefAfterResetWithNonNull() {
   std::unique_ptr P;
   P.reset(new A());
+  clang_analyzer_numTimesReached(); // expected-warning {{1}}
   P->foo(); // No warning.
 }
 
@@ -116,37 +121,40 @@
 void pass_smart_ptr_by_ptr(std::unique_ptr *a);
 void pass_smart_ptr_by_const_ptr(const std::unique_ptr *a);
 
-void regioninvalidationTest() {
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_ref(P);
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ref(P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_rvalue_ref(std::move(P));
-P->foo(); // no-warning
-  }
-  {
-std::unique_ptr 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 P;
-pass_smart_ptr_by_ptr(&P);
-P->foo();
-  }
-  {
-std::unique_ptr P;
-pass_smart_ptr_by_const_ptr(&P);
-P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
-  }
+void regioninvalidationWithPassByRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ref(P);
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByCostRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ref(P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void regioninvalidationWithPassByRValueRef() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_rvalue_ref(std::move(P));
+  P->foo(); // no-warning
+}
+
+void regioninvalidationWithPassByConstRValueRef() {
+  std::unique_ptr 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 regioninvalidationWithPassByPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_ptr(&P);
+  P->foo();
+}
+
+void regioninvalidationWithPassByConstPtr() {
+  std::unique_ptr P;
+  pass_smart_ptr_by_const_ptr(&P);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
 }
 
 struct StructWithSmartPtr {
@@ -160,37 +168,40 @@
 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 '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 {{Dereferenc

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-19 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:147
 
-if (!move::isMovedFrom(State, ThisR)) {
-  // TODO: Model this case as well. At least, avoid invalidation of
-  // globals.
-  return false;
+if (ModelSmartPtrDereference) {
+  handleBoolOperation(Call, C);

xazax.hun wrote:
> vrnithinkumar wrote:
> > This seems little messy here.
> > I guess once we model the `std::move` for smart ptr it will be less messy 
> I agree. `isNullAfterMoveMethod` is especially confusing as it does not do 
> what the name of the function says. It checks if the `Call` is a boolean 
> conversion operator. I'd suggest renaming that method to make this code a bit 
> more sensible. 
> 
> Moreover, when `ModelSmartPtrDereference` is true, we no longer model moves 
> below right? I think a comment that this logic is duplicated 
> `handleBoolOperation` might make the code cleaner. 
> 
> But yeah, this needs to be cleaned up, hopefully really soon.
- Renamed the method to `isBooleanOpMethod`
- Added comments and FIXME
Hopefully we can clean up once `std::move` is modeled.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:389
+}
+C.addTransition(State);
+  } else if (move::isMovedFrom(State, ThisRegion)) {

xazax.hun wrote:
> This looks fine for now, but we often prefer adding a return after each case 
> to avoid executing multiple `addTransition`s accidentally after refactoring.
Added return



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:411
+  if (NotNullState) {
+auto NonNullVal = C.getSValBuilder().makeTruthVal(true);
+NotNullState =

NoQ wrote:
> vrnithinkumar wrote:
> > Since the inner pointer value can be any non-null value, I am not sure what 
> > should be the value to be added to the map for tracking.
> > 
> Don't add values, constrain existing values.
Made changes to create the conjured symbol and use that to constrain. 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-19 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 286632.
vrnithinkumar marked 5 inline comments as done.
vrnithinkumar added a comment.

Changes to use conjureSymbolVal if the inner pointer value is missing


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

Files:
  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
@@ -252,3 +252,46 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr P;
+  if (P)
+P->foo(); // No warning.
+  else
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr P;
+  if (!P)
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (P)
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr 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 P) {
+  P.reset(new A());
+  if (!P)
+P->foo(); // No warning.
+  else
+P->foo(); // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -116,3 +116,80 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
 }
+
+void derefConditionOnNullPtrFalseBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (P) { // expected-note {{Taking false branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // No warning.
+  } else {
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnNullPtrTrueBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnValidPtrTrueBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is non-nul}}
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  } else {
+PNull->foo(); // No warning
+  }
+}
+
+void derefConditionOnValidPtrFalseBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (!P) { // expected-note {{Taking false branch}}
+// expected-note@-1{{Smart pointer 'P' is non-nul}}
+PNull->foo(); // No warning
+  } else {
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  }
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtrAssumeNull(std::unique_ptr P) {
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Assuming smart pointer 'P' is null}}
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  }
+}
+
+void derefConditionOnUnKnownPtrAssumeNonNull(std::unique_ptr P) {
+  std::unique_ptr PNull; // expected-note {{Default c

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-19 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:130
+// Returns empty type if not found valid inner pointer type.
+static QualType getInnerPointerType(const CallEvent &Call, CheckerContext &C) {
+  QualType InnerType{};

It seems like a long shot to me.
I am not sure is there any direct or easy way to get inner pointer type from a 
smart pointer  


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86029: [analyzer] Add modeling for unque_ptr::get()

2020-08-19 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 286675.
vrnithinkumar edited the summary of this revision.
vrnithinkumar added a comment.

- Using conjureSymbolVal in case of missing inner pointer value


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86029/new/

https://reviews.llvm.org/D86029

Files:
  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
@@ -7,6 +7,7 @@
 
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
+void clang_analyzer_eval(bool);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
@@ -252,3 +253,26 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P;
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromMultipleGetOnUnknownPtr(std::unique_ptr P) {
+  A *X = P.get();
+  A *Y = P.get();
+  clang_analyzer_eval(X == Y); // expected-warning{{TRUE}}
+  if (!X) {
+Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+  }
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -116,3 +116,18 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null"
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+  // expected-note@-1 {{Called C++ object pointer is null}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -56,13 +56,15 @@
   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 handleGet(const CallEvent &Call, CheckerContext &C) const;
 
   using SmartPtrMethodHandlerFn =
   void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
   CallDescriptionMap SmartPtrMethodHandlers{
   {{"reset"}, &SmartPtrModeling::handleReset},
   {{"release"}, &SmartPtrModeling::handleRelease},
-  {{"swap", 1}, &SmartPtrModeling::handleSwap}};
+  {{"swap", 1}, &SmartPtrModeling::handleSwap},
+  {{"get"}, &SmartPtrModeling::handleGet}};
 };
 } // end of anonymous namespace
 
@@ -345,6 +347,33 @@
   }));
 }
 
+void SmartPtrModeling::handleGet(const CallEvent &Call,
+ CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  const auto *IC = dyn_cast(&Call);
+  if (!IC)
+return;
+
+  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+  if (!ThisRegion)
+return;
+
+  SVal InnerPointerVal;
+  if (const auto *InnerValPtr = State->get(ThisRegion)) {
+InnerPointerVal = *InnerValPtr;
+  } else {
+const auto *CallExpr = Call.getOriginExpr();
+InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
+CallExpr, C.getLocationContext(), Call.getResultType(), C.blockCount());
+State = State->set(ThisRegion, InnerPointerVal);
+  }
+
+  State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+  InnerPointerVal);
+  // TODO: Add NoteTag, for how the raw pointer got using 'get' method.
+  C.addTransition(State);
+}
+
 void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
   auto *Checker = Mgr.registerChecker();
   Checker->ModelSmartPtrDereference =
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86029: [analyzer] Add modeling for unque_ptr::get()

2020-08-19 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:362-363
+  const auto *InnerPointVal = State->get(ThisRegion);
+  if (!InnerPointVal)
+return;
+

xazax.hun wrote:
> NoQ wrote:
> > You'll have to actively handle this case, sooner or later. Consider the 
> > following test cases that won't work until you do:
> > ```lang=c++
> > void foo(std::unique_ptr p) {
> >   A *x = p.get();
> >   A *y = p.get();
> >   clang_analyzer_eval(x == y); // expected-warning{{TRUE}}
> >   if (!x) {
> > y->foo(); // expected-warning{{Called C++ object pointer is null}}
> >   }
> > }
> > 
> > ```
> You mean the case where we do not have an inner pointer registered in the 
> state yet, right?
> 
> I believe we might also have to handle similar cases for `operator bool()` as 
> well. 
Added the above test case. 
Using conjureSymbolVal in case of missing inner pointer value



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:362-363
+  const auto *InnerPointVal = State->get(ThisRegion);
+  if (!InnerPointVal)
+return;
+

vrnithinkumar wrote:
> xazax.hun wrote:
> > NoQ wrote:
> > > You'll have to actively handle this case, sooner or later. Consider the 
> > > following test cases that won't work until you do:
> > > ```lang=c++
> > > void foo(std::unique_ptr p) {
> > >   A *x = p.get();
> > >   A *y = p.get();
> > >   clang_analyzer_eval(x == y); // expected-warning{{TRUE}}
> > >   if (!x) {
> > > y->foo(); // expected-warning{{Called C++ object pointer is null}}
> > >   }
> > > }
> > > 
> > > ```
> > You mean the case where we do not have an inner pointer registered in the 
> > state yet, right?
> > 
> > I believe we might also have to handle similar cases for `operator bool()` 
> > as well. 
> Added the above test case. 
> Using conjureSymbolVal in case of missing inner pointer value
```
void foo(std::unique_ptr P) {
  A *X = P.get();
  if (!X) {
P->foo(); // expected-warning {{Dereference of null smart pointer 'Pl' 
[alpha.cplusplus.SmartPtr]}}
  }
}
```
I was trying to add the above use case. Since we are using conjureSymbolVal in 
case of missing inner pointer value.

But still the inner pointer value is constrained to [0, 0] in false branch, 
`InnerPointVal->isZeroConstant()` returning false. 
Also I tried `State->isNull(*InnerPointVal).isConstrainedTrue();` This is also 
not working.
How should we check whether the conjureSymbolVal for inner pointer value is 
constrained to [0, 0]?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86029/new/

https://reviews.llvm.org/D86029

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86293: [analyzer] Add modeling of Eq operator in smart ptr

2020-08-20 Thread Nithin VR via Phabricator via cfe-commits
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/D86293

Files:
  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
@@ -215,8 +215,7 @@
 std::unique_ptr P;
 std::unique_ptr Q;
 Q = std::move(P);
-// TODO: Fix test with expecting warning after '=' operator overloading modeling.
-Q->foo(); // no-warning
+Q->foo(); // expected-warning {{Dereference of null smart pointer 'Q' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -252,3 +251,36 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void drefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void drefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+
+void derefOnNullPtrGotMovedFromValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PToMove;
+  P = std::move(PToMove);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void drefOnMovedFromUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  P->foo(); // No warning.
+}
+
+void drefOnMovedUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -109,10 +109,34 @@
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-void noNoteTagsForNonMatchingBugType() {
-  std::unique_ptr P; // No note.
-  std::unique_ptr P1; // No note.
-  P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
-  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
-  // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+void drefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());  // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P;
+  P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
+}
+
+void drefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+
+void derefOnNullPtrGotMovedFromValidPtr() {
+  std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  P = std::move(PToMove); // expected-note {{Smart pointer 'P' is null after a null value moved from 'PToMove'}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1 {{Dereference of null smart pointer 'P'}}
+}
+
+void drefOnMovedUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
 }
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -56,6 +56,7 @@
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
   void handleSwap(const CallEvent &Call, CheckerContext &C) const;
+  bool handleEqOp(const CallEvent &Call, CheckerContext &C) const;
 
   usin

[PATCH] D86293: [analyzer] Add modeling of Eq operator in smart ptr

2020-08-20 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 286868.
vrnithinkumar added a comment.

- Add assignment to nullptr case


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86293/new/

https://reviews.llvm.org/D86293

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -215,8 +215,7 @@
 std::unique_ptr P;
 std::unique_ptr Q;
 Q = std::move(P);
-// TODO: Fix test with expecting warning after '=' operator overloading modeling.
-Q->foo(); // no-warning
+Q->foo(); // expected-warning {{Dereference of null smart pointer 'Q' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -252,3 +251,61 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+
+void derefOnNullPtrGotMovedFromValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PToMove;
+  P = std::move(PToMove);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedFromUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  P->foo(); // No warning.
+}
+
+void derefOnMovedUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullPtrToNullSmartPtr() {
+  std::unique_ptr P;
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedZeroToNullSmartPtr() {
+  std::unique_ptr P(new A());
+  P = 0;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullToUnknowSmartPtr(std::unique_ptr P) {
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&returnRValRefOfUniquePtr();
+
+void drefOnAssignedNullFromMethodPtrValidSmartPtr() {
+  std::unique_ptr P(new A());
+  P = returnRValRefOfUniquePtr();
+  P->foo(); // No warning. 
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
@@ -109,10 +109,49 @@
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-void noNoteTagsForNonMatchingBugType() {
-  std::unique_ptr P; // No note.
-  std::unique_ptr P1; // No note.
-  P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
-  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
-  // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());  // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P;
+  P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null after moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1 {{Dereference of null smart pointer 'PToMove'}}
+}
+
+void derefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+

[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-21 Thread Nithin VR via Phabricator via cfe-commits
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/D86373

Files:
  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
@@ -252,3 +252,44 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefMoveConstructedWithValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefMoveConstructedWithUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefUnknownPtrMovedToConstruct(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&functionReturnsRValueRef();
+
+void derefMoveConstructedWithRValueRefReturn(std::unique_ptr PToMove) {
+  std::unique_ptr P(functionReturnsRValueRef());
+  P->foo();  // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -116,3 +116,32 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
 }
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'P' is constructed with null value moved from 'PToMove'}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after moved to construct 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after moved to construct 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
+}
+
+void derefUnknownPtrMovedToConstruct(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after moved to construct 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -56,6 +56,8 @@
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
   void handleSwap(const CallEvent &Ca

[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-21 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/test/Analysis/smart-ptr.cpp:295
+  P->foo();  // No warning.
+}

I was trying to test the below code.
```
void foo_() {
  std::unique_ptr PToMove;
  std::unique_ptr&& AfterRValeRefCast = 
std::move(functionReturnsRValueRef());
  std::unique_ptr P(AfterRValeRefCast);
  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' 
[alpha.cplusplus.SmartPtr]}}
}
```

But passing the local RValue reference variable to move constructor is always 
invoking the deleted copy constructor.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86029: [analyzer] Add modeling for unque_ptr::get()

2020-08-23 Thread Nithin VR via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG55208f5a2126: [analyzer] Add modeling for unque_ptr::get() 
(authored by vrnithinkumar).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86029/new/

https://reviews.llvm.org/D86029

Files:
  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
@@ -7,6 +7,7 @@
 
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
+void clang_analyzer_eval(bool);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
@@ -252,3 +253,26 @@
   P->foo(); // No warning.
   PValid->foo(); // No warning.
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P;
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromMultipleGetOnUnknownPtr(std::unique_ptr P) {
+  A *X = P.get();
+  A *Y = P.get();
+  clang_analyzer_eval(X == Y); // expected-warning{{TRUE}}
+  if (!X) {
+Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+  }
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -116,3 +116,18 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
 }
+
+void derefOnRawPtrFromGetOnNullPtr() {
+  std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null"
+  P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
+  // expected-note@-1 {{Called C++ object pointer is null}}
+}
+
+void derefOnRawPtrFromGetOnValidPtr() {
+  std::unique_ptr P(new A());
+  P.get()->foo(); // No warning.
+}
+
+void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
+  P.get()->foo(); // No warning.
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -56,13 +56,15 @@
   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 handleGet(const CallEvent &Call, CheckerContext &C) const;
 
   using SmartPtrMethodHandlerFn =
   void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
   CallDescriptionMap SmartPtrMethodHandlers{
   {{"reset"}, &SmartPtrModeling::handleReset},
   {{"release"}, &SmartPtrModeling::handleRelease},
-  {{"swap", 1}, &SmartPtrModeling::handleSwap}};
+  {{"swap", 1}, &SmartPtrModeling::handleSwap},
+  {{"get"}, &SmartPtrModeling::handleGet}};
 };
 } // end of anonymous namespace
 
@@ -345,6 +347,33 @@
   }));
 }
 
+void SmartPtrModeling::handleGet(const CallEvent &Call,
+ CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  const auto *IC = dyn_cast(&Call);
+  if (!IC)
+return;
+
+  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+  if (!ThisRegion)
+return;
+
+  SVal InnerPointerVal;
+  if (const auto *InnerValPtr = State->get(ThisRegion)) {
+InnerPointerVal = *InnerValPtr;
+  } else {
+const auto *CallExpr = Call.getOriginExpr();
+InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
+CallExpr, C.getLocationContext(), Call.getResultType(), C.blockCount());
+State = State->set(ThisRegion, InnerPointerVal);
+  }
+
+  State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+  InnerPointerVal);
+  // TODO: Add NoteTag, for how the raw pointer got using 'get' method.
+  C.addTransition(State);
+}
+
 void ento::registerSmartPtrModeling(CheckerManager &Mgr) {
   auto *Checker = Mgr.registerChecker();
   Checker->ModelSmartPtrDereference =
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-24 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 287512.
vrnithinkumar marked 11 inline comments as done.
vrnithinkumar added a comment.

- Adding checkLiveSymbols and review comments changes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

Files:
  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
@@ -8,12 +8,13 @@
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
 void clang_analyzer_eval(bool);
+void clang_analyzer_warnOnDeadSymbol(int *);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
   if (Q)
 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-  *Q.get() = 1; // no-warning
+  *Q.get() = 1; // expected-warning {{Dereference of null pointer [core.NullDereference]}}
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
@@ -276,3 +277,69 @@
 Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
   }
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr P;
+  if (P)
+P->foo(); // No warning.
+  else
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr P;
+  if (!P)
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (P)
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr 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 P) {
+  P.reset(new A());
+  if (!P)
+P->foo(); // No warning.
+  else
+P->foo(); // No warning.
+}
+
+void innerPointerSymbolLiveness() {
+  std::unique_ptr P(new int());
+  clang_analyzer_warnOnDeadSymbol(P.get());
+  int *RP = P.release();
+} // expected-warning{{SYMBOL DEAD}}
+
+void boolOpCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  if (P) {
+int *X = P.get();
+clang_analyzer_warnOnDeadSymbol(X);
+  }
+} // expected-warning{{SYMBOL DEAD}}
+
+void getCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  int *X = P.get();
+  clang_analyzer_warnOnDeadSymbol(X);
+  int Y;
+  if (!P) {
+Y = *P.get(); // expected-warning {{Dereference of null pointer [core.NullDereference]}}
+// expected-warning@-1 {{SYMBOL DEAD}}
+  }
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -131,3 +131,80 @@
 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
   P.get()->foo(); // No warning.
 }
+
+void derefConditionOnNullPtrFalseBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (P) { // expected-note {{Taking false branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // No warning.
+  } else {
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnNullPtrTrueBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnValidPtrTrueBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is non-nul}}
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  } else {
+PNull->foo(); // No warning
+  }
+}
+
+void derefConditionOnValidPtrFalseBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{D

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-24 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:137
+  const auto *RecordDecl = MethodDecl->getParent();
+  if (!RecordDecl || !RecordDecl->getDeclContext()->isStdNamespace())
+return InnerType;

xazax.hun wrote:
> I'd rather use `Decl::isInStdNamespace` instead of querying the DeclContext 
> of the decl. The former is more robust with inline namespaces. 
Changed to use `Decl::isInStdNamespace`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:141
+  const auto *TSD = dyn_cast(RecordDecl);
+  if (TSD) {
+auto TemplateArgs = TSD->getTemplateArgs().asArray();

xazax.hun wrote:
> Inverting this condition would reduce the indentation in the rest of the 
> function.
inverted the if condition



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:145
+TemplateArgs.size() > 0 &&
+"Smart pointer should have specialized with atleast one template 
type");
+auto InnerValueType = TemplateArgs[0].getAsType();

NoQ wrote:
> That's pretty fundamental, right? If it's a specialization, it must have 
> something specialized. It isn't specific to unique pointers, right?
> 
> Because unique pointers aren't special; technically anybody can define an 
> arbitrary class with name `std::unique_ptr` and any properties they'd like. 
> It's going to be undefined behavior according to the standard (because 
> namespace `std` is explicitly reserved for the standard library) but if the 
> compiler *crashes* it'll still be our fault.
> 
> 
added a check for `TemplateArgs.size() == 0` before accessing the first 
Template argument.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:147
+auto InnerValueType = TemplateArgs[0].getAsType();
+InnerType =
+C.getASTContext().getPointerType(InnerValueType.getCanonicalType());

xazax.hun wrote:
> You could return the real inner type here and replace all other returns with 
> `return {};` making the code a bit cleaner.
Updated to return with {}



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:404
 
+void SmartPtrModeling::handleBoolOperation(const CallEvent &Call,
+   CheckerContext &C) const {

vsavchenko wrote:
> I suggest `BoolConversion`
yeah thats sounds better.
Changed.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:413
+  if (InnerPointVal) {
+bool IsInnerPtrNull = InnerPointVal->isZeroConstant();
+State = State->BindExpr(CallExpr, C.getLocationContext(),

xazax.hun wrote:
> Is this actually correct? What if the InnerPtr is an unconstrained symbol. In 
> that case, it is not a zero constant so we will assume that it is constrained 
> to non-zero. As far as I understand.
Fixed as you suggested in the below comments



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:432
+return;
+  } else {
+// In case of inner pointer SVal is not available we create

xazax.hun wrote:
> I'd do it the other way around as we discussed during the call.
> * Move the task of conjuring a new symbol to the beginning of the method.
> * Start by calling this function at the beginning of modeling operator bool.
> * The rest of the function could assume that there always is a symbol. It 
> could be constrained to be non-null, it could be the zero constant, or it 
> could be a completely unconstrained symbol. The latter will not work as 
> expected with your current implementation, see my comment above.
Made the changes as suggested above



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:448
+
+if (NullState) {
+  auto NullVal = C.getSValBuilder().makeNull();

xazax.hun wrote:
> NoQ wrote:
> > There's no need to check. You just conjured a brand new symbol out of thin 
> > air; you can be sure that it's completely unconstrained and both states are 
> > feasible. You can instead `assert()` that they're both feasible.
> I think instead of removing this check, this method should be reworked. I 
> think it might have some bugs, see my comment at the beginning of this method.
Refactored the method as suggested.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:458-460
+OS << "Assuming smart pointer ";
+ThisRegion->printPretty(OS);
+OS << " is null";

NoQ wrote:
> Wait, what happens when the region can't be pretty-printed? Does it print two 
> spaces between "pointer" and "is"?
Yes.
Created `checkAndPrettyPrintRegion` to check if the region can be pretty 
printed or not to avoid two spaces.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
 

[PATCH] D86293: [analyzer] Add modeling of Eq operator in smart ptr

2020-08-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:351
 
+bool SmartPtrModeling::handleEqOp(const CallEvent &Call,
+  CheckerContext &C) const {

vsavchenko wrote:
> xazax.hun wrote:
> > I'd prefer to call this AssignOp to avoid confusion with `==`. While your 
> > naming is correct, I always found this nomenclature confusing.
> IMO it's not a question of preference with this one, `EqOp` is misleading.
Changed to AssignOp



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:384
+
+  const auto *ArgRegionVal = State->get(ArgRegion);
+  if (ArgRegionVal) {

xazax.hun wrote:
> I also find the names of the variables confusing.
> 
> Instead of `ArgRegion` what about `OtherSmartPtrRegion`?
> Instead of `ArgRegionVal` what about `OtherInnerPtr`?
Changed to `OtherSmartPtrRegion ` and `OtherInnerPtr`



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:391
+
+C.addTransition(State, C.getNoteTag([ThisRegion, ArgRegion, IsArgValNull](
+PathSensitiveBugReport &BR,

xazax.hun wrote:
> Adding return after every `addTransition` is a good practive that we should 
> follow.
Added return



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:399
+ArgRegion->printPretty(OS);
+OS << " is null after moved to ";
+ThisRegion->printPretty(OS);

vsavchenko wrote:
> The grammar seems off in this one.  I think it should be smith like "after 
> being moved to" or "after it was moved to".
Changed to "after being moved to"



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:419
+llvm::raw_ostream &OS) {
+  if (&BR.getBugType() != smartptr::getNullDereferenceBugType() ||
+  !BR.isInteresting(ArgRegion))

xazax.hun wrote:
> Isn't this the same as the beginning of the note tag above?
> 
> I wonder if there is a way to deduplicate this code. Not a huge priority 
> though as I do not have an immediate idea for doing this in a clean way.
Yes.
The check for bug type is duplicated across all the note tags.



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:132
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart 
pointer 'PToMove' is null}}
+  P = std::move(PToMove); // expected-note {{Smart pointer 'P' is null after a 
null value moved from 'PToMove'}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' 
[alpha.cplusplus.SmartPtr]}}

vsavchenko wrote:
> NoQ wrote:
> > I suggest: `Null pointer value move-assigned to 'P'`.
> +1
Updated to `Null pointer value move-assigned to 'P'`



Comment at: clang/test/Analysis/smart-ptr-text-output.cpp:139
+  std::unique_ptr P;
+  P = std::move(PToMove); // expected-note {{Smart pointer 'PToMove' is null 
after moved and assigned to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 
'PToMove' [alpha.cplusplus.SmartPtr]}}

NoQ wrote:
> I suggest: `Smart pointer 'PToMove' is null; previous value moved to 'P'`. Or 
> maybe instead keep the note that the move-checker currently emits?
Going with first option "Smart pointer 'PToMove' is null; previous value moved 
to 'P'"


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86293/new/

https://reviews.llvm.org/D86293

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86293: [analyzer] Add modeling of Eq operator in smart ptr

2020-08-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 287612.
vrnithinkumar marked 9 inline comments as done.
vrnithinkumar edited the summary of this revision.
vrnithinkumar added a comment.

- Addressing review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86293/new/

https://reviews.llvm.org/D86293

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -216,8 +216,7 @@
 std::unique_ptr P;
 std::unique_ptr Q;
 Q = std::move(P);
-// TODO: Fix test with expecting warning after '=' operator overloading modeling.
-Q->foo(); // no-warning
+Q->foo(); // expected-warning {{Dereference of null smart pointer 'Q' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -276,3 +275,61 @@
 Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
   }
 }
+
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+
+void derefOnNullPtrGotMovedFromValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PToMove;
+  P = std::move(PToMove);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedFromUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  P->foo(); // No warning.
+}
+
+void derefOnMovedUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullPtrToNullSmartPtr() {
+  std::unique_ptr P;
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedZeroToNullSmartPtr() {
+  std::unique_ptr P(new A());
+  P = 0;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullToUnknowSmartPtr(std::unique_ptr P) {
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&returnRValRefOfUniquePtr();
+
+void drefOnAssignedNullFromMethodPtrValidSmartPtr() {
+  std::unique_ptr P(new A());
+  P = returnRValRefOfUniquePtr();
+  P->foo(); // No warning. 
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
@@ -109,14 +109,6 @@
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-void noNoteTagsForNonMatchingBugType() {
-  std::unique_ptr P; // No note.
-  std::unique_ptr P1; // No note.
-  P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
-  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
-  // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
-}
-
 void derefOnRawPtrFromGetOnNullPtr() {
   std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null"
   P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
@@ -131,3 +123,50 @@
 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
   P.get()->foo(); // No warning.
 }
+
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());  // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not i

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 287641.
vrnithinkumar added a comment.

- Making the note tags prunable


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

Files:
  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
@@ -8,12 +8,13 @@
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
 void clang_analyzer_eval(bool);
+void clang_analyzer_warnOnDeadSymbol(int *);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
   if (Q)
 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-  *Q.get() = 1; // no-warning
+  *Q.get() = 1; // expected-warning {{Dereference of null pointer [core.NullDereference]}}
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
@@ -276,3 +277,69 @@
 Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
   }
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr P;
+  if (P)
+P->foo(); // No warning.
+  else
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr P;
+  if (!P)
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (P)
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr 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 P) {
+  P.reset(new A());
+  if (!P)
+P->foo(); // No warning.
+  else
+P->foo(); // No warning.
+}
+
+void innerPointerSymbolLiveness() {
+  std::unique_ptr P(new int());
+  clang_analyzer_warnOnDeadSymbol(P.get());
+  int *RP = P.release();
+} // expected-warning{{SYMBOL DEAD}}
+
+void boolOpCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  if (P) {
+int *X = P.get();
+clang_analyzer_warnOnDeadSymbol(X);
+  }
+} // expected-warning{{SYMBOL DEAD}}
+
+void getCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  int *X = P.get();
+  clang_analyzer_warnOnDeadSymbol(X);
+  int Y;
+  if (!P) {
+Y = *P.get(); // expected-warning {{Dereference of null pointer [core.NullDereference]}}
+// expected-warning@-1 {{SYMBOL DEAD}}
+  }
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -131,3 +131,112 @@
 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
   P.get()->foo(); // No warning.
 }
+
+void derefConditionOnNullPtrFalseBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (P) { // expected-note {{Taking false branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // No warning.
+  } else {
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnNullPtrTrueBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is nul}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnValidPtrTrueBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (P) { // expected-note {{Taking true branch}}
+// expected-note@-1{{Smart pointer 'P' is non-nul}}
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  } else {
+PNull->foo(); // No warning
+  }
+}
+
+void derefConditionOnValidPtrFalseBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (!P) { // exp

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-25 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:494-496
+  OS << "Smart pointer";
+  checkAndPrettyPrintRegion(OS, ThisRegion);
+  OS << " is non-null";

NoQ wrote:
> Because these note tags aren't specific to the bug report at hand, they have 
> to be marked as //prunable// (i.e., the optional `getNoteTag()`'s parameter 
> "`IsPrunable`" should be set to true). That'd reduce bug report clutter by 
> not bringing in stack frames that aren't otherwise interesting for the bug 
> report.
> 
> Something like this may act as a test (i didn't try):
> ```lang=c++
> struct S {
>   std::unique_ptr P;
> 
>   void foo() {
> if (!P) { // no-note because foo() is pruned
>   return;
> }
>   }
> 
>   int bar() {
> P = new int(0);
> foo();
> return 1 / *P; // warning: division by zero
>   }
> 
> }
> 
> ```
Marked these tags as prunable and added the tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86293: [analyzer] Add modeling of Eq operator in smart ptr

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG20676cab1168: [analyzer] Add modeling of assignment operator 
in smart ptr (authored by vrnithinkumar).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86293/new/

https://reviews.llvm.org/D86293

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  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
@@ -216,8 +216,7 @@
 std::unique_ptr P;
 std::unique_ptr Q;
 Q = std::move(P);
-// TODO: Fix test with expecting warning after '=' operator overloading modeling.
-Q->foo(); // no-warning
+Q->foo(); // expected-warning {{Dereference of null smart pointer 'Q' [alpha.cplusplus.SmartPtr]}}
   }
 }
 
@@ -276,3 +275,61 @@
 Y->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
   }
 }
+
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedToNullPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P;
+  P = std::move(PToMove); // No note.
+  P->foo(); // No warning.
+}
+
+void derefOnNullPtrGotMovedFromValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PToMove;
+  P = std::move(PToMove);
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnMovedFromUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  P->foo(); // No warning.
+}
+
+void derefOnMovedUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P;
+  P = std::move(PToMove);
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullPtrToNullSmartPtr() {
+  std::unique_ptr P;
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedZeroToNullSmartPtr() {
+  std::unique_ptr P(new A());
+  P = 0;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefOnAssignedNullToUnknowSmartPtr(std::unique_ptr P) {
+  P = nullptr;
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&returnRValRefOfUniquePtr();
+
+void drefOnAssignedNullFromMethodPtrValidSmartPtr() {
+  std::unique_ptr P(new A());
+  P = returnRValRefOfUniquePtr();
+  P->foo(); // No warning. 
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -80,7 +80,7 @@
 void derefOnStdSwappedNullPtr() {
   std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
   std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:978 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::swap(P, PNull); // expected-note@Inputs/system-header-simulator-cxx.h:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
   // expected-note@-1 {{Calling 'swap'}}
   // expected-note@-2 {{Returning from 'swap'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
@@ -109,14 +109,6 @@
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-void noNoteTagsForNonMatchingBugType() {
-  std::unique_ptr P; // No note.
-  std::unique_ptr P1; // No note.
-  P1 = std::move(P); // expected-note {{Smart pointer 'P' of type 'std::unique_ptr' is reset to null when moved from}}
-  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' of type 'std::unique_ptr' [cplusplus.Move]}}
-  // expected-note@-1 {{Dereference of null smart pointer 'P' of type 'std::unique_ptr'}}
-}
-
 void derefOnRawPtrFromGetOnNullPtr() {
   std::unique_ptr P; // FIXME: add note "Default constructed smart pointer 'P' is null"
   P.get()->foo(); // expected-warning {{Called C++ object pointer is null [core.CallAndMessage]}}
@@ -131,3 +123,50 @@
 void derefOnRawPtrFromGetOnUnknownPtr(std::unique_ptr P) {
   P.get()->foo(); // No warning.
 }
+
+void derefOnMovedFromValidPtr() {
+  std::unique_ptr PToMove(new A());  // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  s

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 288048.
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

- Removing unnecessary notetags.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

Files:
  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
@@ -8,12 +8,13 @@
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
 void clang_analyzer_eval(bool);
+void clang_analyzer_warnOnDeadSymbol(int *);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
   if (Q)
 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-  *Q.get() = 1; // no-warning
+  *Q.get() = 1; // expected-warning {{Dereference of null pointer [core.NullDereference]}}
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
@@ -333,3 +334,69 @@
   P = returnRValRefOfUniquePtr();
   P->foo(); // No warning. 
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr P;
+  if (P)
+P->foo(); // No warning.
+  else
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr P;
+  if (!P)
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (P)
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr 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 P) {
+  P.reset(new A());
+  if (!P)
+P->foo(); // No warning.
+  else
+P->foo(); // No warning.
+}
+
+void innerPointerSymbolLiveness() {
+  std::unique_ptr P(new int());
+  clang_analyzer_warnOnDeadSymbol(P.get());
+  int *RP = P.release();
+} // expected-warning{{SYMBOL DEAD}}
+
+void boolOpCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  if (P) {
+int *X = P.get();
+clang_analyzer_warnOnDeadSymbol(X);
+  }
+} // expected-warning{{SYMBOL DEAD}}
+
+void getCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  int *X = P.get();
+  clang_analyzer_warnOnDeadSymbol(X);
+  int Y;
+  if (!P) {
+Y = *P.get(); // expected-warning {{Dereference of null pointer [core.NullDereference]}}
+// expected-warning@-1 {{SYMBOL DEAD}}
+  }
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -170,3 +170,108 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
+
+void derefConditionOnNullPtrFalseBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (P) { // expected-note {{Taking false branch}}
+P->foo(); // No warning.
+  } else {
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnNullPtrTrueBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnValidPtrTrueBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (P) { // expected-note {{Taking true branch}}
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'PNull'}}
+  } else {
+PNull->foo(); // No warning
+  }
+}
+
+void derefConditionOnValidPtrFalseBranch() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
+  if (!P) { // expected-note {{Taking false branch}}
+PNull->foo(); // No warning
+  } else

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked 2 inline comments as done.
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:483
+llvm::raw_ostream &OS) {
+ BR.markInteresting(ThisRegion);
+ OS << "Smart pointer";

NoQ wrote:
> Wait, why are we marking the region interesting here? Not every null smart 
> pointer is interesting, only the ones that are actually dereferenced.
This was added to show how the smart pointer, even though it is not 
dereferenced. But why did we take true/false branch based on this.




Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:497-499
+ OS << "Smart pointer";
+ checkAndPrettyPrintRegion(OS, ThisRegion);
+ OS << " is non-null";

NoQ wrote:
> Also i'm starting to suspect that these notes aren't actually needed when 
> there's no "Assuming..."; in particular, we don't emit such notes for raw 
> pointers, so we probably shouldn't emit them for smart pointers either. 
> There's anyway going to be a note about "Taking true branch..." or something 
> like that, which is sufficient to understand what was the smart pointer.
> 
> I.e., this note is unnecessary:
> ```lang=c++
> void foo() {
>   std::unique_ptr P = nullptr;
>   if (P) {// Smart pointer 'P' is null
>   // Taking false branch
>   }
> }
> ```
> The second note, "Taking false branch", is sufficient for explaining to the 
> user that the smart pointer is known to be null. The user may ask why the 
> smart pointer is null, but the note isn't explaining it. The way you marked 
> the region as interesting (as i noticed in the above inline comment) would 
> have indeed explained why it's null, but at this point we draw the line and 
> believe that if the region isn't already interesting then the user most 
> likely doesn't need to know why it's null (and if it's already interesting 
> then there's no need to mark it again).
> 
> But this note is necessary:
> ```lang=c++
> void foo(std::unique_ptr P) {
>   if (P) {// Assuming smart pointer 'P' is null
>   // Taking false branch
>   }
> }
> ```
> This note conveys the extra information that we don't know for a fact that 
> the smart pointer is null on the current path based on previous analysis, but 
> instead the analyzer is *assuming* that it's possible that it's null due to 
> the presence of the check in the code. That's a big deal.
Since the "Taking false branch" is enough to implies the smart pointer in null, 
removing the notes which are unnecessary.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 288101.
vrnithinkumar added a comment.

- Refactoring to reuse common duplicated code


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

Files:
  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
@@ -17,7 +17,8 @@
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
-  *P.get() = 1; // expected-warning {{Method called on moved-from object 'P'}}
+  *P.get() = 1; // expected-warning {{Method called on moved-from object 'P' [cplusplus.Move]}}
+  // expected-warning@-1 {{Dereference of null pointer [core.NullDereference]}}
 }
 
 // Don't crash when attempting to model a call with unknown callee.
@@ -333,3 +334,44 @@
   P = returnRValRefOfUniquePtr();
   P->foo(); // No warning. 
 }
+
+void derefMoveConstructedWithValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefMoveConstructedWithUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefUnknownPtrMovedToConstruct(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&functionReturnsRValueRef();
+
+void derefMoveConstructedWithRValueRefReturn() {
+  std::unique_ptr P(functionReturnsRValueRef());
+  P->foo();  // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -144,7 +144,7 @@
   std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
   // FIXME: above note should go away once we fix marking region not interested. 
   std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
-  P = std::move(PToMove); // expected-note {{Null pointer value move-assigned to 'P'}}
+  P = std::move(PToMove); // expected-note {{A null pointer value is moved to 'P'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
@@ -170,3 +170,32 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // exp

[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:456
   if (BR.isInteresting(ThisRegion) && IsArgValNull) {
-OS << "Null pointer value move-assigned to ";
+OS << "A null pointer value is moved to ";
 ThisRegion->printPretty(OS);

Same note tag is used for move assignment and move constructor here. 



Comment at: clang/test/Analysis/smart-ptr.cpp:21
+  *P.get() = 1; // expected-warning {{Method called on moved-from object 'P' 
[cplusplus.Move]}}
+  // expected-warning@-1 {{Dereference of null pointer [core.NullDereference]}}
 }

Now both "use after move" and "null pointer dereference" warnings are coming. I 
hope it will be only  "null pointer dereference" after smart pointer modeling 
is complete


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added inline comments.



Comment at: clang/test/Analysis/smart-ptr.cpp:295
+  P->foo();  // No warning.
+}

NoQ wrote:
> vrnithinkumar wrote:
> > I was trying to test the below code.
> > ```
> > void foo_() {
> >   std::unique_ptr PToMove;
> >   std::unique_ptr&& AfterRValeRefCast = 
> > std::move(functionReturnsRValueRef());
> >   std::unique_ptr P(AfterRValeRefCast);
> >   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' 
> > [alpha.cplusplus.SmartPtr]}}
> > }
> > ```
> > 
> > But passing the local RValue reference variable to move constructor is 
> > always invoking the deleted copy constructor.
> Yeah, you still need an explicit move over it. Implicit moves don't happen 
> because it's an rvalue reference, it has more to do with the anonymity of the 
> object; the compiler only auto-moves when there's no possibility for 
> accidental implicit use-after-move, and in presence of a named reference to 
> the value, accidental implicit use-after-move is still very much possible, so 
> an explicit move is required. That's not the exact rules but that's, as far 
> as i understand, the logic behind the exact rules.
Okay 
Thanks for the clarification.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-26 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar marked an inline comment as done.
vrnithinkumar added a comment.

In D86373#2231605 , @NoQ wrote:

> This is easier than D86293  because there's 
> no old value in the freshly constructed smart pointer, right? I suspect that 
> you can still re-use a lot of the implementation with D86293 
> , at least partially.

Refactored to reuse the implementation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86373: [analyzer] Add modeling for unique_ptr move constructor

2020-08-31 Thread Nithin VR via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG1b743a9efa08: [analyzer] Add modeling for unique_ptr move 
constructor (authored by vrnithinkumar).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86373/new/

https://reviews.llvm.org/D86373

Files:
  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
@@ -17,7 +17,8 @@
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
-  *P.get() = 1; // expected-warning {{Method called on moved-from object 'P'}}
+  *P.get() = 1; // expected-warning {{Method called on moved-from object 'P' [cplusplus.Move]}}
+  // expected-warning@-1 {{Dereference of null pointer [core.NullDereference]}}
 }
 
 // Don't crash when attempting to model a call with unknown callee.
@@ -333,3 +334,44 @@
   P = returnRValRefOfUniquePtr();
   P->foo(); // No warning. 
 }
+
+void derefMoveConstructedWithValidPtr() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefMoveConstructedWithUnknownPtr(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  P->foo(); // No warning.
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A());
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove;
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefUnknownPtrMovedToConstruct(std::unique_ptr PToMove) {
+  std::unique_ptr P(std::move(PToMove));
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+}
+
+std::unique_ptr &&functionReturnsRValueRef();
+
+void derefMoveConstructedWithRValueRefReturn() {
+  std::unique_ptr P(functionReturnsRValueRef());
+  P->foo();  // No warning.
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -144,7 +144,7 @@
   std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
   // FIXME: above note should go away once we fix marking region not interested. 
   std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
-  P = std::move(PToMove); // expected-note {{Null pointer value move-assigned to 'P'}}
+  P = std::move(PToMove); // expected-note {{A null pointer value is moved to 'P'}}
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
@@ -170,3 +170,32 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
+
+void derefMoveConstructedWithNullPtr() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}}
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void derefValidPtrMovedToConstruct() {
+  std::unique_ptr PToMove(new A()); // expected-note {{Smart pointer 'PToMove' is constructed}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
+  // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
+}
+
+void derefNullPtrMovedToConstruct() {
+  std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
+  // FIXME: above note should go away once we fix marking region not interested. 
+  std::unique_ptr P(std::move(PToMove)); // expected-note {{Smart pointer 'PToMove' is null after being moved to 'P'}}
+  PToMove->foo(); // expected-warning {{Dereference of null 

[PATCH] D86027: [analyzer] Add bool operator modeling for unque_ptr

2020-08-31 Thread Nithin VR via Phabricator via cfe-commits
vrnithinkumar updated this revision to Diff 288972.
vrnithinkumar added a comment.

- Addressing review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D86027/new/

https://reviews.llvm.org/D86027

Files:
  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
@@ -8,12 +8,13 @@
 void clang_analyzer_warnIfReached();
 void clang_analyzer_numTimesReached();
 void clang_analyzer_eval(bool);
+void clang_analyzer_warnOnDeadSymbol(int *);
 
 void derefAfterMove(std::unique_ptr P) {
   std::unique_ptr Q = std::move(P);
   if (Q)
 clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
-  *Q.get() = 1; // no-warning
+  *Q.get() = 1; // expected-warning {{Dereference of null pointer [core.NullDereference]}}
   if (P)
 clang_analyzer_warnIfReached(); // no-warning
   // TODO: Report a null dereference (instead).
@@ -375,3 +376,77 @@
   std::unique_ptr P(functionReturnsRValueRef());
   P->foo();  // No warning.
 }
+
+void derefConditionOnNullPtr() {
+  std::unique_ptr P;
+  if (P)
+P->foo(); // No warning.
+  else
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotNullPtr() {
+  std::unique_ptr P;
+  if (!P)
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (P)
+PNull->foo(); // expected-warning {{Dereference of null smart pointer 'PNull' [alpha.cplusplus.SmartPtr]}}
+}
+
+void derefConditionOnNotValidPtr() {
+  std::unique_ptr P(new A());
+  std::unique_ptr PNull;
+  if (!P)
+PNull->foo(); // No warning.
+}
+
+void derefConditionOnUnKnownPtr(std::unique_ptr 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 P) {
+  P.reset(new A());
+  if (!P)
+P->foo(); // No warning.
+  else
+P->foo(); // No warning.
+}
+
+void innerPointerSymbolLiveness() {
+  std::unique_ptr P(new int());
+  clang_analyzer_warnOnDeadSymbol(P.get());
+  int *RP = P.release();
+} // expected-warning{{SYMBOL DEAD}}
+
+void boolOpCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  if (P) {
+int *X = P.get();
+clang_analyzer_warnOnDeadSymbol(X);
+  }
+} // expected-warning{{SYMBOL DEAD}}
+
+void getCreatedConjuredSymbolLiveness(std::unique_ptr P) {
+  int *X = P.get();
+  clang_analyzer_warnOnDeadSymbol(X);
+  int Y;
+  if (!P) {
+Y = *P.get(); // expected-warning {{Dereference of null pointer [core.NullDereference]}}
+// expected-warning@-1 {{SYMBOL DEAD}}
+  }
+}
+
+int derefConditionOnUnKnownPtr(int *q) {
+  std::unique_ptr P(q);
+  if (P)
+return *P; // No warning.
+  else
+return *P; // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+}
Index: clang/test/Analysis/smart-ptr-text-output.cpp
===
--- clang/test/Analysis/smart-ptr-text-output.cpp
+++ clang/test/Analysis/smart-ptr-text-output.cpp
@@ -170,7 +170,6 @@
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1 {{Dereference of null smart pointer 'P'}}
 }
-
 void derefMoveConstructedWithNullPtr() {
   std::unique_ptr PToMove; // expected-note {{Default constructed smart pointer 'PToMove' is null}}
   std::unique_ptr P(std::move(PToMove)); // expected-note {{A null pointer value is moved to 'P'}}
@@ -199,3 +198,109 @@
   PToMove->foo(); // expected-warning {{Dereference of null smart pointer 'PToMove' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'PToMove'}}
 }
+
+void derefConditionOnNullPtrFalseBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (P) { // expected-note {{Taking false branch}}
+P->foo(); // No warning.
+  } else {
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnNullPtrTrueBranch() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  if (!P) { // expected-note {{Taking true branch}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void derefConditionOnValidPtrTrueBranch() {
+  std::unique_ptr P(new A());
+  std::unique_

  1   2   >