[libcxx-commits] [libcxx] fb7d255 - [libc++][string] Replace ASAN volatile wrapper with memory barrier (#184693)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 5 21:09:57 PST 2026


Author: Vitaly Buka
Date: 2026-03-05T21:09:53-08:00
New Revision: fb7d25556a3ac6b48deaa63a9195cf47b830e372

URL: https://github.com/llvm/llvm-project/commit/fb7d25556a3ac6b48deaa63a9195cf47b830e372
DIFF: https://github.com/llvm/llvm-project/commit/fb7d25556a3ac6b48deaa63a9195cf47b830e372.diff

LOG: [libc++][string] Replace ASAN volatile wrapper with memory barrier (#184693)

The previous `_LIBCPP_ASAN_VOLATILE_WRAPPER` approach was used to
prevent
speculative loads of string data before the short/long state was
determined. This patch replaces that mechanism with a more explicit
`__annotate_memory_barrier()` using an empty volatile assembly block.

This PR is inspired by #183457 and by downstream false positive on
`__get_long_size`. It fails same way as `__get_long_pointer` before we
have
`_LIBCPP_ASAN_VOLATILE_WRAPPER`. Barrier approach avoids
expanding `_LIBCPP_ASAN_VOLATILE_WRAPPER` for size_t, and to
in general looks more readable.

I failed to create reasonable reproducer for test, I suspect it requires
precise set of compiler flags, and libc++ site_config which will be hard
to maintain in test.

Added: 
    

Modified: 
    libcxx/include/string

Removed: 
    


################################################################################
diff  --git a/libcxx/include/string b/libcxx/include/string
index 37f00c2d189df..fb04eb67d0297 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -770,30 +770,6 @@ public:
       void>;
 #  endif
 
-#  if _LIBCPP_ENABLE_ASAN_CONTAINER_CHECKS_FOR_STRING
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __asan_volatile_wrapper(pointer const& __ptr) const {
-    if (__libcpp_is_constant_evaluated())
-      return __ptr;
-
-    pointer volatile __copy_ptr = __ptr;
-
-    return const_cast<pointer&>(__copy_ptr);
-  }
-
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer
-  __asan_volatile_wrapper(const_pointer const& __ptr) const {
-    if (__libcpp_is_constant_evaluated())
-      return __ptr;
-
-    const_pointer volatile __copy_ptr = __ptr;
-
-    return const_cast<const_pointer&>(__copy_ptr);
-  }
-#    define _LIBCPP_ASAN_VOLATILE_WRAPPER(PTR) __asan_volatile_wrapper(PTR)
-#  else
-#    define _LIBCPP_ASAN_VOLATILE_WRAPPER(PTR) PTR
-#  endif
-
   static_assert(!is_array<value_type>::value, "Character type of basic_string must not be an array");
   static_assert(is_standard_layout<value_type>::value, "Character type of basic_string must be standard-layout");
   static_assert(is_trivially_default_constructible<value_type>::value,
@@ -2211,6 +2187,7 @@ private:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS size_type
   __get_short_size() const _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(!__rep_.__s.__is_long_, "String has to be short when trying to get the short size");
+    __annotate_memory_barrier();
     return __rep_.__s.__size_;
   }
 
@@ -2220,6 +2197,7 @@ private:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_size() const _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long size");
+    __annotate_memory_barrier();
     return __rep_.__l.__size_;
   }
 
@@ -2232,27 +2210,32 @@ private:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long capacity");
+    __annotate_memory_barrier();
     return __rep_.__l.__cap_ * __endian_factor;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer");
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
+    __annotate_memory_barrier();
+    return __rep_.__l.__data_;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_pointer __get_long_pointer() const _NOEXCEPT {
     _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer");
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_);
+    __annotate_memory_barrier();
+    return __rep_.__l.__data_;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS pointer
   __get_short_pointer() _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<pointer>::pointer_to(__rep_.__s.__data_[0]));
+    __annotate_memory_barrier();
+    return pointer_traits<pointer>::pointer_to(__rep_.__s.__data_[0]);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS const_pointer
   __get_short_pointer() const _NOEXCEPT {
-    return _LIBCPP_ASAN_VOLATILE_WRAPPER(pointer_traits<const_pointer>::pointer_to(__rep_.__s.__data_[0]));
+    __annotate_memory_barrier();
+    return pointer_traits<const_pointer>::pointer_to(__rep_.__s.__data_[0]);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_pointer() _NOEXCEPT {
@@ -2336,6 +2319,16 @@ private:
 #  endif
   }
 
+  // Prevents speculative load before short/long state is determined.
+  // The following functions are no-ops outside of AddressSanitizer mode.
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_memory_barrier() const {
+#  if _LIBCPP_ENABLE_ASAN_CONTAINER_CHECKS_FOR_STRING
+    if (__libcpp_is_constant_evaluated())
+      return;
+    asm volatile("" ::: "memory");
+#  endif
+  }
+
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT {
     __annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1);
   }


        


More information about the libcxx-commits mailing list