[libcxx-commits] [libcxx] 605b9c7 - [2a/3][ASan][libcxx] std::deque annotations

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 24 14:27:18 PDT 2023


Author: Advenam Tacet
Date: 2023-05-24T14:26:57-07:00
New Revision: 605b9c76e093f6ed713b3fea47cb9726b346edeb

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

LOG: [2a/3][ASan][libcxx] std::deque annotations

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.

This revision introduces annotations for `std::deque`. Each chunk of the container can now be annotated using the `__sanitizer_annotate_double_ended_contiguous_container` function, which was added in the rG1c5ad6d2c01294a0decde43a88e9c27d7437d157. Any attempt to access poisoned memory will trigger an ASan error. Although false negatives are rare, they are possible due to limitations in the ASan API, where a few (usually up to 7) bytes before the container may remain unpoisoned. There are no false positives in the same way as with `std::vector` annotations.

This patch only supports objects (deques) that use the standard allocator. However, it can be easily extended to support all allocators, as suggested in the D146815 revision.

Furthermore, the patch includes the addition of the `is_double_ended_contiguous_container_asan_correct` function to libcxx/test/support/asan_testing.h. This function can be used to verify whether a `std::deque` object has been correctly annotated.

Finally, the patch extends the unit tests to verify ASan annotations (added LIBCPP_ASSERTs).
If a program is compiled without ASan, all helper functions will be no-ops. In binaries with ASan, there is a negligible performance impact since the code from the change is only executed when the deque container changes in size and it’s proportional to the change. It is important to note that regardless of whether or not these changes are in use, every access to the container's memory is instrumented.

Reviewed By: #libc, philnik

Spies: vitalybuka, hans, mikhail.ramalho, Enna1, #sanitizers, philnik, libcxx-commits

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

Added: 
    libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp

Modified: 
    libcxx/include/__config
    libcxx/include/deque
    libcxx/test/std/containers/sequences/deque/deque.capacity/access.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/empty.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/max_size.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size_value.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/shrink_to_fit.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.capacity/size.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/assign_initializer_list.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/assign_size_value.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/copy.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/copy_alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/default.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list_alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/move.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/move_alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/move_assign.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/op_equal.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/op_equal_initializer_list.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/size.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.cons/size_value_alloc.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/clear.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_front.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.invalidation.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.invalidation.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_initializer_list.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_rvalue.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_size_value.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_value.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.invalidation.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.invalidation.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_rvalue.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_rvalue.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.special/copy.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.special/copy_backward.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.special/move.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.special/move_backward.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.special/swap.pass.cpp
    libcxx/test/support/asan_testing.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__config b/libcxx/include/__config
index 57b225258df46..6890635467c5c 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -902,6 +902,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
 #  ifndef _LIBCPP_HAS_NO_ASAN
     extern "C" _LIBCPP_FUNC_VIS void
     __sanitizer_annotate_contiguous_container(const void*, const void*, const void*, const void*);
+#    if _LIBCPP_CLANG_VER >= 1600
+extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_double_ended_contiguous_container(
+    const void*, const void*, const void*, const void*, const void*, const void*);
+extern "C" _LIBCPP_FUNC_VIS int
+__sanitizer_verify_double_ended_contiguous_container(const void*, const void*, const void*, const void*);
+#    endif
 #  endif
 
 // Try to find out if RTTI is disabled.

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index c865427816d67..c7d3cdaa5b48c 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -457,6 +457,9 @@ const _DiffType __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer,
 template <class _Tp, class _Allocator /*= allocator<_Tp>*/>
 class _LIBCPP_TEMPLATE_VIS deque
 {
+private:
+  using __default_allocator_type = allocator<_Tp>;
+
 public:
     // types:
 
@@ -480,6 +483,7 @@ public:
   using __map_alloc_traits        = allocator_traits<__pointer_allocator>;
   using __map_pointer             = typename __map_alloc_traits::pointer;
   using __map_const_pointer       = typename allocator_traits<__const_pointer_allocator>::const_pointer;
+  using __map_const_iterator      = typename __map::const_iterator;
 
   using reference       = value_type&;
   using const_reference = const value_type&;
@@ -579,10 +583,13 @@ public:
     // construct/copy/destroy:
     _LIBCPP_HIDE_FROM_ABI
     deque() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
-        : __start_(0), __size_(0, __default_init_tag()) {}
+        : __start_(0), __size_(0, __default_init_tag()) {
+      __annotate_new(0);
+    }
 
     _LIBCPP_HIDE_FROM_ABI ~deque() {
       clear();
+      __annotate_delete();
       typename __map::iterator __i = __map_.begin();
       typename __map::iterator __e = __map_.end();
       for (; __i != __e; ++__i)
@@ -590,7 +597,9 @@ public:
     }
 
     _LIBCPP_HIDE_FROM_ABI explicit deque(const allocator_type& __a)
-        : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {}
+        : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a) {
+      __annotate_new(0);
+    }
 
     explicit _LIBCPP_HIDE_FROM_ABI deque(size_type __n);
 #if _LIBCPP_STD_VER >= 14
@@ -602,6 +611,7 @@ public:
     _LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v, const allocator_type& __a)
         : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
     {
+        __annotate_new(0);
         if (__n > 0)
             __append(__n, __v);
     }
@@ -862,7 +872,7 @@ public:
             return false;
         if (__map_.size() >= size_type(-1) / __block_size)
             return false;
-        for (typename __map::const_iterator __i = __map_.begin(), __e = __map_.end();
+        for (__map_const_iterator __i = __map_.begin(), __e = __map_.end();
             __i != __e; ++__i)
             if (*__i == nullptr)
                 return false;
@@ -949,9 +959,248 @@ public:
     }
 
  private:
+   enum __asan_annotation_type {
+     __asan_unposion,
+     __asan_poison
+   };
+
+   enum __asan_annotation_place {
+     __asan_front_moved,
+     __asan_back_moved,
+   };
+
+// The following functions are no-ops outside of AddressSanitizer mode.
+// We call annotations only for the default Allocator.
+#if !defined(_LIBCPP_HAS_NO_ASAN) && _LIBCPP_CLANG_VER >= 1600
+    // TODO LLVM18: Remove the special-casing
+    _LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container(
+        const void* __beg,
+        const void* __end,
+        const void* __old_con_beg,
+        const void* __old_con_end,
+        const void* __new_con_beg,
+        const void* __new_con_end) const {
+        if (__beg && is_same<allocator_type, __default_allocator_type>::value)
+            __sanitizer_annotate_double_ended_contiguous_container(
+                __beg, __end, __old_con_beg, __old_con_end, __new_con_beg, __new_con_end);
+    }
+#else
+    _LIBCPP_HIDE_FROM_ABI void __annotate_double_ended_contiguous_container(
+        const void*, const void*, const void*, const void*, const void*, const void*) const _NOEXCEPT {}
+#endif // !defined(_LIBCPP_HAS_NO_ASAN) && _LIBCPP_CLANG_VER >= 1600
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_from_to(size_type __beg, size_type __end, __asan_annotation_type __annotation_type, __asan_annotation_place __place) const _NOEXCEPT {
+        // __beg - index of the first item to annotate
+        // __end - index behind the last item to annotate (so last item + 1)
+        // __annotation_type - __asan_unposion or __asan_poison
+        // __place - __asan_front_moved or __asan_back_moved
+        // Note: All indexes in __map_
+        if (__beg == __end)
+            return;
+        // __annotations_beg_map - first chunk which annotations we want to modify
+        // __annotations_end_map - last chunk which annotations we want to modify
+        // NOTE: if __end % __block_size == 0, __annotations_end_map points at the next block, which may not exist
+        __map_const_iterator __annotations_beg_map = __map_.begin() + __beg / __block_size;
+        __map_const_iterator __annotations_end_map = __map_.begin() + __end / __block_size;
+
+        bool const __poisoning = __annotation_type == __asan_poison;
+        // __old_c_beg_index - index of the first element in old container
+        // __old_c_end_index - index of the end of old container (last + 1)
+        // Note: may be outside the area we are annotating
+        size_t __old_c_beg_index = (__poisoning && __place == __asan_front_moved) ? __beg : __start_;
+        size_t __old_c_end_index = (__poisoning && __place == __asan_back_moved)  ? __end : __start_ + size();
+        bool const __front = __place == __asan_front_moved;
+
+        if (__poisoning && empty()) {
+            // Special case: we shouldn't trust __start_
+            __old_c_beg_index = __beg;
+            __old_c_end_index = __end;
+        }
+        // __old_c_beg_map - memory block (chunk) with first element
+        // __old_c_end_map - memory block (chunk) with end of old container
+        // Note: if __old_c_end_index % __block_size == 0, __old_c_end_map points at the next block,
+        // which may not exist
+        __map_const_iterator __old_c_beg_map = __map_.begin() + __old_c_beg_index / __block_size;
+        __map_const_iterator __old_c_end_map = __map_.begin() + __old_c_end_index / __block_size;
+
+        // One edge (front/end) of the container was moved and one was not modified.
+        // __new_edge_index - index of new edge
+        // __new_edge_map    - memory block (chunk) with new edge, it always equals to
+        //                    __annotations_beg_map or __annotations_end_map
+        // __old_edge_map    - memory block (chunk) with old edge, it always equals to
+        //                    __old_c_beg_map or __old_c_end_map
+        size_t __new_edge_index                      = (__poisoning ^ __front) ? __beg : __end;
+        __map_const_iterator __new_edge_map = __map_.begin() + __new_edge_index / __block_size;
+        __map_const_iterator __old_edge_map = __front ? __old_c_end_map : __old_c_beg_map;
+
+        // We iterate over map pointers (chunks) and fully poison all memory blocks between the first and the last.
+        // First and last chunk may be partially poisoned.
+        // __annotate_end_map may point at not existing chunk, therefore we have to have a check for it.
+        for (__map_const_iterator __map_it = __annotations_beg_map; __map_it <= __annotations_end_map; ++__map_it) {
+            if (__map_it == __annotations_end_map && __end % __block_size == 0)
+                // Chunk may not exist, but nothing to do here anyway
+                break;
+
+            // The beginning and the end of the current memory block
+            const void* __mem_beg = std::__to_address(*__map_it);
+            const void* __mem_end = std::__to_address(*__map_it + __block_size);
+
+            // The beginning of memory-in-use in the memory block before container modification
+            const void* __old_beg =
+                (__map_it == __old_c_beg_map) ? std::__to_address(*__map_it + (__old_c_beg_index % __block_size)) : __mem_beg;
+
+            // The end of memory-in-use in the memory block before container modification
+            const void* __old_end;
+            if (__map_it < __old_c_beg_map || __map_it > __old_c_end_map || (!__poisoning && empty()))
+                __old_end = __old_beg;
+            else
+                __old_end = (__map_it == __old_c_end_map) ? std::__to_address(*__map_it + (__old_c_end_index % __block_size))
+                                                   : __mem_end;
+
+            // New edge of the container in current memory block
+            // If the edge is in a 
diff erent chunk it points on corresponding end of the memory block
+            const void* __new_edge;
+            if (__map_it == __new_edge_map)
+                __new_edge = std::__to_address(*__map_it + (__new_edge_index % __block_size));
+            else
+                __new_edge = (__poisoning ^ __front) ? __mem_beg : __mem_end;
+
+            // Not modified edge of the container
+            // If the edge is in a 
diff erent chunk it points on corresponding end of the memory block
+            const void* __old_edge;
+            if (__map_it == __old_edge_map)
+                __old_edge = __front ? __old_end : __old_beg;
+            else
+                __old_edge = __front ? __mem_end : __mem_beg;
+
+            // __new_beg - the beginning of memory-in-use in the memory block after container modification
+            // __new_end - the end of memory-in-use in the memory block after container modification
+            const void* __new_beg = __front ? __new_edge : __old_edge;
+            const void* __new_end = __front ? __old_edge : __new_edge;
+
+            __annotate_double_ended_contiguous_container(__mem_beg, __mem_end, __old_beg, __old_end, __new_beg, __new_end);
+        }
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_new(size_type __current_size) const _NOEXCEPT {
+        if (__current_size == 0)
+            __annotate_from_to(0, __map_.size() * __block_size, __asan_poison, __asan_back_moved);
+        else {
+            __annotate_from_to(0, __start_, __asan_poison, __asan_front_moved);
+            __annotate_from_to(__start_ + __current_size, __map_.size() * __block_size, __asan_poison, __asan_back_moved);
+        }
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_delete() const _NOEXCEPT {
+        if (empty())
+            __annotate_from_to(0, __map_.size() * __block_size, __asan_unposion, __asan_back_moved);
+        else {
+            __annotate_from_to(0, __start_, __asan_unposion, __asan_front_moved);
+            __annotate_from_to(__start_ + size(), __map_.size() * __block_size, __asan_unposion, __asan_back_moved);
+        }
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_increase_front(size_type __n) const _NOEXCEPT {
+        __annotate_from_to(__start_ - __n, __start_, __asan_unposion, __asan_front_moved);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_increase_back(size_type __n) const _NOEXCEPT {
+        __annotate_from_to(__start_ + size(), __start_ + size() + __n, __asan_unposion, __asan_back_moved);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_shrink_front(size_type __old_size, size_type __old_start) const _NOEXCEPT {
+        __annotate_from_to(__old_start, __old_start + (__old_size - size()), __asan_poison, __asan_front_moved);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_shrink_back(size_type __old_size, size_type __old_start) const _NOEXCEPT {
+        __annotate_from_to(__old_start + size(), __old_start + __old_size, __asan_poison, __asan_back_moved);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_whole_block(size_t __block_index, __asan_annotation_type __annotation_type, __asan_annotation_place __place) {
+        __annotate_from_to(__block_index * __block_size, (__block_index + 1) * __block_size, __annotation_type, __place);
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    void __annotate_poison_block(void *__beginning, void *__end) {
+        __annotate_double_ended_contiguous_container(__beginning, __end, __beginning, __end, __end, __end);
+    }
+
+#if !defined(_LIBCPP_HAS_NO_ASAN)
+
+  public:
+    _LIBCPP_HIDE_FROM_ABI
+    bool __verify_asan_annotations() const _NOEXCEPT {
+        // This function tests deque object annotations.
+        if (empty()) {
+            for (__map_const_iterator __it = __map_.begin(); __it != __map_.end(); ++__it) {
+                if (!__sanitizer_verify_double_ended_contiguous_container(
+                        std::__to_address(*__it),
+                        std::__to_address(*__it),
+                        std::__to_address(*__it),
+                        std::__to_address(*__it + __block_size)))
+                  return false;
+            }
+
+            return true;
+        }
+
+        size_type __end                           = __start_ + size();
+        __map_const_iterator __first_mp = __map_.begin() + __start_ / __block_size;
+        __map_const_iterator __last_mp  = __map_.begin() + (__end - 1) / __block_size;
+
+        // Pointers to first and after last elements
+        // Those can be in 
diff erent deque blocks
+        void* __p_beg = std::__to_address(*__first_mp + (__start_ % __block_size));
+        void* __p_end =
+            std::__to_address(*__last_mp + ((__end % __block_size == 0) ? __block_size : __end % __block_size));
+
+        for (__map_const_iterator __it = __map_.begin(); __it != __map_.end(); ++__it) {
+            // Go over all blocks, find the place we are in and verify its annotations
+            // Note that __p_end points *behind* the last item.
+
+            // - blocks before the first block with container elements
+            // - first block with items
+            // - last block with items
+            // - blocks after last block with ciontainer elements
+
+            // Is the block before or after deque blocks that contain elements?
+            if (__it < __first_mp || __it > __last_mp) {
+                if (!__sanitizer_verify_double_ended_contiguous_container(
+                        std::__to_address(*__it),
+                        std::__to_address(*__it),
+                        std::__to_address(*__it),
+                        std::__to_address(*__it + __block_size)))
+                  return false;
+            } else {
+                void* __containers_buffer_beg = (__it == __first_mp) ? __p_beg : (void*)std::__to_address(*__it);
+                void* __containers_buffer_end =
+                    (__it == __last_mp) ? __p_end : (void*)std::__to_address(*__it + __block_size);
+                if (!__sanitizer_verify_double_ended_contiguous_container(
+                        std::__to_address(*__it),
+                        __containers_buffer_beg,
+                        __containers_buffer_end,
+                        std::__to_address(*__it + __block_size))) {
+                  return false;
+                }
+            }
+        }
+        return true;
+    }
+
+  private:
+#endif // _LIBCPP_VERIFY_ASAN_DEQUE_ANNOTATIONS
     _LIBCPP_HIDE_FROM_ABI
     bool __maybe_remove_front_spare(bool __keep_one = true) {
       if (__front_spare_blocks() >= 2 || (!__keep_one && __front_spare_blocks())) {
+        __annotate_whole_block(0, __asan_unposion, __asan_back_moved);
         __alloc_traits::deallocate(__alloc(), __map_.front(),
                                    __block_size);
         __map_.pop_front();
@@ -964,6 +1213,7 @@ public:
     _LIBCPP_HIDE_FROM_ABI
     bool __maybe_remove_back_spare(bool __keep_one = true) {
       if (__back_spare_blocks() >= 2 || (!__keep_one && __back_spare_blocks())) {
+        __annotate_whole_block(__map_.size() - 1, __asan_unposion, __asan_back_moved);
         __alloc_traits::deallocate(__alloc(), __map_.back(),
                                    __block_size);
         __map_.pop_back();
@@ -1087,6 +1337,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(size_type __n)
     : __start_(0), __size_(0, __default_init_tag())
 {
+    __annotate_new(0);
     if (__n > 0)
         __append(__n);
 }
@@ -1096,6 +1347,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(size_type __n, const _Allocator& __a)
     : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
 {
+    __annotate_new(0);
     if (__n > 0)
         __append(__n);
 }
@@ -1105,6 +1357,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v)
     : __start_(0), __size_(0, __default_init_tag())
 {
+    __annotate_new(0);
     if (__n > 0)
         __append(__n, __v);
 }
@@ -1115,6 +1368,7 @@ deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l,
               typename enable_if<__has_input_iterator_category<_InputIter>::value>::type*)
     : __start_(0), __size_(0, __default_init_tag())
 {
+    __annotate_new(0);
     __append(__f, __l);
 }
 
@@ -1124,6 +1378,7 @@ deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l, const allocator_ty
               typename enable_if<__has_input_iterator_category<_InputIter>::value>::type*)
     : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
 {
+    __annotate_new(0);
     __append(__f, __l);
 }
 
@@ -1133,6 +1388,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c)
       __start_(0),
       __size_(0, __map_.__alloc())
 {
+    __annotate_new(0);
     __append(__c.begin(), __c.end());
 }
 
@@ -1140,6 +1396,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(const deque& __c, const __type_identity_t<allocator_type>& __a)
     : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
 {
+    __annotate_new(0);
     __append(__c.begin(), __c.end());
 }
 
@@ -1161,6 +1418,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il)
     : __start_(0), __size_(0, __default_init_tag())
 {
+    __annotate_new(0);
     __append(__il.begin(), __il.end());
 }
 
@@ -1168,6 +1426,7 @@ template <class _Tp, class _Allocator>
 deque<_Tp, _Allocator>::deque(initializer_list<value_type> __il, const allocator_type& __a)
     : __map_(__pointer_allocator(__a)), __start_(0), __size_(0, __a)
 {
+    __annotate_new(0);
     __append(__il.begin(), __il.end());
 }
 
@@ -1355,6 +1614,7 @@ deque<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT
     allocator_type& __a = __alloc();
     if (empty())
     {
+        __annotate_delete();
         while (__map_.size() > 0)
         {
             __alloc_traits::deallocate(__a, __map_.back(), __block_size);
@@ -1454,6 +1714,7 @@ deque<_Tp, _Allocator>::push_back(const value_type& __v)
     if (__back_spare() == 0)
         __add_back_capacity();
     // __back_spare() >= 1
+    __annotate_increase_back(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*end()), __v);
     ++__size();
 }
@@ -1466,6 +1727,7 @@ deque<_Tp, _Allocator>::push_front(const value_type& __v)
     if (__front_spare() == 0)
         __add_front_capacity();
     // __front_spare() >= 1
+    __annotate_increase_front(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), __v);
     --__start_;
     ++__size();
@@ -1480,6 +1742,7 @@ deque<_Tp, _Allocator>::push_back(value_type&& __v)
     if (__back_spare() == 0)
         __add_back_capacity();
     // __back_spare() >= 1
+    __annotate_increase_back(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*end()), _VSTD::move(__v));
     ++__size();
 }
@@ -1497,6 +1760,7 @@ deque<_Tp, _Allocator>::emplace_back(_Args&&... __args)
     if (__back_spare() == 0)
         __add_back_capacity();
     // __back_spare() >= 1
+    __annotate_increase_back(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*end()),
                               _VSTD::forward<_Args>(__args)...);
     ++__size();
@@ -1513,6 +1777,7 @@ deque<_Tp, _Allocator>::push_front(value_type&& __v)
     if (__front_spare() == 0)
         __add_front_capacity();
     // __front_spare() >= 1
+    __annotate_increase_front(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), _VSTD::move(__v));
     --__start_;
     ++__size();
@@ -1532,6 +1797,7 @@ deque<_Tp, _Allocator>::emplace_front(_Args&&... __args)
     if (__front_spare() == 0)
         __add_front_capacity();
     // __front_spare() >= 1
+    __annotate_increase_front(1);
     __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), _VSTD::forward<_Args>(__args)...);
     --__start_;
     ++__size();
@@ -1552,6 +1818,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, value_type&& __v)
         if (__front_spare() == 0)
             __add_front_capacity();
         // __front_spare() >= 1
+        __annotate_increase_front(1);
         if (__pos == 0)
         {
             __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), _VSTD::move(__v));
@@ -1575,6 +1842,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, value_type&& __v)
         if (__back_spare() == 0)
             __add_back_capacity();
         // __back_capacity >= 1
+        __annotate_increase_back(1);
         size_type __de = size() - __pos;
         if (__de == 0)
         {
@@ -1608,6 +1876,7 @@ deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
         if (__front_spare() == 0)
             __add_front_capacity();
         // __front_spare() >= 1
+        __annotate_increase_front(1);
         if (__pos == 0)
         {
             __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), _VSTD::forward<_Args>(__args)...);
@@ -1632,6 +1901,7 @@ deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
         if (__back_spare() == 0)
             __add_back_capacity();
         // __back_capacity >= 1
+        __annotate_increase_back(1);
         size_type __de = size() - __pos;
         if (__de == 0)
         {
@@ -1668,6 +1938,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, const value_type& __v)
         if (__front_spare() == 0)
             __add_front_capacity();
         // __front_spare() >= 1
+        __annotate_increase_front(1);
         if (__pos == 0)
         {
             __alloc_traits::construct(__a, _VSTD::addressof(*--begin()), __v);
@@ -1694,6 +1965,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, const value_type& __v)
         if (__back_spare() == 0)
             __add_back_capacity();
         // __back_capacity >= 1
+        __annotate_increase_back(1);
         size_type __de = size() - __pos;
         if (__de == 0)
         {
@@ -1729,6 +2001,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, size_type __n, const value_ty
         if (__n > __front_spare())
             __add_front_capacity(__n - __front_spare());
         // __n <= __front_spare()
+        __annotate_increase_front(__n);
         iterator __old_begin = begin();
         iterator __i = __old_begin;
         if (__n > __pos)
@@ -1753,6 +2026,7 @@ deque<_Tp, _Allocator>::insert(const_iterator __p, size_type __n, const value_ty
         if (__n > __back_capacity)
             __add_back_capacity(__n - __back_capacity);
         // __n <= __back_capacity
+        __annotate_increase_back(__n);
         iterator __old_end = end();
         iterator __i = __old_end;
         size_type __de = size() - __pos;
@@ -1845,6 +2119,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
         if (__n > __front_spare())
             __add_front_capacity(__n - __front_spare());
         // __n <= __front_spare()
+        __annotate_increase_front(__n);
         iterator __old_begin = begin();
         iterator __i = __old_begin;
         _BiIter __m = __f;
@@ -1875,6 +2150,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
         if (__n > __back_capacity)
             __add_back_capacity(__n - __back_capacity);
         // __n <= __back_capacity
+        __annotate_increase_back(__n);
         iterator __old_end = end();
         iterator __i = __old_end;
         _BiIter __m = __l;
@@ -1939,6 +2215,7 @@ void deque<_Tp, _Allocator>::__append_with_size(_InputIterator __f, size_type __
         __add_back_capacity(__n - __back_capacity);
 
     // __n <= __back_capacity
+    __annotate_increase_back(__n);
     for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
       _ConstructTransaction __tx(this, __br);
       for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__f) {
@@ -1956,6 +2233,7 @@ deque<_Tp, _Allocator>::__append(size_type __n)
     if (__n > __back_capacity)
         __add_back_capacity(__n - __back_capacity);
     // __n <= __back_capacity
+    __annotate_increase_back(__n);
     for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
       _ConstructTransaction __tx(this, __br);
       for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
@@ -1973,6 +2251,7 @@ deque<_Tp, _Allocator>::__append(size_type __n, const value_type& __v)
     if (__n > __back_capacity)
         __add_back_capacity(__n - __back_capacity);
     // __n <= __back_capacity
+    __annotate_increase_back(__n);
     for (__deque_block_range __br : __deque_range(end(), end() + __n)) {
       _ConstructTransaction __tx(this, __br);
       for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) {
@@ -2040,6 +2319,7 @@ deque<_Tp, _Allocator>::__add_front_capacity()
                                __block_size / 2 :
                                __start_ + __block_size;
     }
+    __annotate_whole_block(0, __asan_poison, __asan_front_moved);
 }
 
 // Create front capacity for __n elements.
@@ -2075,6 +2355,7 @@ deque<_Tp, _Allocator>::__add_front_capacity(size_type __n)
             if (__map_.__front_spare() == 0)
                 break;
             __map_.push_front(__alloc_traits::allocate(__a, __block_size));
+            __annotate_whole_block(0, __asan_poison, __asan_front_moved);
         }
         for (; __nb > 0; --__nb, ++__back_capacity)
             __map_.push_back(__alloc_traits::allocate(__a, __block_size));
@@ -2085,6 +2366,7 @@ deque<_Tp, _Allocator>::__add_front_capacity(size_type __n)
             pointer __pt = __map_.back();
             __map_.pop_back();
             __map_.push_front(__pt);
+            __annotate_whole_block(0, __asan_poison, __asan_front_moved);
         }
     }
     // Else need to allocate __nb buffers, *and* we need to reallocate __map_.
@@ -2099,12 +2381,18 @@ deque<_Tp, _Allocator>::__add_front_capacity(size_type __n)
         try
         {
 #endif // _LIBCPP_HAS_NO_EXCEPTIONS
-            for (; __nb > 0; --__nb)
+            for (; __nb > 0; --__nb) {
                 __buf.push_back(__alloc_traits::allocate(__a, __block_size));
+                // ASan: this is empty container, we have to poison whole block
+                __annotate_poison_block(
+                    std::__to_address(__buf.back()),
+                    std::__to_address(__buf.back() + __block_size));
+            }
 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
         }
         catch (...)
         {
+            __annotate_delete();
             for (__map_pointer __i = __buf.begin();
                     __i != __buf.end(); ++__i)
                 __alloc_traits::deallocate(__a, *__i, __block_size);
@@ -2156,6 +2444,7 @@ deque<_Tp, _Allocator>::__add_back_capacity()
             __map_.pop_front();
             __map_.push_back(__pt);
         }
+        __annotate_whole_block(__map_.size() - 1, __asan_poison, __asan_back_moved);
     }
     // Else need to allocate 1 buffer, *and* we need to reallocate __map_.
     else
@@ -2179,6 +2468,7 @@ deque<_Tp, _Allocator>::__add_back_capacity()
         _VSTD::swap(__map_.__begin_, __buf.__begin_);
         _VSTD::swap(__map_.__end_, __buf.__end_);
         _VSTD::swap(__map_.__end_cap(), __buf.__end_cap());
+        __annotate_whole_block(__map_.size() - 1, __asan_poison, __asan_back_moved);
     }
 }
 
@@ -2215,10 +2505,13 @@ deque<_Tp, _Allocator>::__add_back_capacity(size_type __n)
             if (__map_.__back_spare() == 0)
                 break;
             __map_.push_back(__alloc_traits::allocate(__a, __block_size));
+            __annotate_whole_block(__map_.size() - 1, __asan_poison, __asan_back_moved);
         }
         for (; __nb > 0; --__nb, ++__front_capacity, __start_ +=
-                                 __block_size - (__map_.size() == 1))
+                                 __block_size - (__map_.size() == 1)) {
             __map_.push_front(__alloc_traits::allocate(__a, __block_size));
+            __annotate_whole_block(0, __asan_poison, __asan_back_moved);
+        }
         // Done allocating, reorder capacity
         __start_ -= __block_size * __front_capacity;
         for (; __front_capacity > 0; --__front_capacity)
@@ -2241,12 +2534,18 @@ deque<_Tp, _Allocator>::__add_back_capacity(size_type __n)
         try
         {
 #endif // _LIBCPP_HAS_NO_EXCEPTIONS
-            for (; __nb > 0; --__nb)
+            for (; __nb > 0; --__nb) {
                 __buf.push_back(__alloc_traits::allocate(__a, __block_size));
+                // ASan: this is an empty container, we have to poison the whole block
+                __annotate_poison_block(
+                    std::__to_address(__buf.back()),
+                    std::__to_address(__buf.back() + __block_size));
+            }
 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
         }
         catch (...)
         {
+            __annotate_delete();
             for (__map_pointer __i = __buf.begin();
                     __i != __buf.end(); ++__i)
                 __alloc_traits::deallocate(__a, *__i, __block_size);
@@ -2273,12 +2572,15 @@ template <class _Tp, class _Allocator>
 void
 deque<_Tp, _Allocator>::pop_front()
 {
+    size_type __old_sz    = size();
+    size_type __old_start = __start_;
     allocator_type& __a = __alloc();
     __alloc_traits::destroy(__a, _VSTD::__to_address(*(__map_.begin() +
                                                     __start_ / __block_size) +
                                                     __start_ % __block_size));
     --__size();
     ++__start_;
+    __annotate_shrink_front(__old_sz, __old_start);
     __maybe_remove_front_spare();
 }
 
@@ -2287,12 +2589,15 @@ void
 deque<_Tp, _Allocator>::pop_back()
 {
     _LIBCPP_ASSERT(!empty(), "deque::pop_back called on an empty deque");
+    size_type __old_sz    = size();
+    size_type __old_start = __start_;
     allocator_type& __a = __alloc();
     size_type __p = size() + __start_ - 1;
     __alloc_traits::destroy(__a, _VSTD::__to_address(*(__map_.begin() +
                                                     __p / __block_size) +
                                                     __p % __block_size));
     --__size();
+    __annotate_shrink_back(__old_sz, __old_start);
     __maybe_remove_back_spare();
 }
 
@@ -2432,6 +2737,8 @@ template <class _Tp, class _Allocator>
 typename deque<_Tp, _Allocator>::iterator
 deque<_Tp, _Allocator>::erase(const_iterator __f)
 {
+    size_type __old_sz    = size();
+    size_type __old_start = __start_;
     iterator __b = begin();
     
diff erence_type __pos = __f - __b;
     iterator __p = __b + __pos;
@@ -2442,6 +2749,7 @@ deque<_Tp, _Allocator>::erase(const_iterator __f)
         __alloc_traits::destroy(__a, _VSTD::addressof(*__b));
         --__size();
         ++__start_;
+        __annotate_shrink_front(__old_sz, __old_start);
         __maybe_remove_front_spare();
     }
     else
@@ -2449,6 +2757,7 @@ deque<_Tp, _Allocator>::erase(const_iterator __f)
         iterator __i = _VSTD::move(_VSTD::next(__p), end(), __p);
         __alloc_traits::destroy(__a, _VSTD::addressof(*__i));
         --__size();
+        __annotate_shrink_back(__old_sz, __old_start);
         __maybe_remove_back_spare();
     }
     return begin() + __pos;
@@ -2458,6 +2767,8 @@ template <class _Tp, class _Allocator>
 typename deque<_Tp, _Allocator>::iterator
 deque<_Tp, _Allocator>::erase(const_iterator __f, const_iterator __l)
 {
+    size_type __old_sz    = size();
+    size_type __old_start = __start_;
     
diff erence_type __n = __l - __f;
     iterator __b = begin();
     
diff erence_type __pos = __f - __b;
@@ -2472,6 +2783,7 @@ deque<_Tp, _Allocator>::erase(const_iterator __f, const_iterator __l)
                 __alloc_traits::destroy(__a, _VSTD::addressof(*__b));
             __size() -= __n;
             __start_ += __n;
+            __annotate_shrink_front(__old_sz, __old_start);
             while (__maybe_remove_front_spare()) {
             }
         }
@@ -2481,6 +2793,7 @@ deque<_Tp, _Allocator>::erase(const_iterator __f, const_iterator __l)
             for (iterator __e = end(); __i != __e; ++__i)
                 __alloc_traits::destroy(__a, _VSTD::addressof(*__i));
             __size() -= __n;
+            __annotate_shrink_back(__old_sz, __old_start);
             while (__maybe_remove_back_spare()) {
             }
         }
@@ -2492,6 +2805,8 @@ template <class _Tp, class _Allocator>
 void
 deque<_Tp, _Allocator>::__erase_to_end(const_iterator __f)
 {
+    size_type __old_sz    = size();
+    size_type __old_start = __start_;
     iterator __e = end();
     
diff erence_type __n = __e - __f;
     if (__n > 0)
@@ -2502,6 +2817,7 @@ deque<_Tp, _Allocator>::__erase_to_end(const_iterator __f)
         for (iterator __p = __b + __pos; __p != __e; ++__p)
             __alloc_traits::destroy(__a, _VSTD::addressof(*__p));
         __size() -= __n;
+        __annotate_shrink_back(__old_sz, __old_start);
         while (__maybe_remove_back_spare()) {
         }
     }
@@ -2529,6 +2845,7 @@ inline
 void
 deque<_Tp, _Allocator>::clear() _NOEXCEPT
 {
+    __annotate_delete();
     allocator_type& __a = __alloc();
     for (iterator __i = begin(), __e = end(); __i != __e; ++__i)
         __alloc_traits::destroy(__a, _VSTD::addressof(*__i));
@@ -2547,6 +2864,7 @@ deque<_Tp, _Allocator>::clear() _NOEXCEPT
         __start_ = __block_size;
         break;
     }
+    __annotate_new(0);
 }
 
 template <class _Tp, class _Allocator>

diff  --git a/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp b/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp
new file mode 100644
index 0000000000000..6067974f3a7e9
--- /dev/null
+++ b/libcxx/test/libcxx/containers/sequences/deque/asan.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: asan
+
+// <deque>
+
+// reference operator[](size_type n);
+
+#include "asan_testing.h"
+#include <deque>
+#include <cassert>
+#include <cstdlib>
+
+#include "min_allocator.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+extern "C" void __sanitizer_set_death_callback(void (*callback)(void));
+
+void do_exit() {
+  exit(0);
+}
+
+int main(int, char**)
+{
+    {
+        typedef cpp17_input_iterator<int*> MyInputIter;
+        // Sould not trigger ASan.
+        std::deque<int> v;
+        int i[] = {42};
+        v.insert(v.begin(), MyInputIter(i), MyInputIter(i + 1));
+        assert(v[0] == 42);
+        assert(is_double_ended_contiguous_container_asan_correct(v));
+    }
+    __sanitizer_set_death_callback(do_exit);
+    {
+        typedef int T;
+        typedef std::deque<T> C;
+        const T t[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+        C c(std::begin(t), std::end(t));
+        assert(is_double_ended_contiguous_container_asan_correct(c));
+        T* ptr = &c[0];
+        for(size_t i = 0; i < (8 + sizeof(T) - 1)/sizeof(T); ++i)
+          c.pop_front();
+        *ptr = 1;
+        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/deque/deque.capacity/access.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/access.pass.cpp
index 583dba28a2417..add0456cdbe4e 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/access.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/access.pass.cpp
@@ -21,6 +21,7 @@
 // const_reference back() const;
 // libc++ marks these as 'noexcept'
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -66,6 +67,7 @@ int main(int, char**)
             assert(c.at(i) == i);
         assert(c.front() == 0);
         assert(c.back() == 9);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
     {
         typedef std::deque<int> C;
@@ -82,6 +84,7 @@ int main(int, char**)
             assert(c.at(i) == i);
         assert(c.front() == 0);
         assert(c.back() == 9);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #if TEST_STD_VER >= 11
     {
@@ -99,6 +102,7 @@ int main(int, char**)
             assert(c.at(i) == i);
         assert(c.front() == 0);
         assert(c.back() == 9);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
     {
         typedef std::deque<int, min_allocator<int>> C;
@@ -115,6 +119,7 @@ int main(int, char**)
             assert(c.at(i) == i);
         assert(c.front() == 0);
         assert(c.back() == 9);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/empty.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/empty.pass.cpp
index 38859411067d4..57393061c4bac 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/empty.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/empty.pass.cpp
@@ -12,6 +12,7 @@
 
 // bool empty() const noexcept;
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -27,8 +28,10 @@ int main(int, char**)
     assert(c.empty());
     c.push_back(C::value_type(1));
     assert(!c.empty());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.clear();
     assert(c.empty());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #if TEST_STD_VER >= 11
     {
@@ -38,8 +41,10 @@ int main(int, char**)
     assert(c.empty());
     c.push_back(C::value_type(1));
     assert(!c.empty());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.clear();
     assert(c.empty());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/max_size.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/max_size.pass.cpp
index 7e2f72eb1e7e0..6f1d0f0491264 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/max_size.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/max_size.pass.cpp
@@ -10,6 +10,7 @@
 
 // size_type max_size() const;
 
+#include "asan_testing.h"
 #include <cassert>
 #include <deque>
 #include <limits>
@@ -25,6 +26,7 @@ int main(int, char**) {
     C c;
     assert(c.max_size() <= 10);
     LIBCPP_ASSERT(c.max_size() == 10);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
   }
   {
     typedef limited_allocator<int, (std::size_t)-1> A;
@@ -34,6 +36,7 @@ int main(int, char**) {
     C c;
     assert(c.max_size() <= max_dist);
     LIBCPP_ASSERT(c.max_size() == max_dist);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
   }
   {
     typedef std::deque<char> C;
@@ -42,6 +45,7 @@ int main(int, char**) {
     C c;
     assert(c.max_size() <= max_dist);
     assert(c.max_size() <= alloc_max_size(c.get_allocator()));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
   }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size.pass.cpp
index 641519b4ac5e7..a38dd60bd1861 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size.pass.cpp
@@ -10,6 +10,7 @@
 
 // void resize(size_type n);
 
+#include "asan_testing.h"
 #include <deque>
 #include <algorithm>
 #include <iterator>
@@ -34,10 +35,13 @@ make(int size, int start = 0 )
     C c(init, 0);
     for (int i = 0; i < init-start; ++i)
         c.pop_back();
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     for (int i = 0; i < size; ++i)
         c.push_back(i);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     for (int i = 0; i < start; ++i)
         c.pop_front();
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     return c;
 }
 
@@ -50,6 +54,7 @@ test(C& c1, int size)
     c1.resize(size);
     assert(c1.size() == static_cast<std::size_t>(size));
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     CI i = c1.begin();
     for (int j = 0; static_cast<std::size_t>(j) < std::min(c1_osize, c1.size()); ++j, ++i)
         assert(*i == j);
@@ -84,6 +89,14 @@ int main(int, char**)
             for (int k = 0; k < N; ++k)
                 testN<std::deque<int, min_allocator<int>>>(rng[i], rng[j], rng[k]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            for (int k = 0; k < N; ++k)
+                testN<std::deque<int, safe_allocator<int>>>(rng[i], rng[j], rng[k]);
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size_value.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size_value.pass.cpp
index 2ab740056940b..e640825ee76a7 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size_value.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/resize_size_value.pass.cpp
@@ -10,6 +10,7 @@
 
 // void resize(size_type n, const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <algorithm>
 #include <iterator>
@@ -34,10 +35,13 @@ make(int size, int start = 0 )
     C c(init, 0);
     for (int i = 0; i < init-start; ++i)
         c.pop_back();
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     for (int i = 0; i < size; ++i)
         c.push_back(i);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     for (int i = 0; i < start; ++i)
         c.pop_front();
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     return c;
 }
 
@@ -50,6 +54,7 @@ test(C& c1, int size, int x)
     c1.resize(size, x);
     assert(c1.size() == static_cast<std::size_t>(size));
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     CI i = c1.begin();
     for (int j = 0; static_cast<std::size_t>(j) < std::min(c1_osize, c1.size()); ++j, ++i)
         assert(*i == j);
@@ -84,6 +89,14 @@ int main(int, char**)
             for (int k = 0; k < N; ++k)
                 testN<std::deque<int, min_allocator<int>>>(rng[i], rng[j], rng[k]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            for (int k = 0; k < N; ++k)
+                testN<std::deque<int, safe_allocator<int>>>(rng[i], rng[j], rng[k]);
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/shrink_to_fit.pass.cpp
index bde2eaaaa38ee..88e8bd53c71d5 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/shrink_to_fit.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/shrink_to_fit.pass.cpp
@@ -10,6 +10,7 @@
 
 // void shrink_to_fit();
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -45,6 +46,7 @@ test(C& c1)
     C s = c1;
     c1.shrink_to_fit();
     assert(c1 == s);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
 }
 
 template <class C>
@@ -72,6 +74,13 @@ int main(int, char**)
         for (int j = 0; j < N; ++j)
             testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j]);
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.capacity/size.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.capacity/size.pass.cpp
index c70abe421cf28..21d5ca03a10a2 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.capacity/size.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.capacity/size.pass.cpp
@@ -12,6 +12,7 @@
 
 // size_type size() const noexcept;
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -25,18 +26,25 @@ int main(int, char**)
     C c;
     ASSERT_NOEXCEPT(c.size());
     assert(c.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(2));
     assert(c.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(1));
     assert(c.size() == 2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(3));
     assert(c.size() == 3);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #if TEST_STD_VER >= 11
     {
@@ -44,18 +52,25 @@ int main(int, char**)
     C c;
     ASSERT_NOEXCEPT(c.size());
     assert(c.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(2));
     assert(c.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(1));
     assert(c.size() == 2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.push_back(C::value_type(3));
     assert(c.size() == 3);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     c.erase(c.begin());
     assert(c.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/alloc.pass.cpp
index 8e4560e339f0b..8e3361e35999f 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/alloc.pass.cpp
@@ -10,6 +10,7 @@
 
 // explicit deque(const allocator_type& a);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -25,6 +26,7 @@ test(const Allocator& a)
     std::deque<T, Allocator> d(a);
     assert(d.size() == 0);
     assert(d.get_allocator() == a);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
 }
 
 int main(int, char**)
@@ -33,7 +35,9 @@ int main(int, char**)
     test<NotConstructible>(test_allocator<NotConstructible>(3));
 #if TEST_STD_VER >= 11
     test<int>(min_allocator<int>());
+    test<int>(safe_allocator<int>());
     test<NotConstructible>(min_allocator<NotConstructible>{});
+    test<NotConstructible>(safe_allocator<NotConstructible>{});
     test<int>(explicit_allocator<int>());
     test<NotConstructible>(explicit_allocator<NotConstructible>{});
 #endif

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_initializer_list.pass.cpp
index bf38932d4fb54..229034e8ca77f 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_initializer_list.pass.cpp
@@ -12,6 +12,7 @@
 
 // void assign(initializer_list<value_type> il);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -28,6 +29,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
     {
     std::deque<int, min_allocator<int>> d;
@@ -37,6 +39,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
index c8ebd683ee4a7..c8ccfd6db7e47 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_iter_iter.pass.cpp
@@ -11,6 +11,7 @@
 // template <class InputIterator>
 //   void assign(InputIterator f, InputIterator l);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -51,6 +52,8 @@ test(C& c1, const C& c2)
     c1.assign(c2.begin(), c2.end());
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 template <class C>
@@ -71,6 +74,8 @@ testI(C& c1, const C& c2)
     c1.assign(ICI(c2.begin()), ICI(c2.end()));
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 template <class C>
@@ -103,6 +108,15 @@ void basic_test()
                 testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j], rng[k]);
     testNI<std::deque<int, min_allocator<int>> >(1500, 2000, 1000);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            for (int k = 0; k < N; ++k)
+                testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j], rng[k]);
+    testNI<std::deque<int, safe_allocator<int>> >(1500, 2000, 1000);
+    }
 #endif
 }
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_size_value.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_size_value.pass.cpp
index d5cafec73e43b..a5272d010cdea 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/assign_size_value.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/assign_size_value.pass.cpp
@@ -10,6 +10,7 @@
 
 // void assign(size_type n, const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -48,6 +49,7 @@ test(C& c1, int size, int v)
     c1.assign(size, v);
     assert(c1.size() == static_cast<std::size_t>(size));
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     for (CI i = c1.begin(); i != c1.end(); ++i)
         assert(*i == v);
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/copy.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/copy.pass.cpp
index 2d42ee38a5089..44245916c0a31 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/copy.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/copy.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque(const deque&);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -23,6 +24,8 @@ test(const C& x)
 {
     C c(x);
     assert(c == x);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(x));
 }
 
 int main(int, char**)
@@ -37,6 +40,8 @@ int main(int, char**)
         std::deque<int, test_allocator<int> > v2 = v;
         assert(v2 == v);
         assert(v2.get_allocator() == v.get_allocator());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v2));
     }
 #if TEST_STD_VER >= 11
     {
@@ -44,6 +49,8 @@ int main(int, char**)
         std::deque<int, other_allocator<int> > v2 = v;
         assert(v2 == v);
         assert(v2.get_allocator() == other_allocator<int>(-2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v2));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -55,6 +62,8 @@ int main(int, char**)
         std::deque<int, min_allocator<int> > v2 = v;
         assert(v2 == v);
         assert(v2.get_allocator() == v.get_allocator());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v2));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/copy_alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_alloc.pass.cpp
index 4e75ff72873e4..3fdfcc3405f0e 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/copy_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/copy_alloc.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque(const deque& c, const allocator_type& a);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -24,6 +25,7 @@ test(const C& x, const typename C::allocator_type& a)
     C c(x, a);
     assert(c == x);
     assert(c.get_allocator() == a);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 }
 
 int main(int, char**)
@@ -47,6 +49,12 @@ int main(int, char**)
         test(std::deque<int, min_allocator<int> >(ab, an, min_allocator<int>()),
                                                           min_allocator<int>());
     }
+    {
+        int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
+        int* an = ab + sizeof(ab)/sizeof(ab[0]);
+        test(std::deque<int, safe_allocator<int> >(ab, an, safe_allocator<int>()),
+                                                          safe_allocator<int>());
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
index 79c35ae7a1744..096db12590d42 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/deduct.pass.cpp
@@ -17,6 +17,7 @@
 //   deque(from_range_t, R&&, Allocator = Allocator())
 //     -> deque<ranges::range_value_t<R>, Allocator>; // C++23
 
+#include "asan_testing.h"
 #include <array>
 #include <cassert>
 #include <climits> // INT_MAX
@@ -41,6 +42,7 @@ int main(int, char**)
 
     static_assert(std::is_same_v<decltype(deq), std::deque<int>>, "");
     assert(std::equal(deq.begin(), deq.end(), std::begin(arr), std::end(arr)));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -51,6 +53,7 @@ int main(int, char**)
     assert(deq[0] == INT_MAX);
     assert(deq[1] == 1L);
     assert(deq[2] == 2L);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
 //  Test the implicit deduction guides
@@ -65,6 +68,7 @@ int main(int, char**)
     static_assert(std::is_same_v<decltype(deq)::value_type, A>, "");
     static_assert(std::is_same_v<decltype(deq)::allocator_type, std::allocator<A>>, "");
     assert(deq.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -72,6 +76,7 @@ int main(int, char**)
     static_assert(std::is_same_v<decltype(deq)::value_type, A>, "");
     static_assert(std::is_same_v<decltype(deq)::allocator_type, test_allocator<A>>, "");
     assert(deq.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -79,6 +84,7 @@ int main(int, char**)
     static_assert(std::is_same_v<decltype(deq)::value_type, unsigned>, "");
     assert(deq.size() == 5);
     assert(deq[2] == 3U);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -87,6 +93,7 @@ int main(int, char**)
     static_assert(std::is_same_v<decltype(deq)::allocator_type, test_allocator<double>>, "");
     assert(deq.size() == 4);
     assert(deq[3] == 4.0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -95,6 +102,7 @@ int main(int, char**)
     static_assert(std::is_same_v<decltype(deq)::value_type, long double>, "");
     static_assert(std::is_same_v<decltype(deq)::allocator_type, std::allocator<long double>>, "");
     assert(deq.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
     }
 
     {
@@ -105,24 +113,32 @@ int main(int, char**)
         std::deque<short, Alloc> source;
         std::deque deq(source, Alloc(2));
         static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(source));
         }
 
         {
         std::deque<short, Alloc> source;
         std::deque deq(source, ConvertibleToAlloc(2));
         static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(source));
         }
 
         {
         std::deque<short, Alloc> source;
         std::deque deq(std::move(source), Alloc(2));
         static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(source));
         }
 
         {
         std::deque<short, Alloc> source;
         std::deque deq(std::move(source), ConvertibleToAlloc(2));
         static_assert(std::is_same_v<decltype(deq), decltype(source)>);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(deq));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(source));
         }
     }
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/default.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/default.pass.cpp
index b7c2ef1e9c13f..493274e932586 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/default.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/default.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque()
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -24,9 +25,11 @@ test()
 {
     std::deque<T, Allocator> d;
     assert(d.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
 #if TEST_STD_VER >= 11
     std::deque<T, Allocator> d1 = {};
     assert(d1.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d1));
 #endif
 }
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list.pass.cpp
index 3d6414063cd7d..bf7bc4bd90acc 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque(initializer_list<value_type> il);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -27,6 +28,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
     {
     std::deque<int, min_allocator<int>> d = {3, 4, 5, 6};
@@ -35,6 +37,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list_alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list_alloc.pass.cpp
index ebefe66b8ba23..99e6195151703 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/initializer_list_alloc.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque(initializer_list<value_type> il, const Allocator& a = allocator_type());
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -29,6 +30,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
     {
     std::deque<int, min_allocator<int>> d({3, 4, 5, 6}, min_allocator<int>());
@@ -38,6 +40,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
index 1d4c9c8d42139..c0df278f00140 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
@@ -10,6 +10,7 @@
 
 // template <class InputIterator> deque(InputIterator f, InputIterator l);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -33,6 +34,7 @@ test(InputIterator f, InputIterator l)
     C d(f, l);
     assert(d.size() == static_cast<std::size_t>(std::distance(f, l)));
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i, ++f)
         assert(*i == *f);
 }
@@ -47,6 +49,7 @@ test(InputIterator f, InputIterator l)
     C d(f, l);
     assert(d.size() == static_cast<std::size_t>(std::distance(f, l)));
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i, ++f)
         assert(*i == *f);
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
index a043f511628ad..40cf5cabc735c 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/iter_iter_alloc.pass.cpp
@@ -11,6 +11,7 @@
 // template <class InputIterator>
 //   deque(InputIterator f, InputIterator l, const allocator_type& a);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -34,6 +35,7 @@ test(InputIterator f, InputIterator l, const Allocator& a)
     assert(d.get_allocator() == a);
     assert(d.size() == static_cast<std::size_t>(std::distance(f, l)));
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i, ++f)
         assert(*i == *f);
 }
@@ -66,12 +68,14 @@ void test_emplacable_concept() {
     {
       std::deque<T> v(It(arr1), It(std::end(arr1)), a);
       assert(v[0].value == 42);
+      LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
     {
       std::deque<T> v(It(arr2), It(std::end(arr2)), a);
       assert(v[0].value == 1);
       assert(v[1].value == 101);
       assert(v[2].value == 42);
+      LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
   }
   {
@@ -82,6 +86,7 @@ void test_emplacable_concept() {
       std::deque<T> v(It(arr1), It(std::end(arr1)), a);
       assert(v[0].copied == 0);
       assert(v[0].value == 42);
+      LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
     {
       std::deque<T> v(It(arr2), It(std::end(arr2)), a);
@@ -91,6 +96,7 @@ void test_emplacable_concept() {
       assert(v[1].value == 101);
       assert(v[2].copied == 0);
       assert(v[2].value == 42);
+      LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
   }
 #endif

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/move.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/move.pass.cpp
index 84e278697e4e9..067b8eb1667bc 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/move.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque(deque&&);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -38,6 +39,9 @@ int main(int, char**)
         assert(c1.size() == 0);
         assert(c3.get_allocator() == old_a);
         assert(c1.get_allocator() == A(test_alloc_base::moved_value));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -53,6 +57,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() == 0);
         assert(c3.get_allocator() == c1.get_allocator());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -68,6 +75,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() == 0);
         assert(c3.get_allocator() == c1.get_allocator());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/move_alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/move_alloc.pass.cpp
index 734508a3e369e..25a838f55e441 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/move_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/move_alloc.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque(deque&& c, const allocator_type& a);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -36,6 +37,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c3.get_allocator() == A(3));
         LIBCPP_ASSERT(c1.size() != 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -51,6 +55,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c3.get_allocator() == A(1));
         LIBCPP_ASSERT(c1.size() == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -66,6 +73,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c3.get_allocator() == A(3));
         LIBCPP_ASSERT(c1.size() != 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -81,6 +91,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c3.get_allocator() == A());
         LIBCPP_ASSERT(c1.size() == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign.pass.cpp
index 9ae923c6ee001..7cf0b63e06b1e 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/move_assign.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque& operator=(deque&& c);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -37,6 +38,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() == 0);
         assert(c3.get_allocator() == A(5));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -53,6 +57,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() != 0);
         assert(c3.get_allocator() == A(6));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -69,6 +76,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() == 0);
         assert(c3.get_allocator() == A(5));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
     {
         int ab[] = {3, 4, 2, 8, 0, 1, 44, 34, 45, 96, 80, 1, 13, 31, 45};
@@ -85,6 +95,9 @@ int main(int, char**)
         assert(c2 == c3);
         assert(c1.size() == 0);
         assert(c3.get_allocator() == A());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c3));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal.pass.cpp
index 985d4bf31b65f..538d3fc4aa445 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque& operator=(const deque& c);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include "test_macros.h"
@@ -23,6 +24,8 @@ test(const C& x)
     C c;
     c = x;
     assert(c == x);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(x));
 }
 
 int main(int, char**)
@@ -38,6 +41,8 @@ int main(int, char**)
         l2 = l;
         assert(l2 == l);
         assert(l2.get_allocator() == test_allocator<int>(3));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l2));
     }
     {
         std::deque<int, other_allocator<int> > l(3, 2, other_allocator<int>(5));
@@ -45,6 +50,8 @@ int main(int, char**)
         l2 = l;
         assert(l2 == l);
         assert(l2.get_allocator() == other_allocator<int>(5));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l2));
     }
 #if TEST_STD_VER >= 11
     {
@@ -58,6 +65,8 @@ int main(int, char**)
         l2 = l;
         assert(l2 == l);
         assert(l2.get_allocator() == min_allocator<int>());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(l2));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal_initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal_initializer_list.pass.cpp
index 433b68cc33355..2331d3017dcd8 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/op_equal_initializer_list.pass.cpp
@@ -12,6 +12,7 @@
 
 // deque& operator=(initializer_list<value_type> il);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -28,6 +29,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
     {
     std::deque<int, min_allocator<int>> d;
@@ -37,6 +39,7 @@ int main(int, char**)
     assert(d[1] == 4);
     assert(d[2] == 5);
     assert(d[3] == 6);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/size.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/size.pass.cpp
index 87b2f3f61505a..de1a9843a478e 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/size.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/size.pass.cpp
@@ -10,6 +10,7 @@
 
 // explicit deque(size_type n);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -32,6 +33,7 @@ test2(unsigned n)
     assert(static_cast<unsigned>(DefaultOnly::count) == n);
     assert(d.size() == n);
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i)
         assert(*i == T());
     }
@@ -53,6 +55,7 @@ test1(unsigned n)
     assert(static_cast<unsigned>(DefaultOnly::count) == n);
     assert(d.size() == n);
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
 #if TEST_STD_VER >= 11
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i)
         assert(*i == T());
@@ -71,6 +74,7 @@ test3(unsigned n, Allocator const &alloc = Allocator())
     C d(n, alloc);
     assert(d.size() == n);
     assert(d.get_allocator() == alloc);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 #else
     ((void)n);

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp
index 8216ed4c1a50b..767c544e95561 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque(size_type n, const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -27,6 +28,7 @@ test(unsigned n, const T& x)
     C d(n, x);
     assert(d.size() == n);
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i)
         assert(*i == x);
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.cons/size_value_alloc.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.cons/size_value_alloc.pass.cpp
index d16fa6689c2fb..746d5a221663f 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.cons/size_value_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.cons/size_value_alloc.pass.cpp
@@ -10,6 +10,7 @@
 
 // deque(size_type n, const value_type& v, const allocator_type& a);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -27,6 +28,7 @@ test(unsigned n, const T& x, const Allocator& a)
     assert(d.get_allocator() == a);
     assert(d.size() == n);
     assert(static_cast<std::size_t>(std::distance(d.begin(), d.end())) == d.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     for (const_iterator i = d.begin(), e = d.end(); i != e; ++i)
         assert(*i == x);
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
index 656884a345fa1..8491165dd4c81 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
@@ -13,6 +13,7 @@
 //   typename deque<T, Allocator>::size_type
 //   erase(deque<T, Allocator>& c, const U& value);
 
+#include "asan_testing.h"
 #include <deque>
 #include <optional>
 
@@ -25,6 +26,7 @@ void test0(S s, U val, S expected, std::size_t expected_erased_count) {
   ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
   assert(expected_erased_count == std::erase(s, val));
   assert(s == expected);
+  LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(s));
 }
 
 template <class S>
@@ -67,6 +69,7 @@ int main(int, char**)
 {
     test<std::deque<int>>();
     test<std::deque<int, min_allocator<int>>> ();
+    test<std::deque<int, safe_allocator<int>>> ();
     test<std::deque<int, test_allocator<int>>> ();
 
     test<std::deque<long>>();

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
index 57657e4b48c86..40e6323ad0a28 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
@@ -13,6 +13,7 @@
 //   typename deque<T, Allocator>::size_type
 //   erase_if(deque<T, Allocator>& c, Predicate pred);
 
+#include "asan_testing.h"
 #include <deque>
 
 #include "test_macros.h"
@@ -24,6 +25,7 @@ void test0(S s, Pred p, S expected, std::size_t expected_erased_count) {
   ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
   assert(expected_erased_count == std::erase_if(s, p));
   assert(s == expected);
+  LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(s));
 }
 
 template <typename S>
@@ -69,6 +71,7 @@ int main(int, char**)
 {
     test<std::deque<int>>();
     test<std::deque<int, min_allocator<int>>> ();
+    test<std::deque<int, safe_allocator<int>>> ();
     test<std::deque<int, test_allocator<int>>> ();
 
     test<std::deque<long>>();

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/clear.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/clear.pass.cpp
index b943aeecbbe4d..1e0b04dd24f25 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/clear.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/clear.pass.cpp
@@ -10,6 +10,7 @@
 
 // void clear() noexcept;
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -26,6 +27,7 @@ int main(int, char**)
         ASSERT_NOEXCEPT(c.clear());
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
     {
         typedef int T;
@@ -36,9 +38,11 @@ int main(int, char**)
         ASSERT_NOEXCEPT(c.clear());
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #if TEST_STD_VER >= 11
     {
@@ -48,6 +52,7 @@ int main(int, char**)
         ASSERT_NOEXCEPT(c.clear());
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
     {
         typedef int T;
@@ -58,9 +63,11 @@ int main(int, char**)
         ASSERT_NOEXCEPT(c.clear());
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 
         c.clear();
         assert(std::distance(c.begin(), c.end()) == 0);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace.pass.cpp
index f550f4c754e63..b992610506538 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace.pass.cpp
@@ -12,6 +12,7 @@
 
 // UNSUPPORTED: c++03
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -54,6 +55,7 @@ test(int P, C& c1)
     assert(c1.size() == c1_osize + 1);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
     assert(*i == Emplaceable(1, 2.5));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
 }
 
 template <class C>
@@ -103,6 +105,13 @@ int main(int, char**)
         for (int j = 0; j < N; ++j)
             testN<std::deque<Emplaceable, min_allocator<Emplaceable>> >(rng[i], rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<Emplaceable, safe_allocator<Emplaceable>> >(rng[i], rng[j]);
+    }
 
   return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
index 4cc56fff9b1fb..1ea3423bd43c6 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
@@ -13,6 +13,7 @@
 // template <class... Args> reference emplace_back(Args&&... args);
 // return type is 'reference' in C++17; 'void' before
 
+#include "asan_testing.h"
 #include <deque>
 #include <cstddef>
 #include <cassert>
@@ -61,6 +62,7 @@ test(C& c1)
                == static_cast<std::ptr
diff _t>(c1.size()));
     I i = c1.end();
     assert(*--i == Emplaceable(1, 2.5));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
 #if TEST_STD_VER > 14
     assert(&(*i) == &ref);
 #endif
@@ -94,12 +96,16 @@ int main(int, char**)
         std::deque<Tag_X, TaggingAllocator<Tag_X>> c;
         c.emplace_back();
         assert(c.size() == 1);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_back(1, 2, 3);
         assert(c.size() == 2);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_front();
         assert(c.size() == 3);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_front(1, 2, 3);
         assert(c.size() == 4);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_front.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_front.pass.cpp
index a63e3cb1cb80e..26926e411c96a 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_front.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_front.pass.cpp
@@ -13,6 +13,7 @@
 // template <class... Args> reference emplace_front(Args&&... args);
 // return type is 'reference' in C++17; 'void' before
 
+#include "asan_testing.h"
 #include <deque>
 #include <cstddef>
 #include <cassert>
@@ -61,6 +62,7 @@ test(C& c1)
                == static_cast<std::ptr
diff _t>(c1.size()));
     I i = c1.begin();
     assert(*i == Emplaceable(1, 2.5));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
 #if TEST_STD_VER > 14
     assert(&res_ref == &(*i));
 #endif
@@ -95,12 +97,16 @@ int main(int, char**)
         std::deque<Tag_X, TaggingAllocator<Tag_X>> c;
         c.emplace_front();
         assert(c.size() == 1);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_front(1, 2, 3);
         assert(c.size() == 2);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_front();
         assert(c.size() == 3);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         c.emplace_front(1, 2, 3);
         assert(c.size() == 4);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.invalidation.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.invalidation.pass.cpp
index de80e5b6f3ed0..22f67b2f92873 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.invalidation.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.invalidation.pass.cpp
@@ -13,6 +13,7 @@
 //  Erasing items from the beginning or the end of a deque shall not invalidate iterators
 //  to items that were not erased.
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -54,6 +55,7 @@ void del_at_end(C c)
     assert(  it2 ==   it4);
     assert( *it2 ==  *it4);
     assert(&*it2 == &*it4);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.pass.cpp
index 3aaa3e34d1871..6b19d5b8bc69b 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter.pass.cpp
@@ -10,6 +10,7 @@
 
 // iterator erase(const_iterator p)
 
+#include "asan_testing.h"
 #include <deque>
 #include <algorithm>
 #include <iterator>
@@ -119,6 +120,7 @@ int main(int, char**)
     v.erase(--v.end());
     v.erase(v.begin());
     assert(v.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.invalidation.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.invalidation.pass.cpp
index 0ac48aaa33d7b..2920b7d83a1a6 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.invalidation.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.invalidation.pass.cpp
@@ -14,6 +14,7 @@
 //  to items that were not erased.
 
 
+#include "asan_testing.h"
 #include <deque>
 #include <cstdint>
 #include <cassert>
@@ -38,6 +39,7 @@ void del_at_start(C c, std::size_t num)
     assert(  it2 ==   it4);
     assert( *it2 ==  *it4);
     assert(&*it2 == &*it4);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 }
 
 template <typename C>
@@ -58,6 +60,7 @@ void del_at_end(C c, std::size_t num)
     assert(  it2 ==   it4);
     assert( *it2 ==  *it4);
     assert(&*it2 == &*it4);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 }
 
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.pass.cpp
index 70cf1193d8021..51e774cb59194 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/erase_iter_iter.pass.cpp
@@ -12,6 +12,7 @@
 
 // iterator erase(const_iterator f, const_iterator l)
 
+#include "asan_testing.h"
 #include <deque>
 #include <algorithm>
 #include <iterator>
@@ -71,6 +72,7 @@ test(int P, C& c1, int size)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize - size);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     i = c1.begin();
     int j = 0;
     for (; j < P; ++j, ++i)
@@ -123,8 +125,10 @@ int main(int, char**)
     Throws::sThrows = true;
     v.erase(v.begin(), --v.end());
     assert(v.size() == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     v.erase(v.begin(), v.end());
     assert(v.size() == 0);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(v));
     }
 #endif
 

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_initializer_list.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_initializer_list.pass.cpp
index 42bcaab48de2e..080a60cec1a3c 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_initializer_list.pass.cpp
@@ -12,6 +12,7 @@
 
 // iterator insert(const_iterator p, initializer_list<value_type> il);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -39,6 +40,7 @@ int main(int, char**)
     assert(d[11] == 1);
     assert(d[12] == 1);
     assert(d[13] == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
     {
     std::deque<int, min_allocator<int>> d(10, 1);
@@ -59,6 +61,7 @@ int main(int, char**)
     assert(d[11] == 1);
     assert(d[12] == 1);
     assert(d[13] == 1);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(d));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp
index aff4703ab4525..4d41c287cca2e 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp
@@ -13,6 +13,7 @@
 // template <class InputIterator>
 //   iterator insert (const_iterator p, InputIterator f, InputIterator l);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -58,6 +59,8 @@ test(int P, const C& c0, const C& c2)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize + c2.size());
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     i = c1.begin();
     for (int j = 0; j < P; ++j, ++i)
         assert(*i == j);
@@ -173,6 +176,8 @@ testI(int P, C& c1, const C& c2)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize + c2.size());
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     i = c1.begin();
     for (int j = 0; j < P; ++j, ++i)
         assert(*i == j);
@@ -284,6 +289,16 @@ int main(int, char**)
     testNI<std::deque<int> >(1500, 2000, 1000);
     test_move<std::deque<MoveOnly, min_allocator<MoveOnly> > >();
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            for (int k = 0; k < N; ++k)
+                testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j], rng[k]);
+    testNI<std::deque<int> >(1500, 2000, 1000);
+    test_move<std::deque<MoveOnly, safe_allocator<MoveOnly> > >();
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_rvalue.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_rvalue.pass.cpp
index 22ebf5c6fcd0d..24092029a7453 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_rvalue.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_rvalue.pass.cpp
@@ -12,6 +12,7 @@
 
 // UNSUPPORTED: c++03
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -53,6 +54,7 @@ test(int P, C& c1, int x)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize + 1);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     i = c1.begin();
     for (int j = 0; j < P; ++j, (void) ++i)
         assert(*i == MoveOnly(j));
@@ -108,6 +110,13 @@ int main(int, char**)
         for (int j = 0; j < N; ++j)
             testN<std::deque<MoveOnly, min_allocator<MoveOnly>> >(rng[i], rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<MoveOnly, safe_allocator<MoveOnly>> >(rng[i], rng[j]);
+    }
 
   return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_size_value.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_size_value.pass.cpp
index 1a51154952587..555cb902d91da 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_size_value.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_size_value.pass.cpp
@@ -12,6 +12,7 @@
 
 // iterator insert (const_iterator p, size_type n, const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -51,6 +52,7 @@ test(int P, C& c1, int size, int x)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize + size);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     i = c1.begin();
     for (int j = 0; j < P; ++j, ++i)
         assert(*i == j);
@@ -153,6 +155,15 @@ int main(int, char**)
                 testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j], rng[k]);
     self_reference_test<std::deque<int, min_allocator<int>> >();
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            for (int k = 0; k < N; ++k)
+                testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j], rng[k]);
+    self_reference_test<std::deque<int, safe_allocator<int>> >();
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_value.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_value.pass.cpp
index e4a72090820fb..250e19418e45b 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_value.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_value.pass.cpp
@@ -10,6 +10,7 @@
 
 // iterator insert (const_iterator p, const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -49,6 +50,7 @@ test(int P, C& c1, int x)
     assert(i == c1.begin() + P);
     assert(c1.size() == c1_osize + 1);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     i = c1.begin();
     for (int j = 0; j < P; ++j, ++i)
         assert(*i == j);
@@ -133,6 +135,14 @@ int main(int, char**)
             testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j]);
     self_reference_test<std::deque<int, min_allocator<int>> >();
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j]);
+    self_reference_test<std::deque<int, safe_allocator<int>> >();
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.invalidation.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.invalidation.pass.cpp
index 9e3bfdf53d3d4..3071d00a9dbff 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.invalidation.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.invalidation.pass.cpp
@@ -13,6 +13,7 @@
 //  Erasing items from the beginning or the end of a deque shall not invalidate iterators
 //  to items that were not erased.
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -34,18 +35,20 @@ void test(C c)
     assert(  it2 ==   it4);
     assert( *it2 ==  *it4);
     assert(&*it2 == &*it4);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
 }
 
 int main(int, char**)
 {
     std::deque<int> queue;
-    for (int i = 0; i < 20; ++i)
+    for (int i = 0; i < 4098; ++i)
         queue.push_back(i);
 
     while (queue.size() > 1)
     {
         test(queue);
         queue.pop_back();
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(queue));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.pass.cpp
index 0174b09f1d605..b027f40d8dd46 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_back.pass.cpp
@@ -10,6 +10,7 @@
 
 // void pop_back()
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -48,6 +49,7 @@ test(C& c1)
     c1.pop_back();
     assert(c1.size() == c1_osize - 1);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     I i = c1.begin();
     for (int j = 0; static_cast<std::size_t>(j) < c1.size(); ++j, ++i)
         assert(*i == j);
@@ -81,6 +83,13 @@ int main(int, char**)
         for (int j = 0; j < N; ++j)
             testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j]);
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.invalidation.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.invalidation.pass.cpp
index d7d32f3ae7465..4e77cdca430d2 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.invalidation.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.invalidation.pass.cpp
@@ -13,6 +13,7 @@
 //  Erasing items from the beginning or the end of a deque shall not invalidate iterators
 //  to items that were not erased.
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -39,13 +40,14 @@ void test(C c)
 int main(int, char**)
 {
     std::deque<int> queue;
-    for (int i = 0; i < 20; ++i)
+    for (int i = 0; i < 4098; ++i)
         queue.push_back(i);
 
     while (queue.size() > 1)
     {
         test(queue);
         queue.pop_back();
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(queue));
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.pass.cpp
index 64e705d4466fb..e28242c8a4890 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/pop_front.pass.cpp
@@ -10,6 +10,7 @@
 
 // void pop_front()
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -48,6 +49,7 @@ test(C& c1)
     c1.pop_front();
     assert(c1.size() == c1_osize - 1);
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     I i = c1.begin();
     for (int j = 1; static_cast<std::size_t>(j) < c1.size(); ++j, ++i)
         assert(*i == j);

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back.pass.cpp
index b813de85cf251..70aa1baa1efcb 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back.pass.cpp
@@ -12,6 +12,7 @@
 // void pop_back();
 // void pop_front();
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -49,6 +50,7 @@ void test(int size)
     {
         C c = make<C>(size, rng[j]);
         typename C::const_iterator it = c.begin();
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         for (int i = 0; i < size; ++i, ++it)
             assert(*it == i);
     }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_rvalue.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_rvalue.pass.cpp
index 74ed7af545ec9..817379b62ae07 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_rvalue.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_rvalue.pass.cpp
@@ -14,6 +14,7 @@
 // void pop_back();
 // void pop_front();
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -53,6 +54,7 @@ void test(int size)
     {
         C c = make<C>(size, rng[j]);
         typename C::const_iterator it = c.begin();
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c));
         for (int i = 0; i < size; ++i, (void) ++it)
             assert(*it == MoveOnly(i));
     }
@@ -73,6 +75,12 @@ int main(int, char**)
     for (int j = 0; j < N; ++j)
         test<std::deque<MoveOnly, min_allocator<MoveOnly>> >(rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2046, 2047, 2048, 2049, 4094, 4095, 4096};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int j = 0; j < N; ++j)
+        test<std::deque<MoveOnly, safe_allocator<MoveOnly>> >(rng[j]);
+    }
 
   return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front.pass.cpp
index 1d8a208e00bef..2d1246b1507e7 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front.pass.cpp
@@ -10,6 +10,7 @@
 
 // void push_front(const value_type& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -50,6 +51,7 @@ test(C& c1, int x)
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
     I i = c1.begin();
     assert(*i == x);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     ++i;
     for (int j = 0; static_cast<std::size_t>(j) < c1_osize; ++j, ++i)
         assert(*i == j);
@@ -80,6 +82,13 @@ int main(int, char**)
         for (int j = 0; j < N; ++j)
             testN<std::deque<int, min_allocator<int>> >(rng[i], rng[j]);
     }
+    {
+    int rng[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049};
+    const int N = sizeof(rng)/sizeof(rng[0]);
+    for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+            testN<std::deque<int, safe_allocator<int>> >(rng[i], rng[j]);
+    }
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_rvalue.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_rvalue.pass.cpp
index cbfb06b8e1e6b..2755433e58cbf 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_rvalue.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_rvalue.pass.cpp
@@ -12,6 +12,7 @@
 
 // void push_front(value_type&& v);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include <cstddef>
@@ -54,6 +55,7 @@ test(C& c1, int x)
     assert(static_cast<std::size_t>(std::distance(c1.begin(), c1.end())) == c1.size());
     I i = c1.begin();
     assert(*i == MoveOnly(x));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
     ++i;
     for (int j = 0; static_cast<std::size_t>(j) < c1_osize; ++j, (void) ++i)
         assert(*i == MoveOnly(j));
@@ -82,7 +84,7 @@ int main(int, char**)
     const int N = sizeof(rng)/sizeof(rng[0]);
     for (int i = 0; i < N; ++i)
         for (int j = 0; j < N; ++j)
-            testN<std::deque<MoveOnly, min_allocator<MoveOnly>> >(rng[i], rng[j]);
+            testN<std::deque<MoveOnly, safe_allocator<MoveOnly>> >(rng[i], rng[j]);
     }
 
   return 0;

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.special/copy.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.special/copy.pass.cpp
index b2a03540cf2f7..e472a1cb59d47 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.special/copy.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.special/copy.pass.cpp
@@ -14,6 +14,7 @@
 //   OutputIterator
 //   copy(InputIterator first, InputIterator last, OutputIterator result);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -55,16 +56,28 @@ void testN(int start, int N)
     C c2 = make<C>(N);
     assert(std::copy(c1.cbegin(), c1.cend(), c2.begin()) == c2.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy(c2.cbegin(), c2.cend(), c1.begin()) == c1.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy(c1.cbegin(), c1.cend(), RAI(c2.begin())) == RAI(c2.end()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy(c2.cbegin(), c2.cend(), RAI(c1.begin())) == RAI(c1.end()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy(RACI(c1.cbegin()), RACI(c1.cend()), c2.begin()) == c2.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy(ICI(c2.cbegin()), ICI(c2.cend()), c1.begin()) == c1.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.special/copy_backward.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.special/copy_backward.pass.cpp
index b6417f79463f0..bba4d173745cb 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.special/copy_backward.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.special/copy_backward.pass.cpp
@@ -14,6 +14,7 @@
 //   OutputIterator
 //   copy_backward(InputIterator first, InputIterator last, OutputIterator result);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -54,16 +55,28 @@ void testN(int start, int N)
     C c2 = make<C>(N);
     assert(std::copy_backward(c1.cbegin(), c1.cend(), c2.end()) == c2.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy_backward(c2.cbegin(), c2.cend(), c1.end()) == c1.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy_backward(c1.cbegin(), c1.cend(), RAI(c2.end())) == RAI(c2.begin()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy_backward(c2.cbegin(), c2.cend(), RAI(c1.end())) == RAI(c1.begin()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy_backward(RACI(c1.cbegin()), RACI(c1.cend()), c2.end()) == c2.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::copy_backward(RACI(c2.cbegin()), RACI(c2.cend()), c1.end()) == c1.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.special/move.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.special/move.pass.cpp
index ae0a75167bf30..497fac1063b6f 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.special/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.special/move.pass.cpp
@@ -14,6 +14,7 @@
 //   OutputIterator
 //   move(InputIterator first, InputIterator last, OutputIterator result);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -54,16 +55,28 @@ void testN(int start, int N)
     C c2 = make<C>(N);
     assert(std::move(c1.cbegin(), c1.cend(), c2.begin()) == c2.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move(c2.cbegin(), c2.cend(), c1.begin()) == c1.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move(c1.cbegin(), c1.cend(), RAI(c2.begin())) == RAI(c2.end()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move(c2.cbegin(), c2.cend(), RAI(c1.begin())) == RAI(c1.end()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move(RACI(c1.cbegin()), RACI(c1.cend()), c2.begin()) == c2.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move(RACI(c2.cbegin()), RACI(c2.cend()), c1.begin()) == c1.end());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.special/move_backward.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.special/move_backward.pass.cpp
index 50da5b790c824..5a261304ff684 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.special/move_backward.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.special/move_backward.pass.cpp
@@ -14,6 +14,7 @@
 //   OutputIterator
 //   move_backward(InputIterator first, InputIterator last, OutputIterator result);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 
@@ -54,16 +55,28 @@ void testN(int start, int N)
     C c2 = make<C>(N);
     assert(std::move_backward(c1.cbegin(), c1.cend(), c2.end()) == c2.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move_backward(c2.cbegin(), c2.cend(), c1.end()) == c1.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move_backward(c1.cbegin(), c1.cend(), RAI(c2.end())) == RAI(c2.begin()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move_backward(c2.cbegin(), c2.cend(), RAI(c1.end())) == RAI(c1.begin()));
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move_backward(RACI(c1.cbegin()), RACI(c1.cend()), c2.end()) == c2.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     assert(std::move_backward(RACI(c2.cbegin()), RACI(c2.cend()), c1.end()) == c1.begin());
     assert(c1 == c2);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.special/swap.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.special/swap.pass.cpp
index 61fa31c5e05c8..e5816326ffac6 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.special/swap.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.special/swap.pass.cpp
@@ -11,6 +11,7 @@
 // template <class T, class A>
 //   void swap(deque<T, A>& x, deque<T, A>& y);
 
+#include "asan_testing.h"
 #include <deque>
 #include <cassert>
 #include "test_macros.h"
@@ -49,6 +50,10 @@ void testN(int start, int N, int M)
     swap(c1, c2);
     assert(c1 == c2_save);
     assert(c2 == c1_save);
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1_save));
+    LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2_save));
 }
 
 int main(int, char**)
@@ -72,6 +77,8 @@ int main(int, char**)
         assert(c1.get_allocator().get_id() == 1);
         assert((c2 == std::deque<int, A>(a1, a1+sizeof(a1)/sizeof(a1[0]))));
         assert(c2.get_allocator().get_id() == 2);
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     }
     {
         int a1[] = {1, 3, 7, 9, 10};
@@ -84,6 +91,8 @@ int main(int, char**)
         assert(c1.get_allocator() == A(2));
         assert((c2 == std::deque<int, A>(a1, a1+sizeof(a1)/sizeof(a1[0]))));
         assert(c2.get_allocator() == A(1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     }
 #if TEST_STD_VER >= 11
     {
@@ -105,6 +114,8 @@ int main(int, char**)
         assert(c1.get_allocator() == A());
         assert((c2 == std::deque<int, A>(a1, a1+sizeof(a1)/sizeof(a1[0]))));
         assert(c2.get_allocator() == A());
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c1));
+        LIBCPP_ASSERT(is_double_ended_contiguous_container_asan_correct(c2));
     }
 #endif
 

diff  --git a/libcxx/test/support/asan_testing.h b/libcxx/test/support/asan_testing.h
index aae93019fe1c6..d8e97af421139 100644
--- a/libcxx/test/support/asan_testing.h
+++ b/libcxx/test/support/asan_testing.h
@@ -10,6 +10,7 @@
 #define ASAN_TESTING_H
 
 #include "test_macros.h"
+#include <vector>
 
 #if TEST_HAS_FEATURE(address_sanitizer)
 extern "C" int __sanitizer_verify_contiguous_container
@@ -25,14 +26,34 @@ TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector<T,
             c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0;
     return true;
 }
-
 #else
 template <typename T, typename Alloc>
 TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &)
 {
     return true;
 }
-#endif
+#endif // TEST_HAS_FEATURE(address_sanitizer)
 
+#if TEST_HAS_FEATURE(address_sanitizer) && _LIBCPP_CLANG_VER >= 1600
+extern "C" int __sanitizer_verify_double_ended_contiguous_container(
+    const void* beg, const void* con_beg, const void* con_end, const void* end);
+extern "C" bool __sanitizer_is_annotable(const void* address, const unsigned long size);
+#include <deque>
+
+template <class T, class Alloc>
+TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std::deque<T, Alloc>& c) {
+  if (TEST_IS_CONSTANT_EVALUATED)
+    return true;
+  if (std::is_same<Alloc, std::allocator<T> >::value)
+    return c.__verify_asan_annotations();
+  return true;
+}
+#else
+#  include <deque>
+template <class T, class Alloc>
+TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std::deque<T, Alloc>&) {
+  return true;
+}
+#endif
 
 #endif // ASAN_TESTING_H


        


More information about the libcxx-commits mailing list