[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 Sep 8 03:23:50 PDT 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/152967

>From fa492fb365d54e344cdb7da1ee258aceef1b3c40 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/__vector/vector.h | 103 +++++++++++++------------------
 1 file changed, 43 insertions(+), 60 deletions(-)

diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 4307e78f6ddbc..c4d56a49f218f 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -65,6 +65,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>
@@ -479,9 +480,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
@@ -548,9 +550,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);
@@ -599,7 +601,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();
@@ -659,8 +661,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 void __append(size_type __n);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n, const_reference __x);
@@ -708,9 +709,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>
@@ -737,33 +738,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 {
@@ -850,6 +829,7 @@ template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
   __annotate_delete();
+  auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
   auto __new_begin = __v.__begin_ - (__end_ - __begin_);
   std::__uninitialized_allocator_relocate(
       this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin));
@@ -859,7 +839,6 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
   std::swap(this->__end_, __v.__end_);
   std::swap(this->__cap_, __v.__cap_);
   __v.__first_ = __v.__begin_;
-  __annotate_new(size());
 }
 
 // __swap_out_circular_buffer relocates the objects in [__begin_, __p) into the front of __v, the objects in
@@ -870,6 +849,7 @@ template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
 vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __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_)
@@ -889,7 +869,6 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
   std::swap(this->__end_, __v.__end_);
   std::swap(this->__cap_, __v.__cap_);
   __v.__first_ = __v.__begin_;
-  __annotate_new(size());
   return __ret;
 }
 
@@ -923,10 +902,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_;
   }
 }
 
@@ -939,19 +920,21 @@ _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) {
+  auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
+  __end_       = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __end_);
 }
 
 //  Default constructs __n objects starting at __end_
@@ -1068,12 +1051,11 @@ vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last,
     if (__new_size > size()) {
 #if _LIBCPP_STD_VER >= 23
       auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in;
-      __construct_at_end(std::move(__mid), std::move(__last), __new_size - size());
 #else
       _Iterator __mid = std::next(__first, size());
       std::copy(__first, __mid, this->__begin_);
-      __construct_at_end(__mid, __last, __new_size - size());
 #endif
+      __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);
@@ -1081,7 +1063,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));
   }
 }
 
@@ -1189,15 +1171,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);
 }
 
@@ -1338,13 +1321,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(__first, __dx, __p);



More information about the libcxx-commits mailing list