[libcxx-commits] [libcxx] a9356a5 - [ASan][libcxx] Annotating std::vector with all allocators
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Feb 23 11:46:52 PST 2023
Author: Advenam Tacet
Date: 2023-02-23T20:46:05+01:00
New Revision: a9356a515b5a1a3637eaf5820fc0d2c0dad21a64
URL: https://github.com/llvm/llvm-project/commit/a9356a515b5a1a3637eaf5820fc0d2c0dad21a64
DIFF: https://github.com/llvm/llvm-project/commit/a9356a515b5a1a3637eaf5820fc0d2c0dad21a64.diff
LOG: [ASan][libcxx] Annotating std::vector with all allocators
This revision is a part of a series of patches extending
AddressSanitizer C++ container overflow detection
capabilities by adding annotations, similar to those existing
in std::vector, to std::string and std::deque collections.
These changes allow ASan to detect cases when the instrumented
program accesses memory which is internally allocated by
the collection but is still not in-use (accesses before or
after the stored elements for std::deque, or between the size and
capacity bounds for std::string).
The motivation for the research and those changes was a bug,
found by Trail of Bits, in a real code where an out-of-bounds read
could happen as two strings were compared via a std::equals function
that took iter1_begin, iter1_end, iter2_begin iterators
(with a custom comparison function).
When object iter1 was longer than iter2, read out-of-bounds on iter2
could happen. Container sanitization would detect it.
In revision D132522, support for non-aligned memory buffers (sharing
first/last granule with other objects) was added, therefore the
check for standard allocator is not necessary anymore.
This patch removes the check in std::vector annotation member
function (__annotate_contiguous_container) to support
different allocators.
Additionally, this revision fixes unpoisoning in std::vector.
It guarantees that __alloc_traits::deallocate may access returned memory.
Originally suggested in D144155 revision.
If you have any questions, please email:
- advenam.tacet at trailofbits.com
- disconnect3d at trailofbits.com
Reviewed By: #libc, #sanitizers, philnik, vitalybuka
Spies: hans, EricWF, philnik, #sanitizers, libcxx-commits
Differential Revision: https://reviews.llvm.org/D136765
Added:
Modified:
libcxx/include/vector
libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp
libcxx/test/std/containers/sequences/vector/access.pass.cpp
libcxx/test/std/containers/sequences/vector/contiguous.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/empty.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/size.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.capacity/swap.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/assign_copy.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/assign_move.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/construct_size.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/construct_size_value_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/copy.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/copy_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/initializer_list_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.cons/move_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.data/data.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.data/data_const.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/clear.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_extra.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_lvalue.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp
libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp
libcxx/test/support/min_allocator.h
Removed:
################################################################################
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 619e25822a462..d1e4b136ae2d9 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -439,11 +439,11 @@ private:
_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 @@ private:
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
diff erent 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<allocator_type, __default_allocator_type>::value)
+# endif
__sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid);
}
#else
@@ -866,6 +883,7 @@ private:
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 @@ vector<_Tp, _Allocator>::__vdeallocate() _NOEXCEPT
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
index 40275f58cb32c..4032e86b70d4b 100644
--- a/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp
+++ b/libcxx/test/libcxx/containers/sequences/vector/asan.pass.cpp
@@ -29,40 +29,65 @@ void do_exit() {
int main(int, char**)
{
-#if TEST_STD_VER >= 11
- {
- typedef int T;
- typedef std::vector<T, min_allocator<T>> 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
+ // TODO LLVM18: Remove the special-test
+ {
+ typedef int T;
+ typedef std::vector<T, min_allocator<T>> 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<int*> MyInputIter;
- // Sould not trigger ASan.
- std::vector<int> 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
+ // TODO LLVM18: Remove the special-casing
+ {
+ typedef int T;
+ typedef cpp17_input_iterator<T*> MyInputIter;
+ std::vector<T, min_allocator<T>> 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<T*> MyInputIter;
+ std::vector<T, unaligned_allocator<T>> 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<int*> MyInputIter;
+ // Sould not trigger ASan.
+ std::vector<int> 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<T> 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<T> 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
index 5989f1e037fd3..026cf92c2d723 100644
--- 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_CONSTEXPR_CXX20 bool tests() {
test<std::vector<int> >();
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int> > >();
+ test<std::vector<int, safe_allocator<int> > >();
#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
index d9f557e6c9770..ad18e65bb8eac 100644
--- 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_CONSTEXPR_CXX20 bool tests()
test_contiguous(C(A{}));
test_contiguous(C(9, 11.0, A{}));
}
+ {
+ typedef double T;
+ typedef safe_allocator<T> A;
+ typedef std::vector<T, A> 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
index cc5f3bc90a670..ad4d7b310af76 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
c.clear();
assert(c.empty());
}
+ {
+ typedef std::vector<int, safe_allocator<int>> 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
index 99c489601b0f5..387657cc3d2c1 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v.capacity() == 150);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> v;
+ v.reserve(10);
+ assert(v.capacity() >= 10);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int, safe_allocator<int>> 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
index 0b9db8e691c08..967daf99f27c7 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v.capacity() >= 200);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> 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
index c0197982b4a45..a880bcf1f9499 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v.capacity() >= 200);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> 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<int, safe_allocator<int>>(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<int, safe_allocator<int>> 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
index 3f2487948430d..8851e2a9ed0c7 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v.size() == 101);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> 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
index aa41da69b31ab..f38aab1e13845 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
c.erase(c.begin());
assert(c.size() == 0);
}
+ {
+ typedef std::vector<int, safe_allocator<int>> 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
index 47a0435674136..1b2ac76eb2b5f 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v2.capacity() == 100);
assert(is_contiguous_container_asan_correct(v2));
}
+ {
+ std::vector<int, safe_allocator<int>> v1(100);
+ std::vector<int, safe_allocator<int>> 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
index f5b461b05a349..e0e227e8dc0c6 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(l2 == l);
assert(l2.get_allocator() == min_allocator<int>());
}
+ {
+ std::vector<int, safe_allocator<int> > l(3, 2, safe_allocator<int>());
+ std::vector<int, safe_allocator<int> > l2(l, safe_allocator<int>());
+ l2 = l;
+ assert(l2 == l);
+ assert(l2.get_allocator() == safe_allocator<int>());
+ }
#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
index e6eba51a43bbb..58081fa0ecef5 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(l2.get_allocator() == lo.get_allocator());
assert(is_contiguous_container_asan_correct(l2));
}
+ {
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > l((safe_allocator<MoveOnly>()));
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > lo((safe_allocator<MoveOnly>()));
+ 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<MoveOnly, safe_allocator<MoveOnly> > l2((safe_allocator<MoveOnly>()));
+ 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
index 0f2fb36aaa67a..44364023c4e8e 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 void basic_test_cases() {
random_access_iterator<const int*>(a),
random_access_iterator<const int*>(an));
test<std::vector<int> >(a, an);
+ test<std::vector<int, safe_allocator<int> > >(
+ cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(an));
+ test<std::vector<int, safe_allocator<int> > >(forward_iterator<const int*>(a), forward_iterator<const int*>(an));
+ test<std::vector<int, safe_allocator<int> > >(
+ bidirectional_iterator<const int*>(a), bidirectional_iterator<const int*>(an));
+ test<std::vector<int, safe_allocator<int> > >(
+ random_access_iterator<const int*>(a), random_access_iterator<const int*>(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
index 5d38543963e5c..b1e34a56fbb8a 100644
--- 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_CONSTEXPR_CXX20 void basic_tests() {
test<std::vector<int, min_allocator<int> > >(a, an, alloc);
test<std::vector<int, implicit_conv_allocator<int> > >(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<int> alloc;
+ test<std::vector<int, safe_allocator<int> > >(
+ cpp17_input_iterator<const int*>(a), cpp17_input_iterator<const int*>(an), alloc);
+ test<std::vector<int, safe_allocator<int> > >(
+ forward_iterator<const int*>(a), forward_iterator<const int*>(an), alloc);
+ test<std::vector<int, safe_allocator<int> > >(
+ bidirectional_iterator<const int*>(a), bidirectional_iterator<const int*>(an), alloc);
+ test<std::vector<int, safe_allocator<int> > >(
+ random_access_iterator<const int*>(a), random_access_iterator<const int*>(an), alloc);
+ test<std::vector<int, safe_allocator<int> > >(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
index e4b1f431ae491..1dc7cd9bc7c1b 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int>>>(0);
test<std::vector<int, min_allocator<int>>>(50);
+ test<std::vector<int, safe_allocator<int>>>(0);
+ test<std::vector<int, safe_allocator<int>>>(50);
#endif
return true;
@@ -76,6 +78,8 @@ int main(int, char**) {
#if TEST_STD_VER >= 11
test<std::vector<DefaultOnly, min_allocator<DefaultOnly>>>(0);
test<std::vector<DefaultOnly, min_allocator<DefaultOnly>>>(500);
+ test<std::vector<DefaultOnly, safe_allocator<DefaultOnly>>>(0);
+ test<std::vector<DefaultOnly, safe_allocator<DefaultOnly>>>(500);
test<std::vector<DefaultOnly, test_allocator<DefaultOnly>>>(0, test_allocator<DefaultOnly>(23));
test<std::vector<DefaultOnly, test_allocator<DefaultOnly>>>(100, test_allocator<DefaultOnly>(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
index 7f7777c2c97dc..0f24e77cd47e0 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int>> >(0, 3);
test<std::vector<int, min_allocator<int>> >(50, 3);
+ test<std::vector<int, safe_allocator<int>> >(0, 3);
+ test<std::vector<int, safe_allocator<int>> >(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
index 17d3a5876bc5b..eb34de8bc9b31 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int>> >(0, 3, min_allocator<int>());
test<std::vector<int, min_allocator<int>> >(50, 3, min_allocator<int>());
+ test<std::vector<int, safe_allocator<int>> >(0, 3, safe_allocator<int>());
+ test<std::vector<int, safe_allocator<int>> >(50, 3, safe_allocator<int>());
#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
index 88822e9c18357..810ea4f9fa44d 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
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<int, min_allocator<int>>(a, an));
+ test(std::vector<int, safe_allocator<int>>(a, an));
}
{
std::vector<int, min_allocator<int> > v(3, 2, min_allocator<int>());
@@ -84,6 +85,16 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(is_contiguous_container_asan_correct(v));
assert(is_contiguous_container_asan_correct(v2));
}
+ {
+ std::vector<int, safe_allocator<int> > v(3, 2, safe_allocator<int>());
+ std::vector<int, safe_allocator<int> > 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
index 70434bcfc578c..0c03c50aed2e8 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
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<int, min_allocator<int>>(a, an), min_allocator<int>());
+ test(std::vector<int, safe_allocator<int>>(a, an), safe_allocator<int>());
}
{
std::vector<int, min_allocator<int> > l(3, 2, min_allocator<int>());
@@ -68,6 +69,12 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(l2 == l);
assert(l2.get_allocator() == min_allocator<int>());
}
+ {
+ std::vector<int, safe_allocator<int> > l(3, 2, safe_allocator<int>());
+ std::vector<int, safe_allocator<int> > l2(l, safe_allocator<int>());
+ assert(l2 == l);
+ assert(l2.get_allocator() == safe_allocator<int>());
+ }
#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
index 6454f87f7e8ab..af2f3e40a91b5 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(d[2] == 5);
assert(d[3] == 6);
}
+ {
+ std::vector<int, safe_allocator<int>> 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
index 157aefc5af823..8396e84681620 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(d.empty());
assert(is_contiguous_container_asan_correct(d));
}
+ {
+ std::vector<int, safe_allocator<int>> d({3, 4, 5, 6}, safe_allocator<int>());
+ assert(d.get_allocator() == safe_allocator<int>());
+ 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<int, safe_allocator<int>> d({}, safe_allocator<int>());
+ 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
index 0f3e737c1709b..95b896b41f530 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(*j == 3);
assert(is_contiguous_container_asan_correct(c2));
}
+ {
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > l((safe_allocator<MoveOnly>()));
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > lo((safe_allocator<MoveOnly>()));
+ 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<MoveOnly, safe_allocator<MoveOnly> > 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<int, safe_allocator<int> > c1(a1, a1 + sizeof(a1) / sizeof(a1[0]));
+ assert(is_contiguous_container_asan_correct(c1));
+ std::vector<int, safe_allocator<int> >::const_iterator i = c1.begin();
+ std::vector<int, safe_allocator<int> > c2 = std::move(c1);
+ assert(is_contiguous_container_asan_correct(c2));
+ std::vector<int, safe_allocator<int> >::iterator j = c2.erase(i);
+ assert(*j == 3);
+ assert(is_contiguous_container_asan_correct(c2));
+ }
{
alloc_stats.clear();
using Vect = std::vector<int, test_allocator<int> >;
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
index 2b6705a38e860..fd0b995b54d54 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(l2.get_allocator() == min_allocator<MoveOnly>());
assert(is_contiguous_container_asan_correct(l2));
}
+ {
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > l((safe_allocator<MoveOnly>()));
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > lo((safe_allocator<MoveOnly>()));
+ 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<MoveOnly, safe_allocator<MoveOnly> > l2(std::move(l), safe_allocator<MoveOnly>());
+ assert(l2 == lo);
+ assert(l.empty());
+ assert(l2.get_allocator() == safe_allocator<MoveOnly>());
+ 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
index 4d2cadc00ceb1..64b85424e54a5 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(v.data() == std::addressof(v.front()));
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> v;
+ assert(v.data() == 0);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<int, safe_allocator<int>> v(100);
+ assert(v.data() == std::addressof(v.front()));
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<Nasty, safe_allocator<Nasty>> 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
index d314f90daf4b6..885caf272afbf 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(v.data() == std::addressof(v.front()));
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ const std::vector<int, safe_allocator<int>> v;
+ assert(v.data() == 0);
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ const std::vector<int, safe_allocator<int>> v(100);
+ assert(v.data() == &v.front());
+ assert(is_contiguous_container_asan_correct(v));
+ }
+ {
+ std::vector<Nasty, safe_allocator<Nasty>> 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
index 72441c12dac8e..01a43a9570830 100644
--- 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_CONSTEXPR_CXX20 bool tests()
test<std::vector<int>>();
test<std::vector<int, min_allocator<int>>> ();
test<std::vector<int, test_allocator<int>>> ();
+ test<std::vector<int, safe_allocator<int>>>();
test<std::vector<long>>();
test<std::vector<double>>();
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
index 1fcc1c9424868..3da8eca862a28 100644
--- 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_CONSTEXPR_CXX20 bool tests()
test<std::vector<int>>();
test<std::vector<int, min_allocator<int>>> ();
test<std::vector<int, test_allocator<int>>> ();
+ test<std::vector<int, safe_allocator<int>>>();
test<std::vector<long>>();
test<std::vector<double>>();
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
index 5a1e134f66fdf..9390b8309736f 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
LIBCPP_ASSERT(c.__invariants());
LIBCPP_ASSERT(is_contiguous_container_asan_correct(c));
}
+ {
+ int a[] = {1, 2, 3};
+ std::vector<int, safe_allocator<int>> 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
index f2c656cd27b2f..4f5e36abb6bb8 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(c.back().geti() == 3);
assert(c.back().getd() == 4.5);
}
+ {
+ std::vector<A, safe_allocator<A> > c;
+ std::vector<A, safe_allocator<A> >::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
index bb7fa745ac355..730ed32bd7334 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
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<A, safe_allocator<A> > 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
index 3e1a1d82c2ebb..8c0caa74a9322 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests() {
assert(v[0] == 3);
assert(is_contiguous_container_asan_correct(v));
}
+ {
+ std::vector<int, safe_allocator<int>> 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<int, safe_allocator<int>> 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<int> 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
index c8bb994258894..8985435e11c9b 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool test() {
for (++j; j < 101; ++j)
assert(v[j] == 0);
}
+ {
+ std::vector<int, safe_allocator<int>> v(100);
+ const int lvalue = 1;
+ std::vector<int, safe_allocator<int>>::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
index 11a7175c61967..4619d7a7d1b6f 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
for (++j; j < 101; ++j)
assert(v[j] == MoveOnly());
}
+ {
+ std::vector<MoveOnly, safe_allocator<MoveOnly> > v(100);
+ std::vector<MoveOnly, safe_allocator<MoveOnly> >::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
index c629428828081..f6e447b2ff294 100644
--- 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 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(v[j] == 0);
}
{
- std::vector<int, min_allocator<int>> v(100);
- std::vector<int, min_allocator<int>>::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<int, safe_allocator<int>> v(100);
+ std::vector<int, safe_allocator<int>>::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
index e1f45208539ac..98aece64c80e7 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.special/swap.pass.cpp
@@ -19,6 +19,81 @@
#include "min_allocator.h"
#include "asan_testing.h"
+template <typename A>
+TEST_CONSTEXPR_CXX20 void test_with_allocator() {
+ {
+ int a1[] = {1, 3, 7, 9, 10};
+ int a2[] = {0, 2, 4, 5, 6, 8, 11};
+ std::vector<int, A> c1(a1, a1 + sizeof(a1) / sizeof(a1[0]));
+ std::vector<int, A> 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<int, A>(a2, a2 + sizeof(a2) / sizeof(a2[0]))));
+ assert((c2 == std::vector<int, A>(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<int, A> c1(a1, a1);
+ std::vector<int, A> 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<int, A>(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<int, A> c1(a1, a1 + sizeof(a1) / sizeof(a1[0]));
+ std::vector<int, A> 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<int, A>(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<int, A> c1(a1, a1);
+ std::vector<int, A> 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};
+ std::vector<int, A> c1(a1, a1 + sizeof(a1) / sizeof(a1[0]), A());
+ std::vector<int, A> 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<int, A>(a2, a2 + sizeof(a2) / sizeof(a2[0]))));
+ assert(c1.get_allocator() == A());
+ assert((c2 == std::vector<int, A>(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));
+ }
+}
+
TEST_CONSTEXPR_CXX20 bool tests()
{
{
@@ -106,78 +181,8 @@ TEST_CONSTEXPR_CXX20 bool tests()
assert(is_contiguous_container_asan_correct(c2));
}
#if TEST_STD_VER >= 11
- {
- int a1[] = {1, 3, 7, 9, 10};
- int a2[] = {0, 2, 4, 5, 6, 8, 11};
- std::vector<int, min_allocator<int>> c1(a1, a1+sizeof(a1)/sizeof(a1[0]));
- std::vector<int, min_allocator<int>> 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<int, min_allocator<int>>(a2, a2+sizeof(a2)/sizeof(a2[0]))));
- assert((c2 == std::vector<int, min_allocator<int>>(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<int, min_allocator<int>> c1(a1, a1);
- std::vector<int, min_allocator<int>> 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<int, min_allocator<int>>(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<int, min_allocator<int>> c1(a1, a1+sizeof(a1)/sizeof(a1[0]));
- std::vector<int, min_allocator<int>> 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<int, min_allocator<int>>(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<int, min_allocator<int>> c1(a1, a1);
- std::vector<int, min_allocator<int>> 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 min_allocator<int> A;
- std::vector<int, A> c1(a1, a1+sizeof(a1)/sizeof(a1[0]), A());
- std::vector<int, A> 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<int, A>(a2, a2+sizeof(a2)/sizeof(a2[0]))));
- assert(c1.get_allocator() == A());
- assert((c2 == std::vector<int, A>(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));
- }
+ test_with_allocator<min_allocator<int>>();
+ test_with_allocator<safe_allocator<int>>();
#endif
return true;
diff --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h
index f27ac80c04649..f9d37e72ef631 100644
--- a/libcxx/test/support/min_allocator.h
+++ b/libcxx/test/support/min_allocator.h
@@ -17,6 +17,7 @@
#include <memory>
#include <new>
#include <type_traits>
+#include <cstring>
#include "test_macros.h"
@@ -432,4 +433,51 @@ class explicit_allocator
TEST_CONSTEXPR_CXX20 friend bool operator!=(explicit_allocator x, explicit_allocator y) {return !(x == y);}
};
+template <class T>
+class unaligned_allocator {
+public:
+ static_assert(TEST_ALIGNOF(T) == 1, "Type T cannot be created on unaligned address (UB)");
+ typedef T value_type;
+
+ TEST_CONSTEXPR_CXX20 unaligned_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ TEST_CONSTEXPR_CXX20 explicit unaligned_allocator(unaligned_allocator<U>) TEST_NOEXCEPT {}
+
+ TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<T>().allocate(n + 1) + 1; }
+
+ TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>().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 T>
+class safe_allocator {
+public:
+ typedef T value_type;
+
+ TEST_CONSTEXPR_CXX20 safe_allocator() TEST_NOEXCEPT {}
+
+ template <class U>
+ TEST_CONSTEXPR_CXX20 safe_allocator(safe_allocator<U>) TEST_NOEXCEPT {}
+
+ TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) {
+ T* memory = std::allocator<T>().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())
+ DoNotOptimize(std::memset(p, 0, sizeof(T) * n));
+ std::allocator<T>().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
More information about the libcxx-commits
mailing list