diff options
Diffstat (limited to 'contrib/llvm-project/libcxx/include/string')
| -rw-r--r-- | contrib/llvm-project/libcxx/include/string | 471 |
1 files changed, 321 insertions, 150 deletions
diff --git a/contrib/llvm-project/libcxx/include/string b/contrib/llvm-project/libcxx/include/string index 4b9627369816..5bb4e941af36 100644 --- a/contrib/llvm-project/libcxx/include/string +++ b/contrib/llvm-project/libcxx/include/string @@ -10,6 +10,8 @@ #ifndef _LIBCPP_STRING #define _LIBCPP_STRING +// clang-format off + /* string synopsis @@ -173,7 +175,7 @@ public: constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 void reserve(size_type res_arg); // constexpr since C++20 - void reserve(); // deprecated in C++20 + void reserve(); // deprecated in C++20, removed in C++26 void shrink_to_fit(); // constexpr since C++20 void clear() noexcept; // constexpr since C++20 bool empty() const noexcept; // constexpr since C++20 @@ -564,6 +566,8 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); */ +// clang-format on + #include <__algorithm/max.h> #include <__algorithm/min.h> #include <__algorithm/remove.h> @@ -614,7 +618,6 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); #include <__utility/swap.h> #include <__utility/unreachable.h> #include <climits> -#include <cstdint> #include <cstdio> // EOF #include <cstring> #include <limits> @@ -646,6 +649,17 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); _LIBCPP_PUSH_MACROS #include <__undef_macros> +#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN) +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// This macro disables AddressSanitizer (ASan) instrumentation for a specific function, +// allowing memory accesses that would normally trigger ASan errors to proceed without crashing. +// This is useful for accessing parts of objects memory, which should not be accessed, +// such as unused bytes in short strings, that should never be accessed +// by other parts of the program. +#else +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS +#endif +#define _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED false _LIBCPP_BEGIN_NAMESPACE_STD @@ -703,6 +717,9 @@ struct __init_with_sentinel_tag {}; template<class _CharT, class _Traits, class _Allocator> class basic_string { +private: + using __default_allocator_type = allocator<_CharT>; + public: typedef basic_string __self; typedef basic_string_view<_CharT, _Traits> __self_view; @@ -830,8 +847,8 @@ private: { union { - __long __l; __short __s; + __long __l; __raw __r; }; }; @@ -857,6 +874,7 @@ private: __set_long_pointer(__allocation); __set_long_size(__size); } + __annotate_new(__size); } template <class _Iter, class _Sent> @@ -879,8 +897,8 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value) - : __r_(__default_init_tag(), __default_init_tag()) { - __default_init(); + : __r_(__value_init_tag(), __default_init_tag()) { + __annotate_new(0); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const allocator_type& __a) @@ -889,46 +907,65 @@ public: #else _NOEXCEPT #endif - : __r_(__default_init_tag(), __a) { - __default_init(); + : __r_(__value_init_tag(), __a) { + __annotate_new(0); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str) + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str) : __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) { if (!__str.__is_long()) + { __r_.first() = __str.__r_.first(); + __annotate_new(__get_short_size()); + } else __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str, const allocator_type& __a) + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str, const allocator_type& __a) : __r_(__default_init_tag(), __a) { if (!__str.__is_long()) + { __r_.first() = __str.__r_.first(); + __annotate_new(__get_short_size()); + } else __init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); } #ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + basic_string(basic_string&& __str) # if _LIBCPP_STD_VER <= 14 _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value) # else _NOEXCEPT # endif - : __r_(std::move(__str.__r_)) { - __str.__default_init(); + // Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS + // does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first. + // __str's memory needs to be unpoisoned only in the case where it's a short string. + : __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) { + __str.__r_.first() = __rep(); + __str.__annotate_new(0); + if(!__is_long()) + __annotate_new(size()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str, const allocator_type& __a) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + basic_string(basic_string&& __str, const allocator_type& __a) : __r_(__default_init_tag(), __a) { if (__str.__is_long() && __a != __str.__alloc()) // copy, not move __init(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size()); else { if (__libcpp_is_constant_evaluated()) __r_.first() = __rep(); + if (!__str.__is_long()) + __str.__annotate_delete(); __r_.first() = __str.__r_.first(); - __str.__default_init(); + __str.__r_.first() = __rep(); + __str.__annotate_new(0); + if(!__is_long() && this != &__str) + __annotate_new(size()); } } #endif // _LIBCPP_CXX03_LANG @@ -936,14 +973,14 @@ public: template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s) : __r_(__default_init_tag(), __default_init_tag()) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "basic_string(const char*) detected nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*) detected nullptr"); __init(__s, traits_type::length(__s)); } template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, const _Allocator& __a) : __r_(__default_init_tag(), __a) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "basic_string(const char*, allocator) detected nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*, allocator) detected nullptr"); __init(__s, traits_type::length(__s)); } @@ -953,15 +990,14 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n) : __r_(__default_init_tag(), __default_init_tag()) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n) detected nullptr"); __init(__s, __n); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* __s, size_type __n, const _Allocator& __a) : __r_(__default_init_tag(), __a) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, - "basic_string(const char*, n, allocator) detected nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "basic_string(const char*, n, allocator) detected nullptr"); __init(__s, __n); } @@ -983,12 +1019,7 @@ public: auto __len = std::min<size_type>(__n, __str.size() - __pos); if (__alloc_traits::is_always_equal::value || __alloc == __str.__alloc()) { - __r_.first() = __str.__r_.first(); - __str.__default_init(); - - _Traits::move(data(), data() + __pos, __len); - __set_size(__len); - _Traits::assign(data()[__len], value_type()); + __move_assign(std::move(__str), __pos, __len); } else { // Perform a copy because the allocators are not compatible. __init(__str.data() + __pos, __len); @@ -1092,6 +1123,7 @@ public: #endif // _LIBCPP_CXX03_LANG inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); } @@ -1099,7 +1131,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator __self_view() const _NOEXCEPT { return __self_view(data(), size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const basic_string& __str); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& __str); template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && !__is_same_uncvref<_Tp, basic_string>::value, int> = 0> @@ -1109,8 +1141,8 @@ public: } #ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(basic_string&& __str) - _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& + operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__str, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>()); return *this; } @@ -1123,7 +1155,7 @@ public: #if _LIBCPP_STD_VER >= 23 basic_string& operator=(nullptr_t) = delete; #endif - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(value_type __c); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(value_type __c); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT @@ -1198,7 +1230,9 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __resize_default_init(size_type __n); +#if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_STRING_RESERVE) _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve() _NOEXCEPT { shrink_to_fit(); } +#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void shrink_to_fit() _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void clear() _NOEXCEPT; @@ -1207,11 +1241,17 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { + return *(__get_long_pointer() + __pos); + } return *(data() + __pos); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); + if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { + return *(__get_long_pointer() + __pos); + } return *(__get_pointer() + __pos); } @@ -1333,6 +1373,30 @@ public: return assign(__sv.data(), __sv.size()); } +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void __move_assign(basic_string&& __str, size_type __pos, size_type __len) { + // Pilfer the allocation from __str. + _LIBCPP_ASSERT_INTERNAL(__alloc() == __str.__alloc(), "__move_assign called with wrong allocator"); + size_type __old_sz = __str.size(); + if (!__str.__is_long()) + __str.__annotate_delete(); + __r_.first() = __str.__r_.first(); + __str.__r_.first() = __rep(); + __str.__annotate_new(0); + + _Traits::move(data(), data() + __pos, __len); + __set_size(__len); + _Traits::assign(data()[__len], value_type()); + + if (!__is_long()) { + __annotate_new(__len); + } else if(__old_sz > __len) { + __annotate_shrink(__old_sz); + } + } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const basic_string& __str) { return *this = __str; } #ifndef _LIBCPP_CXX03_LANG @@ -1727,10 +1791,11 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS bool __is_long() const _NOEXCEPT { - if (__libcpp_is_constant_evaluated()) - return true; + if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) { + return __r_.first().__l.__is_long_; + } return __r_.first().__s.__is_long_; } @@ -1746,26 +1811,8 @@ private: #endif // _LIBCPP_STD_VER >= 20 } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __default_init() { - __r_.first() = __rep(); - if (__libcpp_is_constant_evaluated()) { - size_type __sz = __recommend(0) + 1; - pointer __ptr = __alloc_traits::allocate(__alloc(), __sz); - __begin_lifetime(__ptr, __sz); - __set_long_pointer(__ptr); - __set_long_cap(__sz); - __set_long_size(0); - } - } - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __deallocate_constexpr() { - if (__libcpp_is_constant_evaluated() && __get_pointer() != nullptr) - __alloc_traits::deallocate(__alloc(), __get_pointer(), __get_long_cap()); - } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI static bool __fits_in_sso(size_type __sz) { - // SSO is disabled during constant evaluation because `__is_long` isn't constexpr friendly - return !__libcpp_is_constant_evaluated() && (__sz < __min_cap); + return __sz < __min_cap; } template <class _Iterator, class _Sentinel> @@ -1784,6 +1831,7 @@ private: value_type* __p; if (__cap - __sz >= __n) { + __annotate_increase(__n); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -1810,7 +1858,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __set_short_size(size_type __s) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL( __s < __min_cap, "__s should never be greater than or equal to the short string capacity"); @@ -1818,7 +1866,7 @@ private: __r_.first().__s.__is_long_ = false; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS size_type __get_short_size() const _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL( !__r_.first().__s.__is_long_, "String has to be short when trying to get the short size"); @@ -1868,19 +1916,60 @@ private: const_pointer __get_pointer() const _NOEXCEPT {return __is_long() ? __get_long_pointer() : __get_short_pointer();} + // The following functions are no-ops outside of AddressSanitizer mode. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const { + (void)__old_mid; + (void)__new_mid; +#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN) + const void* __begin = data(); + const void* __end = data() + capacity() + 1; + if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same<allocator_type, __default_allocator_type>::value) + __sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid); +#endif + } + + // ASan: short string is poisoned if and only if this function returns true. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __asan_short_string_is_annotated() const _NOEXCEPT { + return _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED && !__libcpp_is_constant_evaluated(); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_delete() const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_increase(size_type __n) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + __n); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_shrink(size_type __old_size) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long())) + __annotate_contiguous_container(data() + __old_size + 1, data() + size() + 1); + } + template <size_type __a> static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT {return (__s + (__a-1)) & ~(__a-1);} - enum {__alignment = 16}; + enum { + __alignment = +#ifdef _LIBCPP_ABI_STRING_8_BYTE_ALIGNMENT + 8 +#else + 16 +#endif + }; static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __s) _NOEXCEPT { if (__s < __min_cap) { - if (__libcpp_is_constant_evaluated()) - return static_cast<size_type>(__min_cap); - else - return static_cast<size_type>(__min_cap) - 1; + return static_cast<size_type>(__min_cap) - 1; } size_type __guess = __align_it<sizeof(value_type) < __alignment ? __alignment/sizeof(value_type) : 1 > (__s+1) - 1; @@ -1903,7 +1992,7 @@ private: // to call the __init() functions as those are marked as inline which may // result in over-aggressive inlining by the compiler, where our aim is // to only inline the fast path code directly in the ctor. - _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init_copy_ctor_external(const value_type* __s, size_type __sz); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void __init_copy_ctor_external(const value_type* __s, size_type __sz); template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0> inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init(_InputIterator __first, _InputIterator __last); @@ -1937,7 +2026,7 @@ private: // have proof that the input does not alias the current instance. // For example, operator=(basic_string) performs a 'self' check. template <bool __is_short> - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_no_alias(const value_type* __s, size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string& __assign_no_alias(const value_type* __s, size_type __n); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __erase_to_end(size_type __pos) { __null_terminate_at(std::__to_address(__get_pointer()), __pos); @@ -1945,7 +2034,7 @@ private: // __erase_external_with_move is invoked for erase() invocations where // `n ~= npos`, likely requiring memory moves on the string data. - _LIBCPP_CONSTEXPR_SINCE_CXX20 void __erase_external_with_move(size_type __pos, size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void __erase_external_with_move(size_type __pos, size_type __n); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __copy_assign_alloc(const basic_string& __str) @@ -1966,14 +2055,17 @@ private: } else { + __annotate_delete(); allocator_type __a = __str.__alloc(); auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap()); __begin_lifetime(__allocation.ptr, __allocation.count); - __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); + if (__is_long()) + __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); __alloc() = std::move(__a); __set_long_pointer(__allocation.ptr); __set_long_cap(__allocation.count); __set_long_size(__str.size()); + __annotate_new(__get_long_size()); } } } @@ -1986,7 +2078,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __move_assign(basic_string& __str, false_type) _NOEXCEPT_(__alloc_traits::is_always_equal::value); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __move_assign(basic_string& __str, true_type) #if _LIBCPP_STD_VER >= 17 _NOEXCEPT; @@ -2016,23 +2108,33 @@ private: _NOEXCEPT {} - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_external(const value_type* __s); - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_external(const value_type* __s, size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string& __assign_external(const value_type* __s); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string& __assign_external(const value_type* __s, size_type __n); // Assigns the value in __s, guaranteed to be __n < __min_cap in length. - inline basic_string& __assign_short(const value_type* __s, size_type __n) { + inline _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_short(const value_type* __s, size_type __n) { + size_type __old_size = size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __is_long() ? (__set_long_size(__n), __get_long_pointer()) : (__set_short_size(__n), __get_short_pointer()); traits_type::move(std::__to_address(__p), __s, __n); traits_type::assign(__p[__n], value_type()); + if (__old_size > __n) + __annotate_shrink(__old_size); return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __null_terminate_at(value_type* __p, size_type __newsz) { + size_type __old_size = size(); + if (__newsz > __old_size) + __annotate_increase(__newsz - __old_size); __set_size(__newsz); traits_type::assign(__p[__newsz], value_type()); + if (__old_size > __newsz) + __annotate_shrink(__old_size); return *this; } @@ -2139,6 +2241,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> @@ -2167,10 +2270,11 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external( const value_type* __s, size_type __sz) { if (__libcpp_is_constant_evaluated()) @@ -2191,6 +2295,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external( __set_long_size(__sz); } traits_type::copy(std::__to_address(__p), __s, __sz + 1); + __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> @@ -2220,6 +2325,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) } traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); + __annotate_new(__n); } template <class _CharT, class _Traits, class _Allocator> @@ -2234,7 +2340,8 @@ template <class _CharT, class _Traits, class _Allocator> template <class _InputIterator, class _Sentinel> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) { - __default_init(); + __r_.first() = __rep(); + __annotate_new(0); #ifndef _LIBCPP_HAS_NO_EXCEPTIONS try @@ -2246,6 +2353,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputItera } catch (...) { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); throw; @@ -2306,6 +2414,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_size( throw; } #endif // _LIBCPP_HAS_NO_EXCEPTIONS + __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> @@ -2322,6 +2431,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __annotate_delete(); auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2334,13 +2444,14 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace if (__sec_cp_sz != 0) traits_type::copy(std::__to_address(__p) + __n_copy + __n_add, std::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz); - if (__old_cap+1 != __min_cap || __libcpp_is_constant_evaluated()) + if (__old_cap+1 != __min_cap) __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); __set_long_pointer(__p); __set_long_cap(__allocation.count); __old_sz = __n_copy + __n_add + __sec_cp_sz; __set_long_size(__old_sz); traits_type::assign(__p[__old_sz], value_type()); + __annotate_new(__old_cap + __delta_cap); } // __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it @@ -2363,6 +2474,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + __annotate_delete(); auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1); pointer __p = __allocation.ptr; __begin_lifetime(__p, __allocation.count); @@ -2374,7 +2486,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t traits_type::copy(std::__to_address(__p) + __n_copy + __n_add, std::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz); - if (__libcpp_is_constant_evaluated() || __old_cap + 1 != __min_cap) + if (__old_cap + 1 != __min_cap) __alloc_traits::deallocate(__alloc(), __old_p, __old_cap + 1); __set_long_pointer(__p); __set_long_cap(__allocation.count); @@ -2393,22 +2505,28 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add); _LIBCPP_SUPPRESS_DEPRECATED_POP __set_long_size(__old_sz - __n_del + __n_add); + __annotate_new(__old_sz - __n_del + __n_add); } // assign template <class _CharT, class _Traits, class _Allocator> template <bool __is_short> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias( const value_type* __s, size_type __n) { size_type __cap = __is_short ? static_cast<size_type>(__min_cap) : __get_long_cap(); if (__n < __cap) { + size_type __old_size = __is_short ? __get_short_size() : __get_long_size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer(); __is_short ? __set_short_size(__n) : __set_long_size(__n); traits_type::copy(std::__to_address(__p), __s, __n); traits_type::assign(__p[__n], value_type()); + if (__old_size > __n) + __annotate_shrink(__old_size); } else { size_type __sz = __is_short ? __get_short_size() : __get_long_size(); __grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s); @@ -2417,12 +2535,15 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias( } template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::__assign_external( const value_type* __s, size_type __n) { size_type __cap = capacity(); if (__cap >= __n) { + size_type __old_size = size(); + if (__n > __old_size) + __annotate_increase(__n - __old_size); value_type* __p = std::__to_address(__get_pointer()); traits_type::move(__p, __s, __n); return __null_terminate_at(__p, __n); @@ -2438,7 +2559,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::assign received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::assign received nullptr"); return (__builtin_constant_p(__n) && __fits_in_sso(__n)) ? __assign_short(__s, __n) : __assign_external(__s, __n); @@ -2450,11 +2571,15 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) { size_type __cap = capacity(); + size_type __old_size = size(); if (__cap < __n) { size_type __sz = size(); __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); + __annotate_increase(__n); } + else if(__n > __old_size) + __annotate_increase(__n - __old_size); value_type* __p = std::__to_address(__get_pointer()); traits_type::assign(__p, __n, __c); return __null_terminate_at(__p, __n); @@ -2465,24 +2590,26 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c) { - pointer __p; - if (__is_long()) - { - __p = __get_long_pointer(); - __set_long_size(1); - } - else - { - __p = __get_short_pointer(); - __set_short_size(1); - } - traits_type::assign(*__p, __c); - traits_type::assign(*++__p, value_type()); - return *this; + pointer __p; + size_type __old_size = size(); + if (__old_size == 0) + __annotate_increase(1); + if (__is_long()) { + __p = __get_long_pointer(); + __set_long_size(1); + } else { + __p = __get_short_pointer(); + __set_short_size(1); + } + traits_type::assign(*__p, __c); + traits_type::assign(*++__p, value_type()); + if (__old_size > 1) + __annotate_shrink(__old_size); + return *this; } template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str) { @@ -2490,7 +2617,12 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str) __copy_assign_alloc(__str); if (!__is_long()) { if (!__str.__is_long()) { + size_type __old_size = __get_short_size(); + if (__get_short_size() < __str.__get_short_size()) + __annotate_increase(__str.__get_short_size() - __get_short_size()); __r_.first() = __str.__r_.first(); + if (__old_size > __get_short_size()) + __annotate_shrink(__old_size); } else { return __assign_no_alias<true>(__str.data(), __str.size()); } @@ -2516,7 +2648,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, fa } template <class _CharT, class _Traits, class _Allocator> -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 +inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type) #if _LIBCPP_STD_VER >= 17 @@ -2525,6 +2657,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) #endif { + __annotate_delete(); if (__is_long()) { __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); @@ -2532,17 +2665,35 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr if (!is_nothrow_move_assignable<allocator_type>::value) { __set_short_size(0); traits_type::assign(__get_short_pointer()[0], value_type()); + __annotate_new(0); } #endif } + size_type __str_old_size = __str.size(); + bool __str_was_short = !__str.__is_long(); + __move_assign_alloc(__str); __r_.first() = __str.__r_.first(); - if (__libcpp_is_constant_evaluated()) { - __str.__default_init(); - } else { - __str.__set_short_size(0); - traits_type::assign(__str.__get_short_pointer()[0], value_type()); - } + __str.__set_short_size(0); + traits_type::assign(__str.__get_short_pointer()[0], value_type()); + + if (__str_was_short && this != &__str) + __str.__annotate_shrink(__str_old_size); + else + // ASan annotations: was long, so object memory is unpoisoned as new. + // Or is same as *this, and __annotate_delete() was called. + __str.__annotate_new(0); + + // ASan annotations: Guard against `std::string s; s = std::move(s);` + // You can find more here: https://en.cppreference.com/w/cpp/utility/move + // Quote: "Unless otherwise specified, all standard library objects that have been moved + // from are placed in a "valid but unspecified state", meaning the object's class + // invariants hold (so functions without preconditions, such as the assignment operator, + // can be safely used on the object after it was moved from):" + // Quote: "v = std::move(v); // the value of v is unspecified" + if (!__is_long() && &__str != this) + // If it is long string, delete was never called on original __str's buffer. + __annotate_new(__get_short_size()); } #endif @@ -2588,6 +2739,7 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _ _LIBCPP_ASSERT_INTERNAL( __string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial"); + size_type __old_size = size(); size_type __cap = capacity(); if (__cap < __n) { // Unlike `append` functions, if the input range points into the string itself, there is no case that the input @@ -2598,12 +2750,17 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _ // object itself stays valid even if reallocation happens. size_type __sz = size(); __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); + __annotate_increase(__n); } + else if (__n > __old_size) + __annotate_increase(__n - __old_size); pointer __p = __get_pointer(); for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); traits_type::assign(*__p, value_type()); __set_size(__n); + if (__n < __old_size) + __annotate_shrink(__old_size); } template <class _CharT, class _Traits, class _Allocator> @@ -2632,7 +2789,7 @@ basic_string<_CharT, _Traits, _Allocator>::assign(const _Tp& __t, size_type __po } template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::__assign_external(const value_type* __s) { return __assign_external(__s, traits_type::length(__s)); @@ -2643,7 +2800,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::assign received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::assign received nullptr"); return __builtin_constant_p(*__s) ? (__fits_in_sso(traits_type::length(__s)) ? __assign_short(__s, traits_type::length(__s)) @@ -2657,13 +2814,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::append received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::append received nullptr"); size_type __cap = capacity(); size_type __sz = size(); if (__cap - __sz >= __n) { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); traits_type::copy(__p + __sz, __s, __n); __sz += __n; @@ -2687,6 +2845,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c) size_type __sz = size(); if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); traits_type::assign(std::__to_address(__p) + __sz, __n, __c); __sz += __n; @@ -2706,6 +2865,7 @@ basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n) size_type __sz = size(); if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); __sz += __n; __set_size(__sz); @@ -2734,8 +2894,10 @@ basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c) if (__sz == __cap) { __grow_by_without_replace(__cap, 1, __sz, __sz, 0); + __annotate_increase(1); __is_short = false; // the string is always long after __grow_by - } + } else + __annotate_increase(1); pointer __p = __get_pointer(); if (__is_short) { @@ -2767,6 +2929,7 @@ basic_string<_CharT, _Traits, _Allocator>::append( { if (__cap - __sz < __n) __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer() + __sz; for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); @@ -2812,7 +2975,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::append received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::append received nullptr"); return append(__s, traits_type::length(__s)); } @@ -2823,27 +2986,21 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s, size_type __n) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::insert received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::insert received nullptr"); size_type __sz = size(); if (__pos > __sz) __throw_out_of_range(); size_type __cap = capacity(); - if (__libcpp_is_constant_evaluated()) { - if (__cap - __sz >= __n) - __grow_by_and_replace(__cap, 0, __sz, __pos, 0, __n, __s); - else - __grow_by_and_replace(__cap, __sz + __n - __cap, __sz, __pos, 0, __n, __s); - return *this; - } if (__cap - __sz >= __n) { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) { - if (__p + __pos <= __s && __s < __p + __sz) + if (std::__is_pointer_in_range(__p + __pos, __p + __sz, __s)) __s += __n; traits_type::move(__p + __pos + __n, __p + __pos, __n_move); } @@ -2872,6 +3029,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n value_type* __p; if (__cap - __sz >= __n) { + __annotate_increase(__n); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2960,7 +3118,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_type* __s) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::insert received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::insert received nullptr"); return insert(__pos, __s, traits_type::length(__s)); } @@ -2980,6 +3138,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, value_ty } else { + __annotate_increase(1); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -2999,7 +3158,7 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s, size_type __n2) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { - _LIBCPP_ASSERT_UNCATEGORIZED(__n2 == 0 || __s != nullptr, "string::replace received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n2 == 0 || __s != nullptr, "string::replace received nullptr"); size_type __sz = size(); if (__pos > __sz) __throw_out_of_range(); @@ -3010,6 +3169,8 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ value_type* __p = std::__to_address(__get_pointer()); if (__n1 != __n2) { + if (__n2 > __n1) + __annotate_increase(__n2 - __n1); size_type __n_move = __sz - __pos - __n1; if (__n_move != 0) { @@ -3054,20 +3215,18 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ __n1 = std::min(__n1, __sz - __pos); size_type __cap = capacity(); value_type* __p; - if (__cap - __sz + __n1 >= __n2) - { - __p = std::__to_address(__get_pointer()); - if (__n1 != __n2) - { - size_type __n_move = __sz - __pos - __n1; - if (__n_move != 0) - traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); - } - } - else - { - __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); - __p = std::__to_address(__get_long_pointer()); + if (__cap - __sz + __n1 >= __n2) { + __p = std::__to_address(__get_pointer()); + if (__n1 != __n2) { + if (__n2 > __n1) + __annotate_increase(__n2 - __n1); + size_type __n_move = __sz - __pos - __n1; + if (__n_move != 0) + traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); + } + } else { + __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); + __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n2, __c); return __null_terminate_at(__p, __sz - (__n1 - __n2)); @@ -3115,7 +3274,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __n1, const value_type* __s) { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::replace received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::replace received nullptr"); return replace(__pos, __n1, __s, traits_type::length(__s)); } @@ -3124,7 +3283,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ // 'externally instantiated' erase() implementation, called when __n != npos. // Does not check __pos against size() template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void basic_string<_CharT, _Traits, _Allocator>::__erase_external_with_move( size_type __pos, size_type __n) @@ -3195,6 +3354,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_type __old_size = size(); if (__is_long()) { traits_type::assign(*__get_long_pointer(), value_type()); @@ -3205,6 +3365,7 @@ basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_shrink(__old_size); } template <class _CharT, class _Traits, class _Allocator> @@ -3267,6 +3428,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) { + __annotate_delete(); size_type __cap = capacity(); size_type __sz = size(); @@ -3323,6 +3485,7 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target } else __set_short_size(__sz); + __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> @@ -3373,8 +3536,16 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str) __alloc_traits::propagate_on_container_swap::value || __alloc_traits::is_always_equal::value || __alloc() == __str.__alloc(), "swapping non-equal allocators"); + if (!__is_long()) + __annotate_delete(); + if (this != &__str && !__str.__is_long()) + __str.__annotate_delete(); std::swap(__r_.first(), __str.__r_.first()); std::__swap_allocator(__alloc(), __str.__alloc()); + if (!__is_long()) + __annotate_new(__get_short_size()); + if (this != &__str && !__str.__is_long()) + __str.__annotate_new(__str.__get_short_size()); } // find @@ -3395,7 +3566,7 @@ basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::find(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find(): received nullptr"); return std::__str_find<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3427,7 +3598,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::find(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find(): received nullptr"); return std::__str_find<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3451,7 +3622,7 @@ basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::rfind(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::rfind(): received nullptr"); return std::__str_rfind<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3483,7 +3654,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::rfind(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::rfind(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::rfind(): received nullptr"); return std::__str_rfind<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3507,7 +3678,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::find_first_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_first_of(): received nullptr"); return std::__str_find_first_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3539,7 +3710,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_first_of(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::find_first_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find_first_of(): received nullptr"); return std::__str_find_first_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3562,7 +3733,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::find_last_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_last_of(): received nullptr"); return std::__str_find_last_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3594,7 +3765,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_last_of(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::find_last_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find_last_of(): received nullptr"); return std::__str_find_last_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3617,7 +3788,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* _ size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::find_first_not_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_first_not_of(): received nullptr"); return std::__str_find_first_not_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3649,7 +3820,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_first_not_of(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::find_first_not_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find_first_not_of(): received nullptr"); return std::__str_find_first_not_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3673,7 +3844,7 @@ basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __ size_type __pos, size_type __n) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__n == 0 || __s != nullptr, "string::find_last_not_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::find_last_not_of(): received nullptr"); return std::__str_find_last_not_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, __n); } @@ -3705,7 +3876,7 @@ typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::find_last_not_of(const value_type* __s, size_type __pos) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::find_last_not_of(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find_last_not_of(): received nullptr"); return std::__str_find_last_not_of<value_type, size_type, traits_type, npos> (data(), size(), __s, __pos, traits_type::length(__s)); } @@ -3757,7 +3928,7 @@ basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1, const value_type* __s, size_type __n2) const { - _LIBCPP_ASSERT_UNCATEGORIZED(__n2 == 0 || __s != nullptr, "string::compare(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__n2 == 0 || __s != nullptr, "string::compare(): received nullptr"); size_type __sz = size(); if (__pos1 > __sz || __n2 == npos) __throw_out_of_range(); @@ -3822,7 +3993,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 int basic_string<_CharT, _Traits, _Allocator>::compare(const value_type* __s) const _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::compare(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::compare(): received nullptr"); return compare(0, npos, __s, traits_type::length(__s)); } @@ -3833,7 +4004,7 @@ basic_string<_CharT, _Traits, _Allocator>::compare(size_type __pos1, size_type __n1, const value_type* __s) const { - _LIBCPP_ASSERT_UNCATEGORIZED(__s != nullptr, "string::compare(): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::compare(): received nullptr"); return compare(__pos1, __n1, __s, traits_type::length(__s)); } @@ -3862,12 +4033,12 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink() _NOEXCEPT { - clear(); - if(__is_long()) - { - __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1); - __default_init(); - } + clear(); + if (__is_long()) { + __annotate_delete(); + __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1); + __r_.first() = __rep(); + } } // operator== @@ -3915,7 +4086,7 @@ operator==(const _CharT* __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) _NOEXCEPT { typedef basic_string<_CharT, _Traits, _Allocator> _String; - _LIBCPP_ASSERT_UNCATEGORIZED(__lhs != nullptr, "operator==(char*, basic_string): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__lhs != nullptr, "operator==(char*, basic_string): received nullptr"); size_t __lhs_len = _Traits::length(__lhs); if (__lhs_len != __rhs.size()) return false; return __rhs.compare(0, _String::npos, __lhs, __lhs_len) == 0; @@ -3932,7 +4103,7 @@ operator==(const basic_string<_CharT,_Traits,_Allocator>& __lhs, return basic_string_view<_CharT, _Traits>(__lhs) == basic_string_view<_CharT, _Traits>(__rhs); #else typedef basic_string<_CharT, _Traits, _Allocator> _String; - _LIBCPP_ASSERT_UNCATEGORIZED(__rhs != nullptr, "operator==(basic_string, char*): received nullptr"); + _LIBCPP_ASSERT_NON_NULL(__rhs != nullptr, "operator==(basic_string, char*): received nullptr"); size_t __rhs_len = _Traits::length(__rhs); if (__rhs_len != __lhs.size()) return false; return __lhs.compare(0, _String::npos, __rhs, __rhs_len) == 0; |
