diff --git a/libcxx/include/deque b/libcxx/include/deque --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -457,9 +457,6 @@ template */> class _LIBCPP_TEMPLATE_VIS deque { -private: - using __default_allocator_type = allocator<_Tp>; - public: // types: @@ -980,7 +977,7 @@ const void* __old_con_end, const void* __new_con_beg, const void* __new_con_end) const { - if (__beg && is_same::value) + if (__beg != nullptr && __asan_annotate_container_with_allocator<_Allocator>::value) __sanitizer_annotate_double_ended_contiguous_container( __beg, __end, __old_con_beg, __old_con_end, __new_con_beg, __new_con_end); } diff --git a/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp --- a/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp @@ -31,13 +31,28 @@ { { typedef cpp17_input_iterator MyInputIter; - // Sould not trigger ASan. + // Should not trigger ASan. std::deque v; int i[] = {42}; v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 1)); assert(v[0] == 42); assert(is_double_ended_contiguous_container_asan_correct(v)); } + { + typedef int T; + typedef std::deque > C; + const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + C c(std::begin(t), std::end(t)); + assert(is_double_ended_contiguous_container_asan_correct(c)); + } + { + typedef char T; + typedef std::deque > C; + const T t[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + C c(std::begin(t), std::end(t)); + c.pop_front(); + assert(is_double_ended_contiguous_container_asan_correct(c)); + } __sanitizer_set_death_callback(do_exit); { typedef int T; diff --git a/libcxx/test/libcxx/containers/sequences/deque/asan_turning_off.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/asan_turning_off.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/deque/asan_turning_off.pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// + +// Test based on: https://bugs.chromium.org/p/chromium/issues/detail?id=1419798#c5 +// Some allocators during deallocation may not call destructors and just reuse memory. +// In those situations, one may want to deactivate annotations for a specific allocator. +// It's possible with __asan_annotate_container_with_allocator template class. +// This test confirms that those allocators work after turning off annotations. + +#include +#include +#include +#include + +struct reuse_allocator { + static size_t const N = 100; + reuse_allocator() { + for (size_t i = 0; i < N; ++i) + __buffers[i] = malloc(8*1024); + } + ~reuse_allocator() { + for (size_t i = 0; i < N; ++i) + free(__buffers[i]); + } + void* alloc() { + assert(__next_id < N); + return __buffers[__next_id++]; + } + void reset() { __next_id = 0; } + void* __buffers[N]; + size_t __next_id = 0; +} reuse_buffers; + +template +struct user_allocator { + using value_type = T; + user_allocator() = default; + template + user_allocator(user_allocator) {} + friend bool operator==(user_allocator, user_allocator) {return true;} + friend bool operator!=(user_allocator x, user_allocator y) {return !(x == y);} + + T* allocate(size_t) { return (T*)reuse_buffers.alloc(); } + void deallocate(T*, size_t) noexcept {} +}; + +#ifdef _LIBCPP_HAS_ASAN_CONTAINER_ANNOTATIONS_FOR_ALL_ALLOCATORS +template +struct std::__asan_annotate_container_with_allocator> : false_type {}; +#endif + +int main(int, char**) { + using D = std::deque>; + + { + D* d = new (reuse_buffers.alloc()) D(); + for (int i = 0; i < 100; i++) + d->push_back(i); + } + reuse_buffers.reset(); + { + D d; + for (int i = 0; i < 1000; i++) + d.push_back(i); + } + + return 0; +}