diff --git a/libcxx/include/__string/extern_template_lists.h b/libcxx/include/__string/extern_template_lists.h --- a/libcxx/include/__string/extern_template_lists.h +++ b/libcxx/include/__string/extern_template_lists.h @@ -27,6 +27,14 @@ // For stable, the ABI list should rarely change, except for adding new // functions supporting new c++ version / API changes. Typically entries // must never be removed from the stable list. +#if !defined(_LIBCPP_HAS_NO_ASAN) +// TODO LLVM18: Remove the special-casing (_LIBCPP_CLANG_VER) +// This change is relevant to string annotations, which require updated version of ASan API, +// introduced in https://reviews.llvm.org/rGdd1b7b797a116eed588fd752fbe61d34deeb24e4 +# define _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_Func, _CharType) + +# define _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_Func, _CharType) +#else #define _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_Func, _CharType) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::rfind(value_type const*, size_type, size_type) const) \ @@ -126,6 +134,6 @@ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::iterator basic_string<_CharType>::insert(basic_string::const_iterator, value_type)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::resize(size_type, value_type)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, basic_string const&, size_type, size_type)) - +#endif // !defined(_LIBCPP_HAS_NO_ASAN) && (_LIBCPP_CLANG_VER >= 1600) #endif // _LIBCPP___STRING_EXTERN_TEMPLATE_LISTS_H diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -601,6 +601,15 @@ _LIBCPP_PUSH_MACROS #include <__undef_macros> +#ifndef _LIBCPP_HAS_NO_ASAN +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address"))) +// Sometimes string access own memory, which should not be accessed by different parts of program +// (eg. not-in-use bytes of buffer in short string) and are poisoned by ASan. +// This macro turns off instrumentation in a function, so memory accesses which normally would crash +// work as expected. +#else +# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS +#endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -656,6 +665,9 @@ template class basic_string { +private: + using __default_allocator_type = allocator<_CharT>; + public: typedef basic_string __self; typedef basic_string_view<_CharT, _Traits> __self_view; @@ -842,24 +854,27 @@ __default_init(); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str); - _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); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS + basic_string(const basic_string& __str, const allocator_type& __a); #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::value) # else _NOEXCEPT # endif - : __r_(std::move(__str.__r_)) { + : __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) { __str.__default_init(); std::__debug_db_insert_c(this); if (__is_long()) std::__debug_db_swap(this, &__str); } - _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 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS + 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()); @@ -867,6 +882,9 @@ if (__libcpp_is_constant_evaluated()) __r_.first() = __rep(); __r_.first() = __str.__r_.first(); + if (!__str.__is_long()) { + __str.__annotate_delete(); + } __str.__default_init(); } std::__debug_db_insert_c(this); @@ -912,11 +930,11 @@ } #if _LIBCPP_STD_VER >= 23 - _LIBCPP_HIDE_FROM_ABI constexpr + _LIBCPP_HIDE_FROM_ABI _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS constexpr basic_string(basic_string&& __str, size_type __pos, const _Allocator& __alloc = _Allocator()) : basic_string(std::move(__str), __pos, npos, __alloc) {} - _LIBCPP_HIDE_FROM_ABI constexpr + _LIBCPP_HIDE_FROM_ABI _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS constexpr basic_string(basic_string&& __str, size_type __pos, size_type __n, const _Allocator& __alloc = _Allocator()) : __r_(__default_init_tag(), __alloc) { if (__pos > __str.size()) @@ -925,6 +943,9 @@ auto __len = std::min(__n, __str.size() - __pos); if (__alloc_traits::is_always_equal::value || __alloc == __str.__alloc()) { __r_.first() = __str.__r_.first(); + if (!__str.__is_long()) { + __str.__annotate_delete(); + } __str.__default_init(); _Traits::move(data(), data() + __pos, __len); @@ -1019,8 +1040,8 @@ } #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 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& + operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) { __move_assign(__str, integral_constant()); return *this; } @@ -1033,7 +1054,7 @@ #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 @@ -1250,7 +1271,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const basic_string& __str) { return *this = __str; } #ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& assign(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) {*this = std::move(__str); return *this;} @@ -1675,7 +1696,7 @@ _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; @@ -1696,6 +1717,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __default_init() { __r_.first() = __rep(); + __annotate_new(0); if (__libcpp_is_constant_evaluated()) { size_type __sz = __recommend(0) + 1; pointer __ptr = __alloc_traits::allocate(__alloc(), __sz); @@ -1724,6 +1746,7 @@ 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) @@ -1746,14 +1769,14 @@ _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(__s < __min_cap, "__s should never be greater than or equal to the short string capacity"); __r_.first().__s.__size_ = __s; __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(!__r_.first().__s.__is_long_, "String has to be short when trying to get the short size"); return __r_.first().__s.__size_; @@ -1802,6 +1825,50 @@ 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. +#ifndef _LIBCPP_HAS_NO_ASAN + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container( + const void* __begin, const void* __end, const void* __old_mid, const void* __new_mid) const { + if (!__libcpp_is_constant_evaluated() && __begin != nullptr) +# if _LIBCPP_CLANG_VER < 1600 + if (is_same::value) +# endif + __sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid); + } +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void + __annotate_contiguous_container(const void*, const void*, const void*, const void*) const {} +#endif + + // ASan: short string is poisoned if and only if this function returns true. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __annotate_short_string_check() const _NOEXCEPT { +#if (!defined(_LIBCPP_HAS_NO_ASAN)) && (_LIBCPP_CLANG_VER >= 1600) + return !__libcpp_is_constant_evaluated(); +#else + return false; +#endif + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT { + if (!__libcpp_is_constant_evaluated() && (__annotate_short_string_check() || __is_long())) + __annotate_contiguous_container(data(), data() + capacity() + 1, 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() && (__annotate_short_string_check() || __is_long())) + __annotate_contiguous_container(data(), data() + capacity() + 1, 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() && (__annotate_short_string_check() || __is_long())) + __annotate_contiguous_container(data(), data() + capacity() + 1, 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() && (__annotate_short_string_check() || __is_long())) + __annotate_contiguous_container(data(), data() + capacity() + 1, data() + __old_size + 1, data() + size() + 1); + } + template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT @@ -1896,6 +1963,7 @@ } 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); @@ -1904,6 +1972,7 @@ __set_long_pointer(__allocation.ptr); __set_long_cap(__allocation.count); __set_long_size(__str.size()); + __annotate_new(__get_long_size()); } } } @@ -1951,19 +2020,29 @@ // 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) { + 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); __invalidate_iterators_past(__newsz); traits_type::assign(__p[__newsz], value_type()); + if (__old_size > __newsz) + __annotate_shrink(__old_size); return *this; } @@ -2098,6 +2177,7 @@ } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2126,6 +2206,7 @@ } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2140,12 +2221,15 @@ } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string<_CharT, _Traits, _Allocator>::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()); @@ -2159,7 +2243,10 @@ : __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()); @@ -2188,6 +2275,7 @@ __set_long_size(__sz); } traits_type::copy(std::__to_address(__p), __s, __sz + 1); + __annotate_new(__sz); } template @@ -2217,6 +2305,7 @@ } traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); + __annotate_new(__n); } template @@ -2298,6 +2387,7 @@ } catch (...) { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); throw; @@ -2346,17 +2436,20 @@ } catch (...) { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); throw; } #endif // _LIBCPP_HAS_NO_EXCEPTIONS + __annotate_new(__sz); } template _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>::~basic_string() { + __annotate_delete(); std::__debug_db_erase_c(this); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); @@ -2376,6 +2469,7 @@ 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); @@ -2396,6 +2490,7 @@ __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); } template @@ -2411,6 +2506,7 @@ 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); @@ -2427,6 +2523,7 @@ __alloc_traits::deallocate(__alloc(), __old_p, __old_cap + 1); __set_long_pointer(__p); __set_long_cap(__allocation.count); + __annotate_new(__old_cap + __delta_cap); } // assign @@ -2439,11 +2536,16 @@ const value_type* __s, size_type __n) { size_type __cap = __is_short ? static_cast(__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()); __invalidate_iterators_past(__n); + 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); @@ -2458,6 +2560,9 @@ 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); @@ -2484,15 +2589,28 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) { - size_type __cap = capacity(); - if (__cap < __n) - { - size_type __sz = size(); - __grow_by(__cap, __n - __cap, __sz, 0, __sz); - } + size_type __cap = capacity(); + size_type __old_size = size(); + if (__cap < __n) { + size_type __sz = size(); + __grow_by(__cap, __n - __cap, __sz, 0, __sz); + // We cannot call __null_terminate_at, because state of the string may not be correct, + // after __grow_by and correct state is necessery when changing annotations. + // __null_terminate_at is changing annotations. value_type* __p = std::__to_address(__get_pointer()); traits_type::assign(__p, __n, __c); - return __null_terminate_at(__p, __n); + + __set_size(__n); + __invalidate_iterators_past(__n); + traits_type::assign(__p[__n], value_type()); + + return *this; + } 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); } template @@ -2500,25 +2618,31 @@ 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()); - __invalidate_iterators_past(1); - return *this; + pointer __p; + size_type __old_size; + if (__is_long()) { + __old_size = __get_long_size(); + if (__old_size == 0) + __annotate_increase(1); + __p = __get_long_pointer(); + __set_long_size(1); + } else { + __old_size = __get_short_size(); + if (__old_size == 0) + __annotate_increase(1); + __p = __get_short_pointer(); + __set_short_size(1); + } + traits_type::assign(*__p, __c); + traits_type::assign(*++__p, value_type()); + __invalidate_iterators_past(1); + if (__old_size > 1) + __annotate_shrink(__old_size); + return *this; } template -_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) { @@ -2526,7 +2650,12 @@ __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(__str.data(), __str.size()); } @@ -2552,7 +2681,7 @@ } template -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 @@ -2561,6 +2690,7 @@ _NOEXCEPT_(is_nothrow_move_assignable::value) #endif { + __annotate_delete(); if (__is_long()) { __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); @@ -2568,10 +2698,14 @@ if (!is_nothrow_move_assignable::value) { __set_short_size(0); traits_type::assign(__get_short_pointer()[0], value_type()); + __annotate_new(0); } #endif } __move_assign_alloc(__str); + size_type __str_old_size = __str.size(); + bool __str_was_short = !__str.__is_long(); + __r_.first() = __str.__r_.first(); if (__libcpp_is_constant_evaluated()) { __str.__default_init(); @@ -2579,6 +2713,24 @@ __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. + __annotate_new(__get_short_size()); } #endif @@ -2608,6 +2760,7 @@ > basic_string<_CharT, _Traits, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last) { + size_type __old_size = size(); size_type __cap = capacity(); size_type __n = __string_is_trivial_iterator<_ForwardIterator>::value ? static_cast(std::distance(__first, __last)) : 0; @@ -2619,13 +2772,16 @@ { size_type __sz = size(); __grow_by(__cap, __n - __cap, __sz, 0, __sz); - } + } 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); __invalidate_iterators_past(__n); + if (__n < __old_size) + __annotate_shrink(__old_size); } else { @@ -2698,6 +2854,7 @@ { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); traits_type::copy(__p + __sz, __s, __n); __sz += __n; @@ -2721,6 +2878,8 @@ size_type __sz = size(); if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + else + __annotate_increase(__n); pointer __p = __get_pointer(); traits_type::assign(std::__to_address(__p) + __sz, __n, __c); __sz += __n; @@ -2740,6 +2899,8 @@ size_type __sz = size(); if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + else + __annotate_increase(__n); pointer __p = __get_pointer(); __sz += __n; __set_size(__sz); @@ -2769,7 +2930,8 @@ { __grow_by(__cap, 1, __sz, __sz, 0); __is_short = false; // the string is always long after __grow_by - } + } else + __annotate_increase(1); pointer __p = __get_pointer(); if (__is_short) { @@ -2806,6 +2968,8 @@ { if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + else + __annotate_increase(__n); pointer __p = __get_pointer() + __sz; for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); @@ -2881,6 +3045,7 @@ { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2914,6 +3079,7 @@ 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) @@ -3037,6 +3203,7 @@ } else { + __annotate_increase(1); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -3071,6 +3238,8 @@ 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) { @@ -3115,20 +3284,29 @@ __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(__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(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); + __p = std::__to_address(__get_long_pointer()); + + // We cannot call __null_terminate_at, because state of the string may not be correct, + // after __grow_by and correct state is necessery when changing annotations. + // __null_terminate_at is changing annotations. + traits_type::assign(__p + __pos, __n2, __c); + + __set_size(__sz - (__n1 - __n2)); + __invalidate_iterators_past(__sz - (__n1 - __n2)); + traits_type::assign(__p[__sz - (__n1 - __n2)], value_type()); + + return *this; } traits_type::assign(__p + __pos, __n2, __c); return __null_terminate_at(__p, __sz - (__n1 - __n2)); @@ -3271,6 +3449,7 @@ void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_type __old_size = size(); std::__debug_db_invalidate_all(this); if (__is_long()) { @@ -3282,6 +3461,7 @@ traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_shrink(__old_size); } template @@ -3344,6 +3524,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) { + __annotate_delete(); size_type __cap = capacity(); size_type __sz = size(); @@ -3401,6 +3582,7 @@ else __set_short_size(__sz); std::__debug_db_invalidate_all(this); + __annotate_new(__sz); } template @@ -3457,8 +3639,16 @@ __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 @@ -3994,12 +4184,12 @@ 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); + __default_init(); + } } // operator== @@ -4250,6 +4440,7 @@ _Traits::copy(__ptr, __lhs.data(), __lhs_sz); _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz); _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT()); + __r.__annotate_new(__lhs_sz + __rhs_sz); return __r; } @@ -4264,10 +4455,12 @@ _String __r(__uninitialized_size_tag(), __lhs_sz + __rhs_sz, _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator())); + __r.__annotate_delete(); auto __ptr = std::__to_address(__r.__get_pointer()); _Traits::copy(__ptr, __lhs, __lhs_sz); _Traits::copy(__ptr + __lhs_sz, __rhs.data(), __rhs_sz); _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT()); + __r.__annotate_new(__lhs_sz + __rhs_sz); return __r; } @@ -4281,10 +4474,12 @@ _String __r(__uninitialized_size_tag(), __rhs_sz + 1, _String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator())); + __r.__annotate_delete(); auto __ptr = std::__to_address(__r.__get_pointer()); _Traits::assign(__ptr, 1, __lhs); _Traits::copy(__ptr + 1, __rhs.data(), __rhs_sz); _Traits::assign(__ptr + 1 + __rhs_sz, 1, _CharT()); + __r.__annotate_new(1 + __rhs_sz); return __r; } @@ -4299,10 +4494,12 @@ _String __r(__uninitialized_size_tag(), __lhs_sz + __rhs_sz, _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + __r.__annotate_delete(); auto __ptr = std::__to_address(__r.__get_pointer()); _Traits::copy(__ptr, __lhs.data(), __lhs_sz); _Traits::copy(__ptr + __lhs_sz, __rhs, __rhs_sz); _Traits::assign(__ptr + __lhs_sz + __rhs_sz, 1, _CharT()); + __r.__annotate_new(__lhs_sz + __rhs_sz); return __r; } @@ -4316,10 +4513,12 @@ _String __r(__uninitialized_size_tag(), __lhs_sz + 1, _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + __r.__annotate_delete(); auto __ptr = std::__to_address(__r.__get_pointer()); _Traits::copy(__ptr, __lhs.data(), __lhs_sz); _Traits::assign(__ptr + __lhs_sz, 1, __rhs); _Traits::assign(__ptr + 1 + __lhs_sz, 1, _CharT()); + __r.__annotate_new(__lhs_sz + 1); return __r; } diff --git a/libcxx/test/std/strings/basic.string/string.asan/append.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/append.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/append.pass.cpp @@ -0,0 +1,491 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_simple_append(const CharT* s_init) { + typedef std::basic_string S; + S empty_s; + S short_s(2, 'b'); + S long_s(1100, 'a'); + + empty_s.append(empty_s); + short_s.append(empty_s); + long_s.append(empty_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S short_s2(short_s); + const CharT val = s_init[0]; + short_s.append(2, val); + long_s.append(2, val); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + short_s2.append(24, val); + assert(is_string_asan_correct(short_s2)); + short_s2.append(1024, val); + assert(is_string_asan_correct(short_s2)); + + empty_s.append(s_init); + short_s.append(short_s); + long_s.append(short_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S& not_empty_s = empty_s; + short_s.append(empty_s); + long_s.append(long_s); + + assert(is_string_asan_correct(not_empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + not_empty_s.append(1024, val); + short_s.append(1024, val); + long_s.append(1024, val); + + assert(is_string_asan_correct(not_empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); +} + +template +void test_append( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + typedef std::basic_string S; + + const CharT* ptr1 = s_init; + const CharT* ptr2 = s_long_init; + const CharT* ptr3 = s_init2; + const CharT* ptr4 = s_long_init2; + + size_t size1 = std::char_traits::length(ptr1); + size_t size2 = std::char_traits::length(ptr2); + size_t size3 = std::char_traits::length(ptr3); + size_t size4 = std::char_traits::length(ptr4); + + S s1a(s_init2), s1b(s_long_init2), s1c(s_long_init), s1d(s_init); + s1a.append(ptr1, ptr1 + size1); + s1b.append(ptr2, ptr2 + size2); + s1c.append(ptr3, size3); + s1d.append(ptr4, size4); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + S s2a(ptr4), s2b(ptr3), s2c(s1a), s2d(s1b); + s2a.append(s1a); + s2b.append(s1b); + s2c.append(s1c, 1, 1); + s2d.append(s1d, 2); + + assert(is_string_asan_correct(s2a)); + assert(is_string_asan_correct(s2b)); + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s2c.append(ptr4); + s2d.append(ptr3); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + s2c.append(ptr2); + s2d.append(ptr1); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + S s3a, s3b; + s3a.append(s1a.data(), s1a.data() + s1a.size()); + s3b.append(s1b.data(), s1b.data() + s1b.size()); + + assert(is_string_asan_correct(s3a)); + assert(is_string_asan_correct(s3b)); + + S s4; + s4.append(s1a + s1b); + + assert(is_string_asan_correct(s4)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s5a, s5b, s5c(ptr1), s5d(ptr2); + s5a.append(std::move(s1c)); + s5b.append(std::move(s1d)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + s5c.append(std::move(s5a)); + s5d.append(std::move(s5b)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + assert(is_string_asan_correct(s5c)); + assert(is_string_asan_correct(s5d)); + + S s6a, s6b, s6c; + s6a.append(ptr1); + s6b.append(ptr2); + s6c.append(s_init2); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); + + s6a.append(ptr2, 26); + s6b.append(ptr1, 1); + s6c.append(s_init2, 3); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); +#if TEST_STD_VER >= 11 + S s7a(s_init), s7b(s_long_init), s7c(s_init), s7d(s_long_init2); + s7a.append({Val}); + s7b.append({Val}); + s7c.append({Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + s7d.append({Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + + assert(s7c.size() > sizeof(void*) * 3); + + assert(is_string_asan_correct(s7a)); + assert(is_string_asan_correct(s7b)); + assert(is_string_asan_correct(s7c)); + assert(is_string_asan_correct(s7d)); +#endif + + S s8a, s8b, s8c, s8d; +#if TEST_STD_VER >= 11 + s8a.append(s1a.cbegin(), s1a.cend()); + s8b.append(s1b.cbegin(), s1b.cend()); + s8c.append(s1a.crbegin(), s1a.crend()); + s8d.append(s1b.crbegin(), s1b.crend()); +#else + s8a.append(s1a.begin(), s1a.end()); + s8b.append(s1b.begin(), s1b.end()); + s8c.append(s1a.rbegin(), s1a.rend()); + s8d.append(s1b.rbegin(), s1b.rend()); +#endif + + assert(is_string_asan_correct(s8a)); + assert(is_string_asan_correct(s8b)); + assert(is_string_asan_correct(s8c)); + assert(is_string_asan_correct(s8d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S& s9a = s1a; + S& s9b = s1b; +#if TEST_STD_VER >= 11 + s9a.append(s1a.cbegin() + 1, s1a.cend()); + s9b.append(s1b.cbegin() + 4, s1b.cbegin() + 10); +#else + s9a.append(s1a.begin() + 1, s1a.end()); + s9b.append(s1b.begin() + 4, s1b.begin() + 10); +#endif + + assert(is_string_asan_correct(s9a)); + assert(is_string_asan_correct(s9b)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s10a(ptr1), s10b(ptr2), s10c(ptr3), s10d(ptr4); + s2a.append(3, Val); + s2b.append(300, Val); + s2c.append(300, Val); + s2d.append(3, Val); + + assert(is_string_asan_correct(s10a)); + assert(is_string_asan_correct(s10b)); + assert(is_string_asan_correct(s10c)); + assert(is_string_asan_correct(s10d)); +} + +template +void test_add(const CharT* s_init) { + typedef std::basic_string S; + + S empty_s; + S short_s(2, 'b'); + S long_s(1100, 'a'); + + empty_s += empty_s; + short_s += empty_s; + long_s += empty_s; + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S empty_s2, short_s2(short_s), long_s2(long_s); + empty_s2 += s_init; + short_s2 += s_init; + long_s2 += s_init; + + assert(is_string_asan_correct(empty_s2)); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + S empty_s3, short_s3(short_s), long_s3(long_s); + empty_s3 += short_s; + short_s3 += short_s; + long_s3 += short_s; + + assert(is_string_asan_correct(empty_s3)); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + S& not_empty_s3 = empty_s3; + + assert(is_string_asan_correct(not_empty_s3)); + + not_empty_s3 += long_s; + short_s3 += long_s; + long_s3 += long_s; + + assert(is_string_asan_correct(not_empty_s3)); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + S short_s4(short_s), long_s4(long_s); + short_s4 += not_empty_s3; + long_s4 += not_empty_s3; + + assert(is_string_asan_correct(short_s4)); + assert(is_string_asan_correct(long_s4)); + + CharT val = s_init[0]; + S empty_s5, short_s5(short_s), long_s5(long_s); + empty_s5 += val; + short_s5 += val; + long_s5 += val; + + assert(is_string_asan_correct(empty_s5)); + assert(is_string_asan_correct(short_s5)); + assert(is_string_asan_correct(long_s5)); +#if TEST_STD_VER >= 11 + S empty_s6, short_s6(short_s), long_s6(long_s); + empty_s6 += {}; + short_s6 += {}; + long_s6 += {}; + + assert(is_string_asan_correct(empty_s6)); + assert(is_string_asan_correct(short_s6)); + assert(is_string_asan_correct(long_s6)); + + empty_s6 += {val}; + short_s6 += {val}; + long_s6 += {val}; + + assert(is_string_asan_correct(empty_s6)); + assert(is_string_asan_correct(short_s6)); + assert(is_string_asan_correct(long_s6)); + + S empty_s7, short_s7(short_s), long_s7(long_s); + empty_s7 += {val, val, val, val, val, val, val, val, val, val, val, val, + val, val, val, val, val, val, val, val, val, val, val, val}; + short_s7 += {val, val, val, val, val, val, val, val, val, val, val, val, + val, val, val, val, val, val, val, val, val, val, val, val}; + long_s7 += {val, val, val, val, val, val, val, val, val, val, val, val, + val, val, val, val, val, val, val, val, val, val, val, val}; + + assert(is_string_asan_correct(empty_s7)); + assert(is_string_asan_correct(short_s7)); + assert(is_string_asan_correct(long_s7)); +#endif +} + +template +void test_view() { + typedef std::basic_string S; + typedef std::basic_string_view SV; + S empty_s; + S short_s(4, 'b'); + S long_s(1100, 'a'); + + SV empty_v(empty_s); + SV short_v(short_s); + SV long_v(long_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + SV partial_short_v(short_s.data() + 1, 1); + SV partial_long_v(long_s.data() + 10, 200); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + // append + + S empty_s2a(empty_s), short_s2a(short_s), long_s2a(long_s); + empty_s2a.append(empty_v); + short_s2a.append(short_v); + long_s2a.append(long_v); + + assert(is_string_asan_correct(empty_s2a)); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + S partial_short_s2, partial_long_s2(short_s); + partial_short_s2.append(partial_short_v); + partial_long_s2.append(partial_long_v); + + assert(is_string_asan_correct(partial_short_s2)); + assert(is_string_asan_correct(partial_long_s2)); + + S empty_s2b(empty_s), short_s2b(short_s), long_s2b(long_s); + empty_s2b.append(empty_v, 0, 0); + short_s2b.append(short_v, 1, 2); + long_s2b.append(long_v, 4, 280); + + assert(is_string_asan_correct(empty_s2b)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2b)); + + // operator+= + + S empty_s3, short_s3, long_s3; + empty_s3 += empty_v; + short_s3 += short_v; + long_s3 += long_v; + + assert(is_string_asan_correct(empty_s3)); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + S partial_short_s3, partial_long_s3; + partial_short_s3 += partial_short_v; + partial_long_s3 += partial_long_v; + + assert(is_string_asan_correct(partial_short_s3)); + assert(is_string_asan_correct(partial_long_s3)); +} + +template +void test( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + test_simple_append(s_init); + test_append(Val, s_init, s_init2, s_long_init, s_long_init2); + test_add(s_init); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +char literal_2[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"abc"; +char32_t literal32_2[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long2[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + typedef char CharT; + test('x', literal, literal_2, literal_long, literal_long2); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + typedef wchar_t CharT; + test(L'x', wliteral, wliteral_2, wliteral_long, wliteral_long2); + } +#endif +#if TEST_STD_VER >= 11 + { + typedef char16_t CharT; + test(u'x', literal16, literal16_2, literal16_long, literal16_long2); + } + { + typedef char32_t CharT; + test(U'x', literal32, literal32_2, literal32_long, literal32_long2); + } +#endif +#if TEST_STD_VER >= 20 + { + typedef char8_t CharT; + test(u8'x', literal8, literal8_2, literal8_long, literal8_long2); + } +#endif + + return 0; +} + diff --git a/libcxx/test/std/strings/basic.string/string.asan/assign.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/assign.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/assign.pass.cpp @@ -0,0 +1,460 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_eq( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + typedef std::basic_string S; + + S s1a, s1b, s1c = s_init, s1d = s_long_init; + s1a = s_init2; + s1b = s_long_init2; + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + S s2a = s1a, s2b = s1b, s2c = s1c; + + assert(is_string_asan_correct(s2a)); + assert(is_string_asan_correct(s2b)); + assert(is_string_asan_correct(s2c)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + + S s3a, s3b, s3c; + s3a = s1a; + s3b = s1b; + s3c = s1c; + + assert(is_string_asan_correct(s3a)); + assert(is_string_asan_correct(s3b)); + assert(is_string_asan_correct(s3c)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + + S s4a, s4b(s_init), s4c(s_long_init); + s4a = s1a + s1b; + + assert(is_string_asan_correct(s4a)); + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s4b = s1a + s1b; + + assert(is_string_asan_correct(s4b)); + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s4c = s1a + s1b; + + assert(is_string_asan_correct(s4c)); + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s4a = s4a + s1a; + + assert(is_string_asan_correct(s4a)); + assert(is_string_asan_correct(s1a)); + + s4c = s4c + s4c; + + assert(is_string_asan_correct(s4c)); + + S s5a, s5b(s_init), s5c(s_long_init), s5d, s5e(s_init), s5f(s_long_init); + s5a = std::move(s1c); + s5b = std::move(s2c); + s5c = std::move(s3c); + s5d = std::move(s5d); + s5e = std::move(s5e); + s5f = std::move(s5f); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + assert(is_string_asan_correct(s5c)); + assert(is_string_asan_correct(s5d)); + assert(is_string_asan_correct(s5e)); + assert(is_string_asan_correct(s5f)); + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s3c)); + + S s6a, s6b(s_init), s6c(s_long_init); + s6a = Val; + s6b = Val; + s6c = Val; + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); + +#if TEST_STD_VER >= 11 + S s7a(s_init), s7b(s_long_init), s7c(s_init), s7d(s_long_init2); + s7a = {Val}; + s7b = {Val}; + s7c = {Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}; + s7d = {Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}; + + assert(s7c.size() > sizeof(void*) * 3); + + assert(is_string_asan_correct(s7a)); + assert(is_string_asan_correct(s7b)); + assert(is_string_asan_correct(s7c)); + assert(is_string_asan_correct(s7d)); +#endif +} + +template +void test_assign( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + typedef std::basic_string S; + + const CharT* ptr1 = s_init; + const CharT* ptr2 = s_long_init; + const CharT* ptr3 = s_init2; + const CharT* ptr4 = s_long_init2; + + size_t size1 = std::char_traits::length(ptr1); + size_t size2 = std::char_traits::length(ptr2); + size_t size3 = std::char_traits::length(ptr3); + size_t size4 = std::char_traits::length(ptr4); + + S s1a(s_init2), s1b(s_long_init2), s1c(s_long_init), s1d(s_init); + s1a.assign(ptr1, ptr1 + size1); + s1b.assign(ptr2, ptr2 + size2); + s1c.assign(ptr3, size3); + s1d.assign(ptr4, size4); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + S s2a(ptr4), s2b(ptr3), s2c(s1a), s2d(s1b); + s2a.assign(s1a); + s2b.assign(s1b); + s2c.assign(s1c, 1, 1); + s2d.assign(s1d, 2); + + assert(is_string_asan_correct(s2a)); + assert(is_string_asan_correct(s2b)); + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s2c.assign(ptr4); + s2d.assign(ptr3); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + s2c.assign(ptr2); + s2d.assign(ptr1); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + S s3a, s3b; + s3a.assign(s1a.data(), s1a.data() + s1a.size()); + s3b.assign(s1b.data(), s1b.data() + s1b.size()); + + assert(is_string_asan_correct(s3a)); + assert(is_string_asan_correct(s3b)); + + S s4; + s4.assign(s1a + s1b); + + assert(is_string_asan_correct(s4)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s5a, s5b, s5c(ptr1), s5d(ptr2); + s5a.assign(std::move(s1c)); + s5b.assign(std::move(s1d)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + s5c.assign(std::move(s5a)); + s5d.assign(std::move(s5b)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + assert(is_string_asan_correct(s5c)); + assert(is_string_asan_correct(s5d)); + + S s6a, s6b, s6c; + s6a.assign(ptr1); + s6b.assign(ptr2); + s6c.assign(s_init2); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); + + s6a.assign(ptr2, 26); + s6b.assign(ptr1, 1); + s6c.assign(s_init2, 3); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); +#if TEST_STD_VER >= 11 + S s7a(s_init), s7b(s_long_init), s7c(s_init), s7d(s_long_init2); + s7a.assign({Val}); + s7b.assign({Val}); + s7c.assign({Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + s7d.assign({Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + + assert(s7c.size() > sizeof(void*) * 3); + + assert(is_string_asan_correct(s7a)); + assert(is_string_asan_correct(s7b)); + assert(is_string_asan_correct(s7c)); + assert(is_string_asan_correct(s7d)); +#endif + + S s8a, s8b, s8c, s8d; +#if TEST_STD_VER >= 11 + s8a.assign(s1a.cbegin(), s1a.cend()); + s8b.assign(s1b.cbegin(), s1b.cend()); + s8c.assign(s1a.crbegin(), s1a.crend()); + s8d.assign(s1b.crbegin(), s1b.crend()); +#else + s8a.assign(s1a.begin(), s1a.end()); + s8b.assign(s1b.begin(), s1b.end()); + s8c.assign(s1a.rbegin(), s1a.rend()); + s8d.assign(s1b.rbegin(), s1b.rend()); +#endif + + assert(is_string_asan_correct(s8a)); + assert(is_string_asan_correct(s8b)); + assert(is_string_asan_correct(s8c)); + assert(is_string_asan_correct(s8d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S& s9a = s1a; + S& s9b = s1b; +#if TEST_STD_VER >= 11 + s9a.assign(s1a.cbegin() + 1, s1a.cend()); + s9b.assign(s1b.cbegin() + 4, s1b.cbegin() + 10); +#else + s9a.assign(s1a.begin() + 1, s1a.end()); + s9b.assign(s1b.begin() + 4, s1b.begin() + 10); +#endif + + assert(is_string_asan_correct(s9a)); + assert(is_string_asan_correct(s9b)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s10a(ptr1), s10b(ptr2), s10c(ptr3), s10d(ptr4); + s2a.assign(3, Val); + s2b.assign(300, Val); + s2c.assign(300, Val); + s2d.assign(3, Val); + + assert(is_string_asan_correct(s10a)); + assert(is_string_asan_correct(s10b)); + assert(is_string_asan_correct(s10c)); + assert(is_string_asan_correct(s10d)); +} + +template +void test_view() { + typedef std::basic_string S; + typedef std::basic_string_view SV; + S empty_s; + S short_s(4, 'b'); + S long_s(1100, 'a'); + + SV empty_v(empty_s); + SV short_v(short_s); + SV long_v(long_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + SV partial_short_v(short_s.data() + 1, 1); + SV partial_long_v(long_s.data() + 10, 200); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + // assign + + S empty_s2a(empty_s), short_s2a(short_s), long_s2a(long_s); + empty_s2a.assign(empty_v); + short_s2a.assign(short_v); + long_s2a.assign(long_v); + + assert(is_string_asan_correct(empty_s2a)); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + S partial_short_s2, partial_long_s2; + partial_short_s2.assign(partial_short_v); + partial_long_s2.assign(partial_long_v); + + assert(is_string_asan_correct(partial_short_s2)); + assert(is_string_asan_correct(partial_long_s2)); + + S empty_s2b(empty_s), short_s2b(short_s), long_s2b(long_s); + empty_s2b.assign(empty_v, 0, 0); + short_s2b.assign(short_v, 1, 2); + long_s2b.assign(long_v, 4, 280); + + assert(is_string_asan_correct(empty_s2b)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2b)); + + // operator= + + S empty_s3, short_s3, long_s3; + empty_s3 = empty_v; + short_s3 = short_v; + long_s3 = long_v; + + assert(is_string_asan_correct(empty_s3)); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + empty_s3 = short_v; + short_s3 = long_v; + long_s3 = empty_v; + + assert(is_string_asan_correct(empty_s3)); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + S partial_short_s3, partial_long_s3; + partial_short_s3 = partial_short_v; + partial_long_s3 = partial_long_v; + + assert(is_string_asan_correct(partial_short_s3)); + assert(is_string_asan_correct(partial_long_s3)); +} + +template +void test( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + test_eq(Val, s_init, s_init2, s_long_init, s_long_init2); + test_assign(Val, s_init, s_init2, s_long_init, s_long_init2); + test_view(); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +char literal_2[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"abc"; +char32_t literal32_2[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long2[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + typedef char CharT; + test('x', literal, literal_2, literal_long, literal_long2); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + typedef wchar_t CharT; + test(L'x', wliteral, wliteral_2, wliteral_long, wliteral_long2); + } +#endif +#if TEST_STD_VER >= 11 + { + typedef char16_t CharT; + test(u'x', literal16, literal16_2, literal16_long, literal16_long2); + } + { + typedef char32_t CharT; + test(U'x', literal32, literal32_2, literal32_long, literal32_long2); + } +#endif +#if TEST_STD_VER >= 20 + { + typedef char8_t CharT; + test(u8'x', literal8, literal8_2, literal8_long, literal8_long2); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/concatenate.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/concatenate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/concatenate.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test(const CharT* s_init) { + using S = std::basic_string; + + S empty_s; + S short_s(s_init); + S long_s(1100, 'a'); + + assert(is_string_asan_correct(empty_s + empty_s)); + assert(is_string_asan_correct(empty_s + short_s)); + assert(is_string_asan_correct(empty_s + long_s)); + + assert(is_string_asan_correct(short_s + empty_s)); + assert(is_string_asan_correct(short_s + short_s)); + assert(is_string_asan_correct(short_s + long_s)); + + assert(is_string_asan_correct(long_s + empty_s)); + assert(is_string_asan_correct(long_s + long_s)); + assert(is_string_asan_correct(long_s + long_s)); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +int main(int, char**) { + { + using CharT = char; + test(literal); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(wliteral); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(literal16); + } + { + using CharT = char32_t; + test(literal32); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(literal8); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/constructor.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/constructor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/constructor.pass.cpp @@ -0,0 +1,333 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_basic(const CharT* s_init, + const CharT* s_init2, + const CharT* s_init3, + const CharT* s_long_init, + const CharT* s_long_init2, + const CharT* s_long_init3) { + using S = std::basic_string; + + // Allocator + S sa((std::allocator())); + assert(is_string_asan_correct(sa)); + + // Empty string + S s1; + assert(is_string_asan_correct(s1)); + + // + S s2a(s_init), s2b = s_init2, s2c = s_init3; + assert(is_string_asan_correct(s2a)); + assert(is_string_asan_correct(s2b)); + assert(is_string_asan_correct(s2c)); + + S s3a = s_long_init2; + assert(s3a.size() >= 24); + S s3b(s_long_init); + assert(s3b.size() >= 24); + + assert(is_string_asan_correct(s3a)); + assert(is_string_asan_correct(s3b)); + + S s4(s_long_init3); + + assert(s4.size() > 8 * 4); + assert(is_string_asan_correct(s4)); + + S s5a(1, 'a'), s5b(3, 'c'), s5c(1000, 'q'); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + assert(is_string_asan_correct(s5c)); + + S s6a(s5c.data() + 3, s5c.data() + 5), s6b(s4.data(), s4.data() + 22), s6c(s5c.data(), s5c.data() + 999); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); + + S s7a(s6a, 1), s7b(s6b, 20), s7c(s6c, 300), s7d(s6c, 995); + + assert(is_string_asan_correct(s7a)); + assert(is_string_asan_correct(s7b)); + assert(is_string_asan_correct(s7c)); + assert(is_string_asan_correct(s7d)); + + S s8a(s6a, 1, 1), s8b(s6b, 20, 1), s8c(s6c, 300, 600), s8d(s6c, 995, 2); + + assert(is_string_asan_correct(s8a)); + assert(is_string_asan_correct(s8b)); + assert(is_string_asan_correct(s8c)); + assert(is_string_asan_correct(s8d)); + + assert(std::char_traits::length(s_long_init) > 34); + S s9a(s_long_init, 0), s9b(s_long_init, 5), s9c(s_long_init, 34); + + assert(is_string_asan_correct(s9a)); + assert(is_string_asan_correct(s9b)); + assert(is_string_asan_correct(s9c)); + +#if TEST_STD_VER >= 11 + const CharT val = s_long_init[0]; + S s10a{val, val, val, val, val, val}; + S s10b{val, val, val, val, val, val, val, val, val, val, val, val, val, val, val, val, + val, val, val, val, val, val, val, val, val, val, val, val, val, val, val, val}; + S s10c({val, val, val}); + assert(is_string_asan_correct(s10a)); + assert(is_string_asan_correct(s10b)); + assert(is_string_asan_correct(s10c)); +#endif +} + +template +S get_s(size_t n, char c = 'a') { + S s; + while (s.size() < n) + s.push_back(c); + + return s; +} + +template +void test_complex() { + S short_s1a(get_s(1)), short_s1b = get_s(1, 'b'); + S long_s1a(get_s(91, 'c')), long_s1b = get_s(91); + + assert(is_string_asan_correct(short_s1a)); + assert(is_string_asan_correct(short_s1b)); + assert(is_string_asan_correct(long_s1a)); + assert(is_string_asan_correct(long_s1b)); + + S short_s2a(std::move(short_s1a)), short_s2b = std::move(short_s1b); + S long_s2a(std::move(long_s1a)), long_s2b = std::move(long_s1b); + + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2a)); + assert(is_string_asan_correct(long_s2b)); + + assert(is_string_asan_correct(short_s1a)); + assert(is_string_asan_correct(short_s1b)); + assert(is_string_asan_correct(long_s1a)); + assert(is_string_asan_correct(long_s1b)); + + S short_s3a(short_s2a), short_s3b = short_s2b; + S long_s3a(long_s2a), long_s3b = long_s2b; + + assert(is_string_asan_correct(short_s3a)); + assert(is_string_asan_correct(short_s3b)); + assert(is_string_asan_correct(long_s3a)); + assert(is_string_asan_correct(long_s3b)); + + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2a)); + assert(is_string_asan_correct(long_s2b)); + + using value_type = typename S::value_type; + value_type a = value_type('a'); + + S short_s4(1, a); + S long_s4(91, a); + + assert(is_string_asan_correct(short_s4)); + assert(is_string_asan_correct(long_s4)); + + S short_s5(long_s4.begin(), long_s4.begin() + 1); + S long_s5(long_s4.rbegin(), long_s4.rbegin() + 81); + + assert(is_string_asan_correct(short_s5)); + assert(is_string_asan_correct(long_s5)); + assert(is_string_asan_correct(long_s4)); + +#if TEST_STD_VER >= 11 + S short_s6({short_s5[0]}); + S long_s6({ + long_s5[0], long_s5[1], long_s5[2], long_s5[3], long_s5[4], long_s5[5], long_s5[6], long_s5[7], + long_s5[8], long_s5[9], long_s5[0], long_s5[1], long_s5[2], long_s5[3], long_s5[4], long_s5[5], + long_s5[6], long_s5[7], long_s5[1], long_s5[2], long_s5[3], long_s5[4], long_s5[5], long_s5[6], + }); + + assert(is_string_asan_correct(short_s6)); + assert(is_string_asan_correct(long_s6)); + assert(is_string_asan_correct(short_s5)); + assert(is_string_asan_correct(long_s5)); +#endif +} + +template +void test_view() { + using S = std::basic_string; + using SV = std::basic_string_view; + S empty_s; + S short_s(3, 'b'); + S long_s(1100, 'a'); + + SV empty_v(empty_s); + SV short_v(short_s); + SV long_v = long_s; + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + SV partial_short_v(short_s.data() + 1, 1); + SV partial_long_v(long_s.data() + 10, 200); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S empty_sb(empty_v); + S short_sb(short_v); + S long_sb(long_v); + + assert(is_string_asan_correct(empty_sb)); + assert(is_string_asan_correct(short_sb)); + assert(is_string_asan_correct(long_sb)); + + S partial_short_s(partial_short_v); + S partial_long_s(partial_long_v); + S partial_s(long_v, 10, 30); + + assert(is_string_asan_correct(partial_short_s)); + assert(is_string_asan_correct(partial_long_s)); + assert(is_string_asan_correct(partial_s)); +} + +template +void test(const CharT* s_init, + const CharT* s_init2, + const CharT* s_init3, + const CharT* s_long_init, + const CharT* s_long_init2, + const CharT* s_long_init3) { + test_basic(s_init, s_init2, s_init3, s_long_init, s_long_init2, s_long_init3); + using S = std::basic_string; + test_complex(); + test_view(); +} + +char literal[] = "a"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"a"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"a"; +char32_t literal32[] = U"a"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"a"; +#endif + +char literal_2[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"ab"; +char32_t literal32_2[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"ab"; +#endif + +char literal_3[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_3[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_3[] = u"abc"; +char32_t literal32_3[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_3[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +char32_t literal32_long2[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +#endif + +char literal_long3[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long3[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long3[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long3[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long3[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + using CharT = char; + test(literal, literal_2, literal_3, literal_long, literal_long2, literal_long3); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(wliteral, wliteral_2, wliteral_3, wliteral_long, wliteral_long2, wliteral_long3); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(literal16, literal16_2, literal16_3, literal16_long, literal16_long2, literal16_long3); + } + { + using CharT = char32_t; + test(literal32, literal32_2, literal32_3, literal32_long, literal32_long2, literal32_long3); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(literal8, literal8_2, literal8_3, literal8_long, literal8_long2, literal8_long3); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/erase.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/erase.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/erase.pass.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test() { + S short_s, long_s; + + for (size_t i = 0; i < 1000; ++i) { + long_s.push_back('a' + (i % 3)); + + if (i < 6) + short_s.push_back('a' + (i % 3)); + } + + S short_s2(short_s), long_s2(long_s); + short_s2.erase(short_s2.begin()); + long_s2.erase(long_s2.begin()); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + short_s2.erase(short_s2.begin() + 1); + long_s2.erase(long_s2.begin() + 1); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + short_s2.erase(1, 2); + long_s2.erase(30, 200); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + short_s2.erase(1); + long_s2.erase(5); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + short_s2.erase(); + long_s2.erase(); + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + S short_s3(short_s), long_s3(long_s); + short_s3.erase(short_s3.begin() + 1, short_s3.end() - 1); + long_s3.erase(long_s3.begin() + 100, long_s3.end() - 100); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); + + long_s3.erase(long_s3.begin() + 20, long_s3.end() - 20); + assert(is_string_asan_correct(long_s3)); + + short_s3.erase(); + long_s3.erase(); + assert(is_string_asan_correct(short_s3)); + assert(is_string_asan_correct(long_s3)); +} + +int main(int, char**) { + { + using S = std::string; + test(); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using S = std::wstring; + test(); + } +#endif +#if TEST_STD_VER >= 11 + { + using S = std::u16string; + test(); + } + { + using S = std::u32string; + test(); + } +#endif +#if TEST_STD_VER >= 20 + { + using S = std::u8string; + test(); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/insert.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/insert.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/insert.pass.cpp @@ -0,0 +1,384 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03 + +// + +#include +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_simple_insert(const CharT* s_init, const CharT* s_long_init) { + using S = std::basic_string; + const CharT val = s_init[0], val2 = s_long_init[1]; + + S short_s(2, val); + S long_s(1100, val2); + + short_s.insert(1, 2, val); + long_s.insert(10, 9, val2); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + +#if TEST_STD_VER >= 11 + short_s.insert(short_s.cbegin() + 2, val); + long_s.insert(long_s.cbegin() + 22, val); +#else + short_s.insert(short_s.begin() + 2, val); + long_s.insert(long_s.begin() + 22, val); +#endif + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S short_s2(short_s), long_s2(long_s); +#if TEST_STD_VER >= 11 + short_s2.insert(short_s2.cbegin() + 2, 128, val); + long_s2.insert(long_s2.cbegin() + 22, 128, val); +#else + short_s2.insert(short_s2.begin() + 2, 128, val); + long_s2.insert(long_s2.begin() + 22, 128, val); +#endif + + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + +#if TEST_STD_VER >= 14 + short_s.insert(2, s_init, 2, 2); + long_s.insert(2, s_long_init, 22, 2); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + short_s.insert(2, 1000, val2); + + assert(is_string_asan_correct(short_s)); +#endif +} + +template +void test_insert( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + using S = std::basic_string; + + const CharT* ptr1 = s_init; + const CharT* ptr2 = s_long_init; + const CharT* ptr3 = s_init2; + const CharT* ptr4 = s_long_init2; + + size_t size1 = std::char_traits::length(ptr1); + size_t size2 = std::char_traits::length(ptr2); + size_t size3 = std::char_traits::length(ptr3); + size_t size4 = std::char_traits::length(ptr4); + + S s1a(s_init2), s1b(s_long_init2), s1c(s_long_init), s1d(s_init); + s1a.insert(s1a.begin() + 1, ptr1, ptr1 + size1); + s1b.insert(s1b.begin() + 9, ptr2, ptr2 + size2); + s1c.insert(8, ptr3, size3); + s1d.insert(1, ptr4, size4); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + S s2a(ptr4), s2b(ptr3), s2c(s1a), s2d(s1b); + s2a.insert(1, s1a); + s2b.insert(1, s1b); + s2c.insert(1, s1c, 1, 1); + s2d.insert(1, s1d, 2); + + assert(is_string_asan_correct(s2a)); + assert(is_string_asan_correct(s2b)); + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + s2c.insert(1, ptr4); + s2d.insert(1, ptr3); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + s2c.insert(0, ptr2); + s2d.insert(0, ptr1); + + assert(is_string_asan_correct(s2c)); + assert(is_string_asan_correct(s2d)); + + S s3a(s_init2), s3b(s_long_init2); + s3a.insert(s3a.begin() + 1, s1a.data(), s1a.data() + s1a.size() - 1); + s3b.insert(s3b.begin() + 1, s1b.data(), s1b.data() + s1b.size() - 1); + + assert(is_string_asan_correct(s3a)); + assert(is_string_asan_correct(s3b)); + + S s4(s_long_init); + s4.insert(1, s1a + s1b); + + assert(is_string_asan_correct(s4)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s5a, s5b(s_init2), s5c(ptr1), s5d(ptr2); + s5a.insert(0, std::move(s1c)); + s5b.insert(s5b.size(), std::move(s1d)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + + assert(is_string_asan_correct(s1c)); + assert(is_string_asan_correct(s1d)); + + s5c.insert(1, std::move(s5a)); + s5d.insert(1, std::move(s5b)); + + assert(is_string_asan_correct(s5a)); + assert(is_string_asan_correct(s5b)); + assert(is_string_asan_correct(s5c)); + assert(is_string_asan_correct(s5d)); + + S s6a, s6b, s6c; + s6a.insert(0, ptr1); + s6b.insert(0, ptr2); + s6c.insert(s6c.size(), s_init2); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); + + s6a.insert(1, ptr2, 26); + s6b.insert(1, ptr1, 1); + s6c.insert(1, s_init2, 3); + + assert(is_string_asan_correct(s6a)); + assert(is_string_asan_correct(s6b)); + assert(is_string_asan_correct(s6c)); +#if TEST_STD_VER >= 11 + S s7a(s_init), s7b(s_long_init), s7c(s_init), s7d(s_long_init2); + s7a.insert(s7a.begin() + 1, {Val}); + s7b.insert(s7b.begin() + 1, {Val}); + s7c.insert(s7c.begin() + 1, + {Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + s7d.insert(s7d.begin() + 1, + {Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, + Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val, Val}); + + assert(s7c.size() > sizeof(void*) * 3); + + assert(is_string_asan_correct(s7a)); + assert(is_string_asan_correct(s7b)); + assert(is_string_asan_correct(s7c)); + assert(is_string_asan_correct(s7d)); +#endif + + S s8a(ptr1), s8b(ptr2), s8c(ptr4), s8d(ptr3); +#if TEST_STD_VER >= 11 + s8a.insert(s8a.begin() + 1, s1a.cbegin(), s1a.cend()); + s8b.insert(s8b.begin() + 1, s1b.cbegin(), s1b.cend()); + s8c.insert(s8c.begin() + 1, s1a.crbegin(), s1a.crend()); + s8d.insert(s8d.begin() + 1, s1b.crbegin(), s1b.crend()); +#else + s8a.insert(s8a.begin() + 1, s1a.begin(), s1a.end()); + s8b.insert(s8b.begin() + 1, s1b.begin(), s1b.end()); + s8c.insert(s8c.begin() + 1, s1a.rbegin(), s1a.rend()); + s8d.insert(s8d.begin() + 1, s1b.rbegin(), s1b.rend()); +#endif + + assert(is_string_asan_correct(s8a)); + assert(is_string_asan_correct(s8b)); + assert(is_string_asan_correct(s8c)); + assert(is_string_asan_correct(s8d)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S &s9a = s1a, s9b = s1b; +#if TEST_STD_VER >= 11 + s9a.insert(s9a.end() - 1, s1a.cbegin() + 1, s1a.cend()); + s9b.insert(s9b.end() - 1, s1b.cbegin() + 4, s1b.cbegin() + 10); +#else + s9a.insert(s9a.end() - 1, s1a.begin() + 1, s1a.end()); + s9b.insert(s9b.end() - 1, s1b.begin() + 4, s1b.begin() + 10); +#endif + + assert(is_string_asan_correct(s9a)); + assert(is_string_asan_correct(s9b)); + + assert(is_string_asan_correct(s1a)); + assert(is_string_asan_correct(s1b)); + + S s10a(ptr1), s10b(ptr2), s10c(ptr3), s10d(ptr4); + s2a.insert(1, 3, Val); + s2b.insert(10, 300, Val); + s2c.insert(10, 300, Val); + s2d.insert(1, 3, Val); + + assert(is_string_asan_correct(s10a)); + assert(is_string_asan_correct(s10b)); + assert(is_string_asan_correct(s10c)); + assert(is_string_asan_correct(s10d)); +} + +template +void test_view() { + using S = std::basic_string; + using SV = std::basic_string_view; + S empty_s; + S short_s(4, 'b'); + S long_s(1100, 'a'); + + SV empty_v(empty_s); + SV short_v(short_s); + SV long_v(long_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + SV partial_short_v(short_s.data() + 1, 1); + SV partial_long_v(long_s.data() + 10, 200); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + // insert + + S empty_s2a(empty_v), short_s2a(short_v), long_s2a(long_v); + empty_s2a.insert(0, empty_v); + short_s2a.insert(1, short_v); + long_s2a.insert(99, long_v); + + assert(is_string_asan_correct(empty_s2a)); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + S partial_short_s2(short_s), partial_long_s2(long_s); + partial_short_s2.insert(1, partial_short_v); + partial_long_s2.insert(99, partial_long_v); + + assert(is_string_asan_correct(partial_short_s2)); + assert(is_string_asan_correct(partial_long_s2)); + + S empty_s2b(long_s), short_s2b(short_s), long_s2b(long_s); + empty_s2b.insert(0, empty_v, 0, 0); + short_s2b.insert(1, short_v, 1, 2); + long_s2b.insert(99, long_v, 4, 280); + + assert(is_string_asan_correct(empty_s2b)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2b)); + + empty_s2b.insert(0, empty_v, 0); + short_s2b.insert(1, short_v, 1); + long_s2b.insert(99, long_v, 4); + + assert(is_string_asan_correct(empty_s2b)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2b)); +} + +template +void test( + const CharT Val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + test_simple_insert(s_init, s_long_init2); + test_insert(Val, s_init, s_init2, s_long_init, s_long_init2); + test_view(); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +char literal_2[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"abc"; +char32_t literal32_2[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long2[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + using CharT = char; + test('x', literal, literal_2, literal_long, literal_long2); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(L'x', wliteral, wliteral_2, wliteral_long, wliteral_long2); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(u'x', literal16, literal16_2, literal16_long, literal16_long2); + } + { + using CharT = char32_t; + test(U'x', literal32, literal32_2, literal32_long, literal32_long2); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(u8'x', literal8, literal8_2, literal8_long, literal8_long2); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/push_pop_back.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/push_pop_back.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/push_pop_back.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test(const CharT val) { + using S = std::basic_string; + + S s; + while (s.size() < 8000) { + s.push_back(val); + + assert(is_string_asan_correct(s)); + } +#if TEST_STD_VER >= 11 + while (s.size() > 0) { + s.pop_back(); + + assert(is_string_asan_correct(s)); + } +#endif +} + +int main(int, char**) { + { + using CharT = char; + test('x'); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(L'x'); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(u'x'); + } + { + using CharT = char32_t; + test(U'x'); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(u8'x'); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.asan/replace.pass.cpp b/libcxx/test/std/strings/basic.string/string.asan/replace.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.asan/replace.pass.cpp @@ -0,0 +1,327 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03 + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_replace_basic(const CharT val) { + using S = std::basic_string; + + S short_s, long_s, x, one; + + one.push_back('1'); + for (size_t i = 0; i < 1000; ++i) { + long_s.push_back('a' + (i % 3)); + x.push_back('x'); + if (i < 5) + short_s.push_back('a' + (i % 3)); + } + + short_s.replace(1, 2, one.data()); + long_s.replace(20, 20, one.data()); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + short_s.replace(short_s.begin(), short_s.begin() + 1, 2, val); + long_s.replace(long_s.begin(), long_s.begin() + 1, 2, val); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + short_s.replace(1, 2, x.data()); + long_s.replace(20, 2, x.data()); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S short_s2(3, val), long_s2(300, val); + + short_s2.replace(short_s2.begin() + 1, short_s2.begin() + 3, {val}); + long_s2.replace(long_s2.begin() + 1, long_s2.begin() + 3, {val}); + + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); + + short_s2.push_back(val); + + assert(is_string_asan_correct(short_s2)); + + short_s2.replace(short_s2.begin() + 1, short_s2.begin() + 3, {val, val, val, val}); + long_s2.replace(long_s2.begin() + 1, long_s2.begin() + 3, {val, val, val, val}); + + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); +} + +template +void test_replace(const CharT* s_init, const CharT* s_long_init) { + using S = std::basic_string; + + S long_buffer; + while (long_buffer.size() < 190) { + long_buffer.push_back(s_init[0]); + } + + S short_s1a(s_init), long_s1a(s_long_init); + short_s1a.replace(1, 1, long_buffer); + long_s1a.replace(10, 10, long_buffer); + + assert(is_string_asan_correct(short_s1a)); + assert(is_string_asan_correct(long_s1a)); + + S short_s1b(s_init), long_s1b(s_long_init); + short_s1b.replace(short_s1b.begin() + 1, short_s1b.begin() + 2, long_buffer); + long_s1b.replace(long_s1b.begin() + 10, long_s1b.begin() + 20, long_buffer); + + assert(is_string_asan_correct(short_s1b)); + assert(is_string_asan_correct(long_s1b)); + + S short_s2a(s_init), long_s2a(s_long_init); + short_s2a.replace(1, 1, long_buffer, 5, 7); + long_s2a.replace(1, 1, long_buffer, 5, 7); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + short_s2a.replace(1, 1, long_buffer, 5, 77); + long_s2a.replace(1, 10, long_buffer, 5, 7); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + short_s2a.replace(1, 1, long_buffer, 5); + long_s2a.replace(1, 10, long_buffer, 5); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + long_s2a.replace(1, 1, short_s2a, 1, 7000); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + S short_s3a(s_init), long_s3a(s_long_init); + short_s3a.replace(short_s3a.begin() + 1, short_s3a.end(), long_s2a.begin(), long_s2a.begin() + 25); + long_s3a.replace(long_s3a.begin() + 1, long_s3a.begin() + 4, long_s2a.begin(), long_s2a.begin() + 25); + assert(is_string_asan_correct(short_s3a)); + assert(is_string_asan_correct(long_s3a)); + + S short_s4a(s_init), long_s4a(s_long_init); + short_s4a.replace(1, 1, s_long_init, 26); + long_s4a.replace(2, 4, s_long_init, 26); + assert(is_string_asan_correct(short_s4a)); + assert(is_string_asan_correct(long_s4a)); + + S short_s5a(s_init), long_s5a(s_long_init); + short_s5a.replace(1, 1, s_long_init); + long_s5a.replace(2, 4, s_long_init); + assert(is_string_asan_correct(short_s5a)); + assert(is_string_asan_correct(long_s5a)); + + S short_s5b(s_init), long_s5b(s_long_init); + short_s5b.replace(short_s5b.end() - 1, short_s5b.end(), s_long_init); + long_s5b.replace(long_s5b.end() - 4, long_s5b.end() - 2, s_long_init); + assert(is_string_asan_correct(short_s5b)); + assert(is_string_asan_correct(long_s5b)); + + const CharT val = s_init[1]; + S short_s6a(s_init), long_s6a(s_long_init); + short_s6a.replace(1, 1, 128, val); + long_s6a.replace(2, 4, 128, val); + assert(is_string_asan_correct(short_s6a)); + assert(is_string_asan_correct(long_s6a)); + + S short_s6b(s_init), long_s6b(s_long_init); + short_s6b.replace(short_s6b.end() - 1, short_s6b.end(), 1, val); + long_s6b.replace(long_s6b.end() - 4, long_s6b.end() - 2, 1, val); + assert(is_string_asan_correct(short_s6b)); + assert(is_string_asan_correct(long_s6b)); + + short_s6b.replace(short_s6b.end() - 1, short_s6b.end(), 128, val); + long_s6b.replace(long_s6b.end() - 4, long_s6b.end() - 2, 128, val); + assert(is_string_asan_correct(short_s6b)); + assert(is_string_asan_correct(long_s6b)); + + short_s6b.replace(short_s6b.begin() + 1, short_s6b.end() - 1, 1, val); + long_s6b.replace(long_s6b.begin() + 1, long_s6b.end() - 1, 1, val); + assert(is_string_asan_correct(short_s6b)); + assert(is_string_asan_correct(long_s6b)); + + S short_s7a(s_init), long_s7a(s_long_init); + short_s7a.replace(short_s7a.end() - 1, short_s7a.end(), {val, val}); + long_s7a.replace(long_s7a.end() - 4, long_s7a.end() - 2, {val, val}); + assert(is_string_asan_correct(short_s7a)); + assert(is_string_asan_correct(long_s7a)); + + short_s7a.replace(short_s7a.begin() + 1, short_s7a.end() - 1, {val}); + long_s7a.replace(long_s7a.begin() + 1, long_s7a.end() - 1, {val}); + assert(is_string_asan_correct(short_s7a)); + assert(is_string_asan_correct(long_s7a)); + + short_s7a.replace(short_s7a.begin(), short_s7a.end(), {}); + long_s7a.replace(long_s7a.begin(), long_s7a.end(), {}); + assert(is_string_asan_correct(short_s7a)); + assert(is_string_asan_correct(long_s7a)); +} + +template +void test_view() { + using S = std::basic_string; + using SV = std::basic_string_view; + S empty_s; + S short_s(4, 'b'); + S long_s(1100, 'a'); + + SV empty_v(empty_s); + SV short_v(short_s); + SV long_v(long_s); + + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + SV partial_short_v(short_s.data() + 1, 1); + SV partial_long_v(long_s.data() + 10, 200); + + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + // append + + S empty_s2a(empty_s), short_s2a(short_s), long_s2a(long_s); + empty_s2a.replace(0, 0, empty_v); + short_s2a.replace(1, 1, short_v); + long_s2a.replace(11, 5, long_v); + + assert(is_string_asan_correct(empty_s2a)); + assert(is_string_asan_correct(short_s2a)); + assert(is_string_asan_correct(long_s2a)); + + S partial_short_s2(short_s), partial_long_s2(long_s); + partial_short_s2.replace(1, 1, partial_short_v); + partial_long_s2.replace(1, 1, partial_long_v); + + assert(is_string_asan_correct(partial_short_s2)); + assert(is_string_asan_correct(partial_long_s2)); + + S empty_s2b(empty_s), short_s2b(short_s), long_s2b(long_s); + empty_s2b.replace(empty_s2b.begin(), empty_s2b.end(), empty_v); + short_s2b.replace(short_s2b.begin() + 1, short_s2b.end(), short_v); + long_s2b.replace(long_s2b.begin() + 1, long_s2b.end() - 1, long_v); + + assert(is_string_asan_correct(empty_s2b)); + assert(is_string_asan_correct(short_s2b)); + assert(is_string_asan_correct(long_s2b)); + + S empty_s3a(empty_s), short_s3a(short_s), long_s3a(long_s); + empty_s3a.replace(0, 0, long_v, 2, 26); + short_s3a.replace(1, 1, long_v, 2, 25); + long_s3a.replace(11, 5, long_v, 2, 26); + + assert(is_string_asan_correct(empty_s3a)); + assert(is_string_asan_correct(short_s3a)); + assert(is_string_asan_correct(long_s3a)); +} + +template +void test( + const CharT val, const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + test_replace_basic(val); + test_replace(s_init, s_long_init); + test_replace(s_init2, s_long_init); + test_replace(s_init, s_long_init2); + test_replace(s_init2, s_long_init2); + test_view(); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +char literal_2[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"abc"; +char32_t literal32_2[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long2[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + using CharT = char; + test('x', literal, literal_2, literal_long, literal_long2); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(L'x', wliteral, wliteral_2, wliteral_long, wliteral_long2); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(u'x', literal16, literal16_2, literal16_long, literal16_long2); + } + { + using CharT = char32_t; + test(U'x', literal32, literal32_2, literal32_long, literal32_long2); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(u8'x', literal8, literal8_2, literal8_long, literal8_long2); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve.asan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve.asan.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test() { + S short_s1(3, 'a'), long_s1(100, 'c'); + short_s1.reserve(0x1337); + long_s1.reserve(0x1337); + + assert(is_string_asan_correct(short_s1)); + assert(is_string_asan_correct(long_s1)); +#if TEST_STD_VER >= 11 + short_s1.shrink_to_fit(); + long_s1.shrink_to_fit(); + + assert(is_string_asan_correct(short_s1)); + assert(is_string_asan_correct(long_s1)); +#endif + short_s1.clear(); + long_s1.clear(); + + assert(is_string_asan_correct(short_s1)); + assert(is_string_asan_correct(long_s1)); +#if TEST_STD_VER >= 11 + short_s1.shrink_to_fit(); + long_s1.shrink_to_fit(); + + assert(is_string_asan_correct(short_s1)); + assert(is_string_asan_correct(long_s1)); +#endif + S short_s2(3, 'a'), long_s2(100, 'c'); + short_s2.reserve(0x1); + long_s2.reserve(0x1); + + assert(is_string_asan_correct(short_s2)); + assert(is_string_asan_correct(long_s2)); +} + +int main(int, char**) { + { + using S = std::string; + test(); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using S = std::wstring; + test(); + } +#endif +#if TEST_STD_VER >= 11 + { + using S = std::u16string; + test(); + } + { + using S = std::u32string; + test(); + } +#endif +#if TEST_STD_VER >= 20 + { + using S = std::u8string; + test(); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test(const CharT val) { + using S = std::basic_string; + + S empty_s; + S short_s(3, val); + S long_s(1100, val); + + std::swap(empty_s, empty_s); + std::swap(short_s, short_s); + std::swap(long_s, long_s); + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + std::swap(empty_s, short_s); + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + + std::swap(empty_s, short_s); + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(short_s)); + + std::swap(empty_s, long_s); + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(long_s)); + + std::swap(empty_s, long_s); + assert(is_string_asan_correct(empty_s)); + assert(is_string_asan_correct(long_s)); + + std::swap(short_s, long_s); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + std::swap(short_s, long_s); + assert(is_string_asan_correct(short_s)); + assert(is_string_asan_correct(long_s)); + + S long_s2(11100, val); + + std::swap(long_s, long_s2); + assert(is_string_asan_correct(long_s)); + assert(is_string_asan_correct(long_s2)); + + std::swap(long_s, long_s2); + assert(is_string_asan_correct(long_s)); + assert(is_string_asan_correct(long_s2)); + + S long_s3(111, val); + + std::swap(long_s, long_s3); + assert(is_string_asan_correct(long_s)); + assert(is_string_asan_correct(long_s2)); +} + +int main(int, char**) { + { + using CharT = char; + test('x'); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(L'x'); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(u'x'); + } + { + using CharT = char32_t ; + test(U'x'); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(u8'x'); + } +#endif + + return 0; +} diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.asan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.asan.pass.cpp @@ -0,0 +1,135 @@ +#include +#include +#include + +#include "test_macros.h" +#include "asan_testing.h" + +template +void test_substr(const CharT* s_init, const CharT* s_long_init) { + using S = std::basic_string; + S short_s(s_init), long_s(s_long_init); + + S short_substr = short_s.substr(1, 1); + + assert(is_string_asan_correct(short_substr)); + + S long_substr1a = long_s.substr(10, 2); + S long_substr1b = long_s.substr(2, 34); + + assert(is_string_asan_correct(long_substr1a)); + assert(is_string_asan_correct(long_substr1b)); + + S short_empty = short_s.substr(1, 0); + S long_empty = long_s.substr(2, 0); + + assert(is_string_asan_correct(short_empty)); + assert(is_string_asan_correct(long_empty)); + + S short_substr2 = short_s.substr(1); + S long_substr2 = long_s.substr(2); + + assert(is_string_asan_correct(short_substr2)); + assert(is_string_asan_correct(long_substr2)); + + S short_substr3 = short_s.substr(); + S long_substr3 = long_s.substr(); + + assert(is_string_asan_correct(short_substr3)); + assert(is_string_asan_correct(long_substr3)); + + assert(is_string_asan_correct(short_s.substr(0, 1))); + assert(is_string_asan_correct(long_s.substr(2, 32))); + assert(is_string_asan_correct(short_s.substr())); + assert(is_string_asan_correct(long_s.substr())); +} + +template +void test(const CharT* s_init, const CharT* s_init2, const CharT* s_long_init, const CharT* s_long_init2) { + test_substr(s_init, s_long_init); + test_substr(s_init2, s_long_init2); +} + +char literal[] = "ab"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral[] = L"ab"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16[] = u"ab"; +char32_t literal32[] = U"ab"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8[] = u8"ab"; +#endif + +char literal_2[] = "abc"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_2[] = L"abc"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_2[] = u"abc"; +char32_t literal32_2[] = U"abc"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_2[] = u8"abc"; +#endif + +char literal_long[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long[] = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long[] = u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long[] = U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long[] = u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +char literal_long2[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +wchar_t wliteral_long2[] = + L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 11 +char16_t literal16_long2[] = + u"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +char32_t literal32_long2[] = + U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif +#if TEST_STD_VER >= 20 +char8_t literal8_long2[] = + u8"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +int main(int, char**) { + { + using CharT = char; + test(literal, literal_2, literal_long, literal_long2); + } +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + { + using CharT = wchar_t; + test(wliteral, wliteral_2, wliteral_long, wliteral_long2); + } +#endif +#if TEST_STD_VER >= 11 + { + using CharT = char16_t; + test(literal16, literal16_2, literal16_long, literal16_long2); + } + { + using CharT = char32_t; + test(literal32, literal32_2, literal32_long, literal32_long2); + } +#endif +#if TEST_STD_VER >= 20 + { + using CharT = char8_t; + test(literal8, literal8_2, literal8_long, literal8_long2); + } +#endif + + return 0; +} diff --git a/libcxx/test/support/asan_testing.h b/libcxx/test/support/asan_testing.h --- a/libcxx/test/support/asan_testing.h +++ b/libcxx/test/support/asan_testing.h @@ -12,27 +12,55 @@ #include "test_macros.h" #if TEST_HAS_FEATURE(address_sanitizer) -extern "C" int __sanitizer_verify_contiguous_container - ( const void *beg, const void *mid, const void *end ); +extern "C" int __sanitizer_verify_contiguous_container(const void* beg, const void* mid, const void* end); template -TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector &c ) -{ - if (std::__libcpp_is_constant_evaluated()) - return true; - if (std::is_same >::value && c.data() != NULL) - return __sanitizer_verify_contiguous_container( - c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0; +TEST_CONSTEXPR bool is_contiguous_container_asan_correct(const std::vector& c) { + if (std::__libcpp_is_constant_evaluated()) return true; + if (std::is_same >::value && c.data() != NULL) + return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0; + return true; } - #else template -TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector &) -{ - return true; +TEST_CONSTEXPR bool is_contiguous_container_asan_correct(const std::vector&) { + return true; } #endif +#if TEST_HAS_FEATURE(address_sanitizer) +# include +template +bool __is_string_short(S const& s) { + // We do not have access to __is_long(), but we can check if strings + // buffer is inside strings memory. If strings memory contains its content, + // SSO is in use. To check it, we can just confirm that the beginning is in + // the string object memory block. + // &s - beginning of objects memory + // &s[0] - beginning of the buffer + // (&s+1) - end of objects memory + return (void*)&s <= (void*)&s[0] && (void*)&s[0] < (void*)(&s + 1); +} +template +TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string& c) { + if (std::__libcpp_is_constant_evaluated()) + return true; + if (c.data() != NULL) { +#if _LIBCPP_CLANG_VER < 16000 + // TODO LLVM18: remove special case + if(!__is_string_short(c)) +#endif + return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) != 0; + } + return true; +} +#else +# include +template +TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string&) { + return true; +} +#endif // TEST_HAS_FEATURE(address_sanitizer) && _LIBCPP_CLANG_VER >= 16000 #endif // ASAN_TESTING_H