Index: include/string =================================================================== --- include/string +++ include/string @@ -11,6 +11,9 @@ #ifndef _LIBCPP_STRING #define _LIBCPP_STRING +#include +#include + /* string synopsis @@ -943,7 +946,7 @@ // __str_find template _SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY -__str_find(const _CharT *__p, _SizeT __sz, +__str_find(const _CharT *__p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { if (__pos >= __sz) @@ -956,14 +959,14 @@ template _SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY -__str_find(const _CharT *__p, _SizeT __sz, +__str_find(const _CharT *__p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { if (__pos > __sz || __sz - __pos < __n) return __npos; if (__n == 0) return __pos; - const _CharT* __r = + const _CharT* __r = _VSTD::__search(__p + __pos, __p + __sz, __s, __s + __n, _Traits::eq, random_access_iterator_tag(), random_access_iterator_tag()); @@ -977,7 +980,7 @@ template _SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY -__str_rfind(const _CharT *__p, _SizeT __sz, +__str_rfind(const _CharT *__p, _SizeT __sz, _CharT __c, _SizeT __pos) _NOEXCEPT { if (__sz < 1) @@ -996,7 +999,7 @@ template _SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY -__str_rfind(const _CharT *__p, _SizeT __sz, +__str_rfind(const _CharT *__p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { __pos = _VSTD::min(__pos, __sz); @@ -1005,7 +1008,7 @@ else __pos = __sz; const _CharT* __r = _VSTD::__find_end( - __p, __p + __pos, __s, __s + __n, _Traits::eq, + __p, __p + __pos, __s, __s + __n, _Traits::eq, random_access_iterator_tag(), random_access_iterator_tag()); if (__n > 0 && __r == __p + __pos) return __npos; @@ -1030,7 +1033,7 @@ // __str_find_last_of template -_SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY +_SizeT _LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY __str_find_last_of(const _CharT *__p, _SizeT __sz, const _CharT* __s, _SizeT __pos, _SizeT __n) _NOEXCEPT { @@ -1200,6 +1203,95 @@ #endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +template +struct _LIBCPP_TYPE_VIS_ONLY basic_string_asan_traits +{ + typedef allocator_traits<_Allocator> __alloc_traits; + typedef typename __alloc_traits::pointer __pointer; + typedef typename __alloc_traits::const_pointer __const_pointer; + + static void __annotate_contiguous_container + (const char* msg, const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid) + { + } + + static void __annotate_long_delete(__const_pointer __data, size_t __cap, size_t __s) + { + } + + static void __annotate_short_delete(typename __alloc_traits::size_type const * __beg, size_t __cap, __const_pointer __mid) + { + } + + static void __annotate_long_new(__const_pointer __beg, size_t __cap, size_t __size) + { + } + + static void __annotate_short_new(typename __alloc_traits::size_type const *__beg, size_t __cap, __const_pointer __mid) + { + } + + static void __annotate_long_grow(__const_pointer __data, size_t __cap, size_t __old_size, size_t __new_size) + { + } + + static void __annotate_short_grow(typename __alloc_traits::size_type const *__beg, size_t __cap, __const_pointer __old_mid, __const_pointer __new_mid) + { + } +}; + +// for default allocator +template +struct _LIBCPP_TYPE_VIS_ONLY basic_string_asan_traits<_CharT, allocator<_CharT>> +{ + typedef allocator<_CharT> __allocator; + typedef allocator_traits<__allocator> __alloc_traits; + typedef typename __alloc_traits::pointer __pointer; + typedef typename __alloc_traits::const_pointer __const_pointer; + + static void __annotate_long_delete(__const_pointer __beg, size_t __cap, size_t __s) + { + __annotate_contiguous_container("__annotate_long_delete", __beg, __beg + __cap, __beg + __s, __beg + __cap); + } + + static void __annotate_short_delete(typename __alloc_traits::size_type const * __beg, size_t __cap, __const_pointer __mid) + { + __annotate_contiguous_container("__annotate_short_delete", __beg, __beg + __cap, __mid, __beg + __cap); + } + + static void __annotate_contiguous_container + (const char* msg, const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid) + { +#if !defined(_LIBCPP_HAS_NO_ASAN) && !defined(_LIBCPP_NO_ASAN_STD_STRING) + if (__beg) { + fprintf(stderr, "annotate %s [%p %p %s %p %p] \n", msg, __beg, + min(__old_mid, __new_mid), __old_mid < __new_mid ? "->" : "<-", max(__old_mid, __new_mid), __end); + __sanitizer_annotate_contiguous_container(__beg, __end, __old_mid, __new_mid); + } +#endif + } + + static void __annotate_long_new(__const_pointer __beg, size_t __cap, size_t __size) + { + __annotate_contiguous_container("__annotate_long_new", __beg, __beg + __cap, __beg + __cap, __beg + __size); + } + + static void __annotate_short_new(typename __alloc_traits::size_type const * __beg, size_t __cap, __const_pointer __mid) + { + __annotate_contiguous_container("__annotate_short_new", __beg, __beg + __cap, __beg + __cap, __mid); + } + + static void __annotate_long_grow(__const_pointer __beg, size_t __cap, size_t __old_size, size_t __new_size) + { + __annotate_contiguous_container("__annotate_long_new", __beg, __beg + __cap, __beg + __old_size, __beg + __new_size); + } + + static void __annotate_short_grow(typename __alloc_traits::size_type const *__beg, size_t __cap, __const_pointer __old_mid, __const_pointer __new_mid) + { + __annotate_contiguous_container("__annotate_short_grow", __beg, __beg + __cap, __old_mid, __new_mid); + } +}; + template class _LIBCPP_TYPE_VIS_ONLY basic_string : private __basic_string_common @@ -1209,6 +1301,7 @@ typedef _Traits traits_type; typedef typename traits_type::char_type value_type; typedef _Allocator allocator_type; + typedef allocator<_CharT> __default_allocator_type; typedef allocator_traits __alloc_traits; typedef typename __alloc_traits::size_type size_type; typedef typename __alloc_traits::difference_type difference_type; @@ -1216,6 +1309,7 @@ typedef const value_type& const_reference; typedef typename __alloc_traits::pointer pointer; typedef typename __alloc_traits::const_pointer const_pointer; + typedef basic_string_asan_traits<_CharT, _Allocator> __asan_traits; static_assert(is_pod::value, "Character type of basic_string must be a POD"); static_assert((is_same<_CharT, value_type>::value), @@ -1236,6 +1330,10 @@ #ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +#if !defined(_LIBCPP_HAS_NO_ASAN) && !defined(_LIBCPP_NO_ASAN_STD_STRING) + static_assert(false, "alternate layout not supported by asan."); +#endif + struct __long { pointer __data_; @@ -1608,7 +1706,7 @@ #if _LIBCPP_STD_VER >= 14 _NOEXCEPT; #else - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value); #endif @@ -1679,7 +1777,12 @@ _LIBCPP_INLINE_VISIBILITY bool __is_long() const _NOEXCEPT - {return bool(__r_.first().__s.__size_ & __short_mask);} + { +// unsigned char __short_size; +// memcpy(&__short_size, &__r_.first().__s.__size_, sizeof(__short_size)); +// return bool(__short_size & __short_mask); + return bool(__r_.first().__s.__size_ & __short_mask); + } #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -1698,7 +1801,44 @@ const allocator_type& __alloc() const _NOEXCEPT {return __r_.second();} -#ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT + void __annotate_new(size_type __sz) const + { + if (__is_long()) { + __asan_traits::__annotate_long_new(__get_long_pointer(), __get_long_cap(), __sz + 1 /* terminator */); + } else { + __annotate_short_new(__sz); + } + } + + void __annotate_short_new(size_type __sz) const { + __asan_traits::__annotate_short_new( + __r_.first().__r.__words, __n_words, __get_short_pointer() + __sz + 1 /* terminator */); + } + + void __annotate_grow(size_type __old_size, size_type __new_size) const { + if (__is_long()) { + __asan_traits::__annotate_long_grow(__get_long_pointer(), __get_long_cap(), __old_size + 1, __new_size + 1); + } else { + __annotate_short_grow(__old_size, __new_size); + } + } + void __annotate_short_grow(size_type __old_size, size_type __new_size) const { + __asan_traits::__annotate_short_grow(__r_.first().__r.__words, __n_words, + __get_short_pointer() + __old_size + 1, + __get_short_pointer() + __new_size + 1); + } + + basic_string<_CharT, _Traits, _Allocator> const * __annotate_delete() const + { + if (__is_long()) { + __asan_traits::__annotate_long_delete(__get_long_pointer(), __get_long_cap(), __get_long_size()); + } else { + __asan_traits::__annotate_short_delete( + __r_.first().__r.__words, __n_words, __get_short_pointer() + __get_short_size()); + } + + return this; + } _LIBCPP_INLINE_VISIBILITY void __set_short_size(size_type __s) _NOEXCEPT @@ -1770,10 +1910,20 @@ {return pointer_traits::pointer_to(__r_.first().__s.__data_[0]);} _LIBCPP_INLINE_VISIBILITY pointer __get_pointer() _NOEXCEPT - {return __is_long() ? __get_long_pointer() : __get_short_pointer();} + { + if (__is_long()) + return __get_long_pointer(); + else + return __get_short_pointer(); + } _LIBCPP_INLINE_VISIBILITY const_pointer __get_pointer() const _NOEXCEPT - {return __is_long() ? __get_long_pointer() : __get_short_pointer();} + { + if (__is_long()) + return __get_long_pointer(); + else + return __get_short_pointer(); + } _LIBCPP_INLINE_VISIBILITY void __zero() _NOEXCEPT @@ -1781,6 +1931,7 @@ size_type (&__a)[__n_words] = __r_.first().__r.__words; for (unsigned __i = 0; __i < __n_words; ++__i) __a[__i] = 0; + __annotate_new(0); } template static @@ -1832,12 +1983,15 @@ _LIBCPP_INLINE_VISIBILITY void __copy_assign_alloc(const basic_string& __str, true_type) { + fprintf(stderr, "ASSERT __copy_assign_alloc\n"); + assert(false); if (__alloc() != __str.__alloc()) { clear(); shrink_to_fit(); } __alloc() = __str.__alloc(); + assert(false); } _LIBCPP_INLINE_VISIBILITY @@ -1871,6 +2025,8 @@ _NOEXCEPT_(is_nothrow_move_assignable::value) { __alloc() = _VSTD::move(__c.__alloc()); + __annotate_new(size()); + __c.__annotate_delete(); } _LIBCPP_INLINE_VISIBILITY @@ -1975,6 +2131,7 @@ __set_long_cap(__cap+1); __set_long_size(__sz); } + __annotate_new(__sz); traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); } @@ -1999,6 +2156,7 @@ __set_long_cap(__cap+1); __set_long_size(__sz); } + __annotate_new(__sz); traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); } @@ -2053,10 +2211,14 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __str) : __r_(__alloc_traits::select_on_container_copy_construction(__str.__alloc())) { - if (!__str.__is_long()) - __r_.first().__r = __str.__r_.first().__r; - else + if (!__str.__is_long()) { + __str.__annotate_delete(); + __r_.first().__r = __str.__r_.first().__r; + __str.__annotate_new(__str.__get_short_size()); + __annotate_short_new(__get_short_size()); + } else { __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); + } #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); #endif @@ -2066,8 +2228,12 @@ basic_string<_CharT, _Traits, _Allocator>::basic_string(const basic_string& __str, const allocator_type& __a) : __r_(__a) { - if (!__str.__is_long()) + if (!__str.__is_long()) { + __str.__annotate_delete(); __r_.first().__r = __str.__r_.first().__r; + __str.__annotate_new(__str.__get_short_size()); + __annotate_short_new(__get_short_size()); + } else __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -2085,9 +2251,10 @@ #else _NOEXCEPT #endif - : __r_(_VSTD::move(__str.__r_)) + : __r_(_VSTD::move(__str.__annotate_delete()->__r_)) { __str.__zero(); + __annotate_new(size()); #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); if (__is_long()) @@ -2104,8 +2271,10 @@ __init(_VSTD::__to_raw_pointer(__str.__get_long_pointer()), __str.__get_long_size()); else { + __str.__annotate_delete(); __r_.first().__r = __str.__r_.first().__r; __str.__zero(); + __annotate_short_new(__get_short_size()); } #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__insert_c(this); @@ -2136,6 +2305,7 @@ __set_long_cap(__cap+1); __set_long_size(__n); } + __annotate_new(__n); traits_type::assign(_VSTD::__to_raw_pointer(__p), __n, __c); traits_type::assign(__p[__n], value_type()); } @@ -2216,21 +2386,26 @@ if (__sz > max_size()) this->__throw_length_error(); pointer __p; + size_type __cap; if (__sz < __min_cap) { __set_short_size(__sz); __p = __get_short_pointer(); + __cap = __min_cap; } else { - size_type __cap = __recommend(__sz); + __cap = __recommend(__sz); __p = __alloc_traits::allocate(__alloc(), __cap+1); __set_long_pointer(__p); __set_long_cap(__cap+1); __set_long_size(__sz); } - for (; __first != __last; ++__first, (void) ++__p) - traits_type::assign(*__p, *__first); + + __annotate_new(__sz); + for (; __first != __last; ++__first, (void) ++__p) { + traits_type::assign(*__p, *__first); + } traits_type::assign(*__p, value_type()); } @@ -2289,8 +2464,10 @@ #if _LIBCPP_DEBUG_LEVEL >= 2 __get_db()->__erase_c(this); #endif + + __annotate_delete(); if (__is_long()) - __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); + __alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap()); } template @@ -2319,10 +2496,12 @@ _VSTD::__to_raw_pointer(__old_p) + __n_copy + __n_del, __sec_cp_sz); if (__old_cap+1 != __min_cap) __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); + __annotate_delete(); __set_long_pointer(__p); __set_long_cap(__cap+1); __old_sz = __n_copy + __n_add + __sec_cp_sz; __set_long_size(__old_sz); + __annotate_new(__old_sz); traits_type::assign(__p[__old_sz], value_type()); } @@ -2340,16 +2519,20 @@ __ms - 1; pointer __p = __alloc_traits::allocate(__alloc(), __cap+1); __invalidate_all_iterators(); - if (__n_copy != 0) - traits_type::copy(_VSTD::__to_raw_pointer(__p), - _VSTD::__to_raw_pointer(__old_p), __n_copy); + if (__n_copy != 0) { + traits_type::copy(_VSTD::__to_raw_pointer(__p), + _VSTD::__to_raw_pointer(__old_p), __n_copy); + } size_type __sec_cp_sz = __old_sz - __n_del - __n_copy; - if (__sec_cp_sz != 0) + if (__sec_cp_sz != 0) { traits_type::copy(_VSTD::__to_raw_pointer(__p) + __n_copy + __n_add, _VSTD::__to_raw_pointer(__old_p) + __n_copy + __n_del, __sec_cp_sz); - if (__old_cap+1 != __min_cap) - __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); + } + if (__old_cap+1 != __min_cap) { + __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); + } + __annotate_delete(); __set_long_pointer(__p); __set_long_cap(__cap+1); } @@ -2362,19 +2545,19 @@ { _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr"); size_type __cap = capacity(); + size_type __sz = size(); if (__cap >= __n) { value_type* __p = _VSTD::__to_raw_pointer(__get_pointer()); + __annotate_grow(__sz, __n); traits_type::move(__p, __s, __n); traits_type::assign(__p[__n], value_type()); __set_size(__n); __invalidate_iterators_past(__n); } else - { - size_type __sz = size(); __grow_by_and_replace(__cap, __n - __cap, __sz, 0, __sz, __n, __s); - } + return *this; } @@ -2383,14 +2566,16 @@ basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) { size_type __cap = capacity(); + size_type __sz = size(); if (__cap < __n) { - size_type __sz = size(); __grow_by(__cap, __n - __cap, __sz, 0, __sz); + __annotate_new(__sz); } else __invalidate_iterators_past(__n); value_type* __p = _VSTD::__to_raw_pointer(__get_pointer()); + __annotate_grow(__sz, __n); traits_type::assign(__p, __n, __c); traits_type::assign(__p[__n], value_type()); __set_size(__n); @@ -2402,6 +2587,7 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c) { pointer __p; + size_t __sz = size(); if (__is_long()) { __p = __get_long_pointer(); @@ -2412,6 +2598,7 @@ __p = __get_short_pointer(); __set_short_size(1); } + __annotate_grow(__sz, 1); traits_type::assign(*__p, __c); traits_type::assign(*++__p, value_type()); __invalidate_iterators_past(1); @@ -2422,7 +2609,7 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str) { - if (this != &__str) + if (this != &__str) { __copy_assign_alloc(__str); assign(__str); @@ -2456,6 +2643,8 @@ { clear(); shrink_to_fit(); + __str.__annotate_delete(); + __annotate_delete(); __r_.first() = __str.__r_.first(); __move_assign_alloc(__str); __str.__zero(); @@ -2501,14 +2690,16 @@ { size_type __n = static_cast(_VSTD::distance(__first, __last)); size_type __cap = capacity(); + size_type __sz = size(); if (__cap < __n) { - size_type __sz = size(); __grow_by(__cap, __n - __cap, __sz, 0, __sz); + __annotate_new(__sz); } else __invalidate_iterators_past(__n); pointer __p = __get_pointer(); + __annotate_grow(__sz, __n); for (; __first != __last; ++__first, ++__p) traits_type::assign(*__p, *__first); traits_type::assign(*__p, value_type()); @@ -2555,6 +2746,7 @@ { if (__n) { + __annotate_grow(__sz, __sz + __n); value_type* __p = _VSTD::__to_raw_pointer(__get_pointer()); traits_type::copy(__p + __sz, __s, __n); __sz += __n; @@ -2562,8 +2754,9 @@ traits_type::assign(__p[__sz], value_type()); } } - else + else { __grow_by_and_replace(__cap, __sz + __n - __cap, __sz, __sz, 0, __n, __s); + } return *this; } @@ -2571,13 +2764,16 @@ basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c) { - if (__n) + if (__n) { size_type __cap = capacity(); size_type __sz = size(); - if (__cap - __sz < __n) + if (__cap - __sz < __n) { __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_new(__sz); + } pointer __p = __get_pointer(); + __annotate_grow(__sz, __sz + __n); traits_type::assign(_VSTD::__to_raw_pointer(__p) + __sz, __n, __c); __sz += __n; __set_size(__sz); @@ -2606,6 +2802,7 @@ if (__sz == __cap) { __grow_by(__cap, 1, __sz, __sz, 0); + __annotate_new(__sz); __is_short = !__is_long(); } pointer __p; @@ -2619,6 +2816,8 @@ __p = __get_long_pointer() + __sz; __set_long_size(__sz+1); } + + __annotate_grow(__sz, __sz + 1); traits_type::assign(*__p, __c); traits_type::assign(*++__p, value_type()); } @@ -2652,9 +2851,12 @@ size_type __n = static_cast(_VSTD::distance(__first, __last)); if (__n) { - if (__cap - __sz < __n) + if (__cap - __sz < __n) { __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_new(__sz); + } pointer __p = __get_pointer() + __sz; + __annotate_grow(__sz, __sz + __n); for (; __first != __last; ++__p, ++__first) traits_type::assign(*__p, *__first); traits_type::assign(*__p, value_type()); @@ -2706,6 +2908,7 @@ { value_type* __p = _VSTD::__to_raw_pointer(__get_pointer()); size_type __n_move = __sz - __pos; + __annotate_grow(__sz, __sz + __n); if (__n_move != 0) { if (__p + __pos <= __s && __s < __p + __sz) @@ -2736,6 +2939,7 @@ value_type* __p; if (__cap - __sz >= __n) { + __annotate_grow(__sz, __sz + __n); __p = _VSTD::__to_raw_pointer(__get_pointer()); size_type __n_move = __sz - __pos; if (__n_move != 0) @@ -2744,6 +2948,7 @@ else { __grow_by(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); + __annotate_new(__sz + __n); __p = _VSTD::__to_raw_pointer(__get_long_pointer()); } traits_type::assign(__p + __pos, __n, __c); @@ -2771,8 +2976,7 @@ #endif size_type __old_sz = size(); difference_type __ip = __pos - begin(); - for (; __first != __last; ++__first) - push_back(*__first); + append(__first, __last); pointer __p = __get_pointer(); _VSTD::rotate(__p + __ip, __p + __old_sz, __p + size()); #if _LIBCPP_DEBUG_LEVEL >= 2 @@ -2807,14 +3011,18 @@ { __p = _VSTD::__to_raw_pointer(__get_pointer()); size_type __n_move = __sz - __ip; + __annotate_short_grow(__sz, __sz + __n); + if (__n_move != 0) traits_type::move(__p + __ip + __n, __p + __ip, __n_move); } else { __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); + __annotate_new(__sz + __n); __p = _VSTD::__to_raw_pointer(__get_long_pointer()); } + __sz += __n; __set_size(__sz); traits_type::assign(__p[__sz], value_type()); @@ -2862,10 +3070,12 @@ if (__cap == __sz) { __grow_by(__cap, 1, __sz, __ip, 0, 1); + __annotate_new(__sz + 1); __p = _VSTD::__to_raw_pointer(__get_long_pointer()); } else { + __annotate_grow(__sz, __sz + 1); __p = _VSTD::__to_raw_pointer(__get_pointer()); size_type __n_move = __sz - __ip; if (__n_move != 0) @@ -2903,9 +3113,13 @@ if (__pos > __sz) this->__throw_out_of_range(); __n1 = _VSTD::min(__n1, __sz - __pos); + size_type __new_sz = __sz + __n2 - __n1; size_type __cap = capacity(); if (__cap - __sz + __n1 >= __n2) { + if (__new_sz > __sz) { + __annotate_grow(__sz, __new_sz); + } value_type* __p = _VSTD::__to_raw_pointer(__get_pointer()); if (__n1 != __n2) { @@ -2936,6 +3150,9 @@ } traits_type::move(__p + __pos, __s, __n2); __finish: + if (__new_sz < __sz) { + __annotate_grow(__sz, __new_sz); + } __sz += __n2 - __n1; __set_size(__sz); __invalidate_iterators_past(__sz); @@ -2954,25 +3171,34 @@ if (__pos > __sz) this->__throw_out_of_range(); __n1 = _VSTD::min(__n1, __sz - __pos); + size_t __new_sz = __sz + __n2 - __n1; size_type __cap = capacity(); value_type* __p; - if (__cap - __sz + __n1 >= __n2) + if (__cap >= __new_sz) { + if (__new_sz > __sz) { + __annotate_grow(__sz, __new_sz); + } __p = _VSTD::__to_raw_pointer(__get_pointer()); if (__n1 != __n2) { size_type __n_move = __sz - __pos - __n1; - if (__n_move != 0) + 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_new(__new_sz); __p = _VSTD::__to_raw_pointer(__get_long_pointer()); } + if (__new_sz < __sz) { + __annotate_grow(__sz, __new_sz); + } traits_type::assign(__p + __pos, __n2, __c); - __sz += __n2 - __n1; + __sz = __new_sz; __set_size(__sz); __invalidate_iterators_past(__sz); traits_type::assign(__p[__sz], value_type()); @@ -3083,6 +3309,7 @@ size_type __n_move = __sz - __pos - __n; if (__n_move != 0) traits_type::move(__p + __pos, __p + __pos + __n, __n_move); + __annotate_grow(__sz, __sz - __n); __sz -= __n; __set_size(__sz); __invalidate_iterators_past(__sz); @@ -3145,6 +3372,7 @@ __set_short_size(__sz); traits_type::assign(*(__get_short_pointer() + __sz), value_type()); } + __annotate_grow(__sz + 1, __sz); __invalidate_iterators_past(__sz); } @@ -3153,6 +3381,7 @@ void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_t __sz = size(); __invalidate_all_iterators(); if (__is_long()) { @@ -3164,6 +3393,7 @@ traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_grow(__sz, 0); } template @@ -3171,6 +3401,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__erase_to_end(size_type __pos) { + size_type __sz = size(); if (__is_long()) { traits_type::assign(*(__get_long_pointer() + __pos), value_type()); @@ -3181,6 +3412,7 @@ traits_type::assign(*(__get_short_pointer() + __pos), value_type()); __set_short_size(__pos); } + __annotate_grow(__sz, __pos); __invalidate_iterators_past(__pos); } @@ -3255,10 +3487,15 @@ __was_long = __is_long(); __p = __get_pointer(); } + traits_type::copy(_VSTD::__to_raw_pointer(__new_data), _VSTD::__to_raw_pointer(__p), size()+1); + if (__was_long) __alloc_traits::deallocate(__alloc(), __p, __cap+1); + + __annotate_delete(); + if (__now_long) { __set_long_cap(__res_arg+1); @@ -3267,6 +3504,7 @@ } else __set_short_size(__sz); + __annotate_new(__sz); __invalidate_all_iterators(); } } @@ -3370,7 +3608,7 @@ #if _LIBCPP_STD_VER >= 14 _NOEXCEPT #else - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable::value) #endif { @@ -3381,8 +3619,12 @@ __get_db()->__invalidate_all(&__str); __get_db()->swap(this, &__str); #endif + __str.__annotate_delete(); + __annotate_delete(); _VSTD::swap(__r_.first(), __str.__r_.first()); __swap_allocator(__alloc(), __str.__alloc()); + __str.__annotate_new(__str.size()); + __annotate_new(size()); } // find @@ -3970,10 +4212,9 @@ const basic_string<_CharT, _Traits, _Allocator>& __rhs) { basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); - __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + __rhs_sz); - __r.append(__rhs.data(), __rhs_sz); + __r.reserve(__rhs.size() + __lhs.size()); + __r.append(__lhs); + __r.append(__rhs); return __r; } @@ -3982,10 +4223,9 @@ operator+(const _CharT* __lhs , const basic_string<_CharT,_Traits,_Allocator>& __rhs) { basic_string<_CharT, _Traits, _Allocator> __r(__rhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = _Traits::length(__lhs); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); - __r.__init(__lhs, __lhs_sz, __lhs_sz + __rhs_sz); - __r.append(__rhs.data(), __rhs_sz); + __r.reserve(__rhs.size() + _Traits::length(__lhs)); + __r.append(__lhs); + __r.append(__rhs); return __r; } @@ -3994,9 +4234,9 @@ operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Allocator>& __rhs) { basic_string<_CharT, _Traits, _Allocator> __r(__rhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); - __r.__init(&__lhs, 1, 1 + __rhs_sz); - __r.append(__rhs.data(), __rhs_sz); + __r.reserve(__rhs.size() + 1); + __r.push_back(__lhs); + __r.append(__rhs); return __r; } @@ -4005,10 +4245,9 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) { basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = _Traits::length(__rhs); - __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + __rhs_sz); - __r.append(__rhs, __rhs_sz); + __r.reserve(_Traits::length(__rhs) + __lhs.size()); + __r.append(__lhs); + __r.append(__rhs); return __r; } @@ -4017,8 +4256,8 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, _CharT __rhs) { basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); - __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + 1); + __r.reserve(__lhs.size() + 1); + __r.append(__lhs); __r.push_back(__rhs); return __r; } @@ -4237,7 +4476,7 @@ #endif // _LIBCPP_DEBUG_LEVEL >= 2 -#if _LIBCPP_STD_VER > 11 +#if _LIBCPP_STD_VER > 11 // Literal suffixes for basic_string [basic.string.literals] inline namespace literals { Index: test/std/strings/basic.string/asan.pass.cpp =================================================================== --- /dev/null +++ test/std/strings/basic.string/asan.pass.cpp @@ -0,0 +1,387 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Test asan string annotations. + +#include +#include +#include +#include + +#include "asan_testing.h" + +template +void test_empty_string() { + fprintf(stderr, "--- test_empty_string\n"); + S s; + assert(is_asan_correct_string(s)); +} + +template +void test_fill_constructor() { + fprintf(stderr, "--- test_fill_constructor\n"); + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S s(i, static_cast('x')); + assert(s.size() == i); + assert(is_asan_correct_string(s)); + } +} + +template +void test_cstr_constructor() { + fprintf(stderr, "--- test_cstr_constructor\n"); + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S tmp(i, static_cast('x')); + assert(tmp.size() == i); + assert(is_asan_correct_string(tmp)); + + S s(tmp.c_str()); + assert(s.size() == i); + assert(is_asan_correct_string(s)); + } +} + +template +void test_copy_constructor() { + fprintf(stderr, "--- test_copy_constructor\n"); + for (int i = 0; i < 100; ++i) { + S tmp(i, static_cast('x')); + assert(tmp.size() == i); + assert(is_asan_correct_string(tmp)); + + fprintf(stderr, ">>>i=%d\n", i); + S s(tmp); + assert(s.size() == i); + assert(is_asan_correct_string(s)); + } +} + +template +void test_reserve() { + fprintf(stderr, "--- test_reserve\n"); + for (int i = 0; i < 100; ++i) { + S s; + fprintf(stderr, ">>>i=%d\n", i); + s.reserve(i); + assert(is_asan_correct_string(s)); + } +} + +template +void test_push_back() { + fprintf(stderr, "--- test_push_back\n"); + S s; + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>s.size()=%ld\n", s.size()); + s.push_back(1); + assert(is_asan_correct_string(s)); + } +} + +template +void test_insert_range() { + fprintf(stderr, "--- test_insert_range\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + std::vector v(i, static_cast('x')); + S s; + s.insert(s.end(), v.begin(), v.end()); + assert(is_asan_correct_string(s)); + } +} + +template +void test_insert_fill() { + fprintf(stderr, "--- test_insert_fill\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S s; + s.insert(0, i, static_cast('x')); + assert(is_asan_correct_string(s)); + } +} + +template +void test_insert_cstr() { + fprintf(stderr, "--- test_insert_range\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S tmp(i, static_cast('x')); + S s; + s.insert(0, tmp.c_str()); + assert(is_asan_correct_string(s)); + } +} + +template +void test_assign() { + fprintf(stderr, "--- test_assign\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + S s; + s.assign(i, static_cast('x')); + assert(is_asan_correct_string(s)); + } +} + +template +void test_assign_char() { + fprintf(stderr, "--- test_assign\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + S s(i, static_cast('x')); + s = static_cast('z'); + assert(is_asan_correct_string(s)); + } +} + +template +void test_append_str() { + fprintf(stderr, "--- test_append_str\n"); + + for (int i = 0; i < 100; ++i) { + S tmp(i, static_cast('x')); + fprintf(stderr, ">>>i=%d\n", i); + + S s; + s.append(tmp); + assert(is_asan_correct_string(s)); + } +} + +template +void test_append_fill() { + fprintf(stderr, "--- test_append_fill\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + S s; + s.append(i, static_cast('x')); + assert(is_asan_correct_string(s)); + } +} + +template +void test_resize() { + fprintf(stderr, "--- test_resize\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + { + S s; + s.resize(i); + assert(is_asan_correct_string(s)); + } + { + S s(100, static_cast('x')); + s.resize(i); + assert(is_asan_correct_string(s)); + } + } +} + +template +void test_assign_cstr() { + fprintf(stderr, "--- test_assign_cstr\n"); + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S tmp(i, static_cast('x')); + assert(tmp.size() == i); + assert(is_asan_correct_string(tmp)); + + S s; + s.assign(tmp.c_str()); + assert(s.size() == i); + assert(is_asan_correct_string(s)); + } +} + +template +void test_clear() { + fprintf(stderr, "--- test_clear\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S s(i, static_cast('x')); + s.clear(); + assert(is_asan_correct_string(s)); + } +} + +template +void test_append_range() { + fprintf(stderr, "--- test_append_range\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + std::vector v(i, static_cast('x')); + S s; + s.append(v.begin(), v.end()); + assert(is_asan_correct_string(s)); + } +} + +template +void test_assign_range() { + fprintf(stderr, "--- test_assign_range\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + std::vector v(i, static_cast('x')); + S s; + s.assign(v.begin(), v.end()); + assert(is_asan_correct_string(s)); + } +} + +template +void test_replace_cstr() { + fprintf(stderr, "--- test_replace\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + { + S tmp(i, static_cast('x')); + S s; + s.replace(0, 0, tmp.c_str()); + assert(is_asan_correct_string(s)); + } + + { + S tmp; + S s(i, static_cast('x')); + s.replace(0, s.size() / 2, tmp.c_str()); + assert(is_asan_correct_string(s)); + } + } + + { + S s(10, static_cast('x')); + S tmp(10, static_cast('y')); + s.replace(0, 0, tmp.c_str(), 2); + assert(is_asan_correct_string(s)); + } +} + +template +void test_operator_plus() { + fprintf(stderr, "--- test_operator_plus\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + S tmp(i, static_cast('x')); + S s = static_cast('y') + tmp; + assert(is_asan_correct_string(s)); + } +} + +template +void test_erase() { + fprintf(stderr, "--- test_erase\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + { + S s(i, static_cast('x')); + s.erase(0, s.size()); + assert(is_asan_correct_string(s)); + } + + { + S s(i, static_cast('x')); + s.erase(s.size() / 4, s.size() * 3 / 4); + assert(is_asan_correct_string(s)); + } + } +} + +template +void test_pop_back() { + fprintf(stderr, "--- test_erase\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + S s(i, static_cast('x')); + while (!s.empty()) { + s.pop_back(); + assert(is_asan_correct_string(s)); + } + } +} + +template +void test_cstr() { + fprintf(stderr, "--- test_erase\n"); + + for (int i = 0; i < 100; ++i) { + fprintf(stderr, ">>>i=%d\n", i); + + S s(i, static_cast('x')); + assert(is_asan_correct_string(s)); + s.c_str(); + } +} + +template +void test_all() { + test_empty_string(); + test_fill_constructor(); + test_cstr_constructor(); + test_copy_constructor(); + test_resize(); + test_clear(); + test_reserve(); + test_push_back(); + test_insert_range(); + test_insert_cstr(); + test_insert_fill(); + test_assign(); + test_assign_char(); + test_assign_cstr(); + test_assign_range(); + test_append_str(); + test_append_fill(); + test_append_range(); + test_replace_cstr(); + test_operator_plus(); + test_erase(); + test_cstr(); +} + +int main() { + test_all(); + test_all(); + + { + + std::string s("0123456789012345678901234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345678901234567890123456789" + ); + assert(s.size() == 280); + assert(is_asan_correct_string(s)); + assert(strlen(s.c_str()) == 280); + } + +} Index: test/support/asan_testing.h =================================================================== --- test/support/asan_testing.h +++ test/support/asan_testing.h @@ -11,27 +11,72 @@ #define ASAN_TESTING_H #include <__config> +#include +#include #ifndef _LIBCPP_HAS_NO_ASAN -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); + +extern "C" const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg, const void *mid, const void *end); + template -bool is_contiguous_container_asan_correct ( const std::vector &c ) -{ - if ( std::is_same >::value && c.data() != NULL) - return __sanitizer_verify_contiguous_container ( - c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0; +bool is_contiguous_container_asan_correct(const std::vector &c) { + 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; +} + +template +bool is_asan_correct_string(const std::basic_string &s) { + if (!std::is_same>::value || s.data() == NULL) { return true; + } + + const T* s_ptr = reinterpret_cast(&s); + const T* data = reinterpret_cast(s.data()); + bool is_small = (data - s_ptr) < sizeof(void *); + + const T *p1; + const T *p2; + const T *mid; + const void *bad_addr = nullptr; + + if (is_small) { + p1 = s_ptr; + mid = data + s.size() + 1 /* terminator */; + p2 = data + s.capacity() + 1 /* terminator */; + } else { + p1 = data; + mid = data + s.size() + 1 /* terminator */; + p2 = data + s.capacity() + 1 /* terminator */; + } + + bad_addr = __sanitizer_contiguous_container_find_bad_address(p1, mid, p2); + if (bad_addr) { + std::ptrdiff_t offset = reinterpret_cast(bad_addr) - + reinterpret_cast(s.data()); + + fprintf(stderr, "ERROR: broken string: bad_addr=%p (data+%ld), this=%p, data=%p, " + "size=%ld, capacity=%ld [%p %p %p]\n", + bad_addr, offset, s_ptr, s.data(), s.size(), s.capacity(), p1, mid, p2); + return false; + } + + return true; } #else template -bool is_contiguous_container_asan_correct ( const std::vector &c ) -{ - return true; +bool is_contiguous_container_asan_correct(const std::vector &c) { + return true; } + +template +void assert_asan_correct_string(const std::basic_string &s) {} #endif - -#endif // ASAN_TESTING_H +#endif // ASAN_TESTING_H