Index: include/string =================================================================== --- include/string +++ include/string @@ -11,6 +11,9 @@ #ifndef _LIBCPP_STRING #define _LIBCPP_STRING +#include +#include + /* string synopsis @@ -1200,6 +1203,95 @@ #endif // _LIBCPP_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) + { +#ifndef _LIBCPP_HAS_NO_ASAN + 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), @@ -1697,6 +1791,51 @@ const allocator_type& __alloc() const _NOEXCEPT {return __r_.second();} + void __annotate_contiguous_container + (const char* msg, const void *__beg, const void *__end, const void *__old_mid, const void *__new_mid) const + { + return __asan_traits::__annotate_contiguous_container(msg, __beg, __end, __old_mid, __new_mid); + } + + 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; + } + #ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT _LIBCPP_INLINE_VISIBILITY @@ -1780,6 +1919,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 @@ -1965,6 +2105,7 @@ { __set_short_size(__sz); __p = __get_short_pointer(); + _LIBCPP_ASSERT(false, "HERE"); } else { @@ -1974,6 +2115,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()); } @@ -1989,6 +2131,7 @@ { __set_short_size(__sz); __p = __get_short_pointer(); + _LIBCPP_ASSERT(false, "HERE"); } else { @@ -1998,6 +2141,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()); } @@ -2052,10 +2196,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 @@ -2065,8 +2213,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 @@ -2084,9 +2236,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()) @@ -2103,8 +2256,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); @@ -2135,6 +2290,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()); } @@ -2215,21 +2371,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()); } @@ -2288,8 +2449,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 @@ -2318,10 +2481,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()); } @@ -2339,16 +2504,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); } @@ -2361,19 +2530,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; } @@ -2382,14 +2551,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); @@ -2401,6 +2572,7 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c) { pointer __p; + size_t __sz = size(); if (__is_long()) { __p = __get_long_pointer(); @@ -2411,6 +2583,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); @@ -2421,7 +2594,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); @@ -2455,9 +2628,12 @@ { clear(); shrink_to_fit(); + __str.__annotate_delete(); + __annotate_delete(); __r_.first() = __str.__r_.first(); __move_assign_alloc(__str); __str.__zero(); + __annotate_new(size()); } template @@ -2500,14 +2676,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()); @@ -2554,6 +2732,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; @@ -2561,8 +2740,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; } @@ -2570,13 +2750,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); @@ -2605,6 +2788,7 @@ if (__sz == __cap) { __grow_by(__cap, 1, __sz, __sz, 0); + __annotate_new(__sz); __is_short = !__is_long(); } pointer __p; @@ -2618,6 +2802,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()); } @@ -2651,9 +2837,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()); @@ -2705,6 +2894,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) @@ -2735,6 +2925,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) @@ -2743,6 +2934,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); @@ -2806,14 +2998,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()); @@ -2861,10 +3057,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) @@ -2902,9 +3100,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) { @@ -2935,6 +3137,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); @@ -2953,25 +3158,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()); @@ -3152,6 +3366,7 @@ void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { + size_t __sz = size(); __invalidate_all_iterators(); if (__is_long()) { @@ -3163,6 +3378,7 @@ traits_type::assign(*__get_short_pointer(), value_type()); __set_short_size(0); } + __annotate_grow(__sz, 0); } template @@ -3170,6 +3386,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()); @@ -3180,6 +3397,7 @@ traits_type::assign(*(__get_short_pointer() + __pos), value_type()); __set_short_size(__pos); } + __annotate_grow(__sz, __pos); __invalidate_iterators_past(__pos); } @@ -3254,10 +3472,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); @@ -3266,6 +3489,7 @@ } else __set_short_size(__sz); + __annotate_new(__sz); __invalidate_all_iterators(); } } @@ -3380,8 +3604,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 @@ -3969,10 +4197,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; } @@ -3981,10 +4208,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; } @@ -3993,9 +4219,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; } @@ -4004,10 +4230,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; } @@ -4016,8 +4241,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; } Index: test/std/strings/basic.string/asan.pass.cpp =================================================================== --- /dev/null +++ test/std/strings/basic.string/asan.pass.cpp @@ -0,0 +1,323 @@ +//===----------------------------------------------------------------------===// +// +// 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 "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_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(); +} + +int main() { + test_all(); + test_all(); +} Index: test/std/strings/basic.string/string.capacity/capacity.pass.cpp =================================================================== --- test/std/strings/basic.string/string.capacity/capacity.pass.cpp +++ test/std/strings/basic.string/string.capacity/capacity.pass.cpp @@ -16,6 +16,7 @@ #include "test_allocator.h" #include "min_allocator.h" +#include "asan_testing.h" template void 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