[libcxx-commits] [libcxx] e3dd9f7 - [libc++] Safe allocator tests

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 9 04:22:04 PST 2023


Author: Advenam Tacet
Date: 2023-03-09T13:21:38+01:00
New Revision: e3dd9f7e66fec22986605da2dcd8120a7864455d

URL: https://github.com/llvm/llvm-project/commit/e3dd9f7e66fec22986605da2dcd8120a7864455d
DIFF: https://github.com/llvm/llvm-project/commit/e3dd9f7e66fec22986605da2dcd8120a7864455d.diff

LOG: [libc++] Safe allocator tests

This revision adds:
- New test allocator, which cleans memory during allocation and deallocation,
- tests using that allocator to vector.

This patch is part of our efforts to add support for ASan annotations with every
allocator.

This commit adds a new allocator for testing purposes only. The safe allocator
ensures that memory is cleand (zeroed) during allocation and deallocation, and
is intendted to test ASan annotations for every allocator in std::vector.
Check: D136765

Those tests should work correctly, even if support for every allocator in std::vector
is not yet available.

Support in ASan API was added here: rGdd1b7b797a116eed588fd752fbe61d34deeb24e4

Reviewed By: philnik, #libc

Spies: libcxx-commits

Differential Revision: https://reviews.llvm.org/D145597

Added: 
    

Modified: 
    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/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 1f61b16fe9759..ea029ebf9dad8 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