From: Jordan Rose Date: Fri, 15 Nov 2013 02:11:19 +0000 (+0000) Subject: [analyzer] Silence warnings coming from allocators used by std::basic_string. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fda9dbf1f4d15baaedffdd4b4bb529e06172f73d;p=clang [analyzer] Silence warnings coming from allocators used by std::basic_string. 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 --- diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 2aa65fd6d4..e1a92b30c6 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1549,18 +1549,32 @@ LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC, return 0; } } + // The analyzer issues a false positive on // std::basic_string 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(D)) { + const LocationContext *LCtx = N->getLocationContext(); + do { + const CXXMethodDecl *MD = dyn_cast(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); } } diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h index ada94ca188..9bb8ec4892 100644 --- a/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -118,7 +118,20 @@ namespace std { struct random_access_iterator_tag : public bidirectional_iterator_tag { }; template - class allocator {}; + class allocator { + public: + void deallocate(void *p) { + ::delete p; + } + }; + + template + class allocator_traits { + public: + static void deallocate(void *p) { + _Alloc().deallocate(p); + } + }; template class __list_imp @@ -140,19 +153,28 @@ namespace std { }; // basic_string - template + template > 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 - 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(); diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp index fb73246849..c153174d27 100644 --- a/test/Analysis/inlining/stl.cpp +++ b/test/Analysis/inlining/stl.cpp @@ -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 v; + v += 'c'; // no-warning +}