Description
I was looking at libc++'s implementation of container ASAN annotations and I couldn't understand how __sanitizer_annotate_contiguous_container
works. The documentation here says:
// This annotation tells the Sanitizer tool about the current state of the
/// container so that the tool can report errors when memory from
/// [mid, end) is accessed. Insert this annotation into methods like
/// push_back() or pop_back(). Supply the old and new values of
/// mid(old_mid and new_mid). In the initial
/// state mid == end, so that should be the final state when the
/// container is destroyed or when the container reallocates the storage.
This says that [mid, end)
is the range considered invalid to access, which makes sense. However it also says that the initial state is mid == end
, which means that the whole range [begin, mid) == [begin, end)
is considered valid to access. Shouldn't the initial state be that mid == begin
instead, so that the range [mid, end) == the whole vector
be considered invalid to access?
This also ties into a question I have about our usage in libc++ (CC @AdvenamTacet):
template <class _Tp, class _Allocator>
void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
__annotate_delete();
auto __new_begin = __v.__begin_ - (__end_ - __begin_);
std::__uninitialized_allocator_relocate(__alloc_, __begin_, __end_, __new_begin);
__v.__begin_ = __new_begin;
__end_ = __begin_; // All the objects have been destroyed by relocating them.
std::swap(this->__begin_, __v.__begin_);
std::swap(this->__end_, __v.__end_);
std::swap(this->__cap_, __v.__cap_);
__v.__first_ = __v.__begin_;
__annotate_new(size());
}
__annotate_delete()
basically calls
__sanitizer_annotate_contiguous_container(data(), data() + capacity(),
data() + size(), data() + capacity());
If I understand correctly, this sets the sanitizer state to this (using the beg
end
mid
terminology from the sanitizer documentation, not the terminology inside std::vector
):
beg == data()
end == data() + capacity()
mid == data() + capacity()
This means that after calling __annotate_delete()
, ASAN would consider the range [mid, end) == [data() + capacity(), data() + capacity) == empty-range
as invalid. Is that intended? Is the goal to mark the whole range as accessible so we can then touch it (in __uninitialized_allocator_relocate
) without triggering an ASAN violation?