public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Add AddressSanitizer annotations to std::vector
@ 2017-07-05 19:00 ` Jonathan Wakely
  2017-07-05 19:17   ` Jonathan Wakely
                     ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-05 19:00 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Martin Liška, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 2542 bytes --]

This patch adds AddressSanitizer annotations to std::vector, so that
ASan can detect out-of-bounds accesses to the unused capacity of a
vector. e.g.

  std::vector<int> v(2);
  int* p = v.data();
  v.pop_back();
  return p[1];  // ERROR

This cannot be detected by Debug Mode, but with these annotations ASan
knows that only v.data()[0] is valid and will give an error.

The annotations are only enabled for vector<T, std::allocator<T>> and
only when std::allocator's base class is either malloc_allocator or
new_allocator. For other allocators the memory might not come from the
freestore and so isn't tracked by ASan.

Something similar has been on the google branches for some time:
https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=207517
This patch is a complete rewrite from scratch, because the google code
was not exception safe. If an exception happened while appending
elements to a vector, so that the size didn't change, the google code
did not undo the annotation for the increased size. It also didn't
annotate before deallocating, to mark the unused capacity as valid
again.

We can probably do similar annotations for std::deque, so that
partially filled pages are annotated. I also have a patch for
shared_ptr so that objects created by make_shared can be marked as
invalid after they're destroyed.

	* config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
	* config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
	* include/bits/stl_vector.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
	(_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
	(_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
	(_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
	(_GLIBCXX_ASAN_ANNOTATE_SHRINK, _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
	Define annotation helper types and macros.
	(vector::~vector, vector::push_back, vector::pop_back)
	(vector::_M_erase_at_end): Add annotations.
	* include/bits/vector.tcc (vector::reserve, vector::emplace_back)
	(vector::insert, vector::_M_erase, vector::operator=)
	(vector::_M_fill_assign, vector::_M_assign_aux)
	(vector::_M_insert_rval, vector::_M_emplace_aux)
	(vector::_M_insert_aux, vector::_M_realloc_insert)
	(vector::_M_fill_insert, vector::_M_default_append)
	(vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.

Tested x86_64-linux (using -fsanitize=address, with some local patches
to the testsuite) and powerpc64le-linux.

I plan to commit this to trunk tomorrow.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 18204 bytes --]

commit 396bdc35021083dafa4ebb29726219dcb9f1644c
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jul 5 13:25:21 2017 +0100

    Add AddressSanitizer annotations to std::vector
    
    	* config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
    	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
    	* config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
    	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
    	* include/bits/stl_vector.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
    	(_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
    	(_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
    	(_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
    	(_GLIBCXX_ASAN_ANNOTATE_SHRINK, _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
    	Define annotation helper types and macros.
    	(vector::~vector, vector::push_back, vector::pop_back)
    	(vector::_M_erase_at_end): Add annotations.
    	* include/bits/vector.tcc (vector::reserve, vector::emplace_back)
    	(vector::insert, vector::_M_erase, vector::operator=)
    	(vector::_M_fill_assign, vector::_M_assign_aux)
    	(vector::_M_insert_rval, vector::_M_emplace_aux)
    	(vector::_M_insert_aux, vector::_M_realloc_insert)
    	(vector::_M_fill_insert, vector::_M_default_append)
    	(vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.

diff --git a/libstdc++-v3/config/allocator/malloc_allocator_base.h b/libstdc++-v3/config/allocator/malloc_allocator_base.h
index b091bbc..54e0837 100644
--- a/libstdc++-v3/config/allocator/malloc_allocator_base.h
+++ b/libstdc++-v3/config/allocator/malloc_allocator_base.h
@@ -52,4 +52,8 @@ namespace std
 # define __allocator_base  __gnu_cxx::malloc_allocator
 #endif
 
+#if defined(__SANITIZE_ADDRESS__) && !defined(_GLIBCXX_SANITIZE_STD_ALLOCATOR)
+# define _GLIBCXX_SANITIZE_STD_ALLOCATOR 1
+#endif
+
 #endif
diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h
index 3d2bb67..e776ed3 100644
--- a/libstdc++-v3/config/allocator/new_allocator_base.h
+++ b/libstdc++-v3/config/allocator/new_allocator_base.h
@@ -52,4 +52,8 @@ namespace std
 # define __allocator_base  __gnu_cxx::new_allocator
 #endif
 
+#if defined(__SANITIZE_ADDRESS__) && !defined(_GLIBCXX_SANITIZE_STD_ALLOCATOR)
+# define _GLIBCXX_SANITIZE_STD_ALLOCATOR 1
+#endif
+
 #endif
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 7ee3ce9..4edc55b 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -65,6 +65,12 @@
 
 #include <debug/assertions.h>
 
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR
+extern "C" void
+__sanitizer_annotate_contiguous_container(const void*, const void*,
+					  const void*, const void*);
+#endif
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
@@ -106,6 +112,121 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR
+	template<typename = _Tp_alloc_type>
+	  struct _Asan
+	  {
+	    typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>
+	      ::size_type size_type;
+
+	    static void _S_shrink(_Vector_impl&, size_type) { }
+	    static void _S_on_dealloc(_Vector_impl&) { }
+
+	    typedef _Vector_impl& _Reinit;
+
+	    struct _Grow
+	    {
+	      _Grow(_Vector_impl&, size_type) { }
+	      void _M_grew(size_type) { }
+	    };
+	  };
+
+	// Enable ASan annotations for memory obtained from std::allocator.
+	template<typename _Up>
+	  struct _Asan<allocator<_Up> >
+	  {
+	    typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>
+	      ::size_type size_type;
+
+	    // Adjust ASan annotation for [_M_start, _M_end_of_storage) to
+	    // mark end of valid region as __curr instead of __prev.
+	    static void
+	    _S_adjust(_Vector_impl& __impl, pointer __prev, pointer __curr)
+	    {
+	      __sanitizer_annotate_contiguous_container(__impl._M_start,
+		  __impl._M_end_of_storage, __prev, __curr);
+	    }
+
+	    static void
+	    _S_grow(_Vector_impl& __impl, size_type __n)
+	    { _S_adjust(__impl, __impl._M_finish, __impl._M_finish + __n); }
+
+	    static void
+	    _S_shrink(_Vector_impl& __impl, size_type __n)
+	    { _S_adjust(__impl, __impl._M_finish + __n, __impl._M_finish); }
+
+	    static void
+	    _S_on_dealloc(_Vector_impl& __impl)
+	    {
+	      if (__impl._M_start)
+		_S_adjust(__impl, __impl._M_finish, __impl._M_end_of_storage);
+	    }
+
+	    // Used on reallocation to tell ASan unused capacity is invalid.
+	    struct _Reinit
+	    {
+	      explicit _Reinit(_Vector_impl& __impl) : _M_impl(__impl)
+	      {
+		// Mark unused capacity as valid again before deallocating it.
+		_S_on_dealloc(_M_impl);
+	      }
+
+	      ~_Reinit()
+	      {
+		// Mark unused capacity as invalid after reallocation.
+		if (_M_impl._M_start)
+		  _S_adjust(_M_impl, _M_impl._M_end_of_storage,
+			    _M_impl._M_finish);
+	      }
+
+	      _Vector_impl& _M_impl;
+
+#if __cplusplus >= 201103L
+	      _Reinit(const _Reinit&) = delete;
+	      _Reinit& operator=(const _Reinit&) = delete;
+#endif
+	    };
+
+	    // Tell ASan when unused capacity is initialized to be valid.
+	    struct _Grow
+	    {
+	      _Grow(_Vector_impl& __impl, size_type __n)
+	      : _M_impl(__impl), _M_n(__n)
+	      { _S_grow(_M_impl, __n); }
+
+	      ~_Grow() { if (_M_n) _S_shrink(_M_impl, _M_n); }
+
+	      void _M_grew(size_type __n) { _M_n -= __n; }
+
+#if __cplusplus >= 201103L
+	      _Grow(const _Grow&) = delete;
+	      _Grow& operator=(const _Grow&) = delete;
+#endif
+	    private:
+	      _Vector_impl& _M_impl;
+	      size_type _M_n;
+	    };
+	  };
+
+#define _GLIBCXX_ASAN_ANNOTATE_REINIT \
+  typename _Base::_Vector_impl::template _Asan<>::_Reinit const \
+	__attribute__((__unused__)) __reinit_guard(this->_M_impl)
+#define _GLIBCXX_ASAN_ANNOTATE_GROW(n) \
+  typename _Base::_Vector_impl::template _Asan<>::_Grow \
+	__attribute__((__unused__)) __grow_guard(this->_M_impl, (n))
+#define _GLIBCXX_ASAN_ANNOTATE_GREW(n) __grow_guard._M_grew(n)
+#define _GLIBCXX_ASAN_ANNOTATE_SHRINK(n) \
+  _Base::_Vector_impl::template _Asan<>::_S_shrink(this->_M_impl, n)
+#define _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC \
+  _Base::_Vector_impl::template _Asan<>::_S_on_dealloc(this->_M_impl)
+#else
+#define _GLIBCXX_ASAN_ANNOTATE_REINIT
+#define _GLIBCXX_ASAN_ANNOTATE_GROW(n)
+#define _GLIBCXX_ASAN_ANNOTATE_GREW(n)
+#define _GLIBCXX_ASAN_ANNOTATE_SHRINK(n)
+#define _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC
+#endif
       };
 
     public:
@@ -159,8 +280,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
-      { _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage
-		      - this->_M_impl._M_start); }
+      {
+	_M_deallocate(_M_impl._M_start,
+		      _M_impl._M_end_of_storage - _M_impl._M_start);
+      }
 
     public:
       _Vector_impl _M_impl;
@@ -431,8 +554,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  responsibility.
        */
       ~vector() _GLIBCXX_NOEXCEPT
-      { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-		      _M_get_Tp_allocator()); }
+      {
+	std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+		      _M_get_Tp_allocator());
+	_GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC;
+      }
 
       /**
        *  @brief  %Vector assignment operator.
@@ -940,9 +1066,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     __x);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_realloc_insert(end(), __x);
@@ -977,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	__glibcxx_requires_nonempty();
 	--this->_M_impl._M_finish;
 	_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
+	_GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
       }
 
 #if __cplusplus >= 201103L
@@ -1510,8 +1639,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       void
       _M_erase_at_end(pointer __pos) _GLIBCXX_NOEXCEPT
       {
-	std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator());
-	this->_M_impl._M_finish = __pos;
+	if (size_type __n = this->_M_impl._M_finish - __pos)
+	  {
+	    std::_Destroy(__pos, this->_M_impl._M_finish,
+			  _M_get_Tp_allocator());
+	    this->_M_impl._M_finish = __pos;
+	    _GLIBCXX_ASAN_ANNOTATE_SHRINK(__n);
+	  }
       }
 
       iterator
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index 8d68866..f03dba0 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -73,6 +73,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  pointer __tmp = _M_allocate_and_copy(__n,
 	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
 	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+	  _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	  std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			_M_get_Tp_allocator());
 	  _M_deallocate(this->_M_impl._M_start,
@@ -97,9 +98,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     std::forward<_Args>(__args)...);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_realloc_insert(end(), std::forward<_Args>(__args)...);
@@ -122,9 +125,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	if (__position == end())
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     __x);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  {
@@ -157,6 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_GLIBCXX_MOVE3(__position + 1, end(), __position);
       --this->_M_impl._M_finish;
       _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
+      _GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
       return __position;
     }
 
@@ -181,6 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (&__x != this)
 	{
+	  _GLIBCXX_ASAN_ANNOTATE_REINIT;
 #if __cplusplus >= 201103L
 	  if (_Alloc_traits::_S_propagate_on_copy_assign())
 	    {
@@ -245,10 +252,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       else if (__n > size())
 	{
 	  std::fill(begin(), end(), __val);
+	  const size_type __add = __n - size();
+	  _GLIBCXX_ASAN_ANNOTATE_GROW(__add);
 	  this->_M_impl._M_finish =
 	    std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
-					  __n - size(), __val,
-					  _M_get_Tp_allocator());
+					  __add, __val, _M_get_Tp_allocator());
+	  _GLIBCXX_ASAN_ANNOTATE_GREW(__add);
 	}
       else
         _M_erase_at_end(std::fill_n(this->_M_impl._M_start, __n, __val));
@@ -284,6 +293,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (__len > capacity())
 	  {
 	    pointer __tmp(_M_allocate_and_copy(__len, __first, __last));
+	    _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			  _M_get_Tp_allocator());
 	    _M_deallocate(this->_M_impl._M_start,
@@ -300,10 +310,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _ForwardIterator __mid = __first;
 	    std::advance(__mid, size());
 	    std::copy(__first, __mid, this->_M_impl._M_start);
+	    const size_type __attribute__((__unused__)) __n = __len - size();
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_copy_a(__mid, __last,
 					  this->_M_impl._M_finish,
 					  _M_get_Tp_allocator());
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 	  }
       }
 
@@ -317,9 +330,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	if (__position == cend())
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     std::move(__v));
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_insert_aux(begin() + __n, std::move(__v));
@@ -340,9 +355,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  if (__position == cend())
 	    {
+	      _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	      _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				       std::forward<_Args>(__args)...);
 	      ++this->_M_impl._M_finish;
+	      _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	    }
 	  else
 	    {
@@ -370,10 +387,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     _M_insert_aux(iterator __position, const _Tp& __x)
 #endif
     {
+      _GLIBCXX_ASAN_ANNOTATE_GROW(1);
       _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
-			       _GLIBCXX_MOVE(*(this->_M_impl._M_finish
-					       - 1)));
+			       _GLIBCXX_MOVE(*(this->_M_impl._M_finish - 1)));
       ++this->_M_impl._M_finish;
+      _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 #if __cplusplus < 201103L
       _Tp __x_copy = __x;
 #endif
@@ -443,11 +461,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _M_deallocate(__new_start, __len);
 	  __throw_exception_again;
 	}
+      _GLIBCXX_ASAN_ANNOTATE_REINIT;
       std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 		    _M_get_Tp_allocator());
       _M_deallocate(this->_M_impl._M_start,
-		    this->_M_impl._M_end_of_storage
-		    - this->_M_impl._M_start);
+		    this->_M_impl._M_end_of_storage - this->_M_impl._M_start);
       this->_M_impl._M_start = __new_start;
       this->_M_impl._M_finish = __new_finish;
       this->_M_impl._M_end_of_storage = __new_start + __len;
@@ -473,11 +491,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	      pointer __old_finish(this->_M_impl._M_finish);
 	      if (__elems_after > __n)
 		{
+		  _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		  std::__uninitialized_move_a(this->_M_impl._M_finish - __n,
 					      this->_M_impl._M_finish,
 					      this->_M_impl._M_finish,
 					      _M_get_Tp_allocator());
 		  this->_M_impl._M_finish += __n;
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 		  _GLIBCXX_MOVE_BACKWARD3(__position.base(),
 					  __old_finish - __n, __old_finish);
 		  std::fill(__position.base(), __position.base() + __n,
@@ -485,15 +505,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		}
 	      else
 		{
+		  _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		  this->_M_impl._M_finish =
 		    std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
 						  __n - __elems_after,
 						  __x_copy,
 						  _M_get_Tp_allocator());
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
 		  std::__uninitialized_move_a(__position.base(), __old_finish,
 					      this->_M_impl._M_finish,
 					      _M_get_Tp_allocator());
 		  this->_M_impl._M_finish += __elems_after;
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
 		  std::fill(__position.base(), __old_finish, __x_copy);
 		}
 	    }
@@ -536,6 +559,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  _M_deallocate(__new_start, __len);
 		  __throw_exception_again;
 		}
+	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			    _M_get_Tp_allocator());
 	      _M_deallocate(this->_M_impl._M_start,
@@ -559,9 +583,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  if (size_type(this->_M_impl._M_end_of_storage
 			- this->_M_impl._M_finish) >= __n)
 	    {
+	      _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 	      this->_M_impl._M_finish =
 		std::__uninitialized_default_n_a(this->_M_impl._M_finish,
 						 __n, _M_get_Tp_allocator());
+	      _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 	    }
 	  else
 	    {
@@ -587,6 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  _M_deallocate(__new_start, __len);
 		  __throw_exception_again;
 		}
+	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			    _M_get_Tp_allocator());
 	      _M_deallocate(this->_M_impl._M_start,
@@ -606,6 +633,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (capacity() == size())
 	return false;
+      _GLIBCXX_ASAN_ANNOTATE_REINIT;
       return std::__shrink_to_fit_aux<vector>::_S_do_it(*this);
     }
 #endif
@@ -641,11 +669,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		pointer __old_finish(this->_M_impl._M_finish);
 		if (__elems_after > __n)
 		  {
+		    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		    std::__uninitialized_move_a(this->_M_impl._M_finish - __n,
 						this->_M_impl._M_finish,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __n;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 		    _GLIBCXX_MOVE_BACKWARD3(__position.base(),
 					    __old_finish - __n, __old_finish);
 		    std::copy(__first, __last, __position);
@@ -654,15 +684,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  {
 		    _ForwardIterator __mid = __first;
 		    std::advance(__mid, __elems_after);
+		    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		    std::__uninitialized_copy_a(__mid, __last,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __n - __elems_after;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
 		    std::__uninitialized_move_a(__position.base(),
 						__old_finish,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __elems_after;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
 		    std::copy(__first, __mid, __position);
 		  }
 	      }
@@ -694,6 +727,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		    _M_deallocate(__new_start, __len);
 		    __throw_exception_again;
 		  }
+		_GLIBCXX_ASAN_ANNOTATE_REINIT;
 		std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			      _M_get_Tp_allocator());
 		_M_deallocate(this->_M_impl._M_start,
@@ -902,4 +936,9 @@ _GLIBCXX_END_NAMESPACE_VERSION
 
 #endif // C++11
 
+#undef _GLIBCXX_ASAN_ANNOTATE_REINIT
+#undef _GLIBCXX_ASAN_ANNOTATE_GROW
+#undef _GLIBCXX_ASAN_ANNOTATE_GREW
+#undef _GLIBCXX_ASAN_ANNOTATE_SHRINK
+
 #endif /* _VECTOR_TCC */

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-05 19:00 ` [PATCH] Add AddressSanitizer annotations to std::vector Jonathan Wakely
@ 2017-07-05 19:17   ` Jonathan Wakely
  2017-07-05 19:44   ` Yuri Gribov
  2017-07-06 17:23   ` Ivan Baravy
  2 siblings, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-05 19:17 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Martin Liška, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 651 bytes --]

On 05/07/17 20:00 +0100, Jonathan Wakely wrote:
>We can probably do similar annotations for std::deque, so that
>partially filled pages are annotated. I also have a patch for
>shared_ptr so that objects created by make_shared can be marked as
>invalid after they're destroyed.

This is the make_shared annotation patch. This allows ASan to give an
error for:

  auto p = std::make_shared<int>();
  std::weak_ptr<int> w = p;
  int* pi = p.get();
  p = nullptr;
  return *pi;

The error isn't ideal, because ASan thinks we're using a container,
because that's what the annotations are intended for:

==4525==ERROR: AddressSanitizer: container-overflow


[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 1930 bytes --]

commit d0478d9fbd17b9e9d165b4893f784ae897531713
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jun 27 13:31:12 2017 +0100

    Add AddressSanitizer annotations to std::make_shared
    
    	* include/bits/shared_ptr_base.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
    	(__asan_annotate): Add.
    	(_Sp_counted_ptr_inplace::_M_dispose): Call __asan_annotate.

diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index 7e6766b..a720018 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -57,6 +57,12 @@
 #include <bits/stl_function.h>
 #include <ext/aligned_buffer.h>
 
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR
+extern "C" void
+__sanitizer_annotate_contiguous_container(const void*, const void*,
+                                         const void*, const void*);
+#endif
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 #if !__cpp_rtti
@@ -522,6 +528,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
   };
 
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR
+  template<typename _Tp>
+    inline void
+    __asan_annotate(const void* __beg, const void* __mid, const void* __end,
+		    const allocator<_Tp>&)
+    { __sanitizer_annotate_contiguous_container(__beg, __end, __end, __mid); }
+
+  template<typename _Alloc>
+    inline void
+    __asan_annotate(const void*, const void*, const void*, const _Alloc&)
+    { }
+#endif
+
   template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
     class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
     {
@@ -556,6 +575,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _M_dispose() noexcept
       {
 	allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr());
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR
+	__asan_annotate(this, &_M_impl._M_storage, this + 1, _M_impl._M_alloc());
+#endif
       }
 
       // Override because the allocator needs to know the dynamic type

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-05 19:00 ` [PATCH] Add AddressSanitizer annotations to std::vector Jonathan Wakely
  2017-07-05 19:17   ` Jonathan Wakely
@ 2017-07-05 19:44   ` Yuri Gribov
  2017-07-05 20:24     ` Jonathan Wakely
  2017-07-06 17:23   ` Ivan Baravy
  2 siblings, 1 reply; 7+ messages in thread
From: Yuri Gribov @ 2017-07-05 19:44 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: libstdc++,
	GCC Patches, Martin Liška, Jakub Jelinek, Kostya Serebryany

On Wed, Jul 5, 2017 at 8:00 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
> This patch adds AddressSanitizer annotations to std::vector, so that
> ASan can detect out-of-bounds accesses to the unused capacity of a
> vector. e.g.
>
>  std::vector<int> v(2);
>  int* p = v.data();
>  v.pop_back();
>  return p[1];  // ERROR
>
> This cannot be detected by Debug Mode, but with these annotations ASan
> knows that only v.data()[0] is valid and will give an error.
>
> The annotations are only enabled for vector<T, std::allocator<T>> and
> only when std::allocator's base class is either malloc_allocator or
> new_allocator. For other allocators the memory might not come from the
> freestore and so isn't tracked by ASan.

One important issue with enabling this by default is that it may
(will?) break separate sanitization (which is extremely important
feature in practice). If one part of application is sanitized but the
other isn't and some poor std::vector is push_back'ed in latter and
then accessed in former, we'll get a false positive because push_back
wouldn't properly annotate memory.

Perhaps hide this under a compilation flag (disabled by default)?

> Something similar has been on the google branches for some time:
> https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=207517
> This patch is a complete rewrite from scratch, because the google code
> was not exception safe. If an exception happened while appending
> elements to a vector, so that the size didn't change, the google code
> did not undo the annotation for the increased size. It also didn't
> annotate before deallocating, to mark the unused capacity as valid
> again.
>
> We can probably do similar annotations for std::deque, so that
> partially filled pages are annotated. I also have a patch for
> shared_ptr so that objects created by make_shared can be marked as
> invalid after they're destroyed.
>
>         * config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
>         (_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
>         * config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
>         (_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
>         * include/bits/stl_vector.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
>         (_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
>         (_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
>         (_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
>         (_GLIBCXX_ASAN_ANNOTATE_SHRINK,
> _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
>         Define annotation helper types and macros.
>         (vector::~vector, vector::push_back, vector::pop_back)
>         (vector::_M_erase_at_end): Add annotations.
>         * include/bits/vector.tcc (vector::reserve, vector::emplace_back)
>         (vector::insert, vector::_M_erase, vector::operator=)
>         (vector::_M_fill_assign, vector::_M_assign_aux)
>         (vector::_M_insert_rval, vector::_M_emplace_aux)
>         (vector::_M_insert_aux, vector::_M_realloc_insert)
>         (vector::_M_fill_insert, vector::_M_default_append)
>         (vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.
>
> Tested x86_64-linux (using -fsanitize=address, with some local patches
> to the testsuite) and powerpc64le-linux.
>
> I plan to commit this to trunk tomorrow.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-05 19:44   ` Yuri Gribov
@ 2017-07-05 20:24     ` Jonathan Wakely
  2017-07-21 16:07       ` Jonathan Wakely
  0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-05 20:24 UTC (permalink / raw)
  To: Yuri Gribov
  Cc: libstdc++,
	GCC Patches, Martin Liška, Jakub Jelinek, Kostya Serebryany

On 05/07/17 20:44 +0100, Yuri Gribov wrote:
>On Wed, Jul 5, 2017 at 8:00 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
>> This patch adds AddressSanitizer annotations to std::vector, so that
>> ASan can detect out-of-bounds accesses to the unused capacity of a
>> vector. e.g.
>>
>>  std::vector<int> v(2);
>>  int* p = v.data();
>>  v.pop_back();
>>  return p[1];  // ERROR
>>
>> This cannot be detected by Debug Mode, but with these annotations ASan
>> knows that only v.data()[0] is valid and will give an error.
>>
>> The annotations are only enabled for vector<T, std::allocator<T>> and
>> only when std::allocator's base class is either malloc_allocator or
>> new_allocator. For other allocators the memory might not come from the
>> freestore and so isn't tracked by ASan.
>
>One important issue with enabling this by default is that it may
>(will?) break separate sanitization (which is extremely important
>feature in practice). If one part of application is sanitized but the
>other isn't and some poor std::vector is push_back'ed in latter and
>then accessed in former, we'll get a false positive because push_back
>wouldn't properly annotate memory.

Good point.

>Perhaps hide this under a compilation flag (disabled by default)?

If you define _GLIBCXX_SANITIZE_STD_ALLOCATOR to 0 the annotations are
disabled. To make them disabled by default would need some changes, to
use separate macros for "the std::allocator base class can be
sanitized" and "the user wants std::vector to be sanitized".

I'll do that before committing.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-05 19:00 ` [PATCH] Add AddressSanitizer annotations to std::vector Jonathan Wakely
  2017-07-05 19:17   ` Jonathan Wakely
  2017-07-05 19:44   ` Yuri Gribov
@ 2017-07-06 17:23   ` Ivan Baravy
  2017-07-10 12:19     ` Jonathan Wakely
  2 siblings, 1 reply; 7+ messages in thread
From: Ivan Baravy @ 2017-07-06 17:23 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches, Martin Liška, Jakub Jelinek

On 07/05/2017 10:00 PM, Jonathan Wakely wrote:
> This patch adds AddressSanitizer annotations to std::vector, so that
> ASan can detect out-of-bounds accesses to the unused capacity of a
> vector. e.g.
> 
>   std::vector<int> v(2);
>   int* p = v.data();
>   v.pop_back();
>   return p[1];  // ERROR
> 
> This cannot be detected by Debug Mode, but with these annotations ASan
> knows that only v.data()[0] is valid and will give an error.
> 
> The annotations are only enabled for vector<T, std::allocator<T>> and
> only when std::allocator's base class is either malloc_allocator or
> new_allocator. For other allocators the memory might not come from the
> freestore and so isn't tracked by ASan.
> 
> Something similar has been on the google branches for some time:
> https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=207517
> This patch is a complete rewrite from scratch, because the google code
> was not exception safe. If an exception happened while appending
> elements to a vector, so that the size didn't change, the google code
> did not undo the annotation for the increased size. It also didn't
> annotate before deallocating, to mark the unused capacity as valid
> again.
> 
> We can probably do similar annotations for std::deque, so that
> partially filled pages are annotated. I also have a patch for
> shared_ptr so that objects created by make_shared can be marked as
> invalid after they're destroyed.

Could you share your plans on sanitization of other standard containers?
My particular interest is in std::string which I'm working on now.

Also, will you backport the feature to GCC7 and GCC6?

> 	* config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
> 	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
> 	* config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
> 	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
> 	* include/bits/stl_vector.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
> 	(_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
> 	(_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
> 	(_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
> 	(_GLIBCXX_ASAN_ANNOTATE_SHRINK, _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
> 	Define annotation helper types and macros.
> 	(vector::~vector, vector::push_back, vector::pop_back)
> 	(vector::_M_erase_at_end): Add annotations.
> 	* include/bits/vector.tcc (vector::reserve, vector::emplace_back)
> 	(vector::insert, vector::_M_erase, vector::operator=)
> 	(vector::_M_fill_assign, vector::_M_assign_aux)
> 	(vector::_M_insert_rval, vector::_M_emplace_aux)
> 	(vector::_M_insert_aux, vector::_M_realloc_insert)
> 	(vector::_M_fill_insert, vector::_M_default_append)
> 	(vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.
> 
> Tested x86_64-linux (using -fsanitize=address, with some local patches
> to the testsuite) and powerpc64le-linux.
> 
> I plan to commit this to trunk tomorrow.
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-06 17:23   ` Ivan Baravy
@ 2017-07-10 12:19     ` Jonathan Wakely
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-10 12:19 UTC (permalink / raw)
  To: Ivan Baravy; +Cc: libstdc++, gcc-patches, Martin Liška, Jakub Jelinek

On 06/07/17 20:23 +0300, Ivan Baravy wrote:
>On 07/05/2017 10:00 PM, Jonathan Wakely wrote:
>> This patch adds AddressSanitizer annotations to std::vector, so that
>> ASan can detect out-of-bounds accesses to the unused capacity of a
>> vector. e.g.
>>
>>   std::vector<int> v(2);
>>   int* p = v.data();
>>   v.pop_back();
>>   return p[1];  // ERROR
>>
>> This cannot be detected by Debug Mode, but with these annotations ASan
>> knows that only v.data()[0] is valid and will give an error.
>>
>> The annotations are only enabled for vector<T, std::allocator<T>> and
>> only when std::allocator's base class is either malloc_allocator or
>> new_allocator. For other allocators the memory might not come from the
>> freestore and so isn't tracked by ASan.
>>
>> Something similar has been on the google branches for some time:
>> https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=207517
>> This patch is a complete rewrite from scratch, because the google code
>> was not exception safe. If an exception happened while appending
>> elements to a vector, so that the size didn't change, the google code
>> did not undo the annotation for the increased size. It also didn't
>> annotate before deallocating, to mark the unused capacity as valid
>> again.
>>
>> We can probably do similar annotations for std::deque, so that
>> partially filled pages are annotated. I also have a patch for
>> shared_ptr so that objects created by make_shared can be marked as
>> invalid after they're destroyed.
>
>Could you share your plans on sanitization of other standard containers?
>My particular interest is in std::string which I'm working on now.

I might make similar changes to std::deque, but not immediately. I
have no plans to do anything with std::string (because you said you're
working on it).

>Also, will you backport the feature to GCC7 and GCC6?

No, probably not.

>> 	* config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
>> 	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
>> 	* config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
>> 	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
>> 	* include/bits/stl_vector.h [_GLIBCXX_SANITIZE_STD_ALLOCATOR]
>> 	(_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
>> 	(_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
>> 	(_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
>> 	(_GLIBCXX_ASAN_ANNOTATE_SHRINK, _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
>> 	Define annotation helper types and macros.
>> 	(vector::~vector, vector::push_back, vector::pop_back)
>> 	(vector::_M_erase_at_end): Add annotations.
>> 	* include/bits/vector.tcc (vector::reserve, vector::emplace_back)
>> 	(vector::insert, vector::_M_erase, vector::operator=)
>> 	(vector::_M_fill_assign, vector::_M_assign_aux)
>> 	(vector::_M_insert_rval, vector::_M_emplace_aux)
>> 	(vector::_M_insert_aux, vector::_M_realloc_insert)
>> 	(vector::_M_fill_insert, vector::_M_default_append)
>> 	(vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.
>>
>> Tested x86_64-linux (using -fsanitize=address, with some local patches
>> to the testsuite) and powerpc64le-linux.
>>
>> I plan to commit this to trunk tomorrow.
>>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Add AddressSanitizer annotations to std::vector
  2017-07-05 20:24     ` Jonathan Wakely
@ 2017-07-21 16:07       ` Jonathan Wakely
  0 siblings, 0 replies; 7+ messages in thread
From: Jonathan Wakely @ 2017-07-21 16:07 UTC (permalink / raw)
  To: Yuri Gribov
  Cc: libstdc++,
	GCC Patches, Martin Liška, Jakub Jelinek, Kostya Serebryany

[-- Attachment #1: Type: text/plain, Size: 1820 bytes --]

On 05/07/17 21:24 +0100, Jonathan Wakely wrote:
>On 05/07/17 20:44 +0100, Yuri Gribov wrote:
>>On Wed, Jul 5, 2017 at 8:00 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
>>>This patch adds AddressSanitizer annotations to std::vector, so that
>>>ASan can detect out-of-bounds accesses to the unused capacity of a
>>>vector. e.g.
>>>
>>> std::vector<int> v(2);
>>> int* p = v.data();
>>> v.pop_back();
>>> return p[1];  // ERROR
>>>
>>>This cannot be detected by Debug Mode, but with these annotations ASan
>>>knows that only v.data()[0] is valid and will give an error.
>>>
>>>The annotations are only enabled for vector<T, std::allocator<T>> and
>>>only when std::allocator's base class is either malloc_allocator or
>>>new_allocator. For other allocators the memory might not come from the
>>>freestore and so isn't tracked by ASan.
>>
>>One important issue with enabling this by default is that it may
>>(will?) break separate sanitization (which is extremely important
>>feature in practice). If one part of application is sanitized but the
>>other isn't and some poor std::vector is push_back'ed in latter and
>>then accessed in former, we'll get a false positive because push_back
>>wouldn't properly annotate memory.
>
>Good point.
>
>>Perhaps hide this under a compilation flag (disabled by default)?
>
>If you define _GLIBCXX_SANITIZE_STD_ALLOCATOR to 0 the annotations are
>disabled. To make them disabled by default would need some changes, to
>use separate macros for "the std::allocator base class can be
>sanitized" and "the user wants std::vector to be sanitized".
>
>I'll do that before committing.


Here's what I've committed.  std::vector<T, std::allocator<T>>
operations are not annotated unless 
_GLIBCXX_SANITIZE_VECTOR is defined.

Tested powerpc64le-linux and x86_64-linux, committed to trunk.



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 19837 bytes --]

commit 4212dcf491c1187be79c9c905d57eaf4bc17fece
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jul 5 13:25:21 2017 +0100

    Add AddressSanitizer annotations to std::vector
    
    	* config/allocator/malloc_allocator_base.h [__SANITIZE_ADDRESS__]
    	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
    	* config/allocator/new_allocator_base.h [__SANITIZE_ADDRESS__]
    	(_GLIBCXX_SANITIZE_STD_ALLOCATOR): Define.
    	* doc/xml/manual/using.xml (_GLIBCXX_SANITIZE_VECTOR): Document macro.
    	* include/bits/stl_vector.h [_GLIBCXX_SANITIZE_VECTOR]
    	(_Vector_impl::_Asan, _Vector_impl::_Asan::_Reinit)
    	(_Vector_impl::_Asan::_Grow, _GLIBCXX_ASAN_ANNOTATE_REINIT)
    	(_GLIBCXX_ASAN_ANNOTATE_GROW, _GLIBCXX_ASAN_ANNOTATE_GREW)
    	(_GLIBCXX_ASAN_ANNOTATE_SHRINK, _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC):
    	Define annotation helper types and macros.
    	(vector::~vector, vector::push_back, vector::pop_back)
    	(vector::_M_erase_at_end): Add annotations.
    	* include/bits/vector.tcc (vector::reserve, vector::emplace_back)
    	(vector::insert, vector::_M_erase, vector::operator=)
    	(vector::_M_fill_assign, vector::_M_assign_aux)
    	(vector::_M_insert_rval, vector::_M_emplace_aux)
    	(vector::_M_insert_aux, vector::_M_realloc_insert)
    	(vector::_M_fill_insert, vector::_M_default_append)
    	(vector::_M_shrink_to_fit, vector::_M_range_insert): Annotate.

diff --git a/libstdc++-v3/config/allocator/malloc_allocator_base.h b/libstdc++-v3/config/allocator/malloc_allocator_base.h
index b091bbc..54e0837 100644
--- a/libstdc++-v3/config/allocator/malloc_allocator_base.h
+++ b/libstdc++-v3/config/allocator/malloc_allocator_base.h
@@ -52,4 +52,8 @@ namespace std
 # define __allocator_base  __gnu_cxx::malloc_allocator
 #endif
 
+#if defined(__SANITIZE_ADDRESS__) && !defined(_GLIBCXX_SANITIZE_STD_ALLOCATOR)
+# define _GLIBCXX_SANITIZE_STD_ALLOCATOR 1
+#endif
+
 #endif
diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h
index 3d2bb67..e776ed3 100644
--- a/libstdc++-v3/config/allocator/new_allocator_base.h
+++ b/libstdc++-v3/config/allocator/new_allocator_base.h
@@ -52,4 +52,8 @@ namespace std
 # define __allocator_base  __gnu_cxx::new_allocator
 #endif
 
+#if defined(__SANITIZE_ADDRESS__) && !defined(_GLIBCXX_SANITIZE_STD_ALLOCATOR)
+# define _GLIBCXX_SANITIZE_STD_ALLOCATOR 1
+#endif
+
 #endif
diff --git a/libstdc++-v3/doc/xml/manual/using.xml b/libstdc++-v3/doc/xml/manual/using.xml
index 5c0e1b9..6ce29fd 100644
--- a/libstdc++-v3/doc/xml/manual/using.xml
+++ b/libstdc++-v3/doc/xml/manual/using.xml
@@ -991,6 +991,24 @@ g++ -Winvalid-pch -I. -include stdc++.h -H -g -O2 hello.cc -o test.exe
     </listitem></varlistentry>
     </variablelist>
 
+    <varlistentry><term><code>_GLIBCXX_SANITIZE_VECTOR</code></term>
+    <listitem>
+      <para>
+	Undefined by default. When defined, <classname>std::vector</classname>
+        operations will be annotated so that AddressSanitizer can detect
+        invalid accesses to the unused capacity of a
+        <classname>std::vector</classname>. These annotations are only
+        enabled for
+        <classname>std::vector&lt;T, std::allocator&lt;T&gt;&gt;</classname>
+        and only when <classname>std::allocator</classname> is derived from
+        <xref linkend="allocator.impl"><classname>new_allocator</classname>
+        or <classname>malloc_allocator</classname></xref>. The annotations
+        must be present on all vector operations or none, so this macro must
+        be defined to the same value for all translation units that create,
+        destroy or modify vectors.
+      </para>
+    </listitem></varlistentry>
+
   </section>
 
 <section xml:id="manual.intro.using.abi" xreflabel="Dual ABI">
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 7ee3ce9..c7787f7 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -65,6 +65,12 @@
 
 #include <debug/assertions.h>
 
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
+extern "C" void
+__sanitizer_annotate_contiguous_container(const void*, const void*,
+					  const void*, const void*);
+#endif
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
@@ -106,6 +112,121 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+
+#if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
+	template<typename = _Tp_alloc_type>
+	  struct _Asan
+	  {
+	    typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>
+	      ::size_type size_type;
+
+	    static void _S_shrink(_Vector_impl&, size_type) { }
+	    static void _S_on_dealloc(_Vector_impl&) { }
+
+	    typedef _Vector_impl& _Reinit;
+
+	    struct _Grow
+	    {
+	      _Grow(_Vector_impl&, size_type) { }
+	      void _M_grew(size_type) { }
+	    };
+	  };
+
+	// Enable ASan annotations for memory obtained from std::allocator.
+	template<typename _Up>
+	  struct _Asan<allocator<_Up> >
+	  {
+	    typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>
+	      ::size_type size_type;
+
+	    // Adjust ASan annotation for [_M_start, _M_end_of_storage) to
+	    // mark end of valid region as __curr instead of __prev.
+	    static void
+	    _S_adjust(_Vector_impl& __impl, pointer __prev, pointer __curr)
+	    {
+	      __sanitizer_annotate_contiguous_container(__impl._M_start,
+		  __impl._M_end_of_storage, __prev, __curr);
+	    }
+
+	    static void
+	    _S_grow(_Vector_impl& __impl, size_type __n)
+	    { _S_adjust(__impl, __impl._M_finish, __impl._M_finish + __n); }
+
+	    static void
+	    _S_shrink(_Vector_impl& __impl, size_type __n)
+	    { _S_adjust(__impl, __impl._M_finish + __n, __impl._M_finish); }
+
+	    static void
+	    _S_on_dealloc(_Vector_impl& __impl)
+	    {
+	      if (__impl._M_start)
+		_S_adjust(__impl, __impl._M_finish, __impl._M_end_of_storage);
+	    }
+
+	    // Used on reallocation to tell ASan unused capacity is invalid.
+	    struct _Reinit
+	    {
+	      explicit _Reinit(_Vector_impl& __impl) : _M_impl(__impl)
+	      {
+		// Mark unused capacity as valid again before deallocating it.
+		_S_on_dealloc(_M_impl);
+	      }
+
+	      ~_Reinit()
+	      {
+		// Mark unused capacity as invalid after reallocation.
+		if (_M_impl._M_start)
+		  _S_adjust(_M_impl, _M_impl._M_end_of_storage,
+			    _M_impl._M_finish);
+	      }
+
+	      _Vector_impl& _M_impl;
+
+#if __cplusplus >= 201103L
+	      _Reinit(const _Reinit&) = delete;
+	      _Reinit& operator=(const _Reinit&) = delete;
+#endif
+	    };
+
+	    // Tell ASan when unused capacity is initialized to be valid.
+	    struct _Grow
+	    {
+	      _Grow(_Vector_impl& __impl, size_type __n)
+	      : _M_impl(__impl), _M_n(__n)
+	      { _S_grow(_M_impl, __n); }
+
+	      ~_Grow() { if (_M_n) _S_shrink(_M_impl, _M_n); }
+
+	      void _M_grew(size_type __n) { _M_n -= __n; }
+
+#if __cplusplus >= 201103L
+	      _Grow(const _Grow&) = delete;
+	      _Grow& operator=(const _Grow&) = delete;
+#endif
+	    private:
+	      _Vector_impl& _M_impl;
+	      size_type _M_n;
+	    };
+	  };
+
+#define _GLIBCXX_ASAN_ANNOTATE_REINIT \
+  typename _Base::_Vector_impl::template _Asan<>::_Reinit const \
+	__attribute__((__unused__)) __reinit_guard(this->_M_impl)
+#define _GLIBCXX_ASAN_ANNOTATE_GROW(n) \
+  typename _Base::_Vector_impl::template _Asan<>::_Grow \
+	__attribute__((__unused__)) __grow_guard(this->_M_impl, (n))
+#define _GLIBCXX_ASAN_ANNOTATE_GREW(n) __grow_guard._M_grew(n)
+#define _GLIBCXX_ASAN_ANNOTATE_SHRINK(n) \
+  _Base::_Vector_impl::template _Asan<>::_S_shrink(this->_M_impl, n)
+#define _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC \
+  _Base::_Vector_impl::template _Asan<>::_S_on_dealloc(this->_M_impl)
+#else // ! (_GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR)
+#define _GLIBCXX_ASAN_ANNOTATE_REINIT
+#define _GLIBCXX_ASAN_ANNOTATE_GROW(n)
+#define _GLIBCXX_ASAN_ANNOTATE_GREW(n)
+#define _GLIBCXX_ASAN_ANNOTATE_SHRINK(n)
+#define _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC
+#endif // _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
       };
 
     public:
@@ -159,8 +280,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
-      { _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage
-		      - this->_M_impl._M_start); }
+      {
+	_M_deallocate(_M_impl._M_start,
+		      _M_impl._M_end_of_storage - _M_impl._M_start);
+      }
 
     public:
       _Vector_impl _M_impl;
@@ -431,8 +554,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  responsibility.
        */
       ~vector() _GLIBCXX_NOEXCEPT
-      { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-		      _M_get_Tp_allocator()); }
+      {
+	std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+		      _M_get_Tp_allocator());
+	_GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC;
+      }
 
       /**
        *  @brief  %Vector assignment operator.
@@ -940,9 +1066,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     __x);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_realloc_insert(end(), __x);
@@ -977,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	__glibcxx_requires_nonempty();
 	--this->_M_impl._M_finish;
 	_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
+	_GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
       }
 
 #if __cplusplus >= 201103L
@@ -1510,8 +1639,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       void
       _M_erase_at_end(pointer __pos) _GLIBCXX_NOEXCEPT
       {
-	std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator());
-	this->_M_impl._M_finish = __pos;
+	if (size_type __n = this->_M_impl._M_finish - __pos)
+	  {
+	    std::_Destroy(__pos, this->_M_impl._M_finish,
+			  _M_get_Tp_allocator());
+	    this->_M_impl._M_finish = __pos;
+	    _GLIBCXX_ASAN_ANNOTATE_SHRINK(__n);
+	  }
       }
 
       iterator
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index da4a64c..b9dff0e 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -73,6 +73,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  pointer __tmp = _M_allocate_and_copy(__n,
 	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
 	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+	  _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	  std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			_M_get_Tp_allocator());
 	  _M_deallocate(this->_M_impl._M_start,
@@ -97,9 +98,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       {
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     std::forward<_Args>(__args)...);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_realloc_insert(end(), std::forward<_Args>(__args)...);
@@ -122,9 +125,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	if (__position == end())
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     __x);
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  {
@@ -157,6 +162,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_GLIBCXX_MOVE3(__position + 1, end(), __position);
       --this->_M_impl._M_finish;
       _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
+      _GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
       return __position;
     }
 
@@ -181,6 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (&__x != this)
 	{
+	  _GLIBCXX_ASAN_ANNOTATE_REINIT;
 #if __cplusplus >= 201103L
 	  if (_Alloc_traits::_S_propagate_on_copy_assign())
 	    {
@@ -245,10 +252,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       else if (__n > size())
 	{
 	  std::fill(begin(), end(), __val);
+	  const size_type __add = __n - size();
+	  _GLIBCXX_ASAN_ANNOTATE_GROW(__add);
 	  this->_M_impl._M_finish =
 	    std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
-					  __n - size(), __val,
-					  _M_get_Tp_allocator());
+					  __add, __val, _M_get_Tp_allocator());
+	  _GLIBCXX_ASAN_ANNOTATE_GREW(__add);
 	}
       else
         _M_erase_at_end(std::fill_n(this->_M_impl._M_start, __n, __val));
@@ -284,6 +293,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (__len > capacity())
 	  {
 	    pointer __tmp(_M_allocate_and_copy(__len, __first, __last));
+	    _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			  _M_get_Tp_allocator());
 	    _M_deallocate(this->_M_impl._M_start,
@@ -300,10 +310,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _ForwardIterator __mid = __first;
 	    std::advance(__mid, size());
 	    std::copy(__first, __mid, this->_M_impl._M_start);
+	    const size_type __attribute__((__unused__)) __n = __len - size();
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_copy_a(__mid, __last,
 					  this->_M_impl._M_finish,
 					  _M_get_Tp_allocator());
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 	  }
       }
 
@@ -317,9 +330,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	if (__position == cend())
 	  {
+	    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				     std::move(__v));
 	    ++this->_M_impl._M_finish;
+	    _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	  }
 	else
 	  _M_insert_aux(begin() + __n, std::move(__v));
@@ -340,9 +355,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
 	  if (__position == cend())
 	    {
+	      _GLIBCXX_ASAN_ANNOTATE_GROW(1);
 	      _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
 				       std::forward<_Args>(__args)...);
 	      ++this->_M_impl._M_finish;
+	      _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 	    }
 	  else
 	    {
@@ -370,10 +387,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     _M_insert_aux(iterator __position, const _Tp& __x)
 #endif
     {
+      _GLIBCXX_ASAN_ANNOTATE_GROW(1);
       _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
-			       _GLIBCXX_MOVE(*(this->_M_impl._M_finish
-					       - 1)));
+			       _GLIBCXX_MOVE(*(this->_M_impl._M_finish - 1)));
       ++this->_M_impl._M_finish;
+      _GLIBCXX_ASAN_ANNOTATE_GREW(1);
 #if __cplusplus < 201103L
       _Tp __x_copy = __x;
 #endif
@@ -443,11 +461,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _M_deallocate(__new_start, __len);
 	  __throw_exception_again;
 	}
+      _GLIBCXX_ASAN_ANNOTATE_REINIT;
       std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 		    _M_get_Tp_allocator());
       _M_deallocate(this->_M_impl._M_start,
-		    this->_M_impl._M_end_of_storage
-		    - this->_M_impl._M_start);
+		    this->_M_impl._M_end_of_storage - this->_M_impl._M_start);
       this->_M_impl._M_start = __new_start;
       this->_M_impl._M_finish = __new_finish;
       this->_M_impl._M_end_of_storage = __new_start + __len;
@@ -473,11 +491,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	      pointer __old_finish(this->_M_impl._M_finish);
 	      if (__elems_after > __n)
 		{
+		  _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		  std::__uninitialized_move_a(this->_M_impl._M_finish - __n,
 					      this->_M_impl._M_finish,
 					      this->_M_impl._M_finish,
 					      _M_get_Tp_allocator());
 		  this->_M_impl._M_finish += __n;
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 		  _GLIBCXX_MOVE_BACKWARD3(__position.base(),
 					  __old_finish - __n, __old_finish);
 		  std::fill(__position.base(), __position.base() + __n,
@@ -485,15 +505,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		}
 	      else
 		{
+		  _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		  this->_M_impl._M_finish =
 		    std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
 						  __n - __elems_after,
 						  __x_copy,
 						  _M_get_Tp_allocator());
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
 		  std::__uninitialized_move_a(__position.base(), __old_finish,
 					      this->_M_impl._M_finish,
 					      _M_get_Tp_allocator());
 		  this->_M_impl._M_finish += __elems_after;
+		  _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
 		  std::fill(__position.base(), __old_finish, __x_copy);
 		}
 	    }
@@ -536,6 +559,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  _M_deallocate(__new_start, __len);
 		  __throw_exception_again;
 		}
+	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			    _M_get_Tp_allocator());
 	      _M_deallocate(this->_M_impl._M_start,
@@ -559,9 +583,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  if (size_type(this->_M_impl._M_end_of_storage
 			- this->_M_impl._M_finish) >= __n)
 	    {
+	      _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 	      this->_M_impl._M_finish =
 		std::__uninitialized_default_n_a(this->_M_impl._M_finish,
 						 __n, _M_get_Tp_allocator());
+	      _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 	    }
 	  else
 	    {
@@ -587,6 +613,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  _M_deallocate(__new_start, __len);
 		  __throw_exception_again;
 		}
+	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			    _M_get_Tp_allocator());
 	      _M_deallocate(this->_M_impl._M_start,
@@ -606,6 +633,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (capacity() == size())
 	return false;
+      _GLIBCXX_ASAN_ANNOTATE_REINIT;
       return std::__shrink_to_fit_aux<vector>::_S_do_it(*this);
     }
 #endif
@@ -648,11 +676,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		pointer __old_finish(this->_M_impl._M_finish);
 		if (__elems_after > __n)
 		  {
+		    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		    std::__uninitialized_move_a(this->_M_impl._M_finish - __n,
 						this->_M_impl._M_finish,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __n;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 		    _GLIBCXX_MOVE_BACKWARD3(__position.base(),
 					    __old_finish - __n, __old_finish);
 		    std::copy(__first, __last, __position);
@@ -661,15 +691,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  {
 		    _ForwardIterator __mid = __first;
 		    std::advance(__mid, __elems_after);
+		    _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
 		    std::__uninitialized_copy_a(__mid, __last,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __n - __elems_after;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
 		    std::__uninitialized_move_a(__position.base(),
 						__old_finish,
 						this->_M_impl._M_finish,
 						_M_get_Tp_allocator());
 		    this->_M_impl._M_finish += __elems_after;
+		    _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
 		    std::copy(__first, __mid, __position);
 		  }
 	      }
@@ -701,6 +734,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		    _M_deallocate(__new_start, __len);
 		    __throw_exception_again;
 		  }
+		_GLIBCXX_ASAN_ANNOTATE_REINIT;
 		std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			      _M_get_Tp_allocator());
 		_M_deallocate(this->_M_impl._M_start,
@@ -909,4 +943,9 @@ _GLIBCXX_END_NAMESPACE_VERSION
 
 #endif // C++11
 
+#undef _GLIBCXX_ASAN_ANNOTATE_REINIT
+#undef _GLIBCXX_ASAN_ANNOTATE_GROW
+#undef _GLIBCXX_ASAN_ANNOTATE_GREW
+#undef _GLIBCXX_ASAN_ANNOTATE_SHRINK
+
 #endif /* _VECTOR_TCC */

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-07-21 16:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20170705190136epcas3p1766dd72f285b83ab5df4a8474db79b05@epcas3p1.samsung.com>
2017-07-05 19:00 ` [PATCH] Add AddressSanitizer annotations to std::vector Jonathan Wakely
2017-07-05 19:17   ` Jonathan Wakely
2017-07-05 19:44   ` Yuri Gribov
2017-07-05 20:24     ` Jonathan Wakely
2017-07-21 16:07       ` Jonathan Wakely
2017-07-06 17:23   ` Ivan Baravy
2017-07-10 12:19     ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).