]> granicus.if.org Git - clang/commitdiff
[analyzer] Silence warnings coming from allocators used by std::basic_string.
authorJordan Rose <jordan_rose@apple.com>
Fri, 15 Nov 2013 02:11:19 +0000 (02:11 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 15 Nov 2013 02:11:19 +0000 (02:11 +0000)
This is similar to r194004: because we can't reason about the data structure
invariants of std::basic_string, the analyzer decides it's possible for an
allocator to be used to deallocate the string's inline storage. Just ignore
this by walking up the stack, skipping past methods in classes with
"allocator" in the name, and seeing if we reach std::basic_string that way.

PR17866

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

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

index 2aa65fd6d4b8b945a1954169a7df80c20725ed26..e1a92b30c6be6f5227761d245ba6efa18fd86723 100644 (file)
@@ -1549,18 +1549,32 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
           return 0;
         }
       }
+
       // The analyzer issues a false positive on
       //   std::basic_string<uint8_t> v; v.push_back(1);
+      // and
+      //   std::u16string s; s += u'a';
       // because we cannot reason about the internal invariants of the
       // datastructure.
-      if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+      const LocationContext *LCtx = N->getLocationContext();
+      do {
+        const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
+        if (!MD)
+          break;
+
         const CXXRecordDecl *CD = MD->getParent();
         if (CD->getName() == "basic_string") {
           BR.markInvalid(getTag(), 0);
           return 0;
+        } else if (CD->getName().find("allocator") == StringRef::npos) {
+          // Only keep searching if the current method is in a class with the
+          // word "allocator" in its name, e.g. std::allocator or
+          // allocator_traits.
+          break;
         }
-      }
 
+        LCtx = LCtx->getParent();
+      } while (LCtx);
     }
   }
 
index ada94ca188f093cb5dae4f3322bb0ff47b59d491..9bb8ec48923d67e626949f44bca87d0476713e0f 100644 (file)
@@ -118,7 +118,20 @@ namespace std {
   struct random_access_iterator_tag : public bidirectional_iterator_tag { };
 
   template <class _Tp>
-  class allocator {};
+  class allocator {
+  public:
+    void deallocate(void *p) {
+      ::delete p;
+    }
+  };
+
+  template <class _Alloc>
+  class allocator_traits {
+  public:
+    static void deallocate(void *p) {
+      _Alloc().deallocate(p);
+    }
+  };
 
   template <class _Tp, class _Alloc>
   class __list_imp
@@ -140,19 +153,28 @@ namespace std {
   };
 
   // basic_string
-  template<class _CharT>
+  template<class _CharT, class _Alloc = allocator<_CharT> >
   class __attribute__ ((__type_visibility__("default"))) basic_string {
+    _CharT localStorage[4];
+
+    typedef allocator_traits<_Alloc> __alloc_traits;
+
   public:
-    void push_back(int c);
+    void push_back(int c) {
+      // Fake error trigger.
+      // No warning is expected as we are suppressing warning comming
+      // out of std::basic_string.
+      int z = 0;
+      z = 5/z;
+    }
+
+    basic_string &operator +=(int c) {
+      // Fake deallocate stack-based storage.
+      // No warning is expected as we are suppressing warnings within
+      // allocators being used by std::basic_string.
+      __alloc_traits::deallocate(&localStorage);
+    }
   };
-  template <class _CharT>
-  void basic_string<_CharT>::push_back(int __c) {
-        // Fake error trigger.
-        // No warning is expected as we are suppressing warning comming
-        // out of std::basic_string.
-        int z = 0;
-        z = 5/z;
-  }
 }
 
 void* operator new(std::size_t, const std::nothrow_t&) throw();
index fb732468491bf0b32f5903481219f043a0e5d8fe..c153174d27ad7c013ad6cdee9f62352f5a497b03 100644 (file)
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -DINLINE=1 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -std=c++11 -DINLINE=1 -verify %s
 
 #include "../Inputs/system-header-simulator-cxx.h"
 
@@ -38,3 +38,7 @@ void testBasicStringSuppression() {
   v.push_back(1); // no-warning
 }
 
+void testBasicStringSuppression_append() {
+  std::basic_string<char32_t> v;
+  v += 'c'; // no-warning
+}