Skip to content

Commit

Permalink
Add AddressSanitizer annotations to std::vector
Browse files Browse the repository at this point in the history
	* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@250430 138bc75d-0d04-0410-961f-82ee72b054a4
  • Loading branch information
redi committed Jul 21, 2017
1 parent cdfd915 commit 09cc3d8
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 12 deletions.
23 changes: 23 additions & 0 deletions libstdc++-v3/ChangeLog
@@ -1,3 +1,26 @@
2017-07-20 Jonathan Wakely <jwakely@redhat.com>

* 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.

2017-07-19 Jonathan Wakely <jwakely@redhat.com>

PR libstdc++/81476
Expand Down
4 changes: 4 additions & 0 deletions libstdc++-v3/config/allocator/malloc_allocator_base.h
Expand Up @@ -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
4 changes: 4 additions & 0 deletions libstdc++-v3/config/allocator/new_allocator_base.h
Expand Up @@ -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
18 changes: 18 additions & 0 deletions libstdc++-v3/doc/xml/manual/using.xml
Expand Up @@ -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">
Expand Down
146 changes: 140 additions & 6 deletions libstdc++-v3/include/bits/stl_vector.h
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 09cc3d8

Please sign in to comment.