diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h
--- a/compiler-rt/include/sanitizer/common_interface_defs.h
+++ b/compiler-rt/include/sanitizer/common_interface_defs.h
@@ -159,6 +159,66 @@
                                                const void *old_mid,
                                                const void *new_mid);
 
+/// Similar to <c>__sanitizer_annotate_contiguous_container</c>.
+///
+/// Annotates the current state of a contiguous container memory,
+/// such as <c>std::deque</c>'s single chunk, when the beginning is moved.
+///
+/// A contiguous chunk is a chunk that keeps all of its elements
+/// in a contiguous region of memory. The container owns the region of memory
+/// <c>[storage_beg, storage_end)</c>; the memory <c>[container_beg,
+/// container_end)</c> is used to store the current elements, and the memory
+/// <c>[storage_beg, container_beg), [container_end, storage_end)</c> is
+/// reserved for future elements (<c>storage_beg <= container_beg <=
+/// container_end <= storage_end</c>). For example, in <c> std::deque </c>:
+/// - chunk with a frist deques element will have container_beg equal to address
+///  of the first element.
+/// - in every next chunk with elements, true is  <c> container_beg ==
+/// storage_beg </c>.
+///
+/// Argument requirements:
+/// During unpoisoning memory of empty container (before first element is
+/// added):
+/// - container_end_p == old_container_beg_p
+/// During poisoning after last element was removed:
+/// - new_container_beg_p == container_end_p
+/// \param storage_beg Beginning of memory region (container may have many
+/// regions). \param storage_end End of memory region. \param new_container_beg
+/// New beginning of used region. \param old_container_beg Old beginning of used
+/// region. \param container_end End of used region.
+void __sanitizer_annotate_double_ended_contiguous_container_front(
+    const void *storage_beg, const void *storage_end,
+    const void *old_container_beg, const void *container_end,
+    const void *new_container_beg);
+
+// Similar to
+// <c>__sanitizer_annotate_double_ended_contiguous_container_front</c>.
+///
+/// Annotates the current state of a contiguous container memory,
+/// such as <c>std::deque</c>'s single chunk, when the end is moved.
+///
+/// A contiguous chunk is a chunk that keeps all of its elements
+/// in a contiguous region of memory. The container owns the region of memory
+/// <c>[storage_beg, storage_end)</c>; the memory <c>[container_beg,
+/// container_end)</c> is used to store the current elements, and the memory
+/// <c>[storage_beg, container_beg), [container_end, storage_end)</c> is
+/// reserved for future elements (<c>storage_beg <= container_beg <=
+/// container_end <= storage_end</c>).
+///
+/// Argument requirements:
+/// During unpoisoning memory of empty container (before first element is
+/// added):
+/// - container_beg_p == old_container_end_p
+/// During poisoning after last element was removed (empty container case):
+/// - new_container_end_p == container_beg_p
+/// \param storage_beg Beginning of memory region (container may have many
+/// regions). \param storage_end End of memory region. \param new_container_end
+/// New beginning of used region. \param old_container_end Old beginning of used
+/// region. \param container_end End of used region.
+void __sanitizer_annotate_double_ended_contiguous_container_back(
+    const void *storage_beg, const void *storage_end, const void *container_beg,
+    const void *old_container_end, const void *new_container_end);
+
 /// Returns true if the contiguous container <c>[beg, end)</c> is properly
 /// poisoned.
 ///
@@ -178,6 +238,30 @@
 int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
                                             const void *end);
 
+/// Returns true if the double ended contiguous
+/// container <c>[storage_beg, storage_end)</c> is properly poisoned.
+///
+/// Proper poisoning could occur, for example, with
+/// <c>__sanitizer_annotate_double_ended_contiguous_container</c>), that is, if
+/// <c>[storage_beg, container_beg)</c> is not addressable,  <c>[container_beg,
+/// container_end)</c> is addressable and <c>[container_end, end)</c> is
+/// unaddressable. Full verification requires O (<c>storage_end -
+/// storage_beg</c>) time; this function tries to avoid such complexity by
+/// touching only parts of the container around <c><i>storage_beg</i></c>,
+/// <c><i>container_beg</i></c>, <c><i>container_end</i></c>, and
+/// <c><i>storage_end</i></c>.
+///
+/// \param storage_beg Beginning of memory region (container may have many
+/// regions). \param container_beg Beginning of used region. \param
+/// container_end End of used region. \param storage_end End of memory region.
+///
+/// \returns True if the double-ended contiguous container <c>[storage_beg,
+/// container_beg, container_end, end)</c> is properly
+///  poisoned - only [container_beg; container_end) is addressable.
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
+
 /// Similar to <c>__sanitizer_verify_contiguous_container()</c> but also
 /// returns the address of the first improperly poisoned byte.
 ///
diff --git a/compiler-rt/lib/asan/asan_errors.h b/compiler-rt/lib/asan/asan_errors.h
--- a/compiler-rt/lib/asan/asan_errors.h
+++ b/compiler-rt/lib/asan/asan_errors.h
@@ -331,6 +331,48 @@
   void Print();
 };
 
+struct ErrorBadParamsToAnnotateDeContiguousContainerFront : ErrorBase {
+  const BufferedStackTrace *stack;
+  uptr storage_beg, storage_end, new_container_beg, old_container_beg,
+      container_end;
+
+  ErrorBadParamsToAnnotateDeContiguousContainerFront() = default;  // (*)
+  ErrorBadParamsToAnnotateDeContiguousContainerFront(
+      u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_,
+      uptr new_container_beg_, uptr old_container_beg_, uptr container_end_)
+      : ErrorBase(
+            tid, 10,
+            "bad-__sanitizer_annotate_double_ended_contiguous_container_front"),
+        stack(stack_),
+        storage_beg(storage_beg_),
+        storage_end(storage_end_),
+        new_container_beg(new_container_beg_),
+        old_container_beg(old_container_beg_),
+        container_end(container_end_) {}
+  void Print();
+};
+
+struct ErrorBadParamsToAnnotateDeContiguousContainerBack : ErrorBase {
+  const BufferedStackTrace *stack;
+  uptr storage_beg, storage_end, old_container_end, new_container_end,
+      container_beg;
+
+  ErrorBadParamsToAnnotateDeContiguousContainerBack() = default;  // (*)
+  ErrorBadParamsToAnnotateDeContiguousContainerBack(
+      u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_,
+      uptr old_container_end_, uptr new_container_end_, uptr container_beg_)
+      : ErrorBase(
+            tid, 10,
+            "bad-__sanitizer_annotate_double_ended_contiguous_container_back"),
+        stack(stack_),
+        storage_beg(storage_beg_),
+        storage_end(storage_end_),
+        old_container_end(old_container_end_),
+        new_container_end(new_container_end_),
+        container_beg(container_beg_) {}
+  void Print();
+};
+
 struct ErrorODRViolation : ErrorBase {
   __asan_global global1, global2;
   u32 stack_id1, stack_id2;
@@ -398,6 +440,8 @@
   macro(StringFunctionMemoryRangesOverlap)      \
   macro(StringFunctionSizeOverflow)             \
   macro(BadParamsToAnnotateContiguousContainer) \
+  macro(BadParamsToAnnotateDeContiguousContainerFront) \
+  macro(BadParamsToAnnotateDeContiguousContainerBack) \
   macro(ODRViolation)                           \
   macro(InvalidPointerPair)                     \
   macro(Generic)
diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp
--- a/compiler-rt/lib/asan/asan_errors.cpp
+++ b/compiler-rt/lib/asan/asan_errors.cpp
@@ -334,6 +334,42 @@
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
+void ErrorBadParamsToAnnotateDeContiguousContainerFront::Print() {
+  Report(
+      "ERROR: AddressSanitizer: bad parameters to "
+      "__sanitizer_annotate_double_ended_contiguous_container_front:\n"
+      "      storage_beg : %p\n"
+      "      storage_end : %p\n"
+      "      new_container_beg  : %p\n"
+      "      old_container_beg  : %p\n"
+      "      container_end      : %p\n",
+      (void *)storage_beg, (void *)storage_end, (void *)new_container_beg,
+      (void *)old_container_beg, (void *)container_end);
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (!IsAligned(storage_beg, granularity))
+    Report("ERROR: storage_beg is not aligned by %zu\n", granularity);
+  stack->Print();
+  ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
+void ErrorBadParamsToAnnotateDeContiguousContainerBack::Print() {
+  Report(
+      "ERROR: AddressSanitizer: bad parameters to "
+      "__sanitizer_annotate_double_ended_contiguous_container_back:\n"
+      "      storage_beg : %p\n"
+      "      storage_end : %p\n"
+      "      old_container_end  : %p\n"
+      "      new_container_end  : %p\n"
+      "      container_beg      : %p\n",
+      (void *)storage_beg, (void *)storage_end, (void *)old_container_end,
+      (void *)new_container_end, (void *)container_beg);
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (!IsAligned(storage_beg, granularity))
+    Report("ERROR: beg is not aligned by %zu\n", granularity);
+  stack->Print();
+  ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
 void ErrorODRViolation::Print() {
   Decorator d;
   Printf("%s", d.Error());
diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp
--- a/compiler-rt/lib/asan/asan_poisoning.cpp
+++ b/compiler-rt/lib/asan/asan_poisoning.cpp
@@ -393,6 +393,165 @@
   }
 }
 
+// Annotates front for a double ended contiguous container like std::deque
+// It allows detecting buggy accesses to allocated but not used begining or end
+// items of such a container
+void __sanitizer_annotate_double_ended_contiguous_container_front(
+    const void *storage_beg_p, const void *storage_end_p,
+    const void *new_container_beg_p, const void *old_container_beg_p,
+    const void *container_end_p) {
+  // Unchecked argument requirements:
+  // During unpoisoning memory of empty container (before first element is
+  // added):
+  // - container_end_p == old_container_beg_p
+  // During poisoning after last element was removed:
+  // - new_container_beg_p == container_end_p
+  if (!flags()->detect_container_overflow)
+    return;
+  VPrintf(2, "de_contiguous_container (front): %p %p %p %p %p\n", storage_beg_p,
+          storage_end_p, new_container_beg_p, old_container_beg_p,
+          container_end_p);
+  uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+  uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+  uptr new_container_beg =
+      reinterpret_cast<uptr>(new_container_beg_p);  // new container beginning
+  uptr old_container_beg =
+      reinterpret_cast<uptr>(old_container_beg_p);  // old container beginning
+  uptr container_end =
+      reinterpret_cast<uptr>(container_end_p);  // container end
+
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (!((storage_beg <= new_container_beg &&
+         new_container_beg <= storage_end) &&
+        (storage_beg <= old_container_beg &&
+         old_container_beg <= storage_end) &&
+        (old_container_beg <= container_end && container_end <= storage_end) &&
+        IsAligned(storage_beg, granularity))) {
+    GET_STACK_TRACE_FATAL_HERE;
+    ReportBadParamsToAnnotateDeContiguousContainerFront(
+        storage_beg, storage_end, new_container_beg, old_container_beg,
+        container_end, &stack);
+  }
+  CHECK_LE(storage_end - storage_beg,
+           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40));  // Sanity check.
+
+  // There are two situations: we are poisoning or unpoisoning.
+  // WARNING: at the moment we do not poison prefixes of blocks described by one
+  // byte in shadow memory, so we have to unpoison prefixes of blocks with
+  // content. Up to 7 bytes not-in-use may not be poisoned.
+
+  if (new_container_beg < old_container_beg) {  // We are unpoisoning
+    uptr a = RoundDownTo(new_container_beg, granularity);
+    uptr c = RoundDownTo(old_container_beg, granularity);
+    // State at the moment is:
+    // [storage_beg, a] is poisoned and should remain like that.
+    // [a, c] is poisoned as well (may be empty if new_container_beg and
+    // old_container_beg are in the same block) if container is not empty, first
+    // element starts between [c, c+granularity]
+    //   because we do not poison prefixes, memory [c, container_end] is not
+    //   poisoned and we do not have to touch it.
+    // if container is empty, we have to unpoison memory for elements after c,
+    // so [c, container_end]
+    PoisonShadow(a, c - a, 0);
+    if (old_container_beg == container_end &&
+        !IsAligned(old_container_beg,
+                   granularity))  // is empty && ends in the middle of a block
+      *(u8 *)MemToShadow(c) = static_cast<u8>(container_end - c);
+
+    // else: we cannot poison prefix of a block with elements or there is
+    // nothing to poison.
+  } else {  // we are poisoning as beginning moved further in memory
+    uptr a = RoundDownTo(old_container_beg, granularity);
+    uptr c = RoundDownTo(new_container_beg, granularity);
+    // State at the moment is:
+    // [storage_beg, a] is poisoned and should remain like that.
+    // [a, c] is not poisoned (may be empty if new_container_beg and
+    // old_container_beg are in the same block) [c, container_end] is not
+    // poisoned If there are remaining elements in the container:
+    //   We have to poison [a, c], but because we do not poison prefixes, we
+    //   cannot poison memory after c (even that there are not elements of the
+    //   container). Up to granularity-1 unused bytes will not be poisoned.
+    // Otherwise:
+    //   We have to poison the last byte as well.
+    PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic);
+    if (new_container_beg == container_end &&
+        !IsAligned(new_container_beg,
+                   granularity))  // is empty && ends in the middle of a block
+      *(u8 *)MemToShadow(c) = static_cast<u8>(kAsanContiguousContainerOOBMagic);
+  }
+}
+
+// Annotates back for a double ended contiguous container like std::deque
+// It allows detecting buggy accesses to allocated but not used begining or end
+// items of such a container
+void __sanitizer_annotate_double_ended_contiguous_container_back(
+    const void *storage_beg_p, const void *storage_end_p,
+    const void *old_container_end_p, const void *new_container_end_p,
+    const void *container_beg_p) {
+  // Unchecked argument requirements:
+  // During unpoisoning memory of empty container (before first element is
+  // added):
+  // - container_beg_p == old_container_end_p
+  // During poisoning after last element was removed (empty container case):
+  // - new_container_end_p == container_beg_p
+  if (!flags()->detect_container_overflow)
+    return;
+  VPrintf(2, "contiguous_container: %p %p %p %p %p\n", storage_beg_p,
+          storage_end_p, old_container_end_p, new_container_end_p,
+          container_beg_p);
+  uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+  uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+  uptr old_container_end = reinterpret_cast<uptr>(old_container_end_p);
+  uptr new_container_end = reinterpret_cast<uptr>(new_container_end_p);
+  uptr container_beg = reinterpret_cast<uptr>(container_beg_p);
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (!((storage_beg <= old_container_end &&
+         old_container_end <= storage_end) &&
+        (storage_beg <= new_container_end &&
+         new_container_end <= storage_end) &&
+        (storage_beg <= container_beg && container_beg <= old_container_end) &&
+        IsAligned(storage_beg, granularity))) {
+    GET_STACK_TRACE_FATAL_HERE;
+    ReportBadParamsToAnnotateDeContiguousContainerBack(
+        storage_beg, storage_end, old_container_end, new_container_end,
+        container_beg, &stack);
+  }
+  CHECK_LE(storage_end - storage_beg,
+           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40));  // Sanity check.
+
+  if (old_container_end < new_container_end) {  // We are unpoisoning memory
+    uptr a = RoundDownTo(old_container_end, granularity);
+    uptr c = RoundDownTo(new_container_end, granularity);
+    // State at the moment is:
+    // if container_beg < a : [container_beg, a] is correct and we will not be
+    // changing it. else [a, container_beg] cannot be poisoned, so we do not
+    // have to think about it. we have to makr as unpoisoned [a, c]. [c, end] is
+    // correctly poisoned.
+    PoisonShadow(a, c - a, 0);
+    if (!IsAligned(new_container_end,
+                   granularity))  // ends in the middle of a block
+      *(u8 *)MemToShadow(c) = static_cast<u8>(new_container_end - c);
+  } else {  // We are poisoning memory
+    uptr a = RoundDownTo(new_container_end, granularity);
+    uptr c = RoundDownTo(old_container_end, granularity);
+    // State at the moment is:
+    // [storage_beg, a] is correctly addressable
+    // if container is empty after the removal, then a < container_beg and we
+    // will have to poison memory which is adressable only because we are not
+    // poisoning prefixes.
+    uptr a2 = RoundUpTo(new_container_end, granularity);
+    uptr c2 = RoundUpTo(old_container_end, granularity);
+    PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic);
+    if (!IsAligned(new_container_end,
+                   granularity)) {  // Starts in the middle of the block
+      if (new_container_end == container_beg)  // empty
+        *(u8 *)MemToShadow(a) = kAsanContiguousContainerOOBMagic;
+      else  // not empty
+        *(u8 *)MemToShadow(a) = static_cast<u8>(new_container_end - a);
+    }
+  }
+}
+
 const void *__sanitizer_contiguous_container_find_bad_address(
     const void *beg_p, const void *mid_p, const void *end_p) {
   if (!flags()->detect_container_overflow)
@@ -402,8 +561,8 @@
   uptr mid = reinterpret_cast<uptr>(mid_p);
   CHECK_LE(beg, mid);
   CHECK_LE(mid, end);
-  // Check some bytes starting from beg, some bytes around mid, and some bytes
-  // ending with end.
+  // Check some bytes starting from storage_beg, some bytes around mid, and some
+  // bytes ending with end.
   uptr kMaxRangeToCheck = 32;
   uptr r1_beg = beg;
   uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
@@ -433,6 +592,56 @@
                                                            end_p) == nullptr;
 }
 
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg_p, const void *container_beg_p,
+    const void *container_end_p, const void *storage_end_p) {
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  // This exists to verify double ended containers.
+  // We assume that such collection's internal memory layout
+  // consists of contiguous blocks:
+  // [a; b) [b; c) [c; d)
+  // where
+  // a - beginning address of contiguous memory block,
+  // b - beginning address of contiguous memory in use
+  //      (address of the first element in the block)
+  // c - end address of contiguous memory in use
+  //      (address just after the last element in the block)
+  // d - end address of contiguous memory block
+  // [a; b) - poisoned
+  // [b; c) - accessible
+  // [c; d) - poisoned
+  // WARNING: We can't poison [a; b) fully in all cases.
+  // This is because the current shadow memory encoding
+  // does not allow for marking/poisoning that a prefix
+  // of an 8-byte block (or, ASAN_SHADOW_GRANULARITY sized block)
+  // cannot be used by the instrumented program. It only has the
+  // 01, 02, 03, 04, 05, 06, 07 and 00 encodings
+  // for usable/addressable memory
+  // (where 00 means that the whole 8-byte block can be used).
+  //
+  // This means that there are cases where not whole of the [a; b)
+  // region is poisoned and instead only the [a; RoundDown(b))
+  // region is poisoned and we may not detect invalid memory accesses on
+  // [RegionDown(b), b).
+  // This is an inherent design limitation of how AddressSanitizer granularity
+  // and shadow memory encoding works at the moment.
+
+  // If empty, storage_beg_p == container_beg_p == container_end_p
+
+  const void *a = storage_beg_p;
+  // We do not suport poisoning prefixes of blocks, so
+  // memory in the first block with data in us,
+  // just before container beginning cannot be poisoned, as described above.
+  const void *b = reinterpret_cast<const void *>(
+      RoundDownTo(reinterpret_cast<uptr>(container_beg_p), granularity));
+  const void *c = container_end_p;
+  const void *d = storage_end_p;
+  return (__sanitizer_contiguous_container_find_bad_address(a, a, b) ==
+          nullptr) &&
+         (__sanitizer_contiguous_container_find_bad_address(b, c, d) ==
+          nullptr);
+}
+
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
 void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
   AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
diff --git a/compiler-rt/lib/asan/asan_report.h b/compiler-rt/lib/asan/asan_report.h
--- a/compiler-rt/lib/asan/asan_report.h
+++ b/compiler-rt/lib/asan/asan_report.h
@@ -83,6 +83,12 @@
 void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
                                                   uptr old_mid, uptr new_mid,
                                                   BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateDeContiguousContainerFront(
+    uptr storage_beg, uptr storage_end, uptr new_container_beg,
+    uptr old_container_beg, uptr container_end, BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateDeContiguousContainerBack(
+    uptr storage_beg, uptr storage_end, uptr old_container_end,
+    uptr new_container_end, uptr container_beg, BufferedStackTrace *stack);
 
 void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                         const __asan_global *g2, u32 stack_id2);
diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp
--- a/compiler-rt/lib/asan/asan_report.cpp
+++ b/compiler-rt/lib/asan/asan_report.cpp
@@ -354,6 +354,26 @@
   in_report.ReportError(error);
 }
 
+void ReportBadParamsToAnnotateDeContiguousContainerFront(
+    uptr storage_beg, uptr storage_end, uptr new_container_beg,
+    uptr old_container_beg, uptr container_end, BufferedStackTrace *stack) {
+  ScopedInErrorReport in_report;
+  ErrorBadParamsToAnnotateDeContiguousContainerFront error(
+      GetCurrentTidOrInvalid(), stack, storage_beg, storage_end,
+      new_container_beg, old_container_beg, container_end);
+  in_report.ReportError(error);
+}
+
+void ReportBadParamsToAnnotateDeContiguousContainerBack(
+    uptr storage_beg, uptr storage_end, uptr old_container_end,
+    uptr new_container_end, uptr container_beg, BufferedStackTrace *stack) {
+  ScopedInErrorReport in_report;
+  ErrorBadParamsToAnnotateDeContiguousContainerBack error(
+      GetCurrentTidOrInvalid(), stack, storage_beg, storage_end,
+      old_container_end, new_container_end, container_beg);
+  in_report.ReportError(error);
+}
+
 void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                         const __asan_global *g2, u32 stack_id2) {
   ScopedInErrorReport in_report;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc
@@ -9,12 +9,15 @@
 //===----------------------------------------------------------------------===//
 INTERFACE_FUNCTION(__sanitizer_acquire_crash_state)
 INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_annotate_double_ended_contiguous_container_front)
+INTERFACE_FUNCTION(__sanitizer_annotate_double_ended_contiguous_container_back)
 INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
 INTERFACE_FUNCTION(__sanitizer_set_death_callback)
 INTERFACE_FUNCTION(__sanitizer_set_report_path)
 INTERFACE_FUNCTION(__sanitizer_set_report_fd)
 INTERFACE_FUNCTION(__sanitizer_get_report_path)
 INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_verify_double_ended_contiguous_container)
 INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
 INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
 INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
--- a/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
@@ -72,11 +72,25 @@
 const void *__sanitizer_contiguous_container_find_bad_address(const void *beg,
                                                               const void *mid,
                                                               const void *end);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_annotate_double_ended_contiguous_container_front(
+    const void *storage_beg, const void *storage_end,
+    const void *old_container_beg_p, const void *container_end_p,
+    const void *new_container_beg_p);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_annotate_double_ended_contiguous_container_back(
+    const void *storage_beg, const void *storage_end,
+    const void *container_beg_p, const void *old_container_end_p,
+    const void *new_container_end_p);
 
 SANITIZER_INTERFACE_ATTRIBUTE
 int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path,
                                              __sanitizer::uptr module_path_len,
                                              void **pc_offset);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
 
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
 __sanitizer_cov_trace_cmp();
diff --git a/libcxx/include/__config b/libcxx/include/__config
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -880,6 +880,12 @@
 #  ifndef _LIBCPP_HAS_NO_ASAN
     extern "C" _LIBCPP_FUNC_VIS void
     __sanitizer_annotate_contiguous_container(const void*, const void*, const void*, const void*);
+extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_double_ended_contiguous_container_front(
+    const void*, const void*, const void*, const void*, const void*);
+extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_double_ended_contiguous_container_back(
+    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
 
 // Try to find out if RTTI is disabled.