Skip to content

Commit

Permalink
<vector>: Fix ASan annotations when clearing (microsoft#2464)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
  • Loading branch information
cbezault and StephanTLavavej authored Jan 14, 2022
1 parent 0dc93fc commit 86e22c3
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
20 changes: 17 additions & 3 deletions stl/inc/vector
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,12 @@ private:

_CONSTEXPR20 void _Modify_annotation(const difference_type _Count) const noexcept {
// Extends/shrinks the annotated range by _Count
if (_Count == 0) { // nothing to do
// This also avoids calling _Apply_annotation() with null pointers
// when the vector has zero capacity, see GH-2464.
return;
}

auto& _My_data = _Mypair._Myval2;
_Apply_annotation(_My_data._Myfirst, _My_data._Myend, _My_data._Mylast, _My_data._Mylast + _Count);
}
Expand Down Expand Up @@ -1243,7 +1249,7 @@ private:

// Trim.
_Destroy_range(_Next, _Mylast, _Getal());
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Next - _Mylast));
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Next - _Mylast)); // negative when destroying elements
_Mylast = _Next;

// Append.
Expand Down Expand Up @@ -1586,7 +1592,7 @@ public:

const pointer _Newlast = _Move_unchecked(_Lastptr, _Mylast, _Firstptr);
_Destroy_range(_Newlast, _Mylast, _Getal());
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newlast - _Mylast));
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Newlast - _Mylast)); // negative when destroying elements
_Mylast = _Newlast;
}

Expand All @@ -1598,9 +1604,16 @@ public:
pointer& _Myfirst = _My_data._Myfirst;
pointer& _Mylast = _My_data._Mylast;

if (_Myfirst == _Mylast) { // already empty, nothing to do
// This is an optimization for debug mode: we can avoid taking the debug lock to invalidate iterators.
// Note that when clearing an empty vector, this will preserve past-the-end iterators, which is allowed by
// N4901 [tab:container.seq.req] "a.clear() [...] may invalidate the past-the-end iterator".
return;
}

_My_data._Orphan_all();
_Destroy_range(_Myfirst, _Mylast, _Getal());
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Mylast - _Myfirst));
_ASAN_VECTOR_MODIFY(static_cast<difference_type>(_Myfirst - _Mylast)); // negative when destroying elements
_Mylast = _Myfirst;
}

Expand Down Expand Up @@ -1936,6 +1949,7 @@ private:
_ASAN_VECTOR_CREATE_GUARD;
_Mylast = _Uninitialized_move(_First, _Last, _Myfirst, _Al);
}

return;
}

Expand Down
40 changes: 40 additions & 0 deletions tests/std/tests/GH_002030_asan_annotate_vector/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,44 @@ void test_insert_n_throw() {
}
}

template <class Alloc>
void test_clear() {
using T = typename Alloc::value_type;

vector<T, Alloc> v;
v.push_back(T());
v.assign(v.capacity() + 1, T());
assert(verify_vector(v));
v.clear();
assert(verify_vector(v));
v.clear();
assert(verify_vector(v));
}

template <class Alloc>
void test_empty() {
using T = typename Alloc::value_type;

vector<T, Alloc> v1;
v1.clear();
v1.resize(0);
v1.shrink_to_fit();
v1.assign(0, T());
v1.assign({});
v1 = {};

vector<T, Alloc> v2;
v1.assign(v2.begin(), v2.end());

input_iterator_tester<T, 11> in;
auto e = in.end();
v1.assign(e, e); // empty range of input iterators

vector<T, Alloc> v3;
v1 = v3;
v3 = move(v1);
}

template <class Alloc>
void run_tests() {
test_push_pop<Alloc>();
Expand All @@ -933,6 +971,8 @@ void run_tests() {
test_insert_range<Alloc>();
test_assign<Alloc>();
test_resize<Alloc>();
test_clear<Alloc>();
test_empty<Alloc>();
}

template <class T, template <class, class, class> class AllocT>
Expand Down

0 comments on commit 86e22c3

Please sign in to comment.