[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-14 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 358839.
RedDocMD added a comment.

Cleanup, still doesn't work


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
 using namespace ento;
@@ -757,6 +758,7 @@
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
 defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, 
*Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -177,7 +177,9 @@
 
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
+
   ProgramStateRef State = C.getState();
+  Call.dump();
   if (!smartptr::isStdSmartPtrCall(Call))
 return false;
 
@@ -261,6 +263,11 @@
 return true;
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Wohoo\n";
+return true;
+  }
+
   if (handleAssignOp(Call, C))
 return true;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
 using namespace ento;
@@ -757,6 +758,7 @@
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
I != E; ++I)
 defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Chec

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-15 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 358998.
RedDocMD added a comment.

Removed one bug, many more to go


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
 using namespace ento;
@@ -754,9 +755,10 @@
 
   ExplodedNodeSet DstInvalidated;
   StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = 
DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, 
*Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,13 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
+Call.getProgramPoint().dump();
+llvm::errs() << "\n";
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -177,7 +177,9 @@
 
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
+
   ProgramStateRef State = C.getState();
+  Call.dump();
   if (!smartptr::isStdSmartPtrCall(Call))
 return false;
 
@@ -261,6 +263,11 @@
 return true;
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Wohoo\n";
+return true;
+  }
+
   if (handleAssignOp(Call, C))
 return true;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace clang;
 using namespace ento;
@@ -754,9 +755,10 @@
 
   ExplodedNodeSet DstInvalidated;
   StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,13 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = P

[PATCH] D104616: [analyzer] Model comparision methods of std::unique_ptr

2021-07-15 Thread Deep Majumder via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG48688257c52d: [analyzer] Model comparision methods of 
std::unique_ptr (authored by RedDocMD).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D104616

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerHelpers.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
@@ -457,3 +457,52 @@
 P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   }
 }
+
+// The following is a silly function,
+// but serves to test if we are picking out
+// standard comparision functions from custom ones.
+template 
+bool operator<(std::unique_ptr &x, double d);
+
+void uniquePtrComparision(std::unique_ptr unknownPtr) {
+  auto ptr = std::unique_ptr(new int(13));
+  auto nullPtr = std::unique_ptr();
+  auto otherPtr = std::unique_ptr(new int(29));
+
+  clang_analyzer_eval(ptr == ptr); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr > ptr);  // expected-warning{{FALSE}}
+  clang_analyzer_eval(ptr <= ptr); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(nullPtr <= unknownPtr); // expected-warning{{TRUE}}
+  clang_analyzer_eval(unknownPtr >= nullPtr); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(ptr != otherPtr); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr > nullPtr);   // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(ptr != nullptr);// expected-warning{{TRUE}}
+  clang_analyzer_eval(nullPtr != nullptr);// expected-warning{{FALSE}}
+  clang_analyzer_eval(nullptr <= unknownPtr); // expected-warning{{TRUE}}
+}
+
+void uniquePtrComparisionStateSplitting(std::unique_ptr unknownPtr) {
+  auto ptr = std::unique_ptr(new int(13));
+
+  clang_analyzer_eval(ptr > unknownPtr); // expected-warning{{TRUE}}
+  // expected-warning@-1{{FALSE}}
+}
+
+void uniquePtrComparisionDifferingTypes(std::unique_ptr unknownPtr) {
+  auto ptr = std::unique_ptr(new int(13));
+  auto nullPtr = std::unique_ptr();
+  auto otherPtr = std::unique_ptr(new double(3.14));
+
+  clang_analyzer_eval(nullPtr <= unknownPtr); // expected-warning{{TRUE}}
+  clang_analyzer_eval(unknownPtr >= nullPtr); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(ptr != otherPtr); // expected-warning{{TRUE}}
+  clang_analyzer_eval(ptr > nullPtr);   // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(ptr != nullptr);// expected-warning{{TRUE}}
+  clang_analyzer_eval(nullPtr != nullptr);// expected-warning{{FALSE}}
+  clang_analyzer_eval(nullptr <= unknownPtr); // expected-warning{{TRUE}}
+}
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
@@ -978,6 +978,61 @@
 void swap(unique_ptr &x, unique_ptr &y) noexcept {
   x.swap(y);
 }
+
+template 
+bool operator==(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator!=(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator<(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator>(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator<=(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator>=(const unique_ptr &x, const unique_ptr &y);
+
+template 
+bool operator==(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator!=(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator<(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator>(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator<=(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator>=(const unique_ptr &x, nullptr_t y);
+
+template 
+bool operator==(nullptr_t x, const unique_ptr &y);
+
+template 
+bool operator!=(nullptr_t x, const unique_ptr &y);
+
+template 
+bool operator>(nullptr_t x, const unique_ptr &y);
+
+template 
+bool operator<(nullptr_t x, const unique_ptr &y);
+
+template 
+bool operator>=(nullptr_t x, const unique_ptr &y);
+
+template 
+bool operator<=(nullptr_t x, const unique_ptr &y);
+
 } // namespace std
 #endif
 
Index: clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
@@ -148,5 +148,39 @@
   return IntValue.getSExtValue();
 }
 
+OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK,
+ 

[PATCH] D105421: [analyzer] Handle << operator for std::unique_ptr

2021-07-15 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359211.
RedDocMD added a comment.

Post rebase cleanup


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105421

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
@@ -3,6 +3,11 @@
 // RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:   -std=c++11 -verify %s
 
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection\
+// RUN:   -analyzer-checker cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:   -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:   -std=c++20 -verify %s
+
 #include "Inputs/system-header-simulator-cxx.h"
 
 void clang_analyzer_warnIfReached();
@@ -506,3 +511,28 @@
   clang_analyzer_eval(nullPtr != nullptr);// expected-warning{{FALSE}}
   clang_analyzer_eval(nullptr <= unknownPtr); // expected-warning{{TRUE}}
 }
+
+#if __cplusplus >= 202002L
+
+void testOstreamOverload(std::unique_ptr P) {
+  auto &Cout = std::cout;
+  auto &PtrCout = std::cout << P;
+  auto &StringCout = std::cout << "hello";
+  // We are testing the fact that in our modelling of
+  // operator<<(basic_ostream &, const unique_ptr &)
+  // we set the return SVal to the SVal of the ostream arg.
+  clang_analyzer_eval(&Cout == &PtrCout);// expected-warning {{TRUE}}
+  // FIXME: Technically, they should be equal,
+  // that hasn't been modelled yet.
+  clang_analyzer_eval(&Cout == &StringCout); // expected-warning {{UNKNOWN}}
+}
+
+int glob;
+void testOstreamDoesntInvalidateGlobals(std::unique_ptr P) {
+  int x = glob;
+  std::cout << P;
+  int y = glob;
+  clang_analyzer_eval(x == y); // expected-warning {{TRUE}}
+}
+
+#endif
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
@@ -1036,6 +1036,22 @@
 } // namespace std
 #endif
 
+namespace std {
+template 
+class basic_ostream;
+
+using ostream = basic_ostream;
+
+extern std::ostream cout;
+
+ostream &operator<<(ostream &, const string &);
+
+#if __cplusplus >= 202002L
+template 
+ostream &operator<<(ostream &, const std::unique_ptr &);
+#endif
+} // namespace std
+
 #ifdef TEST_INLINABLE_ALLOCATORS
 namespace std {
   void *malloc(size_t);
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -72,6 +72,7 @@
 const MemRegion *OtherSmartPtrRegion) const;
   void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
   bool handleComparisionOp(const CallEvent &Call, CheckerContext &C) const;
+  bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
   std::pair
   retrieveOrConjureInnerPtrVal(ProgramStateRef State,
const MemRegion *ThisRegion, const Expr *E,
@@ -89,6 +90,31 @@
 
 REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
 
+// Checks if RD has name in Names and is in std namespace
+static bool hasStdClassWithName(const CXXRecordDecl *RD,
+ArrayRef Names) {
+  if (!RD || !RD->getDeclContext()->isStdNamespace())
+return false;
+  if (RD->getDeclName().isIdentifier()) {
+StringRef Name = RD->getName();
+return llvm::any_of(Names, [&Name](StringRef GivenName) -> bool {
+  return Name == GivenName;
+});
+  }
+  return false;
+}
+
+constexpr llvm::StringLiteral STD_PTR_NAMES[] = {"shared_ptr", "unique_ptr",
+ "weak_ptr"};
+
+static bool isStdSmartPtr(const CXXRecordDecl *RD) {
+  return hasStdClassWithName(RD, STD_PTR_NAMES);
+}
+
+static bool isStdSmartPtr(const Expr *E) {
+  return isStdSmartPtr(E->getType()->getAsCXXRecordDecl());
+}
+
 // Define the inter-checker API.
 namespace clang {
 namespace ento {
@@ -193,6 +219,30 @@
   return CD && CD->getConversionType()->isBooleanType();
 }
 
+constexpr llvm::StringLiteral BASIC_OSTREAM_NAMES[] = {"basic_ostream"};
+
+bool isStdBasicOstream(const Expr *E) {
+  const auto *RD = E->getType()->getAsCXXRecordDecl();
+  return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
+}
+
+bool isStdOstreamOperatorCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 ||
+  !Call.getDecl()->getDeclContext()->isStdNamespace())
+return false;
+  const auto *FC = dyn_cast(&Call);
+  if (!FC)
+return false;
+  const 

[PATCH] D104300: [analyzer] Handle std::swap for std::unique_ptr

2021-07-18 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359600.
RedDocMD added a comment.

Post rebase cleanup


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D104300

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -69,20 +69,17 @@
 
 void derefOnSwappedNullPtr() {
   std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
-  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  P.swap(PNull); // expected-note {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::unique_ptr PNull;
+  P.swap(PNull);
   PNull->foo(); // No warning.
   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-// FIXME: Fix this test when "std::swap" is modeled seperately.
 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:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
-  // expected-note@-1 {{Calling 'swap'}}
-  // expected-note@-2 {{Returning from 'swap'}}
+  std::unique_ptr PNull;
+  std::swap(P, PNull);
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2263,6 +2263,8 @@
   // The metadata part of markInteresting is not reversed here.
   // Just making the same region not interesting is incorrect
   // in specific cases.
+  if (const auto *meta = dyn_cast(sym))
+markNotInteresting(meta->getRegion());
 }
 
 void PathSensitiveBugReport::markInteresting(const MemRegion *R,
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -63,7 +63,7 @@
 private:
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
-  void handleSwap(const CallEvent &Call, CheckerContext &C) const;
+  void handleSwapMethod(const CallEvent &Call, CheckerContext &C) const;
   void handleGet(const CallEvent &Call, CheckerContext &C) const;
   bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;
   bool handleMoveCtr(const CallEvent &Call, CheckerContext &C,
@@ -73,6 +73,8 @@
   void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
   bool handleComparisionOp(const CallEvent &Call, CheckerContext &C) const;
   bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
+  bool handleSwap(ProgramStateRef State, SVal First, SVal Second,
+  CheckerContext &C) const;
   std::pair
   retrieveOrConjureInnerPtrVal(ProgramStateRef State,
const MemRegion *ThisRegion, const Expr *E,
@@ -83,8 +85,9 @@
   CallDescriptionMap SmartPtrMethodHandlers{
   {{"reset"}, &SmartPtrModeling::handleReset},
   {{"release"}, &SmartPtrModeling::handleRelease},
-  {{"swap", 1}, &SmartPtrModeling::handleSwap},
+  {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
   {{"get"}, &SmartPtrModeling::handleGet}};
+  const CallDescription StdSwapCall{{"std", "swap"}, 2};
 };
 } // end of anonymous namespace
 
@@ -259,6 +262,15 @@
   if (isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
+  if (Call.isCalled(StdSwapCall)) {
+// Check the first arg, if it is of std::unique_ptr type.
+assert(Call.getNumArgs() == 2 && "std::swap should have two arguments");
+const Expr *FirstArg = Call.getArgExpr(0);
+if (!smartptr::isStdSmartPtr(FirstArg->getType()->getAsCXXRecordDecl()))
+  return false;
+return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C);
+  }
+
   if (!smartptr::isStdSmartPtrCall(Call))
 return false;
 
@@ -578,43 +590,52 @@
   // pointer.
 }
 
-void SmartPtrModeling::handleSwap(const CallEvent &Call,
-  CheckerContext &C) const {
+void SmartPtrModeling:

[PATCH] D104300: [analyzer] Handle std::swap for std::unique_ptr

2021-07-18 Thread Deep Majumder 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 rG0cd98bef1b6f: [analyzer] Handle std::swap for 
std::unique_ptr (authored by RedDocMD).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D104300

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtr.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/BugReporter.cpp
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -69,20 +69,17 @@
 
 void derefOnSwappedNullPtr() {
   std::unique_ptr P(new A()); // expected-note {{Smart pointer 'P' is constructed}}
-  std::unique_ptr PNull; // expected-note {{Default constructed smart pointer 'PNull' is null}}
-  P.swap(PNull); // expected-note {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
+  std::unique_ptr PNull;
+  P.swap(PNull);
   PNull->foo(); // No warning.
   (*P).foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
 
-// FIXME: Fix this test when "std::swap" is modeled seperately.
 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:979 {{Swapped null smart pointer 'PNull' with smart pointer 'P'}}
-  // expected-note@-1 {{Calling 'swap'}}
-  // expected-note@-2 {{Returning from 'swap'}}
+  std::unique_ptr PNull;
+  std::swap(P, PNull);
   P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
   // expected-note@-1{{Dereference of null smart pointer 'P'}}
 }
Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2263,6 +2263,8 @@
   // The metadata part of markInteresting is not reversed here.
   // Just making the same region not interesting is incorrect
   // in specific cases.
+  if (const auto *meta = dyn_cast(sym))
+markNotInteresting(meta->getRegion());
 }
 
 void PathSensitiveBugReport::markInteresting(const MemRegion *R,
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -63,7 +63,7 @@
 private:
   void handleReset(const CallEvent &Call, CheckerContext &C) const;
   void handleRelease(const CallEvent &Call, CheckerContext &C) const;
-  void handleSwap(const CallEvent &Call, CheckerContext &C) const;
+  void handleSwapMethod(const CallEvent &Call, CheckerContext &C) const;
   void handleGet(const CallEvent &Call, CheckerContext &C) const;
   bool handleAssignOp(const CallEvent &Call, CheckerContext &C) const;
   bool handleMoveCtr(const CallEvent &Call, CheckerContext &C,
@@ -73,6 +73,8 @@
   void handleBoolConversion(const CallEvent &Call, CheckerContext &C) const;
   bool handleComparisionOp(const CallEvent &Call, CheckerContext &C) const;
   bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
+  bool handleSwap(ProgramStateRef State, SVal First, SVal Second,
+  CheckerContext &C) const;
   std::pair
   retrieveOrConjureInnerPtrVal(ProgramStateRef State,
const MemRegion *ThisRegion, const Expr *E,
@@ -83,8 +85,9 @@
   CallDescriptionMap SmartPtrMethodHandlers{
   {{"reset"}, &SmartPtrModeling::handleReset},
   {{"release"}, &SmartPtrModeling::handleRelease},
-  {{"swap", 1}, &SmartPtrModeling::handleSwap},
+  {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
   {{"get"}, &SmartPtrModeling::handleGet}};
+  const CallDescription StdSwapCall{{"std", "swap"}, 2};
 };
 } // end of anonymous namespace
 
@@ -259,6 +262,15 @@
   if (isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
+  if (Call.isCalled(StdSwapCall)) {
+// Check the first arg, if it is of std::unique_ptr type.
+assert(Call.getNumArgs() == 2 && "std::swap should have two arguments");
+const Expr *FirstArg = Call.getArgExpr(0);
+if (!smartptr::isStdSmartPtr(FirstArg->getType()->getAsCXXRecordDecl()))
+  return false;
+return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C);
+  }
+
   if (!smartptr::isStdSmartPtrCall(Call))
 return false;
 
@@ -578,43 +590,52 @@
   // pointer.
 }
 
-v

[PATCH] D103750: [analyzer] Handle std::make_unique for SmartPtrModeling

2021-07-18 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359605.
RedDocMD added a comment.

Post-rebase cleanup


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103750

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -1,10 +1,17 @@
 // RUN: %clang_analyze_cc1\
-// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:  -analyzer-output=text -std=c++20 %s -verify=expected
+
+// RUN: %clang_analyze_cc1\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
 // RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:  -analyzer-output=text -std=c++11 %s -verify=expected
 
 #include "Inputs/system-header-simulator-cxx.h"
 
+void clang_analyzer_eval(bool);
+
 class A {
 public:
   A(){};
@@ -310,3 +317,55 @@
 // expected-note@-1{{Dereference of null smart pointer 'P'}}
   }
 }
+
+void makeUniqueReturnsNonNullUniquePtr() {
+  auto P = std::make_unique();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#if __cplusplus >= 202002L
+
+void makeUniqueForOverwriteReturnsNullUniquePtr() {
+  auto P = std::make_unique_for_overwrite();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#endif
+
+struct G {
+  int *p;
+  G(int *p): p(p) {}
+  ~G() { *p = 0; }
+};
+
+void foo() {
+  int x = 1;
+  {
+auto P = std::make_unique(&x);
+clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}}
+// expected-note@-1 {{Assuming the condition is false}}
+// expected-note@-2 {{FALSE}}
+// expected-note@-3 {{Assuming the condition is true}}
+// expected-note@-4 {{TRUE}}
+  }
+  clang_analyzer_eval(x == 0); // expected-warning {{FALSE}}
+  // expected-note@-1 {{FALSE}}
+}
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
@@ -1033,6 +1033,16 @@
 template 
 bool operator<=(nullptr_t x, const unique_ptr &y);
 
+template 
+unique_ptr make_unique(Args &&...args);
+
+#if __cplusplus >= 202002L
+
+template 
+unique_ptr make_unique_for_overwrite();
+
+#endif
+
 } // namespace std
 #endif
 
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -192,12 +192,19 @@
   const LocationContext *LCtx,
   unsigned VisitCount) {
   QualType T = E->getType();
-  assert(Loc::isLocType(T));
-  assert(SymbolManager::canSymbolicate(T));
-  if (T->isNullPtrType())
-return makeZeroVal(T);
+  return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
+}
+
+DefinedOrUnknownSVal
+SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+  const LocationContext *LCtx,
+  QualType type, unsigned VisitCount) {
+  assert(Loc::isLocType(type));
+  assert(SymbolManager::canSymbolicate(type));
+  if (type->isNullPtrType())
+return makeZeroVal(type);
 
-  SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount);
+  SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
   return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
 }
 
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
=

[PATCH] D103750: [analyzer] Handle std::make_unique for SmartPtrModeling

2021-07-18 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359625.
RedDocMD added a comment.

Fixed up tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103750

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -1,10 +1,17 @@
 // RUN: %clang_analyze_cc1\
-// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:  -analyzer-output=text -std=c++20 %s -verify=expected
+
+// RUN: %clang_analyze_cc1\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
 // RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:  -analyzer-output=text -std=c++11 %s -verify=expected
 
 #include "Inputs/system-header-simulator-cxx.h"
 
+void clang_analyzer_eval(bool);
+
 class A {
 public:
   A(){};
@@ -310,3 +317,57 @@
 // expected-note@-1{{Dereference of null smart pointer 'P'}}
   }
 }
+
+void makeUniqueReturnsNonNullUniquePtr() {
+  auto P = std::make_unique();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#if __cplusplus >= 202002L
+
+void makeUniqueForOverwriteReturnsNullUniquePtr() {
+  auto P = std::make_unique_for_overwrite();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#endif
+
+struct G {
+  int *p;
+  G(int *p): p(p) {}
+  ~G() { *p = 0; }
+};
+
+void foo() {
+  int x = 1;
+  {
+auto P = std::make_unique(&x);
+clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}}
+// expected-warning@-1 {{FALSE}}
+// expected-note@-2 {{Assuming the condition is true}}
+// expected-note@-3 {{Assuming the condition is false}}
+// expected-note@-4 {{TRUE}}
+// expected-note@-5 {{FALSE}}
+// expected-note@-6 {{Assuming the condition is false}}
+  }
+  clang_analyzer_eval(x == 0); // expected-warning {{FALSE}}
+  // expected-note@-1 {{FALSE}}
+}
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
@@ -1033,6 +1033,16 @@
 template 
 bool operator<=(nullptr_t x, const unique_ptr &y);
 
+template 
+unique_ptr make_unique(Args &&...args);
+
+#if __cplusplus >= 202002L
+
+template 
+unique_ptr make_unique_for_overwrite();
+
+#endif
+
 } // namespace std
 #endif
 
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -192,12 +192,19 @@
   const LocationContext *LCtx,
   unsigned VisitCount) {
   QualType T = E->getType();
-  assert(Loc::isLocType(T));
-  assert(SymbolManager::canSymbolicate(T));
-  if (T->isNullPtrType())
-return makeZeroVal(T);
+  return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
+}
+
+DefinedOrUnknownSVal
+SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+  const LocationContext *LCtx,
+  QualType type, unsigned VisitCount) {
+  assert(Loc::isLocType(type));
+  assert(SymbolManager::canSymbolicate(type));
+  if (type->isNullPtrType())
+return makeZeroVal(type);
 
-  SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount);
+  SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
   return loc::MemRegionVal(MemMgr.getSymb

[PATCH] D103750: [analyzer] Handle std::make_unique for SmartPtrModeling

2021-07-18 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359627.
RedDocMD added a comment.

Marked test with FIXME notes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103750

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -1,10 +1,17 @@
 // RUN: %clang_analyze_cc1\
-// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:  -analyzer-output=text -std=c++20 %s -verify=expected
+
+// RUN: %clang_analyze_cc1\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
 // RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:  -analyzer-output=text -std=c++11 %s -verify=expected
 
 #include "Inputs/system-header-simulator-cxx.h"
 
+void clang_analyzer_eval(bool);
+
 class A {
 public:
   A(){};
@@ -310,3 +317,61 @@
 // expected-note@-1{{Dereference of null smart pointer 'P'}}
   }
 }
+
+void makeUniqueReturnsNonNullUniquePtr() {
+  auto P = std::make_unique();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#if __cplusplus >= 202002L
+
+void makeUniqueForOverwriteReturnsNullUniquePtr() {
+  auto P = std::make_unique_for_overwrite();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#endif
+
+struct G {
+  int *p;
+  G(int *p): p(p) {}
+  ~G() { *p = 0; }
+};
+
+void foo() {
+  int x = 1;
+  {
+auto P = std::make_unique(&x);
+// FIXME: There should not be a state split here, it should take the true path.
+clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}}
+// expected-warning@-1 {{FALSE}}
+// expected-note@-2 {{Assuming the condition is true}}
+// expected-note@-3 {{Assuming the condition is false}}
+// expected-note@-4 {{TRUE}}
+// expected-note@-5 {{FALSE}}
+// expected-note@-6 {{Assuming the condition is false}}
+  }
+  // FIXME: Should be fixed when unique_ptr desctructors are
+  // properly modelled. This includes modelling the call to
+  // the destructor of the inner pointer type.
+  clang_analyzer_eval(x == 0); // expected-warning {{FALSE}}
+  // expected-note@-1 {{FALSE}}
+}
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
@@ -1033,6 +1033,16 @@
 template 
 bool operator<=(nullptr_t x, const unique_ptr &y);
 
+template 
+unique_ptr make_unique(Args &&...args);
+
+#if __cplusplus >= 202002L
+
+template 
+unique_ptr make_unique_for_overwrite();
+
+#endif
+
 } // namespace std
 #endif
 
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -192,12 +192,19 @@
   const LocationContext *LCtx,
   unsigned VisitCount) {
   QualType T = E->getType();
-  assert(Loc::isLocType(T));
-  assert(SymbolManager::canSymbolicate(T));
-  if (T->isNullPtrType())
-return makeZeroVal(T);
+  return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
+}
+
+DefinedOrUnknownSVal
+SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+  const LocationContext *LCtx,
+  QualType type, unsigned VisitCount) {
+  assert(Loc::isLocType(type));
+  assert(Symbol

[PATCH] D103750: [analyzer] Handle std::make_unique for SmartPtrModeling

2021-07-18 Thread Deep Majumder 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 rGd825309352b4: [analyzer] Handle std::make_unique (authored 
by RedDocMD).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103750

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/test/Analysis/Inputs/system-header-simulator-cxx.h
  clang/test/Analysis/smart-ptr-text-output.cpp

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
@@ -1,10 +1,17 @@
 // RUN: %clang_analyze_cc1\
-// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
+// RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
+// RUN:  -analyzer-output=text -std=c++20 %s -verify=expected
+
+// RUN: %clang_analyze_cc1\
+// RUN:  -analyzer-checker=core,cplusplus.Move,alpha.cplusplus.SmartPtr,debug.ExprInspection\
 // RUN:  -analyzer-config cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true\
 // RUN:  -analyzer-output=text -std=c++11 %s -verify=expected
 
 #include "Inputs/system-header-simulator-cxx.h"
 
+void clang_analyzer_eval(bool);
+
 class A {
 public:
   A(){};
@@ -310,3 +317,61 @@
 // expected-note@-1{{Dereference of null smart pointer 'P'}}
   }
 }
+
+void makeUniqueReturnsNonNullUniquePtr() {
+  auto P = std::make_unique();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#if __cplusplus >= 202002L
+
+void makeUniqueForOverwriteReturnsNullUniquePtr() {
+  auto P = std::make_unique_for_overwrite();
+  if (!P) {   // expected-note {{Taking false branch}}
+P->foo(); // should have no warning here, path is impossible
+  }
+  P.reset(); // expected-note {{Smart pointer 'P' reset using a null value}}
+  // Now P is null
+  if (!P) {
+// expected-note@-1 {{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'}}
+  }
+}
+
+#endif
+
+struct G {
+  int *p;
+  G(int *p): p(p) {}
+  ~G() { *p = 0; }
+};
+
+void foo() {
+  int x = 1;
+  {
+auto P = std::make_unique(&x);
+// FIXME: There should not be a state split here, it should take the true path.
+clang_analyzer_eval(*P->p == 1); // expected-warning {{TRUE}}
+// expected-warning@-1 {{FALSE}}
+// expected-note@-2 {{Assuming the condition is true}}
+// expected-note@-3 {{Assuming the condition is false}}
+// expected-note@-4 {{TRUE}}
+// expected-note@-5 {{FALSE}}
+// expected-note@-6 {{Assuming the condition is false}}
+  }
+  // FIXME: Should be fixed when unique_ptr desctructors are
+  // properly modelled. This includes modelling the call to
+  // the destructor of the inner pointer type.
+  clang_analyzer_eval(x == 0); // expected-warning {{FALSE}}
+  // expected-note@-1 {{FALSE}}
+}
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
@@ -1033,6 +1033,16 @@
 template 
 bool operator<=(nullptr_t x, const unique_ptr &y);
 
+template 
+unique_ptr make_unique(Args &&...args);
+
+#if __cplusplus >= 202002L
+
+template 
+unique_ptr make_unique_for_overwrite();
+
+#endif
+
 } // namespace std
 #endif
 
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -192,12 +192,19 @@
   const LocationContext *LCtx,
   unsigned VisitCount) {
   QualType T = E->getType();
-  assert(Loc::isLocType(T));
-  assert(SymbolManager::canSymbolicate(T));
-  if (T->isNullPtrType())
-return makeZeroVal(T);
+  return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
+}
+
+DefinedOrUnknownSVal
+SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
+  const LocationContext *LCtx,
+  

[PATCH] D105421: [analyzer] Handle << operator for std::unique_ptr

2021-07-18 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD closed this revision.
RedDocMD added a comment.

For some reason this revision did not get automatically closed after commit, 
manually merging it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105421

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


[PATCH] D106296: [analyer] Fix for faulty namespace test in SmartPtrModelling

2021-07-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: NoQ, vsavchenko, xazax.hun, teemperor.
Herald added subscribers: martong, rnkovacs.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch:

- Fixes how the std-namespace test is written in SmartPtrModelling

(now accounts for functions with no Decl available)

- Adds the smart pointer checker flag check where it was missing


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106296

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
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,17 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) || 
smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +287,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,17 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) || smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +287,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106296: [analyer] Fix for faulty namespace test in SmartPtrModelling

2021-07-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 359865.
RedDocMD added a comment.

Reformatted patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,18 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +288,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,18 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +288,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:275
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)

xazax.hun wrote:
> Can we model a function call without a declaration? I wonder if we should 
> make this check more eagerly in `evalCall`. 
I think it is not that there is no Decl, but it is more likely the Decl is not 
available at that time.
```
void foo(void (*bar)(bool, bool)) {
bar();
}
```
If just foo is analyzed, then there is no Decl.
If a call to foo is analyzed, then there is a Decl.
That said, I think the check can be done in `evalCall` itself. I don't think it 
will cause a problem.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:291
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))

xazax.hun wrote:
> I'd prefer not repeating the `ModelSmartPtrDereference` check.
I don't think we can do that, since the `isBoolConversion()` check has a branch 
which is executed when `ModelSmartPtrDereference` is false.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360027.
RedDocMD added a comment.

Added a simple test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,18 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +288,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -249,8 +249,12 @@
 }
 
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +269,18 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2)
+return false;
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  if (!Decl->getDeclContext()->isStdNamespace())
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +288,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handle

[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Would this test do?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360051.
RedDocMD added a comment.

Refactored out check


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,15 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  return Decl->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +271,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +285,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,15 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  return Decl->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +271,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +285,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOpera

[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360061.
RedDocMD added a comment.

More refactor


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl() ->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl() ->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCa

[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:252-255
+  const auto *Decl = Call.getDecl();
+  if (!Decl)
+return false;
+  return Decl->getDeclContext()->isStdNamespace();

vsavchenko wrote:
> Can we use a one-liner that I suggested?
Sure


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:252
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl() ->getDeclContext()->isStdNamespace();
+}

vsavchenko wrote:
> nit: there's an extra space here.
Wow, I didn't know this is even valid syntax 😂


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360064.
RedDocMD added a comment.

Removed unnecessary white space


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.is

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360199.
RedDocMD added a comment.

Retrieving patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,11 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = 
DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, 
*Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -269,6 +269,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -335,6 +336,11 @@
 return true;
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+return true;
+  }
+
   if (!smartptr::isStdSmartPtrCall(Call))
 return false;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,11 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call, *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerConte

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360202.
RedDocMD added a comment.

Reformat


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -269,6 +269,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -365,6 +366,11 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // po

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 360218.
RedDocMD added a comment.

Minimal modelling of destructor


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -269,6 +269,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -365,6 +366,18 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);
+State = State->remove(ThisRegion);
+State = State->invalidateRegions({*InnerPtrVal}, nullptr, C.blockCount(),
+ C.getLocationContext(), true);
+C.addTransition(State);
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the s

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

This is a minimal model of destructors in smart-ptr.
Other than the need to probably model the destructor of the pointee, is there 
anything else to do?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-21 Thread Deep Majumder 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 rG80068ca6232b: [analyzer] Fix for faulty namespace test in 
SmartPtrModelling (authored by RedDocMD).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+  return true;
+
+  if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
 return handleOstreamOperator(Call, C);
 
   if (Call.isCalled(StdSwapCall)) {


Index: clang/test/Analysis/smart-ptr.cpp
===
--- clang/test/Analysis/smart-ptr.cpp
+++ clang/test/Analysis/smart-ptr.cpp
@@ -536,3 +536,10 @@
 }
 
 #endif
+
+// The following test isn't really a "smart-ptr" test
+// It came up during a bug fix (D106296)
+void testCheckForFunctionsWithNoDecl(void (*bar)(bool, bool)) {
+  // This should NOT crash.
+  bar(true, false);
+}
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -248,9 +248,12 @@
   return hasStdClassWithName(RD, BASIC_OSTREAM_NAMES);
 }
 
+static bool isStdFunctionCall(const CallEvent &Call) {
+  return Call.getDecl() && Call.getDecl()->getDeclContext()->isStdNamespace();
+}
+
 bool isStdOstreamOperatorCall(const CallEvent &Call) {
-  if (Call.getNumArgs() != 2 ||
-  !Call.getDecl()->getDeclContext()->isStdNamespace())
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
 return false;
   const auto *FC = dyn_cast(&Call);
   if (!FC)
@@ -265,6 +268,13 @@
  isStdBasicOstream(Call.getArgExpr(0));
 }
 
+static bool isPotentiallyComparisionOpCall(const CallEvent &Call) {
+  if (Call.getNumArgs() != 2 || !isStdFunctionCall(Call))
+return false;
+  return smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
+ smartptr::isStdSmartPtr(Call.getArgExpr(1));
+}
+
 bool SmartPtrModeling::evalCall(const CallEvent &Call,
 CheckerContext &C) const {
 
@@ -272,14 +282,11 @@
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))
+ 

[PATCH] D106296: [analyzer] Fix for faulty namespace test in SmartPtrModelling

2021-07-21 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:291
   // we can try this function
-  if (Call.getNumArgs() == 2 &&
-  Call.getDecl()->getDeclContext()->isStdNamespace())
-if (smartptr::isStdSmartPtr(Call.getArgExpr(0)) ||
-smartptr::isStdSmartPtr(Call.getArgExpr(1)))
-  if (handleComparisionOp(Call, C))
-return true;
-
-  if (isStdOstreamOperatorCall(Call))
+  if (ModelSmartPtrDereference && isPotentiallyComparisionOpCall(Call))
+if (handleComparisionOp(Call, C))

xazax.hun wrote:
> RedDocMD wrote:
> > xazax.hun wrote:
> > > I'd prefer not repeating the `ModelSmartPtrDereference` check.
> > I don't think we can do that, since the `isBoolConversion()` check has a 
> > branch which is executed when `ModelSmartPtrDereference` is false.
> That function is way below. I was just thinking about merging the first two 
> check. 
Looks like I missed this. Sorry!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106296

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-22 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

> But before we go there we should decide whether we want to actually go for 
> inlining (or otherwise default-evaluating) these destructors. If we do, we 
> should probably not spend too much time on improving invalidation in the 
> checker, because default evaluation would do that properly for us anyway 
> (well, it doesn't really dodge any problems such as the absence of the 
> necessary AST so we'll probably have to solve all these problems anyway, just 
> in a different setting). So it's great that we've fixed `evalCall` for 
> destructors, this could definitely land as a separate patch (tested via 
> `debug.AnalysisOrder`), but we really need to think what to do next here. So 
> I recommend gathering some data to see if proper destructor evaluation is 
> actually a real problem.

`MallocChecker` doesn't seem to mind not evaluating destructors properly. With 
the current version of the patch, the following code doesn't emit any warnings:

  class SillyPtr {
int *ptr;
bool wasMalloced;
  public:
SillyPtr(int *ptr, bool wasMalloced = false) : 
ptr(ptr), 
wasMalloced(wasMalloced) {}
~SillyPtr() {
if (wasMalloced) free(ptr);
else delete ptr;
}
  };
  
  void foo() {
int *ptr = new int(13);
SillyPtr silly(ptr);
// No leak here!
  }

I am going to remove the debug dumps and run this patch on the projects in the 
`clang/utils/analyzer/projects` folder. If I don't find any false positives 
being caused due to this lack of modelling, then I think we can defer the 
proper handling of destructors (ie, finish up the invalidation) and move on to 
the other remaining problems (notes on get for an instance).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D106739: [analyzer] Add option to SATest.py for extra checkers

2021-07-23 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: vsavchenko, NoQ, xazax.hun, teemperor.
Herald added subscribers: manas, steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch adds the flag `extra-checkers` to the sub-command `build` for
passing a comma separated list of additional checkers to include.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106739

Files:
  clang/utils/analyzer/SATest.py
  clang/utils/analyzer/SATestBuild.py


Index: clang/utils/analyzer/SATestBuild.py
===
--- clang/utils/analyzer/SATestBuild.py
+++ clang/utils/analyzer/SATestBuild.py
@@ -213,6 +213,7 @@
 project: ProjectInfo
 override_compiler: bool = False
 extra_analyzer_config: str = ""
+extra_checkers: str = ""
 is_reference_build: bool = False
 strictness: int = 0
 
@@ -233,13 +234,16 @@
 """
 A component aggregating all of the project testing.
 """
+
 def __init__(self, jobs: int, projects: List[ProjectInfo],
  override_compiler: bool, extra_analyzer_config: str,
+ extra_checkers: str,
  regenerate: bool, strictness: bool):
 self.jobs = jobs
 self.projects = projects
 self.override_compiler = override_compiler
 self.extra_analyzer_config = extra_analyzer_config
+self.extra_checkers = extra_checkers
 self.regenerate = regenerate
 self.strictness = strictness
 
@@ -252,6 +256,7 @@
 TestInfo(project,
  self.override_compiler,
  self.extra_analyzer_config,
+ self.extra_checkers,
  self.regenerate, self.strictness))
 if self.jobs <= 1:
 return self._single_threaded_test_all(projects_to_test)
@@ -305,10 +310,12 @@
 """
 A component aggregating testing for one project.
 """
+
 def __init__(self, test_info: TestInfo, silent: bool = False):
 self.project = test_info.project
 self.override_compiler = test_info.override_compiler
 self.extra_analyzer_config = test_info.extra_analyzer_config
+self.extra_checkers = test_info.extra_checkers
 self.is_reference_build = test_info.is_reference_build
 self.strictness = test_info.strictness
 self.silent = silent
@@ -414,6 +421,8 @@
 if 'SA_ADDITIONAL_CHECKERS' in os.environ:
 all_checkers = (all_checkers + ',' +
 os.environ['SA_ADDITIONAL_CHECKERS'])
+if self.extra_checkers != "":
+all_checkers += "," + self.extra_checkers
 
 # Run scan-build from within the patched source directory.
 cwd = os.path.join(directory, PATCHED_SOURCE_DIR_NAME)
Index: clang/utils/analyzer/SATest.py
===
--- clang/utils/analyzer/SATest.py
+++ clang/utils/analyzer/SATest.py
@@ -42,6 +42,7 @@
   projects,
   args.override_compiler,
   args.extra_analyzer_config,
+  args.extra_checkers,
   args.regenerate,
   args.strictness)
 tests_passed = tester.test_all()
@@ -250,6 +251,10 @@
   dest="extra_analyzer_config", type=str,
   default="",
   help="Arguments passed to to -analyzer-config")
+build_parser.add_argument("--extra-checkers",
+  dest="extra_checkers", type=str,
+  default="",
+  help="Extra checkers to enable")
 build_parser.add_argument("--projects", action="store", default="",
   help="Comma-separated list of projects to test")
 build_parser.add_argument("--max-size", action="store", default=None,


Index: clang/utils/analyzer/SATestBuild.py
===
--- clang/utils/analyzer/SATestBuild.py
+++ clang/utils/analyzer/SATestBuild.py
@@ -213,6 +213,7 @@
 project: ProjectInfo
 override_compiler: bool = False
 extra_analyzer_config: str = ""
+extra_checkers: str = ""
 is_reference_build: bool = False
 strictness: int = 0
 
@@ -233,13 +234,16 @@
 """
 A component aggregating all of the project testing.
 """
+
 def __init__(self, jobs: int, projects: List[ProjectInfo],
  override_compiler: bool, extra_analyzer_config: str,
+ extra_checkers: str,
  regenerate: bool, s

[PATCH] D106739: [analyzer] Add option to SATest.py for extra checkers

2021-07-23 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

It turns out that there is already an option called `extra-analyzer-config` to 
pass analyzer configs, like setting `ModelSmartPtrDereference` to true


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106739

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D105821#2897006 , @NoQ wrote:

>> the following code doesn't emit any warnings
>
> This code doesn't seem to have any `unique_ptr`s in it? It's not like you're 
> modeling this custom class as well? Can you try the same with the actual 
> `unique_ptr`?

The following code emits a warning for leaked memory:

  #include 
  
  class Lame {
int *ptr;
  public:
explicit Lame(int *ptr) : ptr(ptr) {}
~Lame() { delete ptr; }
  };
  
  void foo() {
int *ptr = new int(13);
auto smart = std::make_unique(ptr);
// No leak here
  }

It seems that there is a flaw in the way I was testing for warnings. 
Why does the following command not display the warnings? 
`./llvm/release/bin/clang -std=c++17 -Xclang -analyze -Xclang 
-analyzer-checker=core,cplusplus.Move,cplusplus.NewDelete,alpha.cplusplus.SmartPtr
 -Xclang -analyzer-output=text -Xclang -analyzer-config -Xclang 
cplusplus.SmartPtrModeling:ModelSmartPtrDereference=true -c lame-class.cpp`


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D106739: [analyzer] Add option to SATest.py for extra checkers

2021-07-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko is this okay?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D106739

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 361581.
RedDocMD added a comment.

Removed a fatal bug


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -279,6 +279,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -372,6 +373,19 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);
+State = State->remove(ThisRegion);
+if (InnerPtrVal)
+  State = State->invalidateRegions(*InnerPtrVal, nullptr, C.blockCount(),
+   C.getLocationContext(), true);
+C.addTransition(State);
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: S

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-28 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 362310.
RedDocMD added a comment.

Invalidating via the CallEvent


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -139,7 +139,8 @@
 
   if (RD->getDeclName().isIdentifier()) {
 StringRef Name = RD->getName();
-return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr";
+llvm::ArrayRef ValidNames(STD_PTR_NAMES);
+return llvm::is_contained(ValidNames, Name);
   }
   return false;
 }
@@ -279,6 +280,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -372,6 +374,20 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+State = DC->invalidateRegions(C.blockCount(), State);
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);
+State = State->remove(ThisRegion);
+if (InnerPtrVal)
+  State = State->invalidateRegions(*InnerPtrVal, nullptr, C.blockCount(),
+   C.getLocationContext(), true);
+C.addTransition(State);
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 
@@ -402,8 +418,8 @@
   }));
 } else {
   const auto *TrackingExpr = Call.getArgExpr(0);
-  assert(TrackingExpr->getType()->isPointerType() &&
- "Adding a non pointer value to TrackedRegionMap");
+  if (TrackingExpr->getType()->isPointerType())
+return false;
   auto ArgVal = Call.getArgSVal(0);
   State = State->set(ThisRegion, ArgVal);
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+ 

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-28 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Ah I see.
As a side note, without the "redundant" invalidation that is being done, the 
analyzer crashes on `shared_ptr`. (Because the `State` essentially remains the 
same and that's what causes the crash).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:421-422
   const auto *TrackingExpr = Call.getArgExpr(0);
-  assert(TrackingExpr->getType()->isPointerType() &&
- "Adding a non pointer value to TrackedRegionMap");
+  if (TrackingExpr->getType()->isPointerType())
+return false;
   auto ArgVal = Call.getArgSVal(0);

vsavchenko wrote:
> Okay, I'm either missing something or this condition is missing `!` here.
And that's the ghost bug I am chasing around for the last few hours.
Thanks :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:143
+llvm::ArrayRef ValidNames(STD_PTR_NAMES);
+return llvm::is_contained(ValidNames, Name);
   }

vsavchenko wrote:
> And why can't we pass `STD_PTR_NAMES` directly to `llvm::is_contained`?
Ooh, so there is an overload for that as well. :)



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:381
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);

vsavchenko wrote:
> And if it happens we are going to crash with assertion failure?
Assuming assertions are enabled, that is.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 362738.
RedDocMD added a comment.

Bug fixes, some cleanup


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -139,7 +139,7 @@
 
   if (RD->getDeclName().isIdentifier()) {
 StringRef Name = RD->getName();
-return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr";
+return llvm::is_contained(STD_PTR_NAMES, Name);
   }
   return false;
 }
@@ -279,6 +279,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -372,6 +373,20 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+State = DC->invalidateRegions(C.blockCount(), State);
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);
+State = State->remove(ThisRegion);
+if (InnerPtrVal)
+  State = State->invalidateRegions(*InnerPtrVal, nullptr, C.blockCount(),
+   C.getLocationContext(), true);
+C.addTransition(State);
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 
@@ -402,8 +417,8 @@
   }));
 } else {
   const auto *TrackingExpr = Call.getArgExpr(0);
-  assert(TrackingExpr->getType()->isPointerType() &&
- "Adding a non pointer value to TrackedRegionMap");
+  if (!TrackingExpr->getType()->isPointerType())
+return false;
   auto ArgVal = Call.getArgSVal(0);
   State = State->set(ThisRegion, ArgVal);
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:381
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);

vsavchenko wrote:
> RedDocMD wrote:
> > vsavchenko wrote:
> > > And if it happens we are going to crash with assertion failure?
> > Assuming assertions are enabled, that is.
> We should never crash or fail on valid C++ code.  We can abandon everything, 
> forbid checker to report anything on a function that has something that we 
> don't know how to handle properly, but never fail the overall analysis 
> process because of that. 
Ah right, I should have put in a TODO. This assert was put to see how often I 
run into this (none so far). It must be removed before this patch is accepted.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 362741.
RedDocMD added a comment.

Put in a TODO


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

Files:
  clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
  clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E =
+  // DstPreCall.end();
+  //  I != E; ++I)
+  //   defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  getCheckerManager().runCheckersForEvalCall(DstInvalidated, DstPreCall, *Call,
+ *this, CallOpts);
 
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
  *Call, *this);
Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -664,14 +664,11 @@
 for (const auto &EvalCallChecker : EvalCallCheckers) {
   // TODO: Support the situation when the call doesn't correspond
   // to any Expr.
-  ProgramPoint L = ProgramPoint::getProgramPoint(
-  Call.getOriginExpr(), ProgramPoint::PostStmtKind,
-  Pred->getLocationContext(), EvalCallChecker.Checker);
   bool evaluated = false;
   { // CheckerContext generates transitions(populates checkDest) on
 // destruction, so introduce the scope to make sure it gets properly
 // populated.
-CheckerContext C(B, Eng, Pred, L);
+CheckerContext C(B, Eng, Pred, Call.getProgramPoint());
 evaluated = EvalCallChecker(Call, C);
   }
   assert(!(evaluated && anyEvaluated)
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -139,7 +139,7 @@
 
   if (RD->getDeclName().isIdentifier()) {
 StringRef Name = RD->getName();
-return Name == "shared_ptr" || Name == "unique_ptr" || Name == "weak_ptr";
+return llvm::is_contained(STD_PTR_NAMES, Name);
   }
   return false;
 }
@@ -279,6 +279,7 @@
 CheckerContext &C) const {
 
   ProgramStateRef State = C.getState();
+  Call.dump();
 
   // If any one of the arg is a unique_ptr, then
   // we can try this function
@@ -372,6 +373,21 @@
 }
   }
 
+  if (const auto *DC = dyn_cast(&Call)) {
+llvm::errs() << "Found destructor call\n";
+State = DC->invalidateRegions(C.blockCount(), State);
+const MemRegion *ThisRegion = DC->getCXXThisVal().getAsRegion();
+// TODO: Remove this before pushing
+assert(ThisRegion && "We do not support explicit calls to destructor");
+const auto *InnerPtrVal = State->get(ThisRegion);
+State = State->remove(ThisRegion);
+if (InnerPtrVal)
+  State = State->invalidateRegions(*InnerPtrVal, nullptr, C.blockCount(),
+   C.getLocationContext(), true);
+C.addTransition(State);
+return true;
+  }
+
   if (!ModelSmartPtrDereference)
 return false;
 
@@ -402,8 +418,8 @@
   }));
 } else {
   const auto *TrackingExpr = Call.getArgExpr(0);
-  assert(TrackingExpr->getType()->isPointerType() &&
- "Adding a non pointer value to TrackedRegionMap");
+  if (!TrackingExpr->getType()->isPointerType())
+return false;
   auto ArgVal = Call.getArgSVal(0);
   State = State->set(ThisRegion, ArgVal);
 


Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -753,10 +753,13 @@
 *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
-  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
-   I != E; ++I)
-defaultEvalCall(Bldr, *I, *Call, CallOpts);
+  // StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
+  // for (ExplodedNo

[PATCH] D105821: [analyzer] [WIP] Model destructor for std::unique_ptr

2021-07-29 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

On running this patch on the `projects` directory, a bunch of projects emit 
false-positives: mostly of the form `Potential memory leak`. This points to the 
fact that without calling the destructor of the pointee type, we are going to 
have a lot of false positives (408 for //one// project is the worst I have 
seen). I have attached the result file.F18215302: destructor1.txt 



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105821

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 346632.
RedDocMD added a comment.
Herald added a reviewer: teemperor.
Herald added a subscriber: manas.

Added a test for multiple get's


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,72 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -16,8 +16,11 @@
 
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/OperationKinds.h"
 #include "clang/AST/Type.h"
+#include "clang/Analysis/PathDiagnostic.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -25,10 +28,14 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSen

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 346633.
RedDocMD added a comment.

Removed unnecessary includes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,72 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,10 +76,14 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &SmartPtrModeling::handleSwap},
   {{"get"}, &SmartPtrModeling::handleGet}};
+  mutable llvm::ImmutableSet::Factory StmtSetFactory;
 };
 } // end of anonymous namespace
 
 REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
+// REGISTER_SET_WITH_PROGRAMSTATE(ExprsFromGet, const Stmt *)
+REGISTER_MAP_WITH_PROGRAMSTATE(ExprsFromGet, const MemRegion *,
+   llvm::ImmutableSet)
 
 // Define the inter-checker API.
 namespace clang {
@@ -106,6 +110,142 @@
   return InnerP

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 346808.
RedDocMD marked 10 inline comments as done.
RedDocMD added a comment.

Code clean up


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -26,6 +26,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:141-163
+auto bugReportOnGet = [&](const Expr *E) -> auto {
+  if (const auto *MCE = llvm::dyn_cast(E)) {
+const auto *Method = MCE->getMethodDecl();
+const auto *Record = MCE->getRecordDecl();
+if (Method->getName() == "get" &&
+Record->getDeclContext()->isStdNamespace() &&
+Record->getName() == "unique_ptr") {

vsavchenko wrote:
> Is there any reason it's not a method of `FindWhereConstrained`?
Not really.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:179-180
+  // P.get()
+  if (const auto *InnerCastExpr =
+  llvm::dyn_cast(Sub)) {
+Sub = InnerCastExpr->getSubExpr();

vsavchenko wrote:
> I think it's better to `IgnoreParensAndCasts` instead of manual traversal.
What is IgnoreParensAndCasts`? I didn't find it in the source code anywhere 
(ripgrep, that is).



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:227
+if (const auto *DS = llvm::dyn_cast(S)) {
+  const Decl *D = DS->getSingleDecl();
+  if (const auto *VD = llvm::dyn_cast(D)) {

vsavchenko wrote:
> So, situations like `int *a = nullptr, *b = smart.get();` are not supported?
No it works even in that case (I have added a test for that). It's got to do 
with how the AST data structures are (`int *a = nullptr, *b = smart.get();` is 
considered a single decl).



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:229
+  if (const auto *VD = llvm::dyn_cast(D)) {
+for (const auto *I : PtrsTrackedAndConstrained) {
+  if (I->getName() == VD->getName()) {

vsavchenko wrote:
> `llvm::find_if`
Not sure if that'll work neatly since I actually need the return value of the 
predicate function (the report).



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:238-245
+}
+  }
+}
+  }
+}
+  }
+}

vsavchenko wrote:
> This level of nestedness is frowned upon. It is a good tell that the function 
> should be refactored.
> The following code:
> ```
> if (cond1) {
>   . . .
>   if (cond2) {
> . . .
> if (cond3) {
>   . . .
> }
>   }
> }
> return nullptr;
> ```
> can be refactored into:
> ```
> if (!cond1)
>   return nullptr;
> 
> . . .
> if (!cond2)
>   return nullptr;
> 
> . . .
> if (!cond3)
>   return nullptr;
> 
> . . .
> ```
> 
> It is easier to follow the logic if the function is composed in this manner 
> because from the very beginning you know that `else` with more stuff is not 
> going to follow.
Do you still think that's the case now? (After breaking it into functions).
I also think that for the sort of pattern matching we are doing in this patch, 
the nested if's make more sense.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-20 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 346817.
RedDocMD added a comment.

Removed un-necessary includes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,11 +76,16 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &SmartPtrModeling::handleSwap},
   {{"get"}, &

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-21 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Right, @teemperor, I will do the refactors once we figure out how to utilize 
`trackExpressionValue()` here (because that will eliminate quite a bit of code 
from `GetNoteVisitor`, so no point in refactoring those bits).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-23 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 347259.
RedDocMD added a comment.

Refactors to make code more stylistically accurate


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
+#in

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-23 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 347260.
RedDocMD added a comment.

Removed unnecessary include


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,11 +76,16 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &SmartPtrModeling::handleSwap},
   {{"get"}, &Sm

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-23 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

I have put in the refactors, @teemperor.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-26 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 348165.
RedDocMD marked 10 inline comments as done.
RedDocMD added a comment.

More refactoring


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,11 +76,18 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &SmartPtrModeling::

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-26 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 348166.
RedDocMD added a comment.

Removed extra include


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,11 +76,18 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &SmartPtrModeling::handleSwap},
   {{"get"}, &SmartPtr

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-27 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtr.h:37
+
+class GetNoteVisitor : public BugReporterVisitor {
+private:

vsavchenko wrote:
> Sorry for picking on it again, but is it visiting "get notes"? Otherwise, it 
> is just a placeholder name that doesn't tell the reader what this class is 
> actually for.
> Also, is there a reason why it is declared in the header file and couldn't be 
> a part of `SmartPtrChecker.cpp` instead?
Yes it is the line `const SVal *InnerPtr = 
State->get(ThisRegion);` in the `VisitNode` function. This 
uses the `TrackedRegionMap` which is defined in `SmartPtrModelling.cpp` but the 
visitor must be added to the bug-report in `SmartPtrChecker.cpp`.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:79
   {{"get"}, &SmartPtrModeling::handleGet}};
+  mutable llvm::ImmutableSet::Factory StmtSetFactory;
 };

vsavchenko wrote:
> I think it's better to use `REGISTER_SET_FACTORY_WITH_PROGRAMSTATE` instead 
> and keep factory as part of the state as well.
My bad, I should have put in the TODO.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:180
+  }
+  return std::shared_ptr();
+}

vsavchenko wrote:
> Just wondering if `return {};` will be sufficient here.
Yup



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:632-633
+auto EmptySet = StmtSetFactory.getEmptySet();
+auto NewStmtSet = StmtSetFactory.add(EmptySet, CallExpr);
+State = State->set(ThisRegion, NewStmtSet);
+  }

vsavchenko wrote:
> I generally don't like repeating code in both branches of the `if` statement.
> Here they share the following logic: add `CallExpr` and update the state.
> We can easily update the code to share the code:
> ```
> const auto *ExistingSet = State->get(ThisRegion);
> auto BaseSet = ExistingSet ? *ExistingSet : StmtSetFactory.getEmptySet();
> auto NewStmtSet = StmtSetFactory.add(BaseSet, CallExpr);
> State = State->set(ThisRegion, NewStmtSet);
> ```
Right, thanks :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-27 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

My bad! I forgot to submit the replies.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-27 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD marked 9 inline comments as done.
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtr.h:36
+
+class FindWhereConstrained : public BugReporterVisitor {
+private:

vsavchenko wrote:
> vsavchenko wrote:
> > nit: class name should be a noun (functions and methods are verbs)
> It is again some sort of verb. I don't know how to read it except for "emit 
> note on get"-visitor. What about something like `GetNoteEmitter`? I mean do 
> we really need to put `Visitor` in the name?
I put in `Visitor` because all the visitors that I have come across end with 
*Visitor*. But then again, I am sure that if we look, we'll find 
counter-examples. So your call here ...


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-05-27 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:258
+  const Decl *D = DS->getSingleDecl();
+  assert(D && "DeclStmt should have at least one Decl");
+  const auto *VD = llvm::dyn_cast(D);

NoQ wrote:
> That's not what the assert is saying; the assert is saying that the 
> `DeclStmt` has //exactly// one `Decl`. It basically forbids code like
> ```
> int x = 1, y = 2;
> ```
> . You may wonder why don't you crash all over the place. That's because Clang 
> CFG [[ 
> https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/clang/lib/Analysis/CFG.cpp#L2826
>  | creates its own ]] `DeclStmt`s that aren't normally present in the AST, 
> that always have exactly one declaration. This is necessary because there may 
> be non-trivial control flow between these declarations (due to, say, presence 
> of operator `?:` in the initializer) so they have to be represented as 
> different elements (possibly even in different blocks) in the CFG.
So I guess the tests at lines `317` and `378` of `smart-ptr-text-output.cpp` 
work because of the CFG messing with the AST? So should I remove the assert?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-05-31 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: NoQ, vsavchenko, xazax.hun, teemperor.
Herald added subscribers: manas, steakhal, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, 
baloghadamsoftware.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch introduces the concept of *Stoppable* visitors, ie, a
visitor that must perform some task when it runs out of nodes on which
it has work to do.
Initially, the `ReturnVisitor` is being made *stoppable*, thus allowing
it to run callbacks on completion. These callbacks are meant to be
supplied from `trackExpressionValue`.
Thus, this patch will also allow `trackExpressionValue` to recieve a
callback to run when it is done tracking.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103434

Files:
  clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
  clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -320,6 +320,22 @@
   return P;
 }
 
+//===--===//
+// Implementation of StoppableBugReporterVisitor
+//===--===//
+
+StoppableBugReporterVisitor::~StoppableBugReporterVisitor() {
+  assert(Stopped && "Stoppable visitor not stopped in its lifetime");
+}
+
+void StoppableBugReporterVisitor::Stop(const ExplodedNode *Curr,
+   BugReporterContext &BRC,
+   PathSensitiveBugReport &BR) {
+  assert(!Stopped && "Stop() can be called only once in visitor's lifetime");
+  Stopped = true;
+  OnStop(Curr, BRC, BR);
+}
+
 //===--===//
 // Implementation of NoStoreFuncVisitor.
 //===--===//
@@ -876,6 +892,9 @@
 
 namespace {
 
+using VisitorCallback = llvm::function_ref;
+
 /// Emits an extra note at the return statement of an interesting stack frame.
 ///
 /// The returned value is marked as an interesting value, and if it's null,
@@ -883,7 +902,7 @@
 ///
 /// This visitor is intended to be used when another visitor discovers that an
 /// interesting value comes from an inlined function call.
-class ReturnVisitor : public BugReporterVisitor {
+class ReturnVisitor : public StoppableBugReporterVisitor {
   const StackFrameContext *CalleeSFC;
   enum {
 Initial,
@@ -895,12 +914,14 @@
   bool ShouldInvalidate = true;
   AnalyzerOptions& Options;
   bugreporter::TrackingKind TKind;
+  VisitorCallback Callback;
 
 public:
   ReturnVisitor(const StackFrameContext *Frame, bool Suppressed,
-AnalyzerOptions &Options, bugreporter::TrackingKind TKind)
-  : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed),
-Options(Options), TKind(TKind) {}
+AnalyzerOptions &Options, bugreporter::TrackingKind TKind,
+VisitorCallback &&Callback = nullptr)
+  : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed), Options(Options),
+TKind(TKind), Callback(Callback) {}
 
   static void *getTag() {
 static int Tag = 0;
@@ -913,6 +934,13 @@
 ID.AddBoolean(EnableNullFPSuppression);
   }
 
+  void OnStop(const ExplodedNode *Curr, BugReporterContext &BRC,
+  PathSensitiveBugReport &BR) const override {
+if (Callback) {
+  Callback(Curr, BRC, BR);
+}
+  }
+
   /// Adds a ReturnVisitor if the given statement represents a call that was
   /// inlined.
   ///
@@ -1123,6 +1151,10 @@
 else
   BR.markInteresting(CalleeSFC);
 
+// Since we know that no other notes will be emitted subsequently by this
+// visitor.
+Stop(N, BRC, BR);
+
 return EventPiece;
   }
 
Index: clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
===
--- clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -85,6 +85,26 @@
 const PathSensitiveBugReport &BR);
 };
 
+/// StoppableBugReporterVisitor is a special type of visitor that is known to
+/// not have any useful work to do after it reaches a certain node in its
+/// traversal. When it does reach that node, the \ref Stop method must be
+/// called. This in turn calls the \ref OnStop method (which must be overriden
+/// in the sub-class). Note that such visitors *must* be stopped exactly once.
+class StoppableBugReporterVisitor : public BugReporterVisitor {
+  /// This method is run once the \ref Stop meth

[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-05-31 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

**Note: This patch is only partially done.**

The following things are still left:

- `trackExpressionValue` must receive a callback
- The callback must be passed to a visitor (`ReturnVisitor` for now)
- Tests to verify that `ReturnVisitor` actually does what we intend it to do 
(call the callback at the right place).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103434

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


[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-06-01 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:95
+  /// This method is run once the \ref Stop method is called.
+  virtual void OnStop(const ExplodedNode *Curr, BugReporterContext &BRC,
+  PathSensitiveBugReport &BR) const = 0;

xazax.hun wrote:
> Are we anticipating visitors that do something else other than calling a 
> callback when they are stopped? If that is not the case, I wonder if 
> storing/invoking the visitor in this class would make more sense. 
I think it was decided in the last meet that we should not make this new 
abstraction overtly  //specific//. So a stoppable visitor is free to have a 
callback (like the `ReturnVisitor` now does) and is also free to have some more 
behavior in the `OnStop` method. Also making the `OnStop` method pure-virtual 
means that the sub-classes are required to override it (so it can't be ignored).



Comment at: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:97
+  PathSensitiveBugReport &BR) const = 0;
+  bool Stopped;
+

xazax.hun wrote:
> Should we allow derived classes or even others query if a visitor was 
> stopped? Or is this only for catching bugs? 
Right now it can't be queried. The purpose of the `Stopped` field is primarily 
for catching bugs. (this ensures visitors are stopped exactly //once//).



Comment at: 
clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h:104
+  /// Call this method once the visitor runs out of useful nodes to process.
+  void Stop(const ExplodedNode *Curr, BugReporterContext &BRC,
+PathSensitiveBugReport &BR);

xazax.hun wrote:
> Do you anticipate cases where the visitor itself does not know that it needs 
> to stop (e.g. in the Visit functions) so someone needs to call this from the 
> outside?
No, I don't. Are you suggesting I should make it a protected method?



Comment at: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp:895
 
+using VisitorCallback = llvm::function_ref;

vsavchenko wrote:
> `function_ref` is a reference, it doesn't own the function. It means that it 
> shouldn't outlive the actual function object (very similar to `StringRef`).
So I guess this means that the callback must be a method/lambda that 
//persists// (ie, it can't be a lambda in a `VisitNode` method, but must be 
stored a field in the class).



Comment at: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp:1156
+// visitor.
+Stop(N, BRC, BR);
+

I am **not** entirely certain this is the right place to call the Stop method. 
It seems reasonable but I am not sure.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103434

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


[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-06-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 349295.
RedDocMD added a comment.

trackExpressionValue recieving callback, passing it to ReturnVisitor


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103434

Files:
  clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
  clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -320,6 +320,22 @@
   return P;
 }
 
+//===--===//
+// Implementation of StoppableBugReporterVisitor
+//===--===//
+
+StoppableBugReporterVisitor::~StoppableBugReporterVisitor() {
+  assert(Stopped && "Stoppable visitor not stopped in its lifetime");
+}
+
+void StoppableBugReporterVisitor::Stop(const ExplodedNode *Curr,
+   BugReporterContext &BRC,
+   PathSensitiveBugReport &BR) {
+  assert(!Stopped && "Stop() can be called only once in visitor's lifetime");
+  Stopped = true;
+  OnStop(Curr, BRC, BR);
+}
+
 //===--===//
 // Implementation of NoStoreFuncVisitor.
 //===--===//
@@ -883,7 +899,7 @@
 ///
 /// This visitor is intended to be used when another visitor discovers that an
 /// interesting value comes from an inlined function call.
-class ReturnVisitor : public BugReporterVisitor {
+class ReturnVisitor : public StoppableBugReporterVisitor {
   const StackFrameContext *CalleeSFC;
   enum {
 Initial,
@@ -895,12 +911,14 @@
   bool ShouldInvalidate = true;
   AnalyzerOptions& Options;
   bugreporter::TrackingKind TKind;
+  VisitorCallback Callback;
 
 public:
   ReturnVisitor(const StackFrameContext *Frame, bool Suppressed,
-AnalyzerOptions &Options, bugreporter::TrackingKind TKind)
-  : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed),
-Options(Options), TKind(TKind) {}
+AnalyzerOptions &Options, bugreporter::TrackingKind TKind,
+VisitorCallback &&Callback)
+  : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed), Options(Options),
+TKind(TKind), Callback(Callback) {}
 
   static void *getTag() {
 static int Tag = 0;
@@ -913,6 +931,13 @@
 ID.AddBoolean(EnableNullFPSuppression);
   }
 
+  void OnStop(const ExplodedNode *Curr, BugReporterContext &BRC,
+  PathSensitiveBugReport &BR) const override {
+if (Callback) {
+  Callback(Curr, BRC, BR);
+}
+  }
+
   /// Adds a ReturnVisitor if the given statement represents a call that was
   /// inlined.
   ///
@@ -923,7 +948,8 @@
   static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
 PathSensitiveBugReport &BR,
 bool InEnableNullFPSuppression,
-bugreporter::TrackingKind TKind) {
+bugreporter::TrackingKind TKind,
+VisitorCallback Callback) {
 if (!CallEvent::isCallStmt(S))
   return;
 
@@ -994,9 +1020,9 @@
   if (Optional RetLoc = RetVal.getAs())
 EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
 
-BR.addVisitor(std::make_unique(CalleeContext,
-   EnableNullFPSuppression,
-   Options, TKind));
+BR.addVisitor(
+std::make_unique(CalleeContext, EnableNullFPSuppression,
+Options, TKind, std::move(Callback)));
   }
 
   PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
@@ -1123,6 +1149,10 @@
 else
   BR.markInteresting(CalleeSFC);
 
+// Since we know that no other notes will be emitted subsequently by this
+// visitor.
+Stop(N, BRC, BR);
+
 return EventPiece;
   }
 
@@ -1966,7 +1996,8 @@
const Expr *E,
PathSensitiveBugReport &report,
bugreporter::TrackingKind TKind,
-   bool EnableNullFPSuppression) {
+   bool EnableNullFPSuppression,
+   VisitorCallback Callback) {
 
   if (!E || !InputNode)
 return false;
@@ -2067,7 +2098,7 @@
   SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
 
   ReturnVisitor::addVisitorIfNecessary(
-LVNode, Inner, report, EnableNullFPSuppression, TKind

[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-06-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

The following things are now done:

- `trackExpressionValue` must receive a callback
- The callback must be passed to a visitor (`ReturnVisitor` for now)

I still don't know a good way to test the following:

- Tests to verify that `ReturnVisitor` actually does what we intend it to do 
(call the callback at the right place).

@vsavchenko, @NoQ, @xazax.hun, @teemperor can you give some suggestions?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103434

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-06-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD marked 7 inline comments as done.
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:258
+  const Decl *D = DS->getSingleDecl();
+  assert(D && "DeclStmt should have at least one Decl");
+  const auto *VD = llvm::dyn_cast(D);

RedDocMD wrote:
> NoQ wrote:
> > That's not what the assert is saying; the assert is saying that the 
> > `DeclStmt` has //exactly// one `Decl`. It basically forbids code like
> > ```
> > int x = 1, y = 2;
> > ```
> > . You may wonder why don't you crash all over the place. That's because 
> > Clang CFG [[ 
> > https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/clang/lib/Analysis/CFG.cpp#L2826
> >  | creates its own ]] `DeclStmt`s that aren't normally present in the AST, 
> > that always have exactly one declaration. This is necessary because there 
> > may be non-trivial control flow between these declarations (due to, say, 
> > presence of operator `?:` in the initializer) so they have to be 
> > represented as different elements (possibly even in different blocks) in 
> > the CFG.
> So I guess the tests at lines `317` and `378` of `smart-ptr-text-output.cpp` 
> work because of the CFG messing with the AST? So should I remove the assert?
@NoQ?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-06-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 349332.
RedDocMD added a comment.

Moved visitor entirely to SmartPtrChecker.cpp, other refactors, better naming.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

Files:
  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

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
@@ -306,10 +306,81 @@
 };
 
 void derefAfterBranchingOnUnknownInnerPtr(std::unique_ptr P) {
-  A *RP = P.get();
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
   if (!RP) { // expected-note {{Assuming 'RP' is null}}
 // expected-note@-1 {{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 multpleDeclsWithGet(std::unique_ptr P) {
+  A *dummy1 = nullptr, *RP = P.get(), *dummy2; // expected-note {{Obtained null inner pointer from 'P'}}
+  if (!RP) {   // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 multipleGetsShouldNotAllHaveNotes(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  A *dummy1 = P.get();
+  A *dummy2 = P.get();
+  if (!RP) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{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 getShouldNotAlwaysLeaveANote() {
+  std::unique_ptr P; // expected-note {{Default constructed smart pointer 'P' is null}}
+  A *a = P.get();
+  P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+}
+
+void getShouldNotLeaveANoteAfterReset(std::unique_ptr P) {
+  A *a = P.get();
+  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'}}
+}
+
+void getShouldNotLeaveNoteWhenPtrNotUsed(std::unique_ptr P) {
+  A *a = P.get();
+  if (!P) { // expected-note {{Taking true branch}}
+// expected-note@-1 {{Assuming smart pointer 'P' is null}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithWhileLoop(std::unique_ptr P) {
+  A *RP = P.get(); // expected-note {{Obtained null inner pointer from 'P'}}
+  while (!RP) {// expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveANoteWithForLoop(std::unique_ptr P) {
+  for (A *RP = P.get(); !RP;) { // expected-note {{Assuming 'RP' is null}}
+// expected-note@-1 {{Loop condition is true.  Entering loop body}}
+// expected-note@-2 {{Obtained null inner pointer from 'P'}}
+P->foo(); // expected-warning {{Dereference of null smart pointer 'P' [alpha.cplusplus.SmartPtr]}}
+// expected-note@-1{{Dereference of null smart pointer 'P'}}
+  }
+}
+
+void getShouldLeaveNoteOnChaining(std::unique_ptr P) {
+  A *praw = P.get(), *other; // expected-note {{Obtained null inner pointer from 'P'}}
+  other = praw;  // expected-note {{Obtained null value here}}
+  if (!other) {  // expected-note {{Assuming 'other' is null}}
+// expected-note@-1 {{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'}}
+  }
+}
\ No newline at end of file
Index: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
===
--- clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -76,11 +76,18 @@
   {{"release"}, &SmartPtrModeling::handleRelease},
   {{"swap", 1}, &

[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

2021-06-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Important question from @vsavchenko:

> I have two major questions about this implementation:
>
> - Why don't we need an actual check for `IfStmt`? Won't it trigger on `bool 
> unused = !pointer;`? And if so it won't mean **constrained**.
> - Why do we only care about implicit pointer-to-bool conversion? What about 
> situations like `pointer == nullptr`, `NULL != pointer`, 
> `__builtin_expect(pointer, 0)`, etc?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183

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


[PATCH] D103434: [analyzer] Allow visitors to run callbacks on completion

2021-06-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D103434#2795940 , @vsavchenko 
wrote:

> I was thinking a lot about this problem after our last call, and even though 
> `StoppableVisitor` helps to solve the problem that we have, it is extremely 
> unclear when this callback is called and should be called.
> I decided to restore the balance (and rid of all younglings, maybe) and put 
> together this interface: D103605 .  I still 
> need to migrate the existing code into the new architecture, but it can be 
> done incrementally.

Right. I then perhaps should focus now on D98726 
, and then return to `GetNoteEmitter`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103434

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-24 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, a.sidorin, szepet, baloghadamsoftware.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

In the function isValidBaseClass() of
clang/lib/StaticAnalyzer/Core/MemRegion.cpp,
added a case to return true when BaseClass and Super refer to
the same CXXRecordDecl. This case arises when a pointer-to-member
field is declared with a static cast from a pointer-to-member of
a sub-class.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95307

Files:
  clang/lib/StaticAnalyzer/Core/MemRegion.cpp
  clang/test/Analysis/pointer-to-member.cpp


Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -231,6 +231,23 @@
 }
 } // end of testPointerToMemberDiamond namespace
 
+namespace testPointerToMemberViaStaticCast {
+// From bug #48739
+struct Base {
+  int field;
+};
+
+struct Derived : public Base {};
+
+void static_cast_test() {
+  int Derived::* derived_field = &Derived::field;
+  Base base;
+  base.field = 5;
+  int Base::* base_field = static_cast(derived_field);
+  clang_analyzer_eval(base.*base_field == 5); // expected-warning {{TRUE}}
+}
+}
+
 namespace testAnonymousMember {
 struct A {
   int a;
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1172,6 +1172,9 @@
   if (!Class)
 return true;
 
+  if (Class == BaseClass)
+return true;
+
   if (IsVirtual)
 return Class->isVirtuallyDerivedFrom(BaseClass);
 


Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -231,6 +231,23 @@
 }
 } // end of testPointerToMemberDiamond namespace
 
+namespace testPointerToMemberViaStaticCast {
+// From bug #48739
+struct Base {
+  int field;
+};
+
+struct Derived : public Base {};
+
+void static_cast_test() {
+  int Derived::* derived_field = &Derived::field;
+  Base base;
+  base.field = 5;
+  int Base::* base_field = static_cast(derived_field);
+  clang_analyzer_eval(base.*base_field == 5); // expected-warning {{TRUE}}
+}
+}
+
 namespace testAnonymousMember {
 struct A {
   int a;
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -1172,6 +1172,9 @@
   if (!Class)
 return true;
 
+  if (Class == BaseClass)
+return true;
+
   if (IsVirtual)
 return Class->isVirtuallyDerivedFrom(BaseClass);
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95307#2519283 , @vsavchenko wrote:

> In D95307#2518592 , @NoQ wrote:
>
>> This patch shoots the messenger but someone still needs to conduct a proper 
>> investigation. The assertion is losing a lot more of its bug-finding power 
>> than necessary to uncover the current cornercase; i really hope to preserve 
>> it instead.
>
> You mean the failing assertion from the tests?

Few hours before there was a message saying that there was some buggy commit to 
the build-bot. Are you referring to the build failure above?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Funnily enough, when I run `ninja clang-check` I don't get any errors.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-25 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

Thanks @NoQ for the tip on the right test command!
My own belief is that this patch is just a hack that squelches the problem, 
instead of solving it. I am limited by my own inexperience with the codebase 
and am trying to learn more to help better.

That said, couple of observations that I made while exploring the bug:

1. Referring to loop in line 1119 of `SimpleSValBuilder.cpp`.  This loop is 
necessary since we need to access the right sub-object. (The test at line 203 
in `pointer-to-member.cpp` is a good demonstration why)
2. However,  when we have static casts on the pointer-to-member, this loop is 
also triggered.

The trouble is that the above two cases behave inconsistently with each other. 
Consider the following example for case 1:

  struct B {
int f;
  };
  struct L1 : public B { };
  struct R1 : public B { };
  struct M : public L1, R1 { };
  struct L2 : public M { };
  struct R2 : public M { };
  struct D2 : public L2, R2 { };
  
  void diamond() {
M m;
  
static_cast(&m)->f = 7;
static_cast(&m)->f = 16;
  
int L1::* pl1 = &B::f;
int M::* pm_via_l1 = pl1;
  
int R1::* pr1 = &B::f;
int M::* pm_via_r1 = pr1;
  
(m.*(pm_via_l1) == 7); 
(m.*(pm_via_r1) == 16);
  }

This behaves correctly. If we run `I->getType()->dump()` on each iteration of 
the loop, we get something like this:

  RecordType 0x55a70ad60d50 'struct L1'
  `-CXXRecord 0x55a70ad60cb8 'L1'
  RecordType 0x55a70ad60b20 'struct B'
  `-CXXRecord 0x55a70ad60a90 'B'
  2 levels of base specifiers
  RecordType 0x55a70ad60f50 'struct R1'
  `-CXXRecord 0x55a70ad60ec0 'R1'
  RecordType 0x55a70ad60b20 'struct B'
  `-CXXRecord 0x55a70ad60a90 'B'
  2 levels of base specifiers

Running the same analysis for the regressing code:

  struct Base {
int field;
  };
  
  struct Derived : public Base {};
  
  void static_cast_test() {
int Derived::* derived_field = &Derived::field;
Base base;
base.field = 5;
int Base::* base_field = static_cast(derived_field);
(base.*base_field == 5);

we get the following dump;

  RecordType 0x55676ded06a0 'struct Base'
  `-CXXRecord 0x55676ded0610 'Base'
  RecordType 0x55676ded06a0 'struct Base'
  `-CXXRecord 0x55676ded0610 'Base'
  2 base specifier

Clearly, there is a bug elsewhere. The method `PointerToMember::begin()` 
returns an iterator to a list of `CXXBaseSpecifiers`, which according to the 
docs is for keeping track of `static_casts`. However, it seems that the 
base-specifier list is being used for something else. I am not sure in which 
function introduces this problem. Probably somewhere in the ASTVisitor for the 
StaticAnalyzer this problem is introduced. I will keep on digging and add more 
comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-26 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

On further digging as to how pointer-to-members are handled in StaticAnalyzer, 
I discovered that in `BasicValueFactory::accumCXXBase() for the example given 
in my test produces the two `CXXBaseSpecifier` for the pointer-to-member. At 
line 195, one base specifier is added while the other is added in the loop in 
201. The loop accounts for the static_cast while line 195 adds a base specifier 
from the expression being cast. 
This causes the duplication. I will try to update this patch to handle the 
duplication.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-27 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 319607.
RedDocMD added a comment.

Removing duplication of CXXBaseSpecifiers when they are created for 
PointerToMember
Removed hackish weakening of assert


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

Files:
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/MemRegion.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -231,6 +231,23 @@
 }
 } // end of testPointerToMemberDiamond namespace
 
+namespace testPointerToMemberViaStaticCast {
+// From bug #48739
+struct Base {
+  int field;
+};
+
+struct Derived : public Base {};
+
+void static_cast_test() {
+  int Derived::*derived_field = &Derived::field;
+  Base base;
+  base.field = 5;
+  int Base::*base_field = static_cast(derived_field);
+  clang_analyzer_eval(base.*base_field == 5); // expected-warning {{TRUE}}
+}
+} // namespace testPointerToMemberViaStaticCast
+
 namespace testAnonymousMember {
 struct A {
   int a;
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -63,7 +63,7 @@
 //===--===//
 
 template 
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,
+RegionTy *MemRegionManager::getSubRegion(const Arg1Ty arg1,
  const SuperTy *superRegion) {
   llvm::FoldingSetNodeID ID;
   RegionTy::ProfileRegion(ID, arg1, superRegion);
@@ -80,7 +80,7 @@
 }
 
 template 
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+RegionTy *MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
  const SuperTy *superRegion) {
   llvm::FoldingSetNodeID ID;
   RegionTy::ProfileRegion(ID, arg1, arg2, superRegion);
@@ -96,9 +96,9 @@
   return R;
 }
 
-template 
-RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
+template 
+RegionTy *MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,
  const Arg3Ty arg3,
  const SuperTy *superRegion) {
   llvm::FoldingSetNodeID ID;
@@ -129,8 +129,8 @@
 // Basic methods.
 //===--===//
 
-bool SubRegion::isSubRegionOf(const MemRegion* R) const {
-  const MemRegion* r = this;
+bool SubRegion::isSubRegionOf(const MemRegion *R) const {
+  const MemRegion *r = this;
   do {
 if (r == R)
   return true;
@@ -143,7 +143,7 @@
 }
 
 MemRegionManager &SubRegion::getMemRegionManager() const {
-  const SubRegion* r = this;
+  const SubRegion *r = this;
   do {
 const MemRegion *superRegion = r->getSuperRegion();
 if (const auto *sr = dyn_cast(superRegion)) {
@@ -164,9 +164,7 @@
 
 const ObjCIvarDecl *ObjCIvarRegion::getDecl() const { return IVD; }
 
-QualType ObjCIvarRegion::getValueType() const {
-  return getDecl()->getType();
-}
+QualType ObjCIvarRegion::getValueType() const { return getDecl()->getType(); }
 
 QualType CXXBaseObjectRegion::getValueType() const {
   return QualType(getDecl()->getTypeForDecl(), 0);
@@ -237,26 +235,25 @@
   ID.AddPointer(superRegion);
 }
 
-void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const Expr *Ex, unsigned cnt,
- const MemRegion *superRegion) {
+void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *Ex,
+ unsigned cnt, const MemRegion *superRegion) {
   ID.AddInteger(static_cast(AllocaRegionKind));
   ID.AddPointer(Ex);
   ID.AddInteger(cnt);
   ID.AddPointer(superRegion);
 }
 
-void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+void AllocaRegion::Profile(llvm::FoldingSetNodeID &ID) const {
   ProfileRegion(ID, Ex, Cnt, superRegion);
 }
 
-void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID &ID) const {
   CompoundLiteralRegion::ProfileRegion(ID, CL, superRegion);
 }
 
-void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
   const CompoundLiteralExpr *CL,
-  const MemRegion* superRegion) {
+  const MemRegion *superRegion) {
   ID.AddInteger(static_cast(CompoundLiteralRegionKind));
   ID.AddPointer(CL);
   ID.AddPointer(superRegion);
@@ -278,9 +275,9 @@
   Pro

[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-28 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@kromanenkov  I guess it won't work then. Thanks for the idea!
Now that I think about it removing duplicates is probably not the right thing 
to do. The problem arises because the call PTMD->getCXXBaseList() should 
ideally return the list of previous casts, but instead returns the base 
class(es) of the struct whose pointer-to-member we are defining.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-01-31 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD abandoned this revision.
RedDocMD added a comment.

I clearly am taking the wrong approach to this problem. I will need to 
reconsider how PointerToMember is actually modelled before solving this problem


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

2021-02-01 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95307#2533259 , @vsavchenko wrote:

> I don't know if this is useful or not, but pointer-to-members used to be 
> `void *` up until very recently.  Here is my change on that topic (and it 
> probably where the bug you're trying to fix initiated): 
> https://reviews.llvm.org/D85817
> I thought, it can be useful to see the areas of code where it all happens.

Thank you @vsavchenko. I had actually seen this review by examining the file 
blames. I don't think the problem is in your review. The trouble is that when 
the CXXBaseSpecifier list in PointerToMemberData is initialized, it receives a 
list. That list I suspect contains passed in the base class of the struct. But 
this list is supposed to be for following static casts. I have to localize that 
logic.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95307

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


[PATCH] D95846: [analyzer] Updated comments to reflect D85817

2021-02-01 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: NoQ, vsavchenko.
Herald added subscribers: steakhal, ASDenysPetrov, Charusso, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Changed DeclaratorDecl in comment to NamedDecl


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95846

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -511,10 +511,10 @@
 /// This value is qualified as NonLoc because neither loading nor storing
 /// operations are applied to it. Instead, the analyzer uses the L-value coming
 /// from pointer-to-member applied to an object.
-/// This SVal is represented by a DeclaratorDecl which can be a member function
-/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
-/// is required to accumulate the pointer-to-member cast history to figure out
-/// the correct subobject field.
+/// This SVal is represented by a NamedDecl which can be a member function
+/// pointer or a member data pointer and an optional list of CXXBaseSpecifiers.
+/// This list is required to accumulate the pointer-to-member cast history to
+/// figure out the correct subobject field.
 class PointerToMember : public NonLoc {
   friend class ento::SValBuilder;
 


Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -511,10 +511,10 @@
 /// This value is qualified as NonLoc because neither loading nor storing
 /// operations are applied to it. Instead, the analyzer uses the L-value coming
 /// from pointer-to-member applied to an object.
-/// This SVal is represented by a DeclaratorDecl which can be a member function
-/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
-/// is required to accumulate the pointer-to-member cast history to figure out
-/// the correct subobject field.
+/// This SVal is represented by a NamedDecl which can be a member function
+/// pointer or a member data pointer and an optional list of CXXBaseSpecifiers.
+/// This list is required to accumulate the pointer-to-member cast history to
+/// figure out the correct subobject field.
 class PointerToMember : public NonLoc {
   friend class ento::SValBuilder;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95846: [analyzer] Updated comments to reflect D85817

2021-02-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95846#2536380 , @vsavchenko wrote:

> Thanks for doing that!
> I have a minor nit-picking comment, it is preferable to use present-tense 
> imperative-style commit messages, i.e. "Update comment...".

Noted. I will do that in future.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95846

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


[PATCH] D95877: [analyer] Fix static_cast on pointer-to-member handling

2021-02-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: vsavchenko, NoQ, xazax.hun, dcoughlin.
Herald added subscribers: martong, Charusso, rnkovacs.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This commit fixes bug #48739. The bug was caused by the way static_casts
on pointer-to-member caused the CXXBaseSpecifier list of a
MemberToPointer to grow instead of shrink.
The list is now grown by implicit casts and corresponding entries are
removed by static_casts. No-op static_casts cause no effect.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,25 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,11 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
   llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  CastE->path_begin(), CastE->path_end()),
+  *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -23,6 +23,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include 
 #include 
+#include 
 #include 
 
 using namespace clang;
@@ -178,7 +179,11 @@
 
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
   llvm::ImmutableList PathList;
@@ -195,8 +200,38 @@
 PathList = PTMD->getCXXBaseList();
   }
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
+  if (kind == CK_DerivedToBaseMemberPointer) {
+// Here we pop off matching CXXBaseSpecifiers from PathList.
+// Because, CK_DerivedToBaseMemberPointer comes from a static_cast and
+// serves to remove a matching implicit cast. Note that static_cast's that
+// are no-ops do not count since they produce an empty PathRange, a nice
+// thing about Clang AST.
+std::list BaseList;
+for (const auto &I : PathList)
+  BaseList.push_back(I);
+
+auto find_first =
+[](auto begin, auto end, const CXXBaseSpecifier *baseSpec) -> auto {
+  for (auto it = begin; it != end; ++it)
+if ((*it)->getType() == baseSpec->getType())
+  return it;
+  return end;
+};
+
+for (const auto &PathBase : llvm::reverse(PathRange)) {
+  auto DelIt = find_first(BaseList.begin(), BaseList.end(), PathBase);
+  assert(DelIt != BaseList.end() && "PTM has insufficient base specifiers");
+  BaseList.erase(DelIt);
+}
+
+PathList =

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-02 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:223
+  auto DelIt = find_first(BaseList.begin(), BaseList.end(), PathBase);
+  assert(DelIt != BaseList.end() && "PTM has insufficient base 
specifiers");
+  BaseList.erase(DelIt);

vsavchenko wrote:
> It's better to be more verbose in the assertions.
> Additionally, I'm not sure that it is clear what it is all about because 
> pointer-to-members do not have base specifiers.
Well, the `PointerToMember` contains a `PointerToMemberData`, which has a list 
of `CXXBaseSpecifier`. Should I put something like: "PointerToMemberData has 
insufficient number of base specifiers"?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321074.
RedDocMD added a comment.

Remoevd the use of std::list with llvm::SmallVector. Removed the need to delete 
elements.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,25 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,11 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
   llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  CastE->path_begin(), CastE->path_end()),
+  *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,8 +21,11 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include 
 #include 
 #include 
+#include 
 #include 
 
 using namespace clang;
@@ -178,7 +181,11 @@
 
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
   llvm::ImmutableList PathList;
@@ -195,8 +202,36 @@
 PathList = PTMD->getCXXBaseList();
   }
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
+  if (kind == CK_DerivedToBaseMemberPointer) {
+// Here we pop off matching CXXBaseSpecifiers from PathList.
+// Because, CK_DerivedToBaseMemberPointer comes from a static_cast and
+// serves to remove a matching implicit cast. Note that static_cast's that
+// are no-ops do not count since they produce an empty PathRange, a nice
+// thing about Clang AST.
+
+llvm::SmallVector, 64> BaseList;
+// Initially mark all CXXBaseSpecifier to be included
+for (const auto &I : PathList)
+  BaseList.push_back({I, true});
+
+for (const auto &I : PathRange) {
+  auto *it = std::find_if(
+  BaseList.begin(), BaseList.end(), [&](const auto &B) -> auto {
+return I->getType() == B.first->getType();
+  });
+  it->second = false;
+}
+auto BaseListFilteredRange = llvm::make_filter_range(
+llvm::make_range(BaseList.begin(), BaseList.end()),
+[](const auto &I) -> bool { return I.second; });
+
+PathList = CXXBaseListFactory.getEmptyList();
+for (const auto &I : BaseListFilteredRange)
+  PathList = CXXBaseListFactory.add(I.first, PathList);
+  } else {
+for (const auto &I : llvm::reverse(PathRange))
+  PathLi

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321078.
RedDocMD added a comment.

Made assertion more verbose


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,25 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,11 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
   llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  CastE->path_begin(), CastE->path_end()),
+  *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,8 +21,11 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include 
 #include 
 #include 
+#include 
 #include 
 
 using namespace clang;
@@ -178,7 +181,11 @@
 
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
   llvm::ImmutableList PathList;
@@ -195,8 +202,39 @@
 PathList = PTMD->getCXXBaseList();
   }
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
+  if (kind == CK_DerivedToBaseMemberPointer) {
+// Here we pop off matching CXXBaseSpecifiers from PathList.
+// Because, CK_DerivedToBaseMemberPointer comes from a static_cast and
+// serves to remove a matching implicit cast. Note that static_cast's that
+// are no-ops do not count since they produce an empty PathRange, a nice
+// thing about Clang AST.
+
+llvm::SmallVector, 64> BaseList;
+// Initially mark all CXXBaseSpecifier to be included
+for (const auto &I : PathList)
+  BaseList.push_back({I, true});
+
+for (const auto &I : PathRange) {
+  auto *it = std::find_if(
+  BaseList.begin(), BaseList.end(), [&](const auto &B) -> auto {
+return I->getType() == B.first->getType();
+  });
+  assert(it != BaseList.end() &&
+ "Underlying PointerToMemberData of PTM has insufficient number of "
+ "CXXBaseSpecifiers");
+  it->second = false;
+}
+auto BaseListFilteredRange = llvm::make_filter_range(
+llvm::make_range(BaseList.begin(), BaseList.end()),
+[](const auto &I) -> bool { return I.second; });
+
+PathList = CXXBaseListFactory.getEmptyList();
+for (const auto &I : BaseListFilteredRange)
+  PathList = CXXBaseListFactory.add(I.fi

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko could you please see the current logic if it is better now?




Comment at: clang/test/Analysis/pointer-to-member.cpp:304
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));

vsavchenko wrote:
> What about other type of casts?
I am looking into this.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.






Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:226
+llvm::make_range(BaseList.begin(), BaseList.end()),
+[](const auto &I) -> bool { return I.second; });
+

vsavchenko wrote:
> I think it's all a bit too complicated now.
> 
> Right now you have two nested loops:
>   1. over `PathRange`
>   2. over `BaseList` (in `find_if`)
> 
> It won't be a problem to put them in another order, so when you make a 
> `filter_range`, you can have `llvm::find_if` which will iterate over 
> `PathRange` and captures the given `BaseList` element. So, yes nested lambdas.
> 
> Here is a sketch of the solution:
> ```
> auto BaseListFilteredRange = llvm::make_filter_range(
> BaseList, // you don't need to make_range here, BaseList IS a range
> [&PathRange](const CXXBaseSpecifier *Base) {
>   return llvm::find_if(PathRange, [Base](const auto &It) {
> return Base->getType() == It.first->getType();
>   }) == PathRange.end();
> });
> ```
> 
> Aaaand while I was writing that, it got me thinking that we don't need 
> `BaseList` in the first place:
> ```
> for (const CXXBaseSpecifier *Base : PathList)
>   if (llvm::none_of(PathRange,
> [Base](const auto &It) { return Base->getType() == 
> It.first->getType(); })
>   PathList = CXXBaseListFactory.add(Base, PathList);
> ```
Hmm, I really should brush up on my functional programming and think more in 
terms of STL/LLVM algorithms. Thank you for pointing out this solution, 
@vsavchenko!

One thing I noticed though, the shortened logic that you suggested removes all 
matching instances from PathList, while my intention was to remove only the 
first one of every kind. If there are no repetitions, it is the same. And, 
normally, repetitions should not be present in the PathList retrieved from PTM. 
It is a bug elsewhere if that happens. So should I add an assert for that here?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321139.
RedDocMD added a comment.

Cleaner implementation of the popping logic, using STL/LLVM algorithms


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,25 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,11 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
   llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  CastE->path_begin(), CastE->path_end()),
+  *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,8 +21,10 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
+#include 
 #include 
 
 using namespace clang;
@@ -178,26 +180,63 @@
 
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())
   ND = PTMDT.get();
 
-PathList = CXXBaseListFactory.getEmptyList();
+BaseSpecList = CXXBaseListFactory.getEmptyList();
   } else { // const PointerToMemberData *
 const PointerToMemberData *PTMD = PTMDT.get();
 ND = PTMD->getDeclaratorDecl();
 
-PathList = PTMD->getCXXBaseList();
+BaseSpecList = PTMD->getCXXBaseList();
   }
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
-  return getPointerToMemberData(ND, PathList);
+  if (kind == CK_DerivedToBaseMemberPointer) {
+// Here we pop off matching CXXBaseSpecifiers from BaseSpecList.
+// Because, CK_DerivedToBaseMemberPointer comes from a static_cast and
+// serves to remove a matching implicit cast. Note that static_cast's that
+// are no-ops do not count since they produce an empty PathRange, a nice
+// thing about Clang AST.
+
+// First we need to make sure that there are no-repetitions in BaseSpecList
+llvm::SmallPtrSet BaseSpecSeen;
+for (const auto &BaseSpec : BaseSpecList) {
+  auto BaseType = BaseSpec->getType();
+  assert(BaseSpecSeen.find(BaseType) == BaseSpecSeen.end() &&
+ "CXXBaseSpecifier list of PointerToMemberData must not have "
+ "repeated elements");
+  BaseSpecSeen.insert(BaseType);
+ 

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-03 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD marked 2 inline comments as done.
RedDocMD added a comment.

@vsavchenko , I have used the logic that you suggested and put in a better 
assertion.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-04 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321476.
RedDocMD added a comment.

Updated to use new function


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,25 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,9 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
-  llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
+  CastE->path(), *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,8 +21,10 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
+#include 
 #include 
 
 using namespace clang;
@@ -178,26 +180,62 @@
 
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())
   ND = PTMDT.get();
 
-PathList = CXXBaseListFactory.getEmptyList();
-  } else { // const PointerToMemberData *
+BaseSpecList = CXXBaseListFactory.getEmptyList();
+  } else {
 const PointerToMemberData *PTMD = PTMDT.get();
 ND = PTMD->getDeclaratorDecl();
 
-PathList = PTMD->getCXXBaseList();
+BaseSpecList = PTMD->getCXXBaseList();
+  }
+  // First we need to make sure that there are no-repetitions in BaseSpecList
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const auto &BaseSpec : BaseSpecList) {
+auto BaseType = BaseSpec->getType();
+assert(BaseSpecSeen.find(BaseType) == BaseSpecSeen.end() &&
+   "CXXBaseSpecifier list of PointerToMemberData must not have "
+   "repeated elements");
+BaseSpecSeen.insert(BaseType);
   }
 
-  for (const auto &I : llvm::reverse(PathRange))
-PathList = prependCXXBase(I, PathList);
-  return getPointerToMemberData(ND, PathList);
+  if (kind == CK_DerivedToBaseMemberPointer) {
+// Here we pop off matching CXXBaseSpecifiers from BaseSpecList.
+// Because, CK_DerivedToBaseMemberPointer comes from a static_cast and
+// serves to remove a matching implicit cast. Note that static_cast's that
+// are no-ops do not count since they produce an empty PathRange, a nice
+// thing about Clang AST.
+
+// Now we know that there are no repetitions in BaseSpecList.
+// So, popping the fir

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-04 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko, after some experimentation, I found out that handling 
reinterpret_cast will be a real pain. Consider the following:

  struct Base {
int field;
  };
  
  struct Derived : public Base {};
  
  struct DoubleDerived : public Derived {};
  
  struct Some {};
  
  void f() {
int DoubleDerived::* ddf = &Base::field;
int Base::* bf = reinterpret_cast(reinterpret_cast(reinterpret_cast(ddf)));
int Some::* sf = reinterpret_cast(ddf);
Base base;
base.*bf;
  }

The definition of `bf` can be handled I guess by manually discovering when to 
insert a sub-class or when to remove. It will require a bit of code but I guess 
is doable.
As for the next one, also it has to be manually worked out whether it makes 
sense to process this statement further and add a node to the Exploded Graph. 
For the example I gave I don't think it makes a lot of sense. Multiple 
inheritance will make the task a lot worse as far as I can tell.
Should I try to achieve this in another commit? What are your thoughts on this?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-05 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321714.
RedDocMD marked an inline comment as done.
RedDocMD added a comment.

Added TODO for reinterpret_cast, moved assertion code to its own block


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,47 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
+
+// TODO: The following test will work properly once reinterpret_cast on pointer to member is handled properly
+// namespace testReinterpretCasting {
+// struct Base {
+//   int field;
+// };
+//
+// struct Derived : public Base {};
+//
+// struct DoubleDerived : public Derived {};
+//
+// struct Some {};
+//
+// void f() {
+//   int DoubleDerived::*ddf = &Base::field;
+//   int Base::*bf = reinterpret_cast(reinterpret_cast(reinterpret_cast(ddf)));
+//   int Some::*sf = reinterpret_cast(ddf);
+//   Base base;
+//   base.field = 13;
+//   clang_analyzer_eval(base.*bf == 13); // expected-warning{{TRUE}}
+// }
+// } // namespace testReinterpretCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,9 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
-  llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
+  CastE->path(), *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
 #include 
@@ -176,28 +177,74 @@
   return D;
 }
 
+bool noRepeatedElements(
+const llvm::ImmutableList &BaseSpecList) {
+  // First we need to make sure that there are no-repetitions in BaseSpecList
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const auto &BaseSpec : BaseSpecList) {
+auto BaseType = BaseSpec->getType();
+auto Stat = BaseSpecSeen.insert(BaseType);
+if (!Stat.second)
+  return false;
+  }
+  return true;
+}
+
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())
   ND = PTMDT.get();
 
-PathList = CXXBaseListFactory.getEmptyList();
-  } else { // const PointerToMemberData *
+BaseSpecList = CXXBaseListFactory.getEmptyList();
+  } else {
 const PointerToMemberData *PTMD = PTMDT.get();
 ND = PTMD->getDeclaratorDecl();
 
-PathLis

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-05 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD marked 2 inline comments as done.
RedDocMD added a comment.

@vsavchenko , does it look okay now?




Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:27
 #include 
+#include 
 #include 

vsavchenko wrote:
> We don't need this anymore :)
Wow, sharp eyes!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-05 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD marked an inline comment as done.
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:180
 
+bool noRepeatedElements(
+const llvm::ImmutableList &BaseSpecList) {

vsavchenko wrote:
> nit: functions represent actions, in languages verbs act the same way, so 
> it's recommended to use verbs in functions (`hasNoRepeatedElements`)
> 
> + `LLVM_MAYBE_UNUSED` because in the build without assertions it would be a 
> warning otherwise.
> nit: functions represent actions, in languages verbs act the same way, so 
> it's recommended to use verbs in functions (`hasNoRepeatedElements`)
> 
> + `LLVM_MAYBE_UNUSED` because in the build without assertions it would be a 
> warning otherwise.

How do I put in the LLVM_MAYBE_UNUSED? Sorry for being annoying, but 
ripgrepping or Googling didn't return anything.



Comment at: clang/test/Analysis/pointer-to-member.cpp:314-333
+// namespace testReinterpretCasting {
+// struct Base {
+//   int field;
+// };
+//
+// struct Derived : public Base {};
+//

vsavchenko wrote:
> Uncomment it, and expect the actual current result.  This is where `TODO` 
> will come in handy.
> Uncomment it, and expect the actual current result.  This is where `TODO` 
> will come in handy.
Will do it.
Just one clarification: the static analyzer tests only serve to check whether 
the Static Analyzer crashes or hits an assertion error, or is it something more?



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-05 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 321816.
RedDocMD marked 10 inline comments as done.
RedDocMD added a comment.

Some more aesthetic cleanup, added a failing test.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp

Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,47 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
+
+// TODO: The following test will work properly once reinterpret_cast on pointer to member is handled properly
+namespace testReinterpretCasting {
+struct Base {
+  int field;
+};
+
+struct Derived : public Base {};
+
+struct DoubleDerived : public Derived {};
+
+struct Some {};
+
+void f() {
+  int DoubleDerived::*ddf = &Base::field;
+  int Base::*bf = reinterpret_cast(reinterpret_cast(reinterpret_cast(ddf)));
+  int Some::*sf = reinterpret_cast(ddf);
+  Base base;
+  base.field = 13;
+  clang_analyzer_eval(base.*bf == 13); // expected-warning{{TRUE}}
+}
+} // namespace testReinterpretCasting
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,9 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
-  llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
+  CastE->path(), *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
 #include 
@@ -176,28 +177,73 @@
   return D;
 }
 
+LLVM_ATTRIBUTE_UNUSED bool hasNoRepeatedElements(
+llvm::ImmutableList BaseSpecList) {
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) {
+QualType BaseType = BaseSpec->getType();
+// Check whether inserted
+if (!BaseSpecSeen.insert(BaseType).second)
+  return false;
+  }
+  return true;
+}
+
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())
   ND = PTMDT.get();
 
-PathList = CXXBaseListFactory.getEmptyList();
-  } else { // const PointerToMemberData *
+BaseSpecList = CXXBaseListFactory.getEmptyList();
+  } else {
 const PointerToMemberData *PTMD = PTMDT.get();
 ND = PTMD->getDeclaratorDecl();
 
-PathList = PTMD->getCXXBaseList();
+BaseSpecList = PTMD->getCXXBaseList();
   }
 
-  for (const auto &I : llvm::rev

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-05 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp:184
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const auto &BaseSpec : BaseSpecList) {
+auto BaseType = BaseSpec->getType();

vsavchenko wrote:
> vsavchenko wrote:
> > LLVM Coding Style calls for very limited use of `auto`, so here and the 
> > next line would be better with actual types.
> Let's also reiterate on using functional-style predicates and reimplement it 
> in terms of `llvm::all_of` or `llvm::none_of`.
I couldn't do this since calling llvm::all_of (or std::all_of) on an 
ImmutableList causes a compile error saying that the function 
std::__iterator_category cannot be found for its iterator.



Comment at: clang/test/Analysis/pointer-to-member.cpp:314-333
+// namespace testReinterpretCasting {
+// struct Base {
+//   int field;
+// };
+//
+// struct Derived : public Base {};
+//

vsavchenko wrote:
> RedDocMD wrote:
> > vsavchenko wrote:
> > > Uncomment it, and expect the actual current result.  This is where `TODO` 
> > > will come in handy.
> > > Uncomment it, and expect the actual current result.  This is where `TODO` 
> > > will come in handy.
> > Will do it.
> > Just one clarification: the static analyzer tests only serve to check 
> > whether the Static Analyzer crashes or hits an assertion error, or is it 
> > something more?
> > 
> Mostly they check for reported results, you can see special comments like `// 
> expect-warning{...}` in almost every test.
So right now we have a failing test for this, I guess its my job in the next 
commit to make it pass. :)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-07 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko are there some more changes you want done?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-08 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95877#2547949 , @vsavchenko wrote:

> I think we had a bit of misunderstanding about the test.  It still should 
> pass (we can't have broken tests, it will disrupt CI bots).  Try to put the 
> test case, so it is THERE and you CHANGE the expected outcome when the 
> analyzer behaves correctly.  Right now, as I see above, the test crashes.

Actually, that is the reason why I initially had commented out the crashing 
test. Until `reinterpret_cast` is properly handled, the test will crash due to 
an assertion failure, irrespective of what is put as the expected outcome. Is 
there a way to flag that a test should crash? (I see that after the tests are 
run, there is an expectedly-failed category). The crash is caused when the 
static analyzer tries to evaluate `base.*bf`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D110032: [analyzer] Move docs of SmartPtr to correct subcategory

2021-09-19 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD created this revision.
RedDocMD added reviewers: NoQ, teemperor, xazax.hun, vsavchenko.
Herald added subscribers: manas, steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, rnkovacs, szepet, baloghadamsoftware.
RedDocMD requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The docs of alpha.cplusplus.SmartPtr was incorrectly placed under
alpha.deadcode. Moved it to under alpha.cplusplus


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D110032

Files:
  clang/docs/analyzer/checkers.rst


Index: clang/docs/analyzer/checkers.rst
===
--- clang/docs/analyzer/checkers.rst
+++ clang/docs/analyzer/checkers.rst
@@ -1838,6 +1838,20 @@
a.foo();// warn: method call on a 'moved-from' object 'a'
  }
 
+.. _alpha-cplusplus-SmartPtr:
+
+alpha.cplusplus.SmartPtr (C++)
+""
+Check for dereference of null smart pointers.
+
+.. code-block:: cpp
+
+ void deref_smart_ptr() {
+   std::unique_ptr P;
+   *P; // warn: dereference of a default constructed smart unique_ptr
+ }
+
+
 alpha.deadcode
 ^^
 .. _alpha-deadcode-UnreachableCode:
@@ -1872,19 +1886,6 @@
[x retain]; // warn
  }
 
-.. _alpha-cplusplus-SmartPtr:
-
-alpha.cplusplus.SmartPtr (C++)
-""
-Check for dereference of null smart pointers.
-
-.. code-block:: cpp
-
- void deref_smart_ptr() {
-   std::unique_ptr P;
-   *P; // warn: dereference of a default constructed smart unique_ptr
- }
-
 alpha.fuchsia
 ^
 


Index: clang/docs/analyzer/checkers.rst
===
--- clang/docs/analyzer/checkers.rst
+++ clang/docs/analyzer/checkers.rst
@@ -1838,6 +1838,20 @@
a.foo();// warn: method call on a 'moved-from' object 'a'
  }
 
+.. _alpha-cplusplus-SmartPtr:
+
+alpha.cplusplus.SmartPtr (C++)
+""
+Check for dereference of null smart pointers.
+
+.. code-block:: cpp
+
+ void deref_smart_ptr() {
+   std::unique_ptr P;
+   *P; // warn: dereference of a default constructed smart unique_ptr
+ }
+
+
 alpha.deadcode
 ^^
 .. _alpha-deadcode-UnreachableCode:
@@ -1872,19 +1886,6 @@
[x retain]; // warn
  }
 
-.. _alpha-cplusplus-SmartPtr:
-
-alpha.cplusplus.SmartPtr (C++)
-""
-Check for dereference of null smart pointers.
-
-.. code-block:: cpp
-
- void deref_smart_ptr() {
-   std::unique_ptr P;
-   *P; // warn: dereference of a default constructed smart unique_ptr
- }
-
 alpha.fuchsia
 ^
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D110032: [analyzer] Move docs of SmartPtr to correct subcategory

2021-09-20 Thread Deep Majumder 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 rG5dee50111c13: [analyzer] Move docs of SmartPtr to correct 
subcategory (authored by RedDocMD).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D110032

Files:
  clang/docs/analyzer/checkers.rst


Index: clang/docs/analyzer/checkers.rst
===
--- clang/docs/analyzer/checkers.rst
+++ clang/docs/analyzer/checkers.rst
@@ -1838,6 +1838,20 @@
a.foo();// warn: method call on a 'moved-from' object 'a'
  }
 
+.. _alpha-cplusplus-SmartPtr:
+
+alpha.cplusplus.SmartPtr (C++)
+""
+Check for dereference of null smart pointers.
+
+.. code-block:: cpp
+
+ void deref_smart_ptr() {
+   std::unique_ptr P;
+   *P; // warn: dereference of a default constructed smart unique_ptr
+ }
+
+
 alpha.deadcode
 ^^
 .. _alpha-deadcode-UnreachableCode:
@@ -1872,19 +1886,6 @@
[x retain]; // warn
  }
 
-.. _alpha-cplusplus-SmartPtr:
-
-alpha.cplusplus.SmartPtr (C++)
-""
-Check for dereference of null smart pointers.
-
-.. code-block:: cpp
-
- void deref_smart_ptr() {
-   std::unique_ptr P;
-   *P; // warn: dereference of a default constructed smart unique_ptr
- }
-
 alpha.fuchsia
 ^
 


Index: clang/docs/analyzer/checkers.rst
===
--- clang/docs/analyzer/checkers.rst
+++ clang/docs/analyzer/checkers.rst
@@ -1838,6 +1838,20 @@
a.foo();// warn: method call on a 'moved-from' object 'a'
  }
 
+.. _alpha-cplusplus-SmartPtr:
+
+alpha.cplusplus.SmartPtr (C++)
+""
+Check for dereference of null smart pointers.
+
+.. code-block:: cpp
+
+ void deref_smart_ptr() {
+   std::unique_ptr P;
+   *P; // warn: dereference of a default constructed smart unique_ptr
+ }
+
+
 alpha.deadcode
 ^^
 .. _alpha-deadcode-UnreachableCode:
@@ -1872,19 +1886,6 @@
[x retain]; // warn
  }
 
-.. _alpha-cplusplus-SmartPtr:
-
-alpha.cplusplus.SmartPtr (C++)
-""
-Check for dereference of null smart pointers.
-
-.. code-block:: cpp
-
- void deref_smart_ptr() {
-   std::unique_ptr P;
-   *P; // warn: dereference of a default constructed smart unique_ptr
- }
-
 alpha.fuchsia
 ^
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-08 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD updated this revision to Diff 322094.
RedDocMD added a comment.

Moved failing test of reinterpret_cast to its own file, marked to failx


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
  clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/Analysis/pointer-to-member.cpp
  clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp

Index: clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp
===
--- /dev/null
+++ clang/test/Analysis/reinterpret-cast-pointer-to-member.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+// XFAIL: *
+
+void clang_analyzer_eval(bool);
+
+// TODO: The following test will work properly once reinterpret_cast on pointer-to-member is handled properly
+namespace testReinterpretCasting {
+struct Base {
+  int field;
+};
+
+struct Derived : public Base {};
+
+struct DoubleDerived : public Derived {};
+
+struct Some {};
+
+void f() {
+  int DoubleDerived::*ddf = &Base::field;
+  int Base::*bf = reinterpret_cast(reinterpret_cast(reinterpret_cast(ddf)));
+  int Some::*sf = reinterpret_cast(ddf);
+  Base base;
+  base.field = 13;
+  clang_analyzer_eval(base.*bf == 13); // expected-warning{{TRUE}}
+}
+} // namespace testReinterpretCasting
Index: clang/test/Analysis/pointer-to-member.cpp
===
--- clang/test/Analysis/pointer-to-member.cpp
+++ clang/test/Analysis/pointer-to-member.cpp
@@ -287,3 +287,26 @@
   clang_analyzer_eval(a.*ep == 5); // expected-warning{{TRUE}}
 }
 } // namespace testAnonymousMember
+
+namespace testStaticCasting {
+// From bug #48739
+struct Grandfather {
+  int field;
+};
+
+struct Father : public Grandfather {};
+struct Son : public Father {};
+
+void test() {
+  int Son::*sf = &Son::field;
+  Grandfather grandpa;
+  grandpa.field = 10;
+  int Grandfather::*gpf1 = static_cast(sf);
+  int Grandfather::*gpf2 = static_cast(static_cast(sf));
+  int Grandfather::*gpf3 = static_cast(static_cast(static_cast(sf)));
+  clang_analyzer_eval(grandpa.*gpf1 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf2 == 10); // expected-warning{{TRUE}}
+  clang_analyzer_eval(grandpa.*gpf3 == 10); // expected-warning{{TRUE}}
+}
+} // namespace testStaticCasting
+
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -526,10 +526,9 @@
   case CK_ReinterpretMemberPointer: {
 SVal V = state->getSVal(Ex, LCtx);
 if (auto PTMSV = V.getAs()) {
-  SVal CastedPTMSV = svalBuilder.makePointerToMember(
-  getBasicVals().accumCXXBase(
-  llvm::make_range(
-  CastE->path_begin(), CastE->path_end()), *PTMSV));
+  SVal CastedPTMSV =
+  svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
+  CastE->path(), *PTMSV, CastE->getCastKind()));
   state = state->BindExpr(CastE, LCtx, CastedPTMSV);
   Bldr.generateNode(CastE, Pred, state);
   continue;
Index: clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
===
--- clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -21,6 +21,7 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableList.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include 
 #include 
 #include 
@@ -176,28 +177,73 @@
   return D;
 }
 
+LLVM_ATTRIBUTE_UNUSED bool hasNoRepeatedElements(
+llvm::ImmutableList BaseSpecList) {
+  llvm::SmallPtrSet BaseSpecSeen;
+  for (const CXXBaseSpecifier *BaseSpec : BaseSpecList) {
+QualType BaseType = BaseSpec->getType();
+// Check whether inserted
+if (!BaseSpecSeen.insert(BaseType).second)
+  return false;
+  }
+  return true;
+}
+
 const PointerToMemberData *BasicValueFactory::accumCXXBase(
 llvm::iterator_range PathRange,
-const nonloc::PointerToMember &PTM) {
+const nonloc::PointerToMember &PTM, const CastKind &kind) {
+  assert((kind == CK_DerivedToBaseMemberPointer ||
+  kind == CK_BaseToDerivedMemberPointer ||
+  kind == CK_ReinterpretMemberPointer) &&
+ "accumCXXBase called with wrong CastKind");
   nonloc::PointerToMember::PTMDataType PTMDT = PTM.getPTMData();
   const NamedDecl *ND = nullptr;
-  llvm::ImmutableList PathList;
+  llvm::ImmutableList BaseSpecList;
 
   if (PTMDT.isNull() || PTMDT.is()) {
 if (PTMDT.is())

[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-08 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95877#2548027 , @vsavchenko wrote:

> Yes, it'd be better to extract this case into a separate file and mark it as 
> XFAIL

Done that.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-09 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko, anything else to add?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


[PATCH] D85817: [analyzer] Fix crash with pointer to members values

2021-02-12 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

@vsavchenko, why did you chose NamedDecl instead of ValueDecl to account for 
the indirect fields? I couldn't quite follow it from the discussion above.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85817

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


[PATCH] D95877: [analyzer] Fix static_cast on pointer-to-member handling

2021-02-15 Thread Deep Majumder via Phabricator via cfe-commits
RedDocMD added a comment.

In D95877#2563220 , @RKSimon wrote:

> @RedDocMD Please can you take a look at this buildbot failure: 
> http://lab.llvm.org:8011/#/builders/124

Yes. Thanks for the ping 😀


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95877

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


  1   2   3   >