baloghadamsoftware created this revision.
baloghadamsoftware added a reviewer: NoQ.
baloghadamsoftware added a project: clang.
Herald added subscribers: donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, 
rnkovacs, szepet, whisperity.
Herald added a reviewer: george.karpenkov.

Repository:
  rC Clang

https://reviews.llvm.org/D54149

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
  test/Analysis/Inputs/system-header-simulator-cxx.h
  test/Analysis/diagnostics/explicit-suppression.cpp
  test/Analysis/iterator-range.cpp
  test/Analysis/std-c-library-functions.cpp
  test/Analysis/std-cxx-library-functions.cpp

Index: test/Analysis/std-cxx-library-functions.cpp
===================================================================
--- /dev/null
+++ test/Analysis/std-cxx-library-functions.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=apiModeling.StdCXXLibraryFunctions,debug.ExprInspection -verify %s
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+void test_find(std::vector<int> V, int n) {
+  const std::vector<int>::iterator b = V.begin(), e = V.end();
+  clang_analyzer_eval(std::find(b, e, n) == e); // expected-warning{{TRUE}}
+  // expected-warning@-1{{FALSE}}
+}
Index: test/Analysis/std-c-library-functions.cpp
===================================================================
--- test/Analysis/std-c-library-functions.cpp
+++ test/Analysis/std-c-library-functions.cpp
@@ -12,3 +12,20 @@
 void test() {
   clang_analyzer_eval(isalpha('A')); // no-crash // expected-warning{{UNKNOWN}}
 }
+
+namespace std {
+int isalnum(int);
+}
+
+namespace {
+// Non std!!!
+
+int isalnum(int) {
+  return 0;
+}
+}
+
+void test_non_std() {
+  clang_analyzer_eval(std::isalnum('A')); // expected-warning{{TRUE}}
+  clang_analyzer_eval(isalnum('A')); // expected-warning{{FALSE}}
+}
Index: test/Analysis/iterator-range.cpp
===================================================================
--- test/Analysis/iterator-range.cpp
+++ test/Analysis/iterator-range.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,apiModeling.StdCXXLibraryFunctions,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,apiModeling.StdCXXLibraryFunctions,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
 
 #include "Inputs/system-header-simulator-cxx.h"
 
@@ -97,6 +97,108 @@
     *i2; // expected-warning{{Iterator accessed outside of its range}}
 }
 
+void good_find(std::vector<int> &V, int e) {
+  auto first = std::find(V.begin(), V.end(), e);
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_find(std::vector<int> &V, int e) {
+  auto first = std::find(V.begin(), V.end(), e);
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_find_end(std::vector<int> &V, std::vector<int> &seq) {
+  auto last = std::find_end(V.begin(), V.end(), seq.begin(), seq.end());
+  if (V.end() != last)
+    *last; // no-warning
+}
+
+void bad_find_end(std::vector<int> &V, std::vector<int> &seq) {
+  auto last = std::find_end(V.begin(), V.end(), seq.begin(), seq.end());
+  *last; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_find_first_of(std::vector<int> &V, std::vector<int> &seq) {
+  auto first =
+      std::find_first_of(V.begin(), V.end(), seq.begin(), seq.end());
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_find_first_of(std::vector<int> &V, std::vector<int> &seq) {
+  auto first = std::find_end(V.begin(), V.end(), seq.begin(), seq.end());
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+bool odd(int i) { return i % 2; }
+
+void good_find_if(std::vector<int> &V) {
+  auto first = std::find_if(V.begin(), V.end(), odd);
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_find_if(std::vector<int> &V, int e) {
+  auto first = std::find_if(V.begin(), V.end(), odd);
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_find_if_not(std::vector<int> &V) {
+  auto first = std::find_if_not(V.begin(), V.end(), odd);
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_find_if_not(std::vector<int> &V, int e) {
+  auto first = std::find_if_not(V.begin(), V.end(), odd);
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_lower_bound(std::vector<int> &V, int e) {
+  auto first = std::lower_bound(V.begin(), V.end(), e);
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_lower_bound(std::vector<int> &V, int e) {
+  auto first = std::lower_bound(V.begin(), V.end(), e);
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_upper_bound(std::vector<int> &V, int e) {
+  auto last = std::lower_bound(V.begin(), V.end(), e);
+  if (V.end() != last)
+    *last; // no-warning
+}
+
+void bad_upper_bound(std::vector<int> &V, int e) {
+  auto last = std::lower_bound(V.begin(), V.end(), e);
+  *last; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_search(std::vector<int> &V, std::vector<int> &seq) {
+  auto first = std::search(V.begin(), V.end(), seq.begin(), seq.end());
+  if (V.end() != first)
+    *first; // no-warning
+}
+
+void bad_search(std::vector<int> &V, std::vector<int> &seq) {
+  auto first = std::search(V.begin(), V.end(), seq.begin(), seq.end());
+  *first; // expected-warning{{Iterator accessed outside of its range}}
+}
+
+void good_search_n(std::vector<int> &V, std::vector<int> &seq) {
+  auto nth = std::search_n(V.begin(), V.end(), seq.begin(), seq.end());
+  if (V.end() != nth)
+    *nth; // no-warning
+}
+
+void bad_search_n(std::vector<int> &V, std::vector<int> &seq) {
+  auto nth = std::search_n(V.begin(), V.end(), seq.begin(), seq.end());
+  *nth; // expected-warning{{Iterator accessed outside of its range}}
+}
+
 template <class InputIterator, class T>
 InputIterator nonStdFind(InputIterator first, InputIterator last,
                          const T &val) {
Index: test/Analysis/diagnostics/explicit-suppression.cpp
===================================================================
--- test/Analysis/diagnostics/explicit-suppression.cpp
+++ test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@
 void testCopyNull(C *I, C *E) {
   std::copy(I, E, (C *)0);
 #ifndef SUPPRESSED
-  // expected-warning@../Inputs/system-header-simulator-cxx.h:627 {{Called C++ object pointer is null}}
+  // expected-warning@../Inputs/system-header-simulator-cxx.h:630 {{Called C++ object pointer is null}}
 #endif
 }
Index: test/Analysis/Inputs/system-header-simulator-cxx.h
===================================================================
--- test/Analysis/Inputs/system-header-simulator-cxx.h
+++ test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -232,14 +232,17 @@
 
   template<typename T>
   class vector {
+  public:
     typedef T value_type;
     typedef size_t size_type;
     typedef __vector_iterator<T, T *, T &> iterator;
     typedef __vector_iterator<T, const T *, const T &> const_iterator;
 
+  private:
     T *_start;
     T *_finish;
     T *_end_of_storage;
+
   public:
     vector() : _start(0), _finish(0), _end_of_storage(0) {}
     template <typename InputIterator>
@@ -714,6 +717,32 @@
 
   template <class InputIterator, class T>
   InputIterator find(InputIterator first, InputIterator last, const T &val);
+  template <class ForwardIterator1, class ForwardIterator2>
+  ForwardIterator1 find_end(ForwardIterator1 first1, ForwardIterator1 last1,
+                            ForwardIterator2 first2, ForwardIterator2 last2);
+  template <class ForwardIterator1, class ForwardIterator2>
+  ForwardIterator1 find_first_of(ForwardIterator1 first1,
+                                 ForwardIterator1 last1,
+                                 ForwardIterator2 first2,
+                                 ForwardIterator2 last2);
+  template <class InputIterator, class UnaryPredicate>
+  InputIterator find_if(InputIterator first, InputIterator last,
+                        UnaryPredicate pred);
+  template <class InputIterator, class UnaryPredicate>
+  InputIterator find_if_not(InputIterator first, InputIterator last,
+                            UnaryPredicate pred);
+  template <class InputIterator, class T>
+  InputIterator lower_bound(InputIterator first, InputIterator last,
+                            const T &val);
+  template <class InputIterator, class T>
+  InputIterator upper_bound(InputIterator first, InputIterator last,
+                            const T &val);
+  template <class ForwardIterator1, class ForwardIterator2>
+  ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,
+                          ForwardIterator2 first2, ForwardIterator2 last2);
+  template <class ForwardIterator1, class ForwardIterator2>
+  ForwardIterator1 search_n(ForwardIterator1 first1, ForwardIterator1 last1,
+                            ForwardIterator2 first2, ForwardIterator2 last2);
 
   template <class ForwardIterator1, class ForwardIterator2>
   ForwardIterator1 find_first_of(ForwardIterator1 first1,
Index: lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -77,7 +77,8 @@
   /// Given a range, should the argument stay inside or outside this range?
   /// The special `ComparesToArgument' value indicates that we should
   /// impose a constraint that involves other argument or return value symbols.
-  enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument };
+  enum ValueRangeKindTy { OutOfRange, WithinRange, ComparesToArgument,
+                          BoundToArgument};
 
   // The universal integral type to use in value range descriptions.
   // Unsigned to make sure overflows are well-defined.
@@ -95,6 +96,19 @@
   typedef uint32_t ArgNoTy;
   static const ArgNoTy Ret = std::numeric_limits<ArgNoTy>::max();
 
+public:
+  /// A flag and a string to store which of the various checks are enabled
+  /// and what is their name.
+  enum CheckKindTy {
+    CK_StdCLibraryFunctionsChecker,
+    CK_StdCXXLibraryFunctionsChecker,
+    CK_NumCheckKinds
+  };
+
+  DefaultBool ChecksEnabled[CK_NumCheckKinds];
+  CheckName CheckNames[CK_NumCheckKinds];
+
+private:
   /// Incapsulates a single range on a single symbol within a branch.
   class ValueRange {
     ArgNoTy ArgNo; // Argument to which we apply the range.
@@ -120,7 +134,7 @@
     }
 
     ArgNoTy getOtherArgNo() const {
-      assert(Kind == ComparesToArgument);
+      assert(Kind == ComparesToArgument || Kind == BoundToArgument);
       assert(Args.size() == 1);
       return static_cast<ArgNoTy>(Args[0].second);
     }
@@ -142,6 +156,9 @@
     ProgramStateRef
     applyAsComparesToArgument(ProgramStateRef State, const CallEvent &Call,
                               const FunctionSummaryTy &Summary) const;
+    ProgramStateRef
+    applyAsBoundToArgument(ProgramStateRef State, const CallEvent &Call,
+                           const FunctionSummaryTy &Summary) const;
 
   public:
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -153,6 +170,8 @@
         return applyAsWithinRange(State, Call, Summary);
       case ComparesToArgument:
         return applyAsComparesToArgument(State, Call, Summary);
+      case BoundToArgument:
+        return applyAsBoundToArgument(State, Call, Summary);
       }
       llvm_unreachable("Unknown ValueRange kind!");
     }
@@ -166,6 +185,7 @@
   /// approach to invalidation, and a list of branches - essentially, a list
   /// of list of ranges - essentially, a list of lists of lists of segments.
   struct FunctionSummaryTy {
+    const CheckKindTy CheckKind;
     const std::vector<QualType> ArgTypes;
     const QualType RetType;
     const InvalidationKindTy InvalidationKind;
@@ -322,7 +342,7 @@
   ProgramStateManager &Mgr = State->getStateManager();
   SValBuilder &SVB = Mgr.getSValBuilder();
   QualType CondT = SVB.getConditionType();
-  QualType T = getArgType(Summary, getArgNo());
+  QualType T = getArgType(Call, getArgNo());
   SVal V = getArgSVal(Call, getArgNo());
 
   BinaryOperator::Opcode Op = getOpcode();
@@ -337,6 +357,26 @@
   return State;
 }
 
+ProgramStateRef
+StdLibraryFunctionsChecker::ValueRange::applyAsBoundToArgument(
+    ProgramStateRef State, const CallEvent &Call,
+    const FunctionSummaryTy &Summary) const {
+  assert(getArgNo() == Ret && "Cannot bind argument to another argument");
+
+  ProgramStateManager &Mgr = State->getStateManager();
+  SValBuilder &SVB = Mgr.getSValBuilder();
+  QualType T = getArgType(Call, getArgNo());
+
+  ArgNoTy OtherArg = getOtherArgNo();
+  SVal OtherV = getArgSVal(Call, OtherArg);
+  QualType OtherT = getArgType(Call, OtherArg);
+  // Note: we avoid integral promotion for comparison.
+  OtherV = SVB.evalCast(OtherV, T, OtherT);
+  State = State->BindExpr(Call.getOriginExpr(), Call.getLocationContext(),
+                          OtherV);
+  return State;
+}
+
 void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
                                                CheckerContext &C) const {
   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
@@ -375,7 +415,7 @@
     return false;
 
   Optional<FunctionSummaryTy> FoundSummary = findFunctionSummary(FD, CE, C);
-  if (!FoundSummary)
+  if (!FoundSummary || !ChecksEnabled[FoundSummary->CheckKind])
     return false;
 
   const FunctionSummaryTy &Summary = *FoundSummary;
@@ -444,7 +484,9 @@
   if (!II)
     return None;
   StringRef Name = II->getName();
-  if (Name.empty() || !C.isCLibraryFunction(FD, Name))
+
+  if (Name.empty() ||
+      !(C.isCLibraryFunction(FD, Name) || FD->isInStdNamespace()))
     return None;
 
   auto FSMI = FunctionSummaryMap.find(Name);
@@ -531,12 +573,12 @@
 
 #define SUMMARY_WITH_VARIANTS(identifier) {#identifier, {
 #define END_SUMMARY_WITH_VARIANTS }},
-#define VARIANT(argument_types, return_type, invalidation_approach)            \
-  { argument_types, return_type, invalidation_approach, {
+#define VARIANT(lang, argument_types, return_type, invalidation_approach)      \
+  { lang, argument_types, return_type, invalidation_approach, {
 #define END_VARIANT } },
-#define SUMMARY(identifier, argument_types, return_type,                       \
+#define SUMMARY(identifier, lang, argument_types, return_type,                 \
                 invalidation_approach)                                         \
-  { #identifier, { { argument_types, return_type, invalidation_approach, {
+  { #identifier, { { lang, argument_types, return_type, invalidation_approach, {
 #define END_SUMMARY } } } },
 #define ARGUMENT_TYPES(...) { __VA_ARGS__ }
 #define RETURN_TYPE(x) x
@@ -552,11 +594,15 @@
 #define ARG_NO(x) x##U
 #define RANGE(x, y) { x, y },
 #define SINGLE_VALUE(x) RANGE(x, x)
-#define IS_LESS_THAN(arg) { BO_LE, arg }
+#define IS_EQUAL_TO(arg) { BO_EQ, arg }
+#define IS_NOT_EQUAL_TO(arg) { BO_NE, arg }
+#define IS_LESS_THAN_OR_EQUAL_TO(arg) { BO_LE, arg }
+#define LANG_C CK_StdCLibraryFunctionsChecker
+#define LANG_CXX CK_StdCXXLibraryFunctionsChecker
 
   FunctionSummaryMap = {
     // The isascii() family of functions.
-    SUMMARY(isalnum, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isalnum, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Boils down to isupper() or islower() or isdigit()
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -587,7 +633,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isalpha, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isalpha, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // isupper() or islower(). Note that 'Z' is less than 'a'.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -614,7 +660,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isascii, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isascii, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Is ASCII.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -633,7 +679,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isblank, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isblank, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -654,7 +700,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(iscntrl, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(iscntrl, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // 0..31 or 127
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -675,7 +721,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isdigit, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Is a digit.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -694,7 +740,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isgraph, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isgraph, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -713,7 +759,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(islower, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(islower, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Is certainly lowercase.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -748,7 +794,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isprint, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isprint, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -767,7 +813,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(ispunct, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(ispunct, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -792,7 +838,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isspace, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isspace, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Space, '\f', '\n', '\r', '\t', '\v'.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -819,7 +865,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isupper, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
+    SUMMARY(isupper, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE (IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE // Is certainly uppercase.
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -843,7 +889,7 @@
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(isxdigit, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
+    SUMMARY(isxdigit, LANG_C, ARGUMENT_TYPES(IntTy), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(EvalCallAsPure))
       CASE
         ARGUMENT_CONDITION(ARG_NO(0), WithinRange)
@@ -868,23 +914,23 @@
     END_SUMMARY
 
     // The getc() family of functions that returns either a char or an EOF.
-    SUMMARY(getc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
+    SUMMARY(getc, LANG_C, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(NoEvalCall))
       CASE // FIXME: EOF is assumed to be defined as -1.
         RETURN_VALUE_CONDITION(WithinRange)
           RANGE(-1, 255)
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(fgetc, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
+    SUMMARY(fgetc, LANG_C, ARGUMENT_TYPES(Irrelevant), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(NoEvalCall))
       CASE // FIXME: EOF is assumed to be defined as -1.
         RETURN_VALUE_CONDITION(WithinRange)
           RANGE(-1, 255)
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(getchar, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
+    SUMMARY(getchar, LANG_C, ARGUMENT_TYPES(), RETURN_TYPE(IntTy),
             INVALIDATION_APPROACH(NoEvalCall))
       CASE // FIXME: EOF is assumed to be defined as -1.
         RETURN_VALUE_CONDITION(WithinRange)
@@ -897,33 +943,33 @@
     // We are not sure how ssize_t is defined on every platform, so we provide
     // three variants that should cover common cases.
     SUMMARY_WITH_VARIANTS(read)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, IntMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, LongMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, LongLongMax)
@@ -934,80 +980,80 @@
     SUMMARY_WITH_VARIANTS(write)
       // Again, due to elusive nature of ssize_t, we have duplicate
       // our summaries to cover different variants.
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, IntMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, LongMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy),
               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(ComparesToArgument)
-            IS_LESS_THAN(ARG_NO(2))
+            IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
           END_RETURN_VALUE_CONDITION
           RETURN_VALUE_CONDITION(WithinRange)
             RANGE(-1, LongLongMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
     END_SUMMARY_WITH_VARIANTS
-    SUMMARY(fread,
+    SUMMARY(fread, LANG_C,
             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
       CASE
         RETURN_VALUE_CONDITION(ComparesToArgument)
-          IS_LESS_THAN(ARG_NO(2))
+          IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
-    SUMMARY(fwrite,
+    SUMMARY(fwrite, LANG_C,
             ARGUMENT_TYPES(Irrelevant, Irrelevant, SizeTy, Irrelevant),
             RETURN_TYPE(SizeTy), INVALIDATION_APPROACH(NoEvalCall))
       CASE
         RETURN_VALUE_CONDITION(ComparesToArgument)
-          IS_LESS_THAN(ARG_NO(2))
+          IS_LESS_THAN_OR_EQUAL_TO(ARG_NO(2))
         END_RETURN_VALUE_CONDITION
       END_CASE
     END_SUMMARY
 
     // getline()-like functions either fail or read at least the delimiter.
     SUMMARY_WITH_VARIANTS(getline)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
               RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
             SINGLE_VALUE(-1)
             RANGE(1, IntMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
               RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
             SINGLE_VALUE(-1)
             RANGE(1, LongMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C, ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
               RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
@@ -1018,25 +1064,28 @@
       END_VARIANT
     END_SUMMARY_WITH_VARIANTS
     SUMMARY_WITH_VARIANTS(getdelim)
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C,
+              ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
             RETURN_TYPE(IntTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
             SINGLE_VALUE(-1)
             RANGE(1, IntMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C,
+              ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
             RETURN_TYPE(LongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
             SINGLE_VALUE(-1)
             RANGE(1, LongMax)
           END_RETURN_VALUE_CONDITION
         END_CASE
       END_VARIANT
-      VARIANT(ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+      VARIANT(LANG_C,
+              ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
             RETURN_TYPE(LongLongTy), INVALIDATION_APPROACH(NoEvalCall))
         CASE
           RETURN_VALUE_CONDITION(WithinRange)
@@ -1046,13 +1095,149 @@
         END_CASE
       END_VARIANT
     END_SUMMARY_WITH_VARIANTS
+
+    // C++ STL
+
+    // STL algorithms
+
+    // std::find() at el.
+    SUMMARY(find, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(find_end, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(find_first_of, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(find_if, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(find_if_not, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(lower_bound, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(upper_bound, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(search, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+    SUMMARY(search_n, LANG_CXX,
+            ARGUMENT_TYPES(Irrelevant, Irrelevant, Irrelevant, Irrelevant),
+            RETURN_TYPE(Irrelevant), INVALIDATION_APPROACH(EvalCallAsPure))
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(ARG_NO(1))
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+      CASE
+        RETURN_VALUE_CONDITION(BoundToArgument)
+          IS_EQUAL_TO(Ret)
+        END_RETURN_VALUE_CONDITION
+      END_CASE
+    END_SUMMARY
+
   };
 }
 
-void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
-  // If this checker grows large enough to support C++, Objective-C, or other
-  // standard libraries, we could use multiple register...Checker() functions,
-  // which would register various checkers with the help of the same Checker
-  // class, turning on different function summaries.
-  mgr.registerChecker<StdLibraryFunctionsChecker>();
+#define REGISTER_CHECKER(name)                                                 \
+  void ento::register##name(CheckerManager &Mgr) {                             \
+    auto *checker = Mgr.registerChecker<StdLibraryFunctionsChecker>();         \
+    checker->ChecksEnabled[StdLibraryFunctionsChecker::CK_##name] = true;      \
+    checker->CheckNames[StdLibraryFunctionsChecker::CK_##name] =               \
+        Mgr.getCurrentCheckName();                                             \
 }
+
+REGISTER_CHECKER(StdCLibraryFunctionsChecker)
+REGISTER_CHECKER(StdCXXLibraryFunctionsChecker)
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -224,6 +224,10 @@
   HelpText<"Improve modeling of the C standard library functions">,
   DescFile<"StdLibraryFunctionsChecker.cpp">;
 
+def StdCXXLibraryFunctionsChecker : Checker<"StdCXXLibraryFunctions">,
+  HelpText<"Improve modeling of the C++ standard library functions">,
+  DescFile<"StdLibraryFunctionsChecker.cpp">;
+
 def TrustNonnullChecker : Checker<"TrustNonnull">,
   HelpText<"Trust that returns from framework methods annotated with _Nonnull are not null">,
   DescFile<"TrustNonnullChecker.cpp">;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D54149: [Analyzer]... Balogh , Ádám via Phabricator via cfe-commits

Reply via email to