[libcxx-commits] [libcxx] [libc++] Refactor vector's ASan annotations to only ever delete and add the annotations (PR #152967)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Feb 23 11:46:43 PST 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/152967
>From cfb8e6b76386397efb2805fc1d8a702f8ee8fa66 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 11 Aug 2025 10:02:01 +0200
Subject: [PATCH] [libc++] Refactor vector's ASan annotations to only ever
delete and add the annotations
---
libcxx/include/__utility/scope_guard.h | 3 +
libcxx/include/__vector/vector.h | 103 +++++++++++--------------
2 files changed, 47 insertions(+), 59 deletions(-)
diff --git a/libcxx/include/__utility/scope_guard.h b/libcxx/include/__utility/scope_guard.h
index db4f0e4c73a2a..19da144d5c980 100644
--- a/libcxx/include/__utility/scope_guard.h
+++ b/libcxx/include/__utility/scope_guard.h
@@ -37,7 +37,10 @@ class __scope_guard {
// C++14 doesn't have mandatory RVO, so we have to provide a declaration even though no compiler will ever generate
// a call to the move constructor.
#if _LIBCPP_STD_VER <= 14
+ _LIBCPP_DIAGNOSTIC_PUSH
+ _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wundefined-internal")
__scope_guard(__scope_guard&&);
+ _LIBCPP_DIAGNOSTIC_POP
#else
__scope_guard(__scope_guard&&) = delete;
#endif
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index d1c3f7ddcec1c..2b1234562f5fa 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -64,6 +64,7 @@
#include <__utility/is_pointer_in_range.h>
#include <__utility/move.h>
#include <__utility/pair.h>
+#include <__utility/scope_guard.h>
#include <__utility/swap.h>
#include <initializer_list>
#include <limits>
@@ -473,9 +474,10 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __emplace_back_assume_capacity(_Args&&... __args) {
_LIBCPP_ASSERT_INTERNAL(
size() < capacity(), "We assume that we have enough space to insert an element at the end of the vector");
- _ConstructTransaction __tx(*this, 1);
- __alloc_traits::construct(this->__alloc_, std::__to_address(__tx.__pos_), std::forward<_Args>(__args)...);
- ++__tx.__pos_;
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end_), std::forward<_Args>(__args)...);
+ ++__end_;
}
#if _LIBCPP_STD_VER >= 23
@@ -556,9 +558,9 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT {
- size_type __old_size = size();
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
__base_destruct_at_end(this->__begin_);
- __annotate_shrink(__old_size);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void resize(size_type __sz);
@@ -607,7 +609,7 @@ class vector {
if (__n > 0) {
__vallocate(__n);
- __construct_at_end(std::move(__first), std::move(__last), __n);
+ __construct_at_end(std::move(__first), std::move(__last));
}
__guard.__complete();
@@ -662,8 +664,7 @@ class vector {
__insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n);
template <class _InputIterator, class _Sentinel>
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
- __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(_InputIterator __first, _Sentinel __last);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __make_iter(pointer __p) _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
@@ -707,9 +708,9 @@ class vector {
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign(vector& __c, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last) _NOEXCEPT {
- size_type __old_size = size();
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
__base_destruct_at_end(__new_last);
- __annotate_shrink(__old_size);
}
template <class... _Args>
@@ -736,33 +737,11 @@ class vector {
__annotate_contiguous_container(data() + size(), data() + capacity());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __annotate_increase(size_type __n) const _NOEXCEPT {
- __annotate_contiguous_container(data() + size(), data() + size() + __n);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __annotate_shrink(size_type __old_size) const _NOEXCEPT {
- __annotate_contiguous_container(data() + __old_size, data() + size());
- }
-
- struct _ConstructTransaction {
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(vector& __v, size_type __n)
- : __v_(__v), __pos_(__v.__end_), __new_end_(__v.__end_ + __n) {
- __v_.__annotate_increase(__n);
- }
-
- _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() {
- __v_.__end_ = __pos_;
- if (__pos_ != __new_end_) {
- __v_.__annotate_shrink(__new_end_ - __v_.__begin_);
- }
- }
-
- vector& __v_;
- pointer __pos_;
- const_pointer const __new_end_;
+ struct __annotate_new_size {
+ vector& __vec_;
- _ConstructTransaction(_ConstructTransaction const&) = delete;
- _ConstructTransaction& operator=(_ConstructTransaction const&) = delete;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotate_new_size(vector& __vec) : __vec_(__vec) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() { __vec_.__annotate_new(__vec_.size()); }
};
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __base_destruct_at_end(pointer __new_last) _NOEXCEPT {
@@ -866,6 +845,7 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_buffer(_SplitBuffer& __v) {
__annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
auto __new_begin = __v.begin() - size();
std::__uninitialized_allocator_relocate(
this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin));
@@ -874,7 +854,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__swap_out_circular_
__swap_layouts(__v);
__v.__set_data(__v.begin());
- __annotate_new(size());
}
// __swap_out_circular_buffer relocates the objects in [__begin_, __p) into the front of __v, the objects in
@@ -885,6 +864,7 @@ template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
vector<_Tp, _Allocator>::__swap_out_circular_buffer(_SplitBuffer& __v, pointer __p) {
__annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
pointer __ret = __v.begin();
// Relocate [__p, __end_) first to avoid having a hole in [__begin_, __end_)
@@ -902,7 +882,6 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(_SplitBuffer& __v, pointer _
__end_ = __begin_; // All the objects have been destroyed by relocating them.
__swap_layouts(__v);
__v.__set_data(__v.begin());
- __annotate_new(size());
return __ret;
}
@@ -936,10 +915,12 @@ vector<_Tp, _Allocator>::__recommend(size_type __new_size) const {
// Postcondition: size() == size() + __n
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(size_type __n) {
- _ConstructTransaction __tx(*this, __n);
- const_pointer __new_end = __tx.__new_end_;
- for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
- __alloc_traits::construct(this->__alloc_, std::__to_address(__pos));
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+
+ for (size_t __i = 0; __i != __n; ++__i) {
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end_));
+ ++__end_;
}
}
@@ -952,19 +933,22 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(s
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void
vector<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) {
- _ConstructTransaction __tx(*this, __n);
- const_pointer __new_end = __tx.__new_end_;
- for (pointer __pos = __tx.__pos_; __pos != __new_end; __tx.__pos_ = ++__pos) {
- __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), __x);
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+
+ for (size_t __i = 0; __i != __n; ++__i) {
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end_), __x);
+ ++__end_;
}
}
template <class _Tp, class _Allocator>
template <class _InputIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
-vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) {
- _ConstructTransaction __tx(*this, __n);
- __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __tx.__pos_);
+vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last) {
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+ __end_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __end_);
}
template <class _Tp, class _Allocator>
@@ -1051,7 +1035,7 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
auto const __size = size();
if (__new_size > __size) {
auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), __size, this->__begin_).first;
- __construct_at_end(std::move(__mid), std::move(__last), __new_size - __size);
+ __construct_at_end(std::move(__mid), std::move(__last));
} else {
pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second;
this->__destruct_at_end(__m);
@@ -1059,7 +1043,7 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
} else {
__vdeallocate();
__vallocate(__recommend(__new_size));
- __construct_at_end(std::move(__first), std::move(__last), __new_size);
+ __construct_at_end(std::move(__first), std::move(__last));
}
}
@@ -1188,15 +1172,16 @@ vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) {
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void
vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointer __to) {
+ __annotate_delete();
+ auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
pointer __old_last = this->__end_;
difference_type __n = __old_last - __to;
- {
- pointer __i = __from_s + __n;
- _ConstructTransaction __tx(*this, __from_e - __i);
- for (pointer __pos = __tx.__pos_; __i < __from_e; ++__i, (void)++__pos, __tx.__pos_ = __pos) {
- __alloc_traits::construct(this->__alloc_, std::__to_address(__pos), std::move(*__i));
- }
+
+ for (pointer __i = __from_s + __n; __i != __from_e; ++__i) {
+ __alloc_traits::construct(this->__alloc_, std::__to_address(__end_), std::move(*__i));
+ ++__end_;
}
+
std::move_backward(__from_s, __from_s + __n, __old_last);
}
@@ -1337,13 +1322,13 @@ vector<_Tp, _Allocator>::__insert_with_size(
if (__n > __dx) {
#if _LIBCPP_STD_VER >= 23
if constexpr (!forward_iterator<_Iterator>) {
- __construct_at_end(std::move(__first), std::move(__last), __n);
+ __construct_at_end(std::move(__first), std::move(__last));
std::rotate(__p, __old_last, this->__end_);
} else
#endif
{
_Iterator __m = std::next(__first, __dx);
- __construct_at_end(__m, __last, __n - __dx);
+ __construct_at_end(__m, __last);
if (__dx > 0) {
__move_range(__p, __old_last, __p + __n);
__insert_assign_n_unchecked<_AlgPolicy>(__first, __dx, __p);
More information about the libcxx-commits
mailing list