@@ -1874,8 +1874,6 @@ private:
18741874 operator ==(const basic_string<char , char_traits<char >, _Alloc>& __lhs,
18751875 const basic_string<char , char_traits<char >, _Alloc>& __rhs) _NOEXCEPT;
18761876
1877- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend (size_type __target_capacity);
1878-
18791877 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool
18801878 __is_long () const _NOEXCEPT {
18811879 if (__libcpp_is_constant_evaluated () && __builtin_constant_p (__rep_.__l .__is_long_ )) {
@@ -2070,6 +2068,21 @@ private:
20702068#endif
20712069 }
20722070
2071+ // Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2072+ // state at that point, so `size()` can be called safely.
2073+ struct [[__nodiscard__]] __annotation_guard {
2074+ __annotation_guard (const __annotation_guard&) = delete ;
2075+ __annotation_guard& operator =(const __annotation_guard&) = delete ;
2076+
2077+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard (basic_string& __str) : __str_ (__str) {
2078+ __str_.__annotate_delete ();
2079+ }
2080+
2081+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard () { __str_.__annotate_new (__str_.size ()); }
2082+
2083+ basic_string& __str_;
2084+ };
2085+
20732086 template <size_type __a>
20742087 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
20752088 return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3348,7 +3361,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
33483361 if (__requested_capacity <= capacity ())
33493362 return ;
33503363
3351- __shrink_or_extend (__recommend (__requested_capacity));
3364+ __annotation_guard __g (*this );
3365+ auto __allocation = std::__allocate_at_least (__alloc_, __recommend (__requested_capacity) + 1 );
3366+ auto __size = size ();
3367+ __begin_lifetime (__allocation.ptr , __allocation.count );
3368+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), __size + 1 );
3369+ if (__is_long ())
3370+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_size () + 1 );
3371+ __set_long_cap (__allocation.count );
3372+ __set_long_size (__size);
3373+ __set_long_pointer (__allocation.ptr );
33523374}
33533375
33543376template <class _CharT , class _Traits , class _Allocator >
@@ -3357,70 +3379,46 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
33573379 if (__target_capacity == capacity ())
33583380 return ;
33593381
3360- __shrink_or_extend (__target_capacity);
3361- }
3382+ _LIBCPP_ASSERT_INTERNAL (__is_long (), " Trying to shrink small string" );
33623383
3363- template <class _CharT , class _Traits , class _Allocator >
3364- inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3365- basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3366- __annotate_delete ();
3367- size_type __cap = capacity ();
3368- size_type __sz = size ();
3369-
3370- pointer __new_data, __p;
3371- bool __was_long, __now_long;
3384+ // We're a long string and we're shrinking into the small buffer.
33723385 if (__fits_in_sso (__target_capacity)) {
3373- __was_long = true ;
3374- __now_long = false ;
3375- __new_data = __get_short_pointer ();
3376- __p = __get_long_pointer ();
3377- } else {
3378- if (__target_capacity > __cap) {
3379- // Extend
3380- // - called from reserve should propagate the exception thrown.
3381- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3382- __new_data = __allocation.ptr ;
3383- __target_capacity = __allocation.count - 1 ;
3384- } else {
3385- // Shrink
3386- // - called from shrink_to_fit should not throw.
3387- // - called from reserve may throw but is not required to.
3386+ __annotation_guard __g (*this );
3387+ auto __ptr = __get_long_pointer ();
3388+ auto __size = __get_long_size ();
3389+ auto __cap = __get_long_cap ();
3390+ traits_type::copy (std::__to_address (__get_short_pointer ()), std::__to_address (__ptr), __size + 1 );
3391+ __set_short_size (__size);
3392+ __alloc_traits::deallocate (__alloc_, __ptr, __cap);
3393+ return ;
3394+ }
3395+
33883396#if _LIBCPP_HAS_EXCEPTIONS
3389- try {
3397+ try {
33903398#endif // _LIBCPP_HAS_EXCEPTIONS
3391- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3392-
3393- // The Standard mandates shrink_to_fit() does not increase the capacity.
3394- // With equal capacity keep the existing buffer. This avoids extra work
3395- // due to swapping the elements.
3396- if (__allocation.count - 1 > __target_capacity) {
3397- __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3398- __annotate_new (__sz); // Undoes the __annotate_delete()
3399- return ;
3400- }
3401- __new_data = __allocation.ptr ;
3402- __target_capacity = __allocation.count - 1 ;
3399+ __annotation_guard __g (*this );
3400+ auto __size = size ();
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 > __target_capacity) {
3407+ __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3408+ return ;
3409+ }
3410+
3411+ __begin_lifetime (__allocation.ptr , __allocation.count );
3412+ auto __ptr = __get_long_pointer ();
3413+ traits_type::copy (std::__to_address (__allocation.ptr ), std::__to_address (__ptr), __size + 1 );
3414+ __alloc_traits::deallocate (__alloc_, __ptr, __get_long_cap ());
3415+ __set_long_cap (__allocation.count );
3416+ __set_long_pointer (__allocation.ptr );
34033417#if _LIBCPP_HAS_EXCEPTIONS
3404- } catch (...) {
3405- return ;
3406- }
3418+ } catch (...) {
3419+ return ;
3420+ }
34073421#endif // _LIBCPP_HAS_EXCEPTIONS
3408- }
3409- __begin_lifetime (__new_data, __target_capacity + 1 );
3410- __now_long = true ;
3411- __was_long = __is_long ();
3412- __p = __get_pointer ();
3413- }
3414- traits_type::copy (std::__to_address (__new_data), std::__to_address (__p), size () + 1 );
3415- if (__was_long)
3416- __alloc_traits::deallocate (__alloc_, __p, __cap + 1 );
3417- if (__now_long) {
3418- __set_long_cap (__target_capacity + 1 );
3419- __set_long_size (__sz);
3420- __set_long_pointer (__new_data);
3421- } else
3422- __set_short_size (__sz);
3423- __annotate_new (__sz);
34243422}
34253423
34263424template <class _CharT , class _Traits , class _Allocator >
0 commit comments