]> granicus.if.org Git - clang/commitdiff
[analyzer] Suppress reports reported in std::list
authorAnna Zaks <ganna@apple.com>
Thu, 4 Jul 2013 02:38:10 +0000 (02:38 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 4 Jul 2013 02:38:10 +0000 (02:38 +0000)
The motivation is to suppresses false use-after-free reports that occur when calling
std::list::pop_front() or std::list::pop_back() twice. The analyzer does not
reason about the internal invariants of the list implementation, so just do not report
any of warnings in std::list.

Fixes radar://14317928.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@185609 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
test/Analysis/Inputs/system-header-simulator-cxx.h
test/Analysis/inlining/stl.cpp

index ffc8f09dcb86ed7e92e6fdb85f4436ae4810e04f..70354fe21c3fbf3464123f4ecafd0021d3875cbe 100644 (file)
@@ -1521,18 +1521,33 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
                                                     BugReport &BR) {
   // Here we suppress false positives coming from system headers. This list is
   // based on known issues.
-
-  // Skip reports within the 'std' namespace. Although these can sometimes be
-  // the user's fault, we currently don't report them very well, and
-  // Note that this will not help for any other data structure libraries, like
-  // TR1, Boost, or llvm/ADT.
   ExprEngine &Eng = BRC.getBugReporter().getEngine();
   AnalyzerOptions &Options = Eng.getAnalysisManager().options;
-  if (Options.shouldSuppressFromCXXStandardLibrary()) {
-    const LocationContext *LCtx = N->getLocationContext();
-    if (isInStdNamespace(LCtx->getDecl())) {
+  const Decl *D = N->getLocationContext()->getDecl();
+
+  if (isInStdNamespace(D)) {
+    // Skip reports within the 'std' namespace. Although these can sometimes be
+    // the user's fault, we currently don't report them very well, and
+    // Note that this will not help for any other data structure libraries, like
+    // TR1, Boost, or llvm/ADT.
+    if (Options.shouldSuppressFromCXXStandardLibrary()) {
       BR.markInvalid(getTag(), 0);
       return 0;
+
+    } else {
+      // If the the complete 'std' suppression is not enabled, suppress reports
+      // from the 'std' namespace that are known to produce false positives.
+
+      // The analyzer issues a false use-after-free when std::list::pop_front
+      // or std::list::pop_back are called multiple times because we cannot
+      // reason about the internal invariants of the datastructure.
+      const DeclContext *DC =
+        D->getDeclContext()->getEnclosingNamespaceContext();
+      const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+      if (ND && ND->getName() == "list") {
+          BR.markInvalid(getTag(), 0);
+          return 0;
+      }
     }
   }
 
index 6e434a04b23df4beebaa360613afdc55047ff0a2..049d6be91b46b1b35f5150d0d74984503537fe45 100644 (file)
@@ -86,6 +86,23 @@ namespace std {
   struct forward_iterator_tag : public input_iterator_tag { };
   struct bidirectional_iterator_tag : public forward_iterator_tag { };
   struct random_access_iterator_tag : public bidirectional_iterator_tag { };
+
+  template <class _Tp>
+  class allocator {};
+
+  template <class _Tp, class _Alloc>
+  class __list_imp
+  {};
+
+  template <class _Tp, class _Alloc = allocator<_Tp> >
+  class list
+  : private __list_imp<_Tp, _Alloc>
+  {
+  public:
+    void pop_front();
+    bool empty() const;
+  };
+
 }
 
 void* operator new(std::size_t, const std::nothrow_t&) throw();
index 6053daaf3a21aa6ab8705595b35d775252ec2803..7f3bcdab5ec5e31a751094aa321f76efa2369d71 100644 (file)
@@ -27,3 +27,9 @@ void testException(std::exception e) {
   // expected-warning@-4 {{UNKNOWN}}
 #endif
 }
+
+void testList_pop_front(std::list<int> list) {
+  while(!list.empty())
+    list.pop_front();  // no-warning
+}
+