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,12 @@ // 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) +# 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 +132,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) #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 @@ -607,6 +607,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 @@ -662,6 +671,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; @@ -848,24 +860,31 @@ __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_)) { + // Turning off ASan instrumentation for variable initialization with _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS + // is inconsistent and that initialization may be annotated. + // Therefore, to copy __str memory, we have to unpoison it first (if object is poisoned and not external buffer, + // so short string case). + : __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()); @@ -873,6 +892,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); @@ -918,11 +940,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()) @@ -931,6 +953,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); @@ -1025,8 +1050,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; } @@ -1039,7 +1064,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 @@ -1256,7 +1281,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;} @@ -1681,7 +1706,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; @@ -1702,6 +1727,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); @@ -1730,6 +1756,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) @@ -1738,6 +1765,7 @@ else { __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); + __annotate_increase(__n); __p = std::__to_address(__get_long_pointer()); } __sz += __n; @@ -1752,14 +1780,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_; @@ -1808,6 +1836,53 @@ 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* __old_mid, const void* __new_mid) const { + const void* __begin = data(); + const void* __end = data() + capacity() + 1; + # if _LIBCPP_CLANG_VER < 1600 + if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same::value) + #else + if (!__libcpp_is_constant_evaluated() && __begin != nullptr) + # 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 {} +#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() + 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() + 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() + 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() + __old_size + 1, data() + size() + 1); + } + template static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __align_it(size_type __s) _NOEXCEPT @@ -1902,6 +1977,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); @@ -1910,6 +1986,7 @@ __set_long_pointer(__allocation.ptr); __set_long_cap(__allocation.count); __set_long_size(__str.size()); + __annotate_new(__get_long_size()); } } } @@ -1957,19 +2034,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; } @@ -2104,6 +2191,7 @@ } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2132,6 +2220,7 @@ } traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); + __annotate_new(__sz); } template @@ -2146,12 +2235,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()); @@ -2165,7 +2257,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()); @@ -2194,6 +2289,7 @@ __set_long_size(__sz); } traits_type::copy(std::__to_address(__p), __s, __sz + 1); + __annotate_new(__sz); } template @@ -2223,6 +2319,7 @@ } traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); + __annotate_new(__n); } template @@ -2304,6 +2401,7 @@ } catch (...) { + __annotate_delete(); if (__is_long()) __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); throw; @@ -2352,17 +2450,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()); @@ -2382,6 +2483,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); @@ -2402,6 +2504,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 @@ -2417,6 +2520,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); @@ -2433,6 +2537,8 @@ __alloc_traits::deallocate(__alloc(), __old_p, __old_cap + 1); __set_long_pointer(__p); __set_long_cap(__allocation.count); + __set_long_size(__old_sz); + __annotate_new(__old_sz); } // assign @@ -2445,11 +2551,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); @@ -2464,6 +2575,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); @@ -2491,11 +2605,14 @@ basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) { size_type __cap = capacity(); + size_type __old_size = size(); if (__cap < __n) { size_type __sz = size(); __grow_by(__cap, __n - __cap, __sz, 0, __sz); } + 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); @@ -2506,25 +2623,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) { @@ -2532,7 +2655,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()); } @@ -2558,7 +2686,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 @@ -2567,6 +2695,7 @@ _NOEXCEPT_(is_nothrow_move_assignable::value) #endif { + __annotate_delete(); if (__is_long()) { __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); @@ -2574,10 +2703,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(); @@ -2585,6 +2718,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 @@ -2614,6 +2765,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; @@ -2626,12 +2778,16 @@ size_type __sz = size(); __grow_by(__cap, __n - __cap, __sz, 0, __sz); } + 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 { @@ -2704,6 +2860,7 @@ { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); traits_type::copy(__p + __sz, __s, __n); __sz += __n; @@ -2727,6 +2884,7 @@ size_type __sz = size(); if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); traits_type::assign(std::__to_address(__p) + __sz, __n, __c); __sz += __n; @@ -2746,6 +2904,7 @@ size_type __sz = size(); if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer(); __sz += __n; __set_size(__sz); @@ -2774,8 +2933,10 @@ if (__sz == __cap) { __grow_by(__cap, 1, __sz, __sz, 0); + __annotate_increase(1); __is_short = false; // the string is always long after __grow_by - } + } else + __annotate_increase(1); pointer __p = __get_pointer(); if (__is_short) { @@ -2812,6 +2973,7 @@ { if (__cap - __sz < __n) __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); pointer __p = __get_pointer() + __sz; for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); @@ -2887,6 +3049,7 @@ { if (__n) { + __annotate_increase(__n); value_type* __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2920,6 +3083,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) @@ -2928,6 +3092,7 @@ else { __grow_by(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); + __annotate_increase(__n); __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n, __c); @@ -3039,10 +3204,12 @@ if (__cap == __sz) { __grow_by(__cap, 1, __sz, __ip, 0, 1); + __annotate_increase(1); __p = std::__to_address(__get_long_pointer()); } else { + __annotate_increase(1); __p = std::__to_address(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -3077,6 +3244,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) { @@ -3121,20 +3290,20 @@ __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); + __annotate_increase(__n2 - __n1); + __set_long_size(__sz - __n1 + __n2); + __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n2, __c); return __null_terminate_at(__p, __sz - (__n1 - __n2)); @@ -3277,6 +3446,7 @@ void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_type __old_size = size(); std::__debug_db_invalidate_all(this); if (__is_long()) { @@ -3288,6 +3458,7 @@ traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_shrink(__old_size); } template @@ -3350,6 +3521,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) { + __annotate_delete(); size_type __cap = capacity(); size_type __sz = size(); @@ -3407,6 +3579,7 @@ else __set_short_size(__sz); std::__debug_db_invalidate_all(this); + __annotate_new(__sz); } template @@ -3463,8 +3636,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 @@ -4000,12 +4181,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== @@ -4256,6 +4437,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; } @@ -4270,10 +4452,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; } @@ -4287,10 +4471,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; } @@ -4305,10 +4491,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; } @@ -4322,10 +4510,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.capacity/capacity.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp @@ -15,6 +15,7 @@ #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" #include "test_macros.h" diff --git a/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -22,26 +23,32 @@ { s.clear(); assert(s.size() == 0); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template TEST_CONSTEXPR_CXX20 void test_string() { S s; test(s); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.assign(10, 'a'); s.erase(5); + LIBCPP_ASSERT(is_string_asan_correct(s)); test(s); s.assign(100, 'a'); s.erase(50); + LIBCPP_ASSERT(is_string_asan_correct(s)); test(s); + LIBCPP_ASSERT(is_string_asan_correct(s)); } TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template void @@ -35,6 +36,7 @@ assert(s == s0); assert(s.capacity() <= old_cap); assert(s.capacity() >= s.size()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -48,6 +50,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.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); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); +#if TEST_STD_VER >= 11 + short_s1.shrink_to_fit(); + long_s1.shrink_to_fit(); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); +#endif + short_s1.clear(); + long_s1.clear(); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_ASSERT(is_string_asan_correct(long_s1)); +#if TEST_STD_VER >= 11 + short_s1.shrink_to_fit(); + long_s1.shrink_to_fit(); + + LIBCPP_ASSERT(is_string_asan_correct(short_s1)); + LIBCPP_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); + + LIBCPP_ASSERT(is_string_asan_correct(short_s2)); + LIBCPP_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.capacity/reserve_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.pass.cpp @@ -20,6 +20,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp @@ -19,6 +19,7 @@ #include "make_string.h" #include "test_macros.h" +#include "asan_testing.h" template constexpr void test_appending(size_t k, size_t N, size_t new_capacity) { @@ -77,11 +78,14 @@ void test_value_categories() { std::string s; s.resize_and_overwrite(10, [](char*&&, size_t&&) { return 0; }); + LIBCPP_ASSERT(is_string_asan_correct(s)); s.resize_and_overwrite(10, [](char* const&, const size_t&) { return 0; }); + LIBCPP_ASSERT(is_string_asan_correct(s)); struct RefQualified { int operator()(char*, size_t) && { return 0; } }; s.resize_and_overwrite(10, RefQualified{}); + LIBCPP_ASSERT(is_string_asan_correct(s)); } int main(int, char**) { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ s.resize(n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -67,6 +69,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_size_char.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ s.resize(n, c); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -61,6 +63,16 @@ test(S("12345678901234567890123456789012345678901234567890"), 60, 'a', S("12345678901234567890123456789012345678901234567890aaaaaaaaaa")); test(S(), S::npos, 'a', S("not going to happen")); + //ASan: + test(S(), 21, 'a', S("aaaaaaaaaaaaaaaaaaaaa")); + test(S(), 22, 'a', S("aaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 23, 'a', S("aaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 24, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 29, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 30, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 31, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 32, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); + test(S(), 33, 'a', S("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.capacity/shrink_to_fit.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -27,6 +28,7 @@ assert(s == s0); assert(s.capacity() <= old_cap); assert(s.capacity() >= s.size()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -41,12 +43,18 @@ s.assign(100, 'a'); s.erase(50); test(s); + + s.assign(100, 'a'); + for(int i = 0; i < 90; ++i) + s.erase(1); + test(s); } TEST_CONSTEXPR_CXX20 bool test() { test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/T_size_size.pass.cpp @@ -23,6 +23,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -41,6 +42,7 @@ assert(T::compare(s2.data(), sv.data() + pos, rlen) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/alloc.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -33,6 +34,7 @@ assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { #if TEST_STD_VER > 14 @@ -46,6 +48,7 @@ assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type(5)); + LIBCPP_ASSERT(is_string_asan_correct(s)); } } @@ -67,6 +70,7 @@ assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { #if TEST_STD_VER > 14 @@ -80,6 +84,7 @@ assert(s.size() == 0); assert(s.capacity() >= s.size()); assert(s.get_allocator() == typename S::allocator_type()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } } @@ -89,6 +94,7 @@ test, test_allocator > >(); #if TEST_STD_VER >= 11 test2, min_allocator > >(); + test2, safe_allocator > >(); test2, explicit_allocator > >(); #endif diff --git a/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/brace_assignment.pass.cpp @@ -17,6 +17,7 @@ #include #include "test_macros.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { // Test that assignment from {} and {ptr, len} are allowed and are not @@ -25,11 +26,13 @@ std::string s = "hello world"; s = {}; assert(s.empty()); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { std::string s = "hello world"; s = {"abc", 2}; assert(s == "ab"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/char_assignment.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ assert(s1.size() == 1); assert(T::eq(s1[0], s2)); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); } template diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,8 @@ assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == s1.get_allocator()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { @@ -44,6 +47,13 @@ test(S("1", A())); test(S("1234567890123456789012345678901234567890123456789012345678901234567890", A())); } + { + typedef safe_allocator A; + typedef std::basic_string, A> S; + test(S(A{})); + test(S("1", A())); + test(S("1234567890123456789012345678901234567890123456789012345678901234567890", A())); + } #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy_alloc.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" #ifndef TEST_HAS_NO_EXCEPTIONS struct alloc_imp { @@ -86,6 +87,8 @@ assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == a); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/copy_assignment.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -25,6 +26,8 @@ LIBCPP_ASSERT(s1.__invariants()); assert(s1 == s2); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template diff --git a/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/default.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "test_allocator.h" +#include "asan_testing.h" #if TEST_STD_VER >= 11 // Test the noexcept specification, which is a conforming extension @@ -28,6 +29,7 @@ TEST_CONSTEXPR_CXX20 bool test() { std::string str; assert(str.empty()); + LIBCPP_ASSERT(is_string_asan_correct(str)); return true; } diff --git a/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/initializer_list.pass.cpp @@ -18,23 +18,33 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { { std::string s = {'a', 'b', 'c'}; assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_WIDE_CHARACTERS { std::wstring s; s = {L'a', L'b', L'c'}; assert(s == L"abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #endif { typedef std::basic_string, min_allocator> S; S s = {'a', 'b', 'c'}; assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + typedef std::basic_string, safe_allocator> S; + S s = {'a', 'b', 'c'}; + assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_WIDE_CHARACTERS { @@ -42,6 +52,7 @@ S s; s = {L'a', L'b', L'c'}; assert(s == L"abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #endif diff --git a/libcxx/test/std/strings/basic.string/string.cons/initializer_list_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/initializer_list_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/initializer_list_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/initializer_list_assignment.pass.cpp @@ -17,18 +17,35 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { { std::string s; s = {'a', 'b', 'c'}; assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { typedef std::basic_string, min_allocator> S; S s; s = {'a', 'b', 'c'}; assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + typedef std::basic_string, safe_allocator> S; + S s; + s = {'a', 'b', 'c'}; + assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + { + typedef std::basic_string, safe_allocator> S; + S s; + s = {'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a'}; + assert(s == "aaaaaaaaaaaaaaaaaaaaaaaa"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc.pass.cpp @@ -22,6 +22,7 @@ #include "test_allocator.h" #include "test_iterators.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -41,6 +42,7 @@ } assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -60,6 +62,7 @@ } assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc_deduction.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc_deduction.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/iter_alloc_deduction.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/iter_alloc_deduction.pass.cpp @@ -29,6 +29,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" class NotAnIterator {}; using NotAnInputIterator = std::back_insert_iterator>; diff --git a/libcxx/test/std/strings/basic.string/string.cons/move.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/move.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/move.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,9 @@ assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == s1.get_allocator()); + LIBCPP_ASSERT(is_string_asan_correct(s0)); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { @@ -47,6 +51,13 @@ test(S("1", A())); test(S("1234567890123456789012345678901234567890123456789012345678901234567890", A())); } + { + typedef safe_allocator A; + typedef std::basic_string, A> S; + test(S(A{})); + test(S("1", A())); + test(S("1234567890123456789012345678901234567890123456789012345678901234567890", A())); + } return true; } diff --git a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,9 @@ assert(s2 == s1); assert(s2.capacity() >= s2.size()); assert(s2.get_allocator() == a); + LIBCPP_ASSERT(is_string_asan_correct(s0)); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.cons/move_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/move_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/move_assignment.pass.cpp @@ -19,6 +19,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,9 @@ LIBCPP_ASSERT(s2.__invariants()); assert(s1 == s0); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s0)); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -55,6 +59,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/pointer_alloc.pass.cpp @@ -19,6 +19,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -34,6 +35,7 @@ assert(T::compare(s2.data(), s, n) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -49,6 +51,7 @@ assert(T::compare(s2.data(), s, n) == 0); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.cons/pointer_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/pointer_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/pointer_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/pointer_assignment.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -27,6 +28,7 @@ assert(s1.size() == T::length(s2)); assert(T::compare(s1.data(), s2, s1.size()) == 0); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); } template @@ -52,6 +54,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/pointer_size_alloc.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -32,6 +33,7 @@ assert(T::compare(s2.data(), s, n) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -46,6 +48,7 @@ assert(T::compare(s2.data(), s, n) == 0); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/size_char_alloc.pass.cpp @@ -19,6 +19,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -33,6 +34,7 @@ assert(s2[i] == c); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -47,6 +49,7 @@ assert(s2[i] == c); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template @@ -115,6 +118,24 @@ test(100, 'a'); test(100, 'a', A()); + test(static_cast(100), static_cast(65)); + test(static_cast(100), static_cast(65), A()); + } + { + typedef safe_allocator A; + + test(0, 'a'); + test(0, 'a', A()); + + test(1, 'a'); + test(1, 'a', A()); + + test(10, 'a'); + test(10, 'a', A()); + + test(100, 'a'); + test(100, 'a', A()); + test(static_cast(100), static_cast(65)); test(static_cast(100), static_cast(65), A()); } diff --git a/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/string_view.pass.cpp @@ -20,6 +20,7 @@ #include "min_allocator.h" #include "test_allocator.h" #include "test_macros.h" +#include "asan_testing.h" static_assert(!std::is_convertible::value, ""); static_assert(!std::is_convertible::value, ""); @@ -38,6 +39,7 @@ assert(T::compare(s2.data(), sv.data(), sv.size()) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } { S s2; @@ -47,6 +49,7 @@ assert(T::compare(s2.data(), sv.data(), sv.size()) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } } @@ -63,6 +66,7 @@ assert(T::compare(s2.data(), sv.data(), sv.size()) == 0); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } { S s2(a); @@ -72,6 +76,7 @@ assert(T::compare(s2.data(), sv.data(), sv.size()) == 0); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } } diff --git a/libcxx/test/std/strings/basic.string/string.cons/string_view_assignment.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/string_view_assignment.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/string_view_assignment.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/string_view_assignment.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ assert(s1.size() == sv.size()); assert(T::compare(s1.data(), sv.data(), s1.size()) == 0); assert(s1.capacity() >= s1.size()); + LIBCPP_ASSERT(is_string_asan_correct(s1)); } template @@ -52,6 +54,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/substr.pass.cpp @@ -26,6 +26,7 @@ #include "test_macros.h" #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -43,6 +44,7 @@ assert(T::compare(s2.data(), str.data() + pos, rlen) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -75,6 +77,7 @@ assert(T::compare(s2.data(), str.data() + pos, rlen) == 0); assert(s2.get_allocator() == A()); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -107,6 +110,7 @@ assert(T::compare(s2.data(), str.data() + pos, rlen) == 0); assert(s2.get_allocator() == a); assert(s2.capacity() >= s2.size()); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp @@ -18,7 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" #include "nasty_string.h" - +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test() { using CharT = typename S::value_type; @@ -26,6 +26,7 @@ S s(CONVERT_TO_CSTRING(CharT, "123")); s.append({CharT('a'), CharT('b'), CharT('c')}); assert(s == CONVERT_TO_CSTRING(CharT, "123abc")); + LIBCPP_ASSERT(is_string_asan_correct(s)); } TEST_CONSTEXPR_CXX20 bool test() { @@ -40,6 +41,7 @@ test(); test, min_allocator>>(); + test, safe_allocator>>(); #ifndef TEST_HAS_NO_NASTY_STRING test(); #endif diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "test_iterators.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -25,6 +26,7 @@ s.append(first, last); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s.append(str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -25,6 +26,7 @@ s.append(str, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" struct VeryLarge { long long a; @@ -63,6 +64,7 @@ s.push_back(c); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s.append(n, c); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s.append(str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -28,6 +29,7 @@ s.append(str, pos, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/T_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/T_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/T_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/T_size_size.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -27,6 +28,7 @@ s.assign(sv, pos, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp @@ -17,18 +17,21 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { { std::string s("123"); s.assign({'a', 'b', 'c'}); assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { typedef std::basic_string, min_allocator> S; S s("123"); s.assign({'a', 'b', 'c'}); assert(s == "abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "test_iterators.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -25,6 +26,7 @@ s.assign(first, last); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s.assign(str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -25,6 +26,7 @@ s.assign(str, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s.assign(n, c); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp @@ -18,12 +18,15 @@ #include "nasty_string.h" #include "min_allocator.h" #include "test_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S dest, S src) { dest.assign(src); LIBCPP_ASSERT(dest.__invariants()); assert(dest == src); + LIBCPP_ASSERT(is_string_asan_correct(src)); + LIBCPP_ASSERT(is_string_asan_correct(dest)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -28,6 +29,7 @@ s.assign(str, pos, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_copy/copy.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_copy/copy.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_copy/copy.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_copy/copy.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -29,6 +30,9 @@ typename S::size_type r = cs.copy(s, n, pos); typename S::size_type rlen = std::min(n, cs.size() - pos); assert(r == rlen); + LIBCPP_ASSERT(is_string_asan_correct(str)); + LIBCPP_ASSERT(is_string_asan_correct(cs)); + for (r = 0; r < rlen; ++r) assert(S::traits_type::eq(cs[pos+r], s[r])); } diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ assert(s[s.size()] == typename S::value_type()); assert(s == expected); assert(i - s.begin() == pos); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/iter_iter.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -27,6 +28,7 @@ assert(s[s.size()] == typename S::value_type()); assert(s == expected); assert(i - s.begin() == pos); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// + +#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); + + LIBCPP_ASSERT(is_string_asan_correct(s)); + } + while (s.size() > 0) { + s.pop_back(); + + LIBCPP_ASSERT(is_string_asan_correct(s)); + } +} + +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.modifiers/string_erase/pop_back.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ LIBCPP_ASSERT(s.__invariants()); assert(s[s.size()] == typename S::value_type()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -37,6 +39,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/size_size.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,7 @@ LIBCPP_ASSERT(s.__invariants()); assert(s[s.size()] == typename S::value_type()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp @@ -16,11 +16,13 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test(S& s, typename S::const_iterator p, typename S::value_type c, S expected) { + LIBCPP_ASSERT(is_string_asan_correct(s)); bool sufficient_cap = s.size() < s.capacity(); typename S::difference_type pos = p - s.begin(); typename S::iterator i = s.insert(p, c); @@ -30,6 +32,8 @@ assert(*i == c); if (sufficient_cap) assert(i == p); + LIBCPP_ASSERT(is_string_asan_correct(s)); + } template @@ -55,6 +59,7 @@ test_string(); #if TEST_STD_VER >= 11 test_string, min_allocator>>(); + test_string, safe_allocator>>(); #endif return true; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { { @@ -25,6 +26,7 @@ std::string::iterator i = s.insert(s.begin() + 3, {'a', 'b', 'c'}); assert(i - s.begin() == 3); assert(s == "123abc456"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { typedef std::basic_string, min_allocator> S; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "test_iterators.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -27,6 +28,7 @@ LIBCPP_ASSERT(s.__invariants()); assert(i - s.begin() == pos); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -26,6 +27,7 @@ LIBCPP_ASSERT(s.__invariants()); assert(i - s.begin() == pos); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -29,6 +30,7 @@ s.insert(pos, str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,7 @@ s.insert(pos, str, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -30,6 +31,7 @@ s.insert(pos, n, str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -29,6 +30,7 @@ s.insert(pos, str); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp @@ -19,6 +19,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -32,6 +33,7 @@ s.insert(pos1, str, pos2, n); LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/char.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -23,6 +24,7 @@ s += str; LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/initializer_list.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/initializer_list.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/initializer_list.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/initializer_list.pass.cpp @@ -17,18 +17,21 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" TEST_CONSTEXPR_CXX20 bool test() { { std::string s("123"); s += {'a', 'b', 'c'}; assert(s == "123abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } { typedef std::basic_string, min_allocator> S; S s("123"); s += {'a', 'b', 'c'}; assert(s == "123abc"); + LIBCPP_ASSERT(is_string_asan_correct(s)); } return true; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/pointer.pass.cpp @@ -15,6 +15,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -23,6 +24,7 @@ s += str; LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_op_plus_equal/string.pass.cpp @@ -16,6 +16,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -24,6 +25,7 @@ s += str; LIBCPP_ASSERT(s.__invariants()); assert(s == expected); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -31,6 +32,7 @@ assert(s == expected); typename S::size_type rlen = str.size(); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } template @@ -298,6 +300,7 @@ test(); #if TEST_STD_VER >= 11 test, min_allocator>>(); + test, safe_allocator>>(); #endif return 0; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_T_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_T_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_T_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_T_size_size.pass.cpp @@ -21,6 +21,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -45,6 +46,7 @@ SizeT xlen = std::min(n1, old_size - pos1); SizeT rlen = std::min(n2, sv.size() - pos2); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -34,6 +35,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos); typename S::size_type rlen = S::traits_type::length(str); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -388,6 +390,7 @@ test(); #if TEST_STD_VER >= 11 test, min_allocator>>(); + test, safe_allocator>>(); #endif return 0; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -35,6 +36,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos); typename S::size_type rlen = n2; assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) @@ -1357,6 +1359,7 @@ test(); #if TEST_STD_VER >= 11 test, min_allocator>>(); + test, safe_allocator>>(); #endif return 0; diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -35,6 +36,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos); typename S::size_type rlen = n2; assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -33,6 +34,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos1); typename S::size_type rlen = str.size(); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp @@ -20,6 +20,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -37,6 +38,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos1); typename S::size_type rlen = std::min(n2, str.size() - pos2); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_view.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_view.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_view.pass.cpp @@ -18,6 +18,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -33,6 +34,7 @@ typename S::size_type xlen = std::min(n1, old_size - pos1); typename S::size_type rlen = sv.size(); assert(s.size() == old_size - xlen + rlen); + LIBCPP_ASSERT(is_string_asan_correct(s)); } #ifndef TEST_HAS_NO_EXCEPTIONS else if (!TEST_IS_CONSTANT_EVALUATED) 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); + LIBCPP_ASSERT(is_string_asan_correct(empty_s)); + LIBCPP_ASSERT(is_string_asan_correct(short_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + + std::swap(empty_s, short_s); + LIBCPP_ASSERT(is_string_asan_correct(empty_s)); + LIBCPP_ASSERT(is_string_asan_correct(short_s)); + + std::swap(empty_s, short_s); + LIBCPP_ASSERT(is_string_asan_correct(empty_s)); + LIBCPP_ASSERT(is_string_asan_correct(short_s)); + + std::swap(empty_s, long_s); + LIBCPP_ASSERT(is_string_asan_correct(empty_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + + std::swap(empty_s, long_s); + LIBCPP_ASSERT(is_string_asan_correct(empty_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + + std::swap(short_s, long_s); + LIBCPP_ASSERT(is_string_asan_correct(short_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + + std::swap(short_s, long_s); + LIBCPP_ASSERT(is_string_asan_correct(short_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + + S long_s2(11100, val); + + std::swap(long_s, long_s2); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s2)); + + std::swap(long_s, long_s2); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + LIBCPP_ASSERT(is_string_asan_correct(long_s2)); + + S long_s3(111, val); + + std::swap(long_s, long_s3); + LIBCPP_ASSERT(is_string_asan_correct(long_s)); + LIBCPP_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.modifiers/string_swap/swap.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.pass.cpp @@ -17,6 +17,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -29,6 +30,8 @@ LIBCPP_ASSERT(s2.__invariants()); assert(s1 == s2_); assert(s2 == s1_); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } template diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string.special/swap.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string.special/swap.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string.special/swap.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string.special/swap.pass.cpp @@ -19,6 +19,7 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void @@ -31,6 +32,8 @@ LIBCPP_ASSERT(s2.__invariants()); assert(s1 == s2_); assert(s2 == s1_); + LIBCPP_ASSERT(is_string_asan_correct(s1)); + LIBCPP_ASSERT(is_string_asan_correct(s2)); } TEST_CONSTEXPR_CXX20 bool test() { diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/char_string.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/char_string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/char_string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/char_string.pass.cpp @@ -22,10 +22,12 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test0(typename S::value_type lhs, const S& rhs, const S& x) { assert(lhs + rhs == x); + LIBCPP_ASSERT(is_string_asan_correct(lhs + rhs)); } #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_char.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_char.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_char.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_char.pass.cpp @@ -22,10 +22,12 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test0(const S& lhs, typename S::value_type rhs, const S& x) { assert(lhs + rhs == x); + LIBCPP_ASSERT(is_string_asan_correct(lhs + rhs)); } #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_pointer.pass.cpp @@ -22,10 +22,12 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test0(const S& lhs, const typename S::value_type* rhs, const S& x) { assert(lhs + rhs == x); + LIBCPP_ASSERT(is_string_asan_correct(lhs + rhs)); } #if TEST_STD_VER >= 11 diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_string.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_string.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_string.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string_string.pass.cpp @@ -34,10 +34,12 @@ #include "test_macros.h" #include "min_allocator.h" +#include "asan_testing.h" template TEST_CONSTEXPR_CXX20 void test0(const S& lhs, const S& rhs, const S& x) { assert(lhs + rhs == x); + LIBCPP_ASSERT(is_string_asan_correct(lhs + rhs)); } #if TEST_STD_VER >= 11 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,57 @@ #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 (TEST_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 +# 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*)std::addressof(s) <= (void*)std::addressof(s[0]) && + (void*)std::addressof(s[0]) < (void*)(std::addressof(s) + 1); +} +template +TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string& c) { + if (TEST_IS_CONSTANT_EVALUATED) + return true; + if (c.data() != NULL) { +#if TEST_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) #endif // ASAN_TESTING_H