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
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);
}
}
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
};
// 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();
-// 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"
v.push_back(1); // no-warning
}
+void testBasicStringSuppression_append() {
+ std::basic_string<char32_t> v;
+ v += 'c'; // no-warning
+}