Add Address Sanitizer support to std::vector

llvm-svn: 208319
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 5c520bd985ee51472d2396fe28a3ef8b30eb5a6c
diff --git a/include/__config b/include/__config
index fb775c6..ce39243 100644
--- a/include/__config
+++ b/include/__config
@@ -629,6 +629,11 @@
 #define _LIBCPP_DEPRECATED_AFTER_CXX11 [[deprecated]]
 #endif
 
+#ifndef _LIBCPP_HAS_NO_ASAN
+extern "C" void __sanitizer_annotate_contiguous_container(
+  const void *, const void *, const void *, const void *);
+#endif
+
 // Try to find out if RTTI is disabled.
 // g++ and cl.exe have RTTI on by default and define a macro when it is.
 // g++ only defines the macro in 4.3.2 and onwards.
diff --git a/include/vector b/include/vector
index 6ac78d5..2cc23e5 100644
--- a/include/vector
+++ b/include/vector
@@ -483,6 +483,7 @@
 {
 private:
     typedef __vector_base<_Tp, _Allocator>           __base;
+    typedef allocator<_Tp>                           __default_allocator_type;
 public:
     typedef vector                                   __self;
     typedef _Tp                                      value_type;
@@ -749,7 +750,9 @@
     _LIBCPP_INLINE_VISIBILITY
     void clear() _NOEXCEPT
     {
+        size_type __old_size = size();
         __base::clear();
+        __annotate_shrink(__old_size);
         __invalidate_all_iterators();
     }
 
@@ -816,7 +819,9 @@
         }
         __get_db()->unlock();
 #endif
+        size_type __old_size = size();
         __base::__destruct_at_end(__new_last);
+        __annotate_shrink(__old_size);
     }
     template <class _Up>
         void
@@ -830,17 +835,52 @@
         void
         __emplace_back_slow_path(_Args&&... __args);
 #endif
+    // The following functions are no-ops outside of AddressSanitizer mode.
+    // We call annotatations only for the default Allocator because other allocators
+    // may not meet the AddressSanitizer alignment constraints.
+    // See the documentation for __sanitizer_annotate_contiguous_container for more details.
+    void __annotate_contiguous_container
+    (const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid)
+    {
+#ifndef _LIBCPP_HAS_NO_ASAN
+      if (__beg && is_same<allocator_type, __default_allocator_type>::value)
+        __sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid);
+#endif
+    }
+
+    void __annotate_new(size_type __current_size)
+    {
+      __annotate_contiguous_container(data(), data() + capacity(),
+                                      data() + capacity(), data() + __current_size);
+    }
+    void __annotate_delete()
+    {
+      __annotate_contiguous_container(data(), data() + capacity(),
+                                      data() + size(), data() + capacity());
+    }
+    void __annotate_increase(size_type __n)
+    {
+      __annotate_contiguous_container(data(), data() + capacity(),
+                                      data() + size(), data() + size() + __n);
+    }
+    void __annotate_shrink(size_type __old_size)
+    {
+      __annotate_contiguous_container(data(), data() + capacity(),
+                                      data() + __old_size, data() + size());
+    }
 };
 
 template <class _Tp, class _Allocator>
 void
 vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v)
 {
+    __annotate_delete();
     __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, this->__end_, __v.__begin_);
     _VSTD::swap(this->__begin_, __v.__begin_);
     _VSTD::swap(this->__end_, __v.__end_);
     _VSTD::swap(this->__end_cap(), __v.__end_cap());
     __v.__first_ = __v.__begin_;
+    __annotate_new(size());
     __invalidate_all_iterators();
 }
 
@@ -848,6 +888,7 @@
 typename vector<_Tp, _Allocator>::pointer
 vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p)
 {
+    __annotate_delete();
     pointer __r = __v.__begin_;
     __alloc_traits::__construct_backward(this->__alloc(), this->__begin_, __p, __v.__begin_);
     __alloc_traits::__construct_forward(this->__alloc(), __p, this->__end_, __v.__end_);
@@ -855,6 +896,7 @@
     _VSTD::swap(this->__end_, __v.__end_);
     _VSTD::swap(this->__end_cap(), __v.__end_cap());
     __v.__first_ = __v.__begin_;
+    __annotate_new(size());
     __invalidate_all_iterators();
     return __r;
 }
@@ -874,6 +916,7 @@
         this->__throw_length_error();
     this->__begin_ = this->__end_ = __alloc_traits::allocate(this->__alloc(), __n);
     this->__end_cap() = this->__begin_ + __n;
+    __annotate_new(0);
 }
 
 template <class _Tp, class _Allocator>
@@ -920,6 +963,7 @@
 vector<_Tp, _Allocator>::__construct_at_end(size_type __n)
 {
     allocator_type& __a = this->__alloc();
+    __annotate_increase(__n);
     do
     {
         __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_));
@@ -940,6 +984,7 @@
 vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x)
 {
     allocator_type& __a = this->__alloc();
+    __annotate_increase(__n);
     do
     {
         __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_), __x);
@@ -960,6 +1005,7 @@
     allocator_type& __a = this->__alloc();
     for (; __first != __last; ++__first)
     {
+        __annotate_increase(1);
         __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_), *__first);
         ++this->__end_;
     }
@@ -972,6 +1018,7 @@
     allocator_type& __a = this->__alloc();
     for (; __first != __last; ++__first)
     {
+        __annotate_increase(1);
         __alloc_traits::construct(__a, _VSTD::__to_raw_pointer(this->__end_),
                                   _VSTD::move(*__first));
         ++this->__end_;
@@ -1535,6 +1582,7 @@
 {
     if (this->__end_ != this->__end_cap())
     {
+        __annotate_increase(1);
         __alloc_traits::construct(this->__alloc(),
                                   _VSTD::__to_raw_pointer(this->__end_), __x);
         ++this->__end_;
@@ -1552,6 +1600,7 @@
 {
     if (this->__end_ < this->__end_cap())
     {
+        __annotate_increase(1);
         __alloc_traits::construct(this->__alloc(),
                                   _VSTD::__to_raw_pointer(this->__end_),
                                   _VSTD::move(__x));
@@ -1584,6 +1633,7 @@
 {
     if (this->__end_ < this->__end_cap())
     {
+        __annotate_increase(1);
         __alloc_traits::construct(this->__alloc(),
                                   _VSTD::__to_raw_pointer(this->__end_),
                                   _VSTD::forward<_Args>(__args)...);
@@ -1666,6 +1716,7 @@
     pointer __p = this->__begin_ + (__position - begin());
     if (this->__end_ < this->__end_cap())
     {
+        __annotate_increase(1);
         if (__p == this->__end_)
         {
             __alloc_traits::construct(this->__alloc(),
@@ -1705,6 +1756,7 @@
     pointer __p = this->__begin_ + (__position - begin());
     if (this->__end_ < this->__end_cap())
     {
+        __annotate_increase(1);
         if (__p == this->__end_)
         {
             __alloc_traits::construct(this->__alloc(),
@@ -1743,6 +1795,7 @@
     pointer __p = this->__begin_ + (__position - begin());
     if (this->__end_ < this->__end_cap())
     {
+        __annotate_increase(1);
         if (__p == this->__end_)
         {
             __alloc_traits::construct(this->__alloc(),
@@ -1794,6 +1847,7 @@
             }
             if (__n > 0)
             {
+                __annotate_increase(__n);
                 __move_range(__p, __old_last, __p + __old_n);
                 const_pointer __xr = pointer_traits<const_pointer>::pointer_to(__x);
                 if (__p <= __xr && __xr < this->__end_)
@@ -1904,6 +1958,7 @@
             }
             if (__n > 0)
             {
+                __annotate_increase(__n);
                 __move_range(__p, __old_last, __p + __old_n);
                 _VSTD::copy(__first, __m, __p);
             }