diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -439,11 +439,11 @@ _LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() { - __vec_.__annotate_delete(); std::__debug_db_erase_c(std::addressof(__vec_)); if (__vec_.__begin_ != nullptr) { __vec_.__clear(); + __vec_.__annotate_delete(); __alloc_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.capacity()); } } @@ -743,8 +743,25 @@ const void *__old_mid, const void *__new_mid) const { - +# if _LIBCPP_CLANG_VER >= 1600 + if (!__libcpp_is_constant_evaluated() && __beg) + // Implementation of __sanitizer_annotate_contiguous_container function changed with commit + // rGdd1b7b797a116eed588fd752fbe61d34deeb24e4 and supports: + // - unaligned beginnings of buffers, + // - shared first/last granule (if memory granule is shared with a different object + // just after the end of unaligned end/before the unaligned beginning, memory of that object won't be poisoned). + // + // Therefore, check for standard allocator is not necessary. +# else + // TODO LLVM18: Remove the special-casing + // + // Vectors annotations rely on __sanitizer_annotate_contiguous_container function, + // its implementation from LLVM15 (and earlier) requires that + // beginning of a containers data buffer is aligned to shadow granularity and + // memory just after is not shared with another object. + // Default allocator satisfies that. if (!__libcpp_is_constant_evaluated() && __beg && is_same::value) +# endif __sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid); } #else @@ -866,6 +883,7 @@ if (__alloc() != __c.__alloc()) { __clear(); + __annotate_delete(); __alloc_traits::deallocate(__alloc(), this->__begin_, capacity()); this->__begin_ = this->__end_ = __end_cap() = nullptr; } @@ -954,6 +972,7 @@ if (this->__begin_ != nullptr) { clear(); + __annotate_delete(); __alloc_traits::deallocate(this->__alloc(), this->__begin_, capacity()); this->__begin_ = this->__end_ = this->__end_cap() = nullptr; } diff --git a/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp --- a/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp +++ b/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp @@ -29,40 +29,63 @@ int main(int, char**) { -#if TEST_STD_VER >= 11 - { - typedef int T; - typedef std::vector> C; - const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - C c(std::begin(t), std::end(t)); - c.reserve(2*c.size()); - volatile T foo = c[c.size()]; // bad, but not caught by ASAN - ((void)foo); - } +#if TEST_STD_VER >= 11 && TEST_CLANG_VER < 1600 + { + typedef int T; + typedef std::vector> C; + const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + C c(std::begin(t), std::end(t)); + c.reserve(2 * c.size()); + volatile T foo = c[c.size()]; // bad, but not caught by ASAN + ((void)foo); + } #endif - { - typedef cpp17_input_iterator MyInputIter; - // Sould not trigger ASan. - std::vector v; - v.reserve(1); - int i[] = {42}; - v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 1)); - assert(v[0] == 42); - assert(is_contiguous_container_asan_correct(v)); - } +#if TEST_STD_VER >= 11 && TEST_CLANG_VER >= 1600 + { + typedef int T; + typedef cpp17_input_iterator MyInputIter; + std::vector> v; + v.reserve(1); + int i[] = {42}; + v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 1)); + assert(v[0] == 42); + assert(is_contiguous_container_asan_correct(v)); + } + { + typedef char T; + typedef cpp17_input_iterator MyInputIter; + std::vector> v; + v.reserve(1); + char i[] = {'a', 'b'}; + v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 2)); + assert(v[0] == 'a'); + assert(v[1] == 'b'); + assert(is_contiguous_container_asan_correct(v)); + } +#endif + { + typedef cpp17_input_iterator MyInputIter; + // Sould not trigger ASan. + std::vector v; + v.reserve(1); + int i[] = {42}; + v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 1)); + assert(v[0] == 42); + assert(is_contiguous_container_asan_correct(v)); + } - __sanitizer_set_death_callback(do_exit); - { - typedef int T; - typedef std::vector C; - const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - C c(std::begin(t), std::end(t)); - c.reserve(2*c.size()); - assert(is_contiguous_container_asan_correct(c)); - assert(!__sanitizer_verify_contiguous_container( c.data(), c.data() + 1, c.data() + c.capacity())); - volatile T foo = c[c.size()]; // should trigger ASAN. Use volatile to prevent being optimized away. - assert(false); // if we got here, ASAN didn't trigger - ((void)foo); - } + __sanitizer_set_death_callback(do_exit); + { + typedef int T; + typedef std::vector C; + const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + C c(std::begin(t), std::end(t)); + c.reserve(2 * c.size()); + assert(is_contiguous_container_asan_correct(c)); + assert(!__sanitizer_verify_contiguous_container(c.data(), c.data() + 1, c.data() + c.capacity())); + volatile T foo = c[c.size()]; // should trigger ASAN. Use volatile to prevent being optimized away. + assert(false); // if we got here, ASAN didn't trigger + ((void)foo); + } } diff --git a/libcxx/test/std/containers/sequences/vector/access.pass.cpp b/libcxx/test/std/containers/sequences/vector/access.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/access.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/access.pass.cpp @@ -116,6 +116,7 @@ test >(); #if TEST_STD_VER >= 11 test > >(); + test > >(); #endif return true; } diff --git a/libcxx/test/std/containers/sequences/vector/contiguous.pass.cpp b/libcxx/test/std/containers/sequences/vector/contiguous.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/contiguous.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/contiguous.pass.cpp @@ -48,6 +48,13 @@ test_contiguous(C(A{})); test_contiguous(C(9, 11.0, A{})); } + { + typedef double T; + typedef safe_allocator A; + typedef std::vector C; + test_contiguous(C(A{})); + test_contiguous(C(9, 11.0, A{})); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/empty.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/empty.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/empty.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/empty.pass.cpp @@ -40,6 +40,16 @@ c.clear(); assert(c.empty()); } + { + typedef std::vector> C; + C c; + ASSERT_NOEXCEPT(c.empty()); + assert(c.empty()); + c.push_back(C::value_type(1)); + assert(!c.empty()); + c.clear(); + assert(c.empty()); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp @@ -99,6 +99,23 @@ assert(v.capacity() == 150); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v; + v.reserve(10); + assert(v.capacity() >= 10); + assert(is_contiguous_container_asan_correct(v)); + } + { + std::vector> v(100); + assert(v.capacity() == 100); + v.reserve(50); + assert(v.size() == 100); + assert(v.capacity() == 100); + v.reserve(150); + assert(v.size() == 100); + assert(v.capacity() == 150); + assert(is_contiguous_container_asan_correct(v)); + } #endif #ifndef TEST_HAS_NO_EXCEPTIONS if (!TEST_IS_CONSTANT_EVALUATED) { diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp @@ -78,6 +78,17 @@ assert(v.capacity() >= 200); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v(100); + v.resize(50); + assert(v.size() == 50); + assert(v.capacity() == 100); + assert(is_contiguous_container_asan_correct(v)); + v.resize(200); + assert(v.size() == 200); + assert(v.capacity() >= 200); + assert(is_contiguous_container_asan_correct(v)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp @@ -72,6 +72,33 @@ assert(v.capacity() >= 200); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v(100); + v.resize(50, 1); + assert(v.size() == 50); + assert(v.capacity() == 100); + assert(is_contiguous_container_asan_correct(v)); + assert((v == std::vector>(50))); + v.resize(200, 1); + assert(v.size() == 200); + assert(v.capacity() >= 200); + assert(is_contiguous_container_asan_correct(v)); + for (unsigned i = 0; i < 50; ++i) + assert(v[i] == 0); + for (unsigned i = 50; i < 200; ++i) + assert(v[i] == 1); + } + { + std::vector> v(100); + v.resize(50, 1); + assert(v.size() == 50); + assert(v.capacity() == 100); + assert(is_contiguous_container_asan_correct(v)); + v.resize(200, 1); + assert(v.size() == 200); + assert(v.capacity() >= 200); + assert(is_contiguous_container_asan_correct(v)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp @@ -57,6 +57,15 @@ assert(v.size() == 101); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v(100); + v.push_back(1); + assert(is_contiguous_container_asan_correct(v)); + v.shrink_to_fit(); + assert(v.capacity() == 101); + assert(v.size() == 101); + assert(is_contiguous_container_asan_correct(v)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/size.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/size.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/size.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/size.pass.cpp @@ -57,6 +57,24 @@ c.erase(c.begin()); assert(c.size() == 0); } + { + typedef std::vector> C; + C c; + ASSERT_NOEXCEPT(c.size()); + assert(c.size() == 0); + c.push_back(C::value_type(2)); + assert(c.size() == 1); + c.push_back(C::value_type(1)); + assert(c.size() == 2); + c.push_back(C::value_type(3)); + assert(c.size() == 3); + c.erase(c.begin()); + assert(c.size() == 2); + c.erase(c.begin()); + assert(c.size() == 1); + c.erase(c.begin()); + assert(c.size() == 0); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/swap.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/swap.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/swap.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/swap.pass.cpp @@ -45,6 +45,19 @@ assert(v2.capacity() == 100); assert(is_contiguous_container_asan_correct(v2)); } + { + std::vector> v1(100); + std::vector> v2(200); + assert(is_contiguous_container_asan_correct(v1)); + assert(is_contiguous_container_asan_correct(v2)); + v1.swap(v2); + assert(v1.size() == 200); + assert(v1.capacity() == 200); + assert(is_contiguous_container_asan_correct(v1)); + assert(v2.size() == 100); + assert(v2.capacity() == 100); + assert(is_contiguous_container_asan_correct(v2)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp @@ -78,6 +78,13 @@ assert(l2 == l); assert(l2.get_allocator() == min_allocator()); } + { + std::vector > l(3, 2, safe_allocator()); + std::vector > l2(l, safe_allocator()); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == safe_allocator()); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/assign_move.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/assign_move.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/assign_move.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/assign_move.pass.cpp @@ -95,6 +95,24 @@ assert(l2.get_allocator() == lo.get_allocator()); assert(is_contiguous_container_asan_correct(l2)); } + { + std::vector > l((safe_allocator())); + std::vector > lo((safe_allocator())); + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); + } + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + std::vector > l2((safe_allocator())); + l2 = std::move(l); + assert(l2 == lo); + assert(l.empty()); + assert(l2.get_allocator() == lo.get_allocator()); + assert(is_contiguous_container_asan_correct(l2)); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp @@ -81,6 +81,13 @@ random_access_iterator(a), random_access_iterator(an)); test >(a, an); + test > >( + cpp17_input_iterator(a), cpp17_input_iterator(an)); + test > >(forward_iterator(a), forward_iterator(an)); + test > >( + bidirectional_iterator(a), bidirectional_iterator(an)); + test > >( + random_access_iterator(a), random_access_iterator(an)); #endif } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp @@ -83,6 +83,20 @@ test > >(a, an, alloc); test > >(a, an, nullptr); } + { + int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0}; + int* an = a + sizeof(a) / sizeof(a[0]); + safe_allocator alloc; + test > >( + cpp17_input_iterator(a), cpp17_input_iterator(an), alloc); + test > >( + forward_iterator(a), forward_iterator(an), alloc); + test > >( + bidirectional_iterator(a), bidirectional_iterator(an), alloc); + test > >( + random_access_iterator(a), random_access_iterator(an), alloc); + test > >(a, an, alloc); + } #endif } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size.pass.cpp @@ -59,6 +59,8 @@ #if TEST_STD_VER >= 11 test>>(0); test>>(50); + test>>(0); + test>>(50); #endif return true; @@ -76,6 +78,8 @@ #if TEST_STD_VER >= 11 test>>(0); test>>(500); + test>>(0); + test>>(500); test>>(0, test_allocator(23)); test>>(100, test_allocator(23)); assert(DefaultOnly::count == 0); diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp @@ -40,6 +40,8 @@ #if TEST_STD_VER >= 11 test> >(0, 3); test> >(50, 3); + test> >(0, 3); + test> >(50, 3); #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp @@ -37,6 +37,8 @@ #if TEST_STD_VER >= 11 test> >(0, 3, min_allocator()); test> >(50, 3, min_allocator()); + test> >(0, 3, safe_allocator()); + test> >(50, 3, safe_allocator()); #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/copy.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/copy.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/copy.pass.cpp @@ -73,6 +73,7 @@ int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0}; int* an = a + sizeof(a)/sizeof(a[0]); test(std::vector>(a, an)); + test(std::vector>(a, an)); } { std::vector > v(3, 2, min_allocator()); @@ -84,6 +85,16 @@ assert(is_contiguous_container_asan_correct(v)); assert(is_contiguous_container_asan_correct(v2)); } + { + std::vector > v(3, 2, safe_allocator()); + std::vector > v2 = v; + assert(is_contiguous_container_asan_correct(v)); + assert(is_contiguous_container_asan_correct(v2)); + assert(v2 == v); + assert(v2.get_allocator() == v.get_allocator()); + assert(is_contiguous_container_asan_correct(v)); + assert(is_contiguous_container_asan_correct(v2)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_alloc.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/copy_alloc.pass.cpp @@ -61,6 +61,7 @@ int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0}; int* an = a + sizeof(a)/sizeof(a[0]); test(std::vector>(a, an), min_allocator()); + test(std::vector>(a, an), safe_allocator()); } { std::vector > l(3, 2, min_allocator()); @@ -68,6 +69,12 @@ assert(l2 == l); assert(l2.get_allocator() == min_allocator()); } + { + std::vector > l(3, 2, safe_allocator()); + std::vector > l2(l, safe_allocator()); + assert(l2 == l); + assert(l2.get_allocator() == safe_allocator()); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list.pass.cpp @@ -38,6 +38,15 @@ assert(d[2] == 5); assert(d[3] == 6); } + { + std::vector> d = {3, 4, 5, 6}; + assert(d.size() == 4); + assert(is_contiguous_container_asan_correct(d)); + assert(d[0] == 3); + assert(d[1] == 4); + assert(d[2] == 5); + assert(d[3] == 6); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list_alloc.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list_alloc.pass.cpp @@ -48,6 +48,22 @@ assert(d.empty()); assert(is_contiguous_container_asan_correct(d)); } + { + std::vector> d({3, 4, 5, 6}, safe_allocator()); + assert(d.get_allocator() == safe_allocator()); + assert(d.size() == 4); + assert(is_contiguous_container_asan_correct(d)); + assert(d[0] == 3); + assert(d[1] == 4); + assert(d[2] == 5); + assert(d[3] == 6); + } + { + std::vector> d({}, safe_allocator()); + assert(d.size() == 0); + assert(d.empty()); + assert(is_contiguous_container_asan_correct(d)); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp @@ -100,6 +100,34 @@ assert(*j == 3); assert(is_contiguous_container_asan_correct(c2)); } + { + std::vector > l((safe_allocator())); + std::vector > lo((safe_allocator())); + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); + } + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + std::vector > l2 = std::move(l); + assert(l2 == lo); + assert(l.empty()); + assert(l2.get_allocator() == lo.get_allocator()); + assert(is_contiguous_container_asan_correct(l2)); + } + { + int a1[] = {1, 3, 7, 9, 10}; + std::vector > c1(a1, a1 + sizeof(a1) / sizeof(a1[0])); + assert(is_contiguous_container_asan_correct(c1)); + std::vector >::const_iterator i = c1.begin(); + std::vector > c2 = std::move(c1); + assert(is_contiguous_container_asan_correct(c2)); + std::vector >::iterator j = c2.erase(i); + assert(*j == 3); + assert(is_contiguous_container_asan_correct(c2)); + } { alloc_stats.clear(); using Vect = std::vector >; diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/move_alloc.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/move_alloc.pass.cpp @@ -94,6 +94,23 @@ assert(l2.get_allocator() == min_allocator()); assert(is_contiguous_container_asan_correct(l2)); } + { + std::vector > l((safe_allocator())); + std::vector > lo((safe_allocator())); + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); + } + assert(is_contiguous_container_asan_correct(l)); + assert(is_contiguous_container_asan_correct(lo)); + std::vector > l2(std::move(l), safe_allocator()); + assert(l2 == lo); + assert(l.empty()); + assert(l2.get_allocator() == safe_allocator()); + assert(is_contiguous_container_asan_correct(l2)); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.data/data.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.data/data.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.data/data.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.data/data.pass.cpp @@ -59,6 +59,21 @@ assert(v.data() == std::addressof(v.front())); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v; + assert(v.data() == 0); + assert(is_contiguous_container_asan_correct(v)); + } + { + std::vector> v(100); + assert(v.data() == std::addressof(v.front())); + assert(is_contiguous_container_asan_correct(v)); + } + { + std::vector> v(100); + assert(v.data() == std::addressof(v.front())); + assert(is_contiguous_container_asan_correct(v)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.data/data_const.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.data/data_const.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.data/data_const.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.data/data_const.pass.cpp @@ -59,6 +59,21 @@ assert(v.data() == std::addressof(v.front())); assert(is_contiguous_container_asan_correct(v)); } + { + const std::vector> v; + assert(v.data() == 0); + assert(is_contiguous_container_asan_correct(v)); + } + { + const std::vector> v(100); + assert(v.data() == &v.front()); + assert(is_contiguous_container_asan_correct(v)); + } + { + std::vector> v(100); + assert(v.data() == std::addressof(v.front())); + assert(is_contiguous_container_asan_correct(v)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp @@ -68,6 +68,7 @@ test>(); test>> (); test>> (); + test>>(); test>(); test>(); diff --git a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp @@ -70,6 +70,7 @@ test>(); test>> (); test>> (); + test>>(); test>(); test>(); diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/clear.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/clear.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/clear.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/clear.pass.cpp @@ -38,6 +38,15 @@ LIBCPP_ASSERT(c.__invariants()); LIBCPP_ASSERT(is_contiguous_container_asan_correct(c)); } + { + int a[] = {1, 2, 3}; + std::vector> c(a, a + 3); + ASSERT_NOEXCEPT(c.clear()); + c.clear(); + assert(c.empty()); + LIBCPP_ASSERT(c.__invariants()); + LIBCPP_ASSERT(is_contiguous_container_asan_correct(c)); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp @@ -132,6 +132,30 @@ assert(c.back().geti() == 3); assert(c.back().getd() == 4.5); } + { + std::vector > c; + std::vector >::iterator i = c.emplace(c.cbegin(), 2, 3.5); + assert(i == c.begin()); + assert(c.size() == 1); + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + i = c.emplace(c.cend(), 3, 4.5); + assert(i == c.end() - 1); + assert(c.size() == 2); + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + assert(c.back().geti() == 3); + assert(c.back().getd() == 4.5); + i = c.emplace(c.cbegin() + 1, 4, 6.5); + assert(i == c.begin() + 1); + assert(c.size() == 3); + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + assert(c[1].geti() == 4); + assert(c[1].getd() == 6.5); + assert(c.back().geti() == 3); + assert(c.back().getd() == 4.5); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp @@ -130,6 +130,33 @@ assert(is_contiguous_container_asan_correct(c)); c.emplace_back(3, 4.5); assert(c.size() == 2); +#endif + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + assert(c.back().geti() == 3); + assert(c.back().getd() == 4.5); + assert(is_contiguous_container_asan_correct(c)); + } + { + std::vector > c; +#if TEST_STD_VER > 14 + A& r1 = c.emplace_back(2, 3.5); + assert(c.size() == 1); + assert(&r1 == &c.back()); + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + assert(is_contiguous_container_asan_correct(c)); + A& r2 = c.emplace_back(3, 4.5); + assert(c.size() == 2); + assert(&r2 == &c.back()); +#else + c.emplace_back(2, 3.5); + assert(c.size() == 1); + assert(c.front().geti() == 2); + assert(c.front().getd() == 3.5); + assert(is_contiguous_container_asan_correct(c)); + c.emplace_back(3, 4.5); + assert(c.size() == 2); #endif assert(c.front().geti() == 2); assert(c.front().getd() == 3.5); diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp @@ -56,6 +56,24 @@ assert(v[0] == 3); assert(is_contiguous_container_asan_correct(v)); } + { + std::vector> v; + v.reserve(3); + assert(is_contiguous_container_asan_correct(v)); + v = {1, 2, 3}; + v.emplace(v.begin(), v.back()); + assert(v[0] == 3); + assert(is_contiguous_container_asan_correct(v)); + } + { + std::vector> v; + v.reserve(4); + assert(is_contiguous_container_asan_correct(v)); + v = {1, 2, 3}; + v.emplace(v.begin(), v.back()); + assert(v[0] == 3); + assert(is_contiguous_container_asan_correct(v)); + } { std::vector v; v.reserve(8); diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp @@ -114,6 +114,20 @@ for (++j; j < 101; ++j) assert(v[j] == 0); } + { + std::vector> v(100); + const int lvalue = 1; + std::vector>::iterator i = v.insert(v.cbegin() + 10, lvalue); + assert(v.size() == 101); + assert(is_contiguous_container_asan_correct(v)); + assert(i == v.begin() + 10); + int j; + for (j = 0; j < 10; ++j) + assert(v[j] == 0); + assert(v[j] == 1); + for (++j; j < 101; ++j) + assert(v[j] == 0); + } #endif return true; diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp @@ -62,6 +62,19 @@ for (++j; j < 101; ++j) assert(v[j] == MoveOnly()); } + { + std::vector > v(100); + std::vector >::iterator i = v.insert(v.cbegin() + 10, MoveOnly(3)); + assert(v.size() == 101); + assert(is_contiguous_container_asan_correct(v)); + assert(i == v.begin() + 10); + int j; + for (j = 0; j < 10; ++j) + assert(v[j] == MoveOnly()); + assert(v[j] == MoveOnly(3)); + for (++j; j < 101; ++j) + assert(v[j] == MoveOnly()); + } return true; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp @@ -97,18 +97,18 @@ assert(v[j] == 0); } { - std::vector> v(100); - std::vector>::iterator i = v.insert(v.cbegin() + 10, 5, 1); - assert(v.size() == 105); - assert(is_contiguous_container_asan_correct(v)); - assert(i == v.begin() + 10); - int j; - for (j = 0; j < 10; ++j) - assert(v[j] == 0); - for (; j < 15; ++j) - assert(v[j] == 1); - for (++j; j < 105; ++j) - assert(v[j] == 0); + std::vector> v(100); + std::vector>::iterator i = v.insert(v.cbegin() + 10, 5, 1); + assert(v.size() == 105); + assert(is_contiguous_container_asan_correct(v)); + assert(i == v.begin() + 10); + int j; + for (j = 0; j < 10; ++j) + assert(v[j] == 0); + for (; j < 15; ++j) + assert(v[j] == 1); + for (++j; j < 105; ++j) + assert(v[j] == 0); } #endif diff --git a/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp @@ -178,6 +178,79 @@ assert(is_contiguous_container_asan_correct(c1)); assert(is_contiguous_container_asan_correct(c2)); } + // safe_allocator + { + int a1[] = {1, 3, 7, 9, 10}; + int a2[] = {0, 2, 4, 5, 6, 8, 11}; + std::vector> c1(a1, a1 + sizeof(a1) / sizeof(a1[0])); + std::vector> c2(a2, a2 + sizeof(a2) / sizeof(a2[0])); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + swap(c1, c2); + assert((c1 == std::vector>(a2, a2 + sizeof(a2) / sizeof(a2[0])))); + assert((c2 == std::vector>(a1, a1 + sizeof(a1) / sizeof(a1[0])))); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + } + { + int a1[] = {1, 3, 7, 9, 10}; + int a2[] = {0, 2, 4, 5, 6, 8, 11}; + std::vector> c1(a1, a1); + std::vector> c2(a2, a2 + sizeof(a2) / sizeof(a2[0])); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + swap(c1, c2); + assert((c1 == std::vector>(a2, a2 + sizeof(a2) / sizeof(a2[0])))); + assert(c2.empty()); + assert(std::distance(c2.begin(), c2.end()) == 0); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + } + { + int a1[] = {1, 3, 7, 9, 10}; + int a2[] = {0, 2, 4, 5, 6, 8, 11}; + std::vector> c1(a1, a1 + sizeof(a1) / sizeof(a1[0])); + std::vector> c2(a2, a2); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + swap(c1, c2); + assert(c1.empty()); + assert(std::distance(c1.begin(), c1.end()) == 0); + assert((c2 == std::vector>(a1, a1 + sizeof(a1) / sizeof(a1[0])))); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + } + { + int a1[] = {1, 3, 7, 9, 10}; + int a2[] = {0, 2, 4, 5, 6, 8, 11}; + std::vector> c1(a1, a1); + std::vector> c2(a2, a2); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + swap(c1, c2); + assert(c1.empty()); + assert(std::distance(c1.begin(), c1.end()) == 0); + assert(c2.empty()); + assert(std::distance(c2.begin(), c2.end()) == 0); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + } + { + int a1[] = {1, 3, 7, 9, 10}; + int a2[] = {0, 2, 4, 5, 6, 8, 11}; + typedef safe_allocator A; + std::vector c1(a1, a1 + sizeof(a1) / sizeof(a1[0]), A()); + std::vector c2(a2, a2 + sizeof(a2) / sizeof(a2[0]), A()); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + swap(c1, c2); + assert((c1 == std::vector(a2, a2 + sizeof(a2) / sizeof(a2[0])))); + assert(c1.get_allocator() == A()); + assert((c2 == std::vector(a1, a1 + sizeof(a1) / sizeof(a1[0])))); + assert(c2.get_allocator() == A()); + assert(is_contiguous_container_asan_correct(c1)); + assert(is_contiguous_container_asan_correct(c2)); + } #endif return true; diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h --- a/libcxx/test/support/min_allocator.h +++ b/libcxx/test/support/min_allocator.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "test_macros.h" @@ -432,4 +433,51 @@ TEST_CONSTEXPR_CXX20 friend bool operator!=(explicit_allocator x, explicit_allocator y) {return !(x == y);} }; +template +class unaligned_allocator { +public: + static_assert(alignof(T) == 1); + typedef T value_type; + + TEST_CONSTEXPR_CXX20 unaligned_allocator() TEST_NOEXCEPT {} + + template + TEST_CONSTEXPR_CXX20 explicit unaligned_allocator(unaligned_allocator) TEST_NOEXCEPT {} + + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return static_cast(std::allocator().allocate(n + 1)) + 1; } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator().deallocate(p - 1, n + 1); } + + TEST_CONSTEXPR_CXX20 friend bool operator==(unaligned_allocator, unaligned_allocator) { return true; } + TEST_CONSTEXPR_CXX20 friend bool operator!=(unaligned_allocator x, unaligned_allocator y) { return !(x == y); } +}; + +template +class safe_allocator { +public: + typedef T value_type; + + TEST_CONSTEXPR_CXX20 safe_allocator() TEST_NOEXCEPT {} + + template + TEST_CONSTEXPR_CXX20 safe_allocator(safe_allocator) TEST_NOEXCEPT {} + + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { + T* memory = static_cast(std::allocator().allocate(n)); + if (!std::__libcpp_is_constant_evaluated()) + std::memset(memory, 0, sizeof(T) * n); + + return memory; + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { + if (!std::__libcpp_is_constant_evaluated()) + std::memset(p, 0, sizeof(T) * n); + std::allocator().deallocate(p, n); + } + + TEST_CONSTEXPR_CXX20 friend bool operator==(safe_allocator, safe_allocator) { return true; } + TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); } +}; + #endif // MIN_ALLOCATOR_H