@@ -1882,8 +1882,6 @@ public:
18821882 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __clear_and_shrink () _NOEXCEPT;
18831883
18841884private:
1885- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend (size_type __target_capacity);
1886-
18871885 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
18881886 __is_long () const _NOEXCEPT {
18891887 if (__libcpp_is_constant_evaluated () && __builtin_constant_p (__rep_.__l .__is_long_ )) {
@@ -2079,6 +2077,21 @@ private:
20792077# endif
20802078 }
20812079
2080+ // Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2081+ // state at that point, so `size()` can be called safely.
2082+ struct [[__nodiscard__]] __annotation_guard {
2083+ __annotation_guard (const __annotation_guard&) = delete ;
2084+ __annotation_guard& operator =(const __annotation_guard&) = delete ;
2085+
2086+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard (basic_string& __str) : __str_ (__str) {
2087+ __str_.__annotate_delete ();
2088+ }
2089+
2090+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard () { __str_.__annotate_new (__str_.size ()); }
2091+
2092+ basic_string& __str_;
2093+ };
2094+
20822095 template <size_type __a>
20832096 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
20842097 return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3357,7 +3370,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
33573370 if (__requested_capacity <= capacity ())
33583371 return ;
33593372
3360- __shrink_or_extend (__recommend (__requested_capacity));
3373+ __annotation_guard __g (*this );
3374+ auto __allocation = std::__allocate_at_least (__alloc_, __recommend (__requested_capacity) + 1 );
3375+ auto __size = size ();
3376+ __begin_lifetime (__allocation.ptr , __allocation.count );
3377+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), __size + 1 );
3378+ if (__is_long ())
3379+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_cap ());
3380+ __set_long_cap (__allocation.count );
3381+ __set_long_size (__size);
3382+ __set_long_pointer (__allocation.ptr );
33613383}
33623384
33633385template <class _CharT , class _Traits , class _Allocator >
@@ -3366,69 +3388,46 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
33663388 if (__target_capacity == capacity ())
33673389 return ;
33683390
3369- __shrink_or_extend (__target_capacity);
3370- }
3391+ _LIBCPP_ASSERT_INTERNAL (__is_long (), " Trying to shrink small string" );
33713392
3372- template <class _CharT , class _Traits , class _Allocator >
3373- inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3374- basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3375- __annotate_delete ();
3376- auto __guard = std::__make_scope_guard (__annotate_new_size (*this ));
3377- size_type __cap = capacity ();
3378- size_type __sz = size ();
3379-
3380- pointer __new_data, __p;
3381- bool __was_long, __now_long;
3393+ // We're a long string and we're shrinking into the small buffer.
33823394 if (__fits_in_sso (__target_capacity)) {
3383- __was_long = true ;
3384- __now_long = false ;
3385- __new_data = __get_short_pointer ();
3386- __p = __get_long_pointer ();
3387- } else {
3388- if (__target_capacity > __cap) {
3389- // Extend
3390- // - called from reserve should propagate the exception thrown.
3391- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3392- __new_data = __allocation.ptr ;
3393- __target_capacity = __allocation.count - 1 ;
3394- } else {
3395- // Shrink
3396- // - called from shrink_to_fit should not throw.
3397- // - called from reserve may throw but is not required to.
3395+ __annotation_guard __g (*this );
3396+ auto __ptr = __get_long_pointer ();
3397+ auto __size = __get_long_size ();
3398+ auto __cap = __get_long_cap ();
3399+ traits_type::copy (std::__to_address (__get_short_pointer ()), std::__to_address (__ptr), __size + 1 );
3400+ __set_short_size (__size);
3401+ __alloc_traits::deallocate (__alloc_, __ptr, __cap);
3402+ return ;
3403+ }
3404+
33983405# if _LIBCPP_HAS_EXCEPTIONS
3399- try {
3406+ try {
34003407# endif // _LIBCPP_HAS_EXCEPTIONS
3401- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3402-
3403- // The Standard mandates shrink_to_fit() does not increase the capacity.
3404- // With equal capacity keep the existing buffer. This avoids extra work
3405- // due to swapping the elements.
3406- if (__allocation.count - 1 > capacity ()) {
3407- __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3408- return ;
3409- }
3410- __new_data = __allocation.ptr ;
3411- __target_capacity = __allocation.count - 1 ;
3408+ __annotation_guard __g (*this );
3409+ auto __size = size ();
3410+ auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3411+
3412+ // The Standard mandates shrink_to_fit() does not increase the capacity.
3413+ // With equal capacity keep the existing buffer. This avoids extra work
3414+ // due to swapping the elements.
3415+ if (__allocation.count - 1 > capacity ()) {
3416+ __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3417+ return ;
3418+ }
3419+
3420+ __begin_lifetime (__allocation.ptr , __allocation.count );
3421+ auto __ptr = __get_long_pointer ();
3422+ traits_type::copy (std::__to_address (__allocation.ptr ), std::__to_address (__ptr), __size + 1 );
3423+ __alloc_traits::deallocate (__alloc_, __ptr, __get_long_cap ());
3424+ __set_long_cap (__allocation.count );
3425+ __set_long_pointer (__allocation.ptr );
34123426# if _LIBCPP_HAS_EXCEPTIONS
3413- } catch (...) {
3414- return ;
3415- }
3427+ } catch (...) {
3428+ return ;
3429+ }
34163430# endif // _LIBCPP_HAS_EXCEPTIONS
3417- }
3418- __begin_lifetime (__new_data, __target_capacity + 1 );
3419- __now_long = true ;
3420- __was_long = __is_long ();
3421- __p = __get_pointer ();
3422- }
3423- traits_type::copy (std::__to_address (__new_data), std::__to_address (__p), size () + 1 );
3424- if (__was_long)
3425- __alloc_traits::deallocate (__alloc_, __p, __cap + 1 );
3426- if (__now_long) {
3427- __set_long_cap (__target_capacity + 1 );
3428- __set_long_size (__sz);
3429- __set_long_pointer (__new_data);
3430- } else
3431- __set_short_size (__sz);
34323431}
34333432
34343433template <class _CharT , class _Traits , class _Allocator >
0 commit comments