@@ -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_ )) {
@@ -2060,6 +2058,21 @@ private:
20602058#endif
20612059 }
20622060
2061+ // Disable ASan annotations and enable them again when going out of scope. It is assumed that the string is in a valid
2062+ // state at that point, so `size()` can be called safely.
2063+ struct [[__nodiscard__]] __annotation_guard {
2064+ __annotation_guard (const __annotation_guard&) = delete ;
2065+ __annotation_guard& operator =(const __annotation_guard&) = delete ;
2066+
2067+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotation_guard (basic_string& __str) : __str_ (__str) {
2068+ __str_.__annotate_delete ();
2069+ }
2070+
2071+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__annotation_guard () { __str_.__annotate_new (__str_.size ()); }
2072+
2073+ basic_string& __str_;
2074+ };
2075+
20632076 template <size_type __a>
20642077 static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it (size_type __s) _NOEXCEPT {
20652078 return (__s + (__a - 1 )) & ~(__a - 1 );
@@ -3340,7 +3353,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re
33403353 if (__target_capacity == capacity ())
33413354 return ;
33423355
3343- __shrink_or_extend (__target_capacity);
3356+ __annotation_guard __g (*this );
3357+ auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3358+ auto __size = size ();
3359+ __begin_lifetime (__allocation.ptr , __allocation.count );
3360+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), __size + 1 );
3361+ if (__is_long ())
3362+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_size () + 1 );
3363+ __set_long_cap (__allocation.count );
3364+ __set_long_size (__size);
3365+ __set_long_pointer (__allocation.ptr );
33443366}
33453367
33463368template <class _CharT , class _Traits , class _Allocator >
@@ -3349,70 +3371,48 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat
33493371 if (__target_capacity == capacity ())
33503372 return ;
33513373
3352- __shrink_or_extend (__target_capacity);
3353- }
3354-
3355- template <class _CharT , class _Traits , class _Allocator >
3356- inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
3357- basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend (size_type __target_capacity) {
3358- __annotate_delete ();
3359- size_type __cap = capacity ();
3360- size_type __sz = size ();
3361-
3362- pointer __new_data, __p;
3363- bool __was_long, __now_long;
33643374 if (__fits_in_sso (__target_capacity)) {
3365- __was_long = true ;
3366- __now_long = false ;
3367- __new_data = __get_short_pointer ( );
3368- __p = __get_long_pointer ();
3369- } else {
3370- if (__target_capacity > __cap) {
3371- // Extend
3372- // - called from reserve should propagate the exception thrown.
3373- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3374- __new_data = __allocation. ptr ;
3375- __target_capacity = __allocation. count - 1 ;
3376- } else {
3377- // Shrink
3378- // - called from shrink_to_fit should not throw.
3379- // - called from reserve may throw but is not required to.
3375+ if (! __is_long ())
3376+ return ;
3377+ __annotation_guard __g (* this );
3378+ auto __ptr = __get_long_pointer ();
3379+ auto __size = __get_long_size ();
3380+ auto __cap = __get_long_cap ();
3381+ traits_type::copy ( std::__to_address ( __get_short_pointer ()), data (), __size + 1 );
3382+ __alloc_traits::deallocate (__alloc_, __ptr, __cap);
3383+ __set_short_size (__size );
3384+ return ;
3385+ }
3386+
3387+ // Shrink
3388+ // - called from shrink_to_fit should not throw.
3389+ // - called from reserve may throw but is not required to.
33803390#if _LIBCPP_HAS_EXCEPTIONS
3381- try {
3391+ try {
33823392#endif // _LIBCPP_HAS_EXCEPTIONS
3383- auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3384-
3385- // The Standard mandates shrink_to_fit() does not increase the capacity.
3386- // With equal capacity keep the existing buffer. This avoids extra work
3387- // due to swapping the elements.
3388- if (__allocation.count - 1 > __target_capacity) {
3389- __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3390- __annotate_new (__sz); // Undoes the __annotate_delete()
3391- return ;
3392- }
3393- __new_data = __allocation.ptr ;
3394- __target_capacity = __allocation.count - 1 ;
3393+ __annotation_guard __g (*this );
3394+ auto __size = size ();
3395+ auto __allocation = std::__allocate_at_least (__alloc_, __target_capacity + 1 );
3396+
3397+ // The Standard mandates shrink_to_fit() does not increase the capacity.
3398+ // With equal capacity keep the existing buffer. This avoids extra work
3399+ // due to swapping the elements.
3400+ if (__allocation.count - 1 > __target_capacity) {
3401+ __alloc_traits::deallocate (__alloc_, __allocation.ptr , __allocation.count );
3402+ __annotate_new (__size); // Undoes the __annotate_delete()
3403+ return ;
3404+ }
3405+
3406+ __begin_lifetime (__allocation.ptr , __allocation.count );
3407+ traits_type::copy (std::__to_address (__allocation.ptr ), data (), size () + 1 );
3408+ __alloc_traits::deallocate (__alloc_, __get_long_pointer (), __get_long_cap ());
3409+ __set_long_cap (__allocation.count );
3410+ __set_long_pointer (__allocation.ptr );
33953411#if _LIBCPP_HAS_EXCEPTIONS
3396- } catch (...) {
3397- return ;
3398- }
3412+ } catch (...) {
3413+ return ;
3414+ }
33993415#endif // _LIBCPP_HAS_EXCEPTIONS
3400- }
3401- __begin_lifetime (__new_data, __target_capacity + 1 );
3402- __now_long = true ;
3403- __was_long = __is_long ();
3404- __p = __get_pointer ();
3405- }
3406- traits_type::copy (std::__to_address (__new_data), std::__to_address (__p), size () + 1 );
3407- if (__was_long)
3408- __alloc_traits::deallocate (__alloc_, __p, __cap + 1 );
3409- if (__now_long) {
3410- __set_long_cap (__target_capacity + 1 );
3411- __set_long_size (__sz);
3412- __set_long_pointer (__new_data);
3413- } else
3414- __set_short_size (__sz);
3415- __annotate_new (__sz);
34163416}
34173417
34183418template <class _CharT , class _Traits , class _Allocator >
0 commit comments