[libcxx-commits] [libcxxabi] [libcxx] [ASan][libc++] std::basic_string annotations (PR #72677)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Dec 11 05:56:57 PST 2023
https://github.com/AdvenamTacet updated https://github.com/llvm/llvm-project/pull/72677
>From b1c286fb2da26726597a01c6df9c0ae41fb1f74a Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Fri, 17 Nov 2023 01:51:21 +0100
Subject: [PATCH 1/8] [ASan][libc++] std::basic_string annotations
This commit turns on basic annotations for std::basic_string, similar to those in std::vector and std::deque.
Originally proposed here: https://reviews.llvm.org/D132769
Related patches:
Turning on annotations for short strings: https://reviews.llvm.org/D147680
Turning on annotations for all allocators: https://reviews.llvm.org/D146214
This revision is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in std::vector, to std::string and std::deque collections. These changes allow ASan to detect cases when the instrumented program accesses memory which is internally allocated by the collection but is still not in-use (accesses before or after the stored elements for std::deque, or between the size and capacity bounds for std::string).
The motivation for the research and those changes was a bug, found by Trail of Bits, in a real code where an out-of-bounds read could happen as two strings were compared via a std::equals function that took iter1_begin, iter1_end, iter2_begin iterators (with a custom comparison function). When object iter1 was longer than iter2, read out-of-bounds on iter2 could happen. Container sanitization would detect it.
This Pull Request adds annotations for `std::basic_string`. Long string is very similar to std::vector, and therefore works well with `__sanitizer_annotate_contiguous_container` from LLVM 15 and therefore annotations works if that implementation is compiled with previous LLVM.
However, only the standard allocator is supported.
As D132522 extended possibilities of `__sanitizer_annotate_contiguous_container`, now annotations may be supported with all allocators, but that support will be added in a next PR. Only strings with default allocator are annotated with that commit.
If you have any questions, please email:
- advenam.tacet at trailofbits.com
- disconnect3d at trailofbits.com
---
libcxx/include/string | 274 ++++++++++++++----
.../string.capacity/capacity.pass.cpp | 9 +
.../string.capacity/clear.pass.cpp | 7 +
.../string.capacity/reserve.pass.cpp | 3 +
.../reserve_size.asan.pass.cpp | 66 +++++
.../string.capacity/reserve_size.pass.cpp | 3 +
.../resize_and_overwrite.pass.cpp | 4 +
.../string.capacity/resize_size.pass.cpp | 3 +
.../string.capacity/resize_size_char.pass.cpp | 13 +
.../string.capacity/shrink_to_fit.pass.cpp | 8 +
.../string.cons/T_size_size.pass.cpp | 3 +
.../basic.string/string.cons/alloc.pass.cpp | 6 +
.../string.cons/brace_assignment.pass.cpp | 3 +
.../string.cons/char_assignment.pass.cpp | 3 +
.../basic.string/string.cons/copy.pass.cpp | 4 +
.../string.cons/copy_alloc.pass.cpp | 4 +
.../string.cons/copy_assignment.pass.cpp | 4 +
.../basic.string/string.cons/default.pass.cpp | 2 +
.../string.cons/initializer_list.pass.cpp | 10 +
.../initializer_list_assignment.pass.cpp | 14 +
.../string.cons/iter_alloc.pass.cpp | 3 +
.../string.cons/iter_alloc_deduction.pass.cpp | 6 +
.../basic.string/string.cons/move.pass.cpp | 4 +
.../string.cons/move_alloc.pass.cpp | 4 +
.../string.cons/move_assignment.pass.cpp | 5 +
.../string.cons/pointer_alloc.pass.cpp | 4 +
.../string.cons/pointer_assignment.pass.cpp | 3 +
.../string.cons/pointer_size_alloc.pass.cpp | 4 +
.../string.cons/size_char_alloc.pass.cpp | 4 +
.../string.cons/string_view.pass.cpp | 6 +
.../string_view_assignment.pass.cpp | 3 +
.../basic.string/string.cons/substr.pass.cpp | 5 +
.../string_append/initializer_list.pass.cpp | 3 +
.../string_append/iterator.pass.cpp | 3 +
.../string_append/pointer.pass.cpp | 3 +
.../string_append/pointer_size.pass.cpp | 3 +
.../string_append/push_back.pass.cpp | 3 +
.../string_append/size_char.pass.cpp | 3 +
.../string_append/string.pass.cpp | 3 +
.../string_append/string_size_size.pass.cpp | 3 +
.../string_assign/T_size_size.pass.cpp | 3 +
.../string_assign/initializer_list.pass.cpp | 3 +
.../string_assign/iterator.pass.cpp | 3 +
.../string_assign/pointer.pass.cpp | 3 +
.../string_assign/pointer_size.pass.cpp | 3 +
.../string_assign/size_char.pass.cpp | 3 +
.../string_assign/string.pass.cpp | 3 +
.../string_assign/string_size_size.pass.cpp | 3 +
.../string_copy/copy.pass.cpp | 5 +
.../string_erase/iter.pass.cpp | 3 +
.../string_erase/iter_iter.pass.cpp | 3 +
.../string_erase/pop_back.asan.pass.cpp | 50 ++++
.../string_erase/pop_back.pass.cpp | 3 +
.../string_erase/size_size.pass.cpp | 3 +
.../string_insert/iter_char.pass.cpp | 4 +
.../iter_initializer_list.pass.cpp | 3 +
.../string_insert/iter_iter_iter.pass.cpp | 3 +
.../string_insert/iter_size_char.pass.cpp | 3 +
.../string_insert/size_pointer.pass.cpp | 3 +
.../string_insert/size_pointer_size.pass.cpp | 3 +
.../string_insert/size_size_char.pass.cpp | 3 +
.../string_insert/size_string.pass.cpp | 3 +
.../size_string_size_size.pass.cpp | 3 +
.../string_op_plus_equal/char.pass.cpp | 3 +
.../initializer_list.pass.cpp | 3 +
.../string_op_plus_equal/pointer.pass.cpp | 3 +
.../string_op_plus_equal/string.pass.cpp | 4 +
.../string_replace/iter_iter_string.pass.cpp | 3 +
.../size_size_T_size_size.pass.cpp | 3 +
.../string_replace/size_size_pointer.pass.cpp | 3 +
.../size_size_pointer_size.pass.cpp | 3 +
.../size_size_size_char.pass.cpp | 3 +
.../string_replace/size_size_string.pass.cpp | 3 +
.../size_size_string_size_size.pass.cpp | 3 +
.../size_size_string_view.pass.cpp | 3 +
.../string_swap/swap.asan.pass.cpp | 87 ++++++
.../string_swap/swap.pass.cpp | 4 +
.../string.special/swap.pass.cpp | 4 +
.../string_op+/char_string.pass.cpp | 3 +
.../string_op+/string_char.pass.cpp | 3 +
.../string_op+/string_pointer.pass.cpp | 3 +
.../string_op+/string_string.pass.cpp | 3 +
libcxx/test/support/asan_testing.h | 63 +++-
83 files changed, 780 insertions(+), 64 deletions(-)
create mode 100644 libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp
create mode 100644 libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp
create mode 100644 libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp
diff --git a/libcxx/include/string b/libcxx/include/string
index 9c97abefcb8d0..93725c2acc619 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -649,6 +649,17 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
+#ifndef _LIBCPP_HAS_NO_ASAN
+# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address")))
+// This macro disables AddressSanitizer (ASan) instrumentation for a specific function,
+// allowing memory accesses that would normally trigger ASan errors to proceed without crashing.
+// This is useful for accessing parts of objects memory, which should not be accessed,
+// such as unused bytes in short strings, that should never be accessed
+// by other parts of the program.
+#else
+# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
+#endif
+#define _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED false
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -706,6 +717,9 @@ struct __init_with_sentinel_tag {};
template<class _CharT, class _Traits, class _Allocator>
class basic_string
{
+private:
+ using __default_allocator_type = allocator<_CharT>;
+
public:
typedef basic_string __self;
typedef basic_string_view<_CharT, _Traits> __self_view;
@@ -892,34 +906,46 @@ public:
#endif
: __r_(__value_init_tag(), __a) {}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str)
: __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
if (!__str.__is_long())
+ {
__r_.first() = __str.__r_.first();
+ __annotate_new(__get_short_size());
+ }
else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
}
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const basic_string& __str, const allocator_type& __a)
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str, const allocator_type& __a)
: __r_(__default_init_tag(), __a) {
if (!__str.__is_long())
+ {
__r_.first() = __str.__r_.first();
+ __annotate_new(__get_short_size());
+ }
else
__init_copy_ctor_external(std::__to_address(__str.__get_long_pointer()), __str.__get_long_size());
}
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(basic_string&& __str)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ basic_string(basic_string&& __str)
# if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
# else
_NOEXCEPT
# endif
- : __r_(std::move(__str.__r_)) {
+ // 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 only the short string case).
+ : __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) {
__str.__r_.first() = __rep();
}
- _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());
@@ -927,6 +953,9 @@ public:
if (__libcpp_is_constant_evaluated())
__r_.first() = __rep();
__r_.first() = __str.__r_.first();
+ if (!__str.__is_long()) {
+ __str.__annotate_delete();
+ }
__str.__r_.first() = __rep();
}
}
@@ -969,11 +998,11 @@ public:
}
#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())
@@ -1085,6 +1114,7 @@ public:
#endif // _LIBCPP_CXX03_LANG
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() {
+ __annotate_delete();
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
}
@@ -1102,8 +1132,8 @@ public:
}
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(basic_string&& __str)
- _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _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<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
}
@@ -1116,7 +1146,7 @@ public:
#if _LIBCPP_STD_VER >= 23
basic_string& operator=(nullptr_t) = delete;
#endif
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(value_type __c);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(value_type __c);
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
iterator begin() _NOEXCEPT
@@ -1335,7 +1365,7 @@ public:
}
#if _LIBCPP_STD_VER >= 20
- _LIBCPP_HIDE_FROM_ABI constexpr
+ _LIBCPP_HIDE_FROM_ABI constexpr _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void __move_assign(basic_string&& __str, size_type __pos, size_type __len) {
// Pilfer the allocation from __str.
_LIBCPP_ASSERT_INTERNAL(__alloc() == __str.__alloc(), "__move_assign called with wrong allocator");
@@ -1351,7 +1381,7 @@ public:
_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;}
@@ -1742,7 +1772,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __shrink_or_extend(size_type __target_capacity);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
bool __is_long() const _NOEXCEPT {
if (__libcpp_is_constant_evaluated() && __builtin_constant_p(__r_.first().__l.__is_long_)) {
return __r_.first().__l.__is_long_;
@@ -1782,6 +1812,7 @@ private:
value_type* __p;
if (__cap - __sz >= __n)
{
+ __annotate_increase(__n);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
@@ -1808,7 +1839,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 allocator_type& __alloc() _NOEXCEPT { return __r_.second(); }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void __set_short_size(size_type __s) _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(
__s < __min_cap, "__s should never be greater than or equal to the short string capacity");
@@ -1816,7 +1847,7 @@ private:
__r_.first().__s.__is_long_ = false;
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
size_type __get_short_size() const _NOEXCEPT {
_LIBCPP_ASSERT_INTERNAL(
!__r_.first().__s.__is_long_, "String has to be short when trying to get the short size");
@@ -1866,6 +1897,45 @@ private:
const_pointer __get_pointer() const _NOEXCEPT
{return __is_long() ? __get_long_pointer() : __get_short_pointer();}
+ // The following functions are no-ops outside of AddressSanitizer mode.
+#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_is_constant_evaluated() && __begin != nullptr && is_same<allocator_type, __default_allocator_type>::value)
+ __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 __asan_short_string_is_annotated() const _NOEXCEPT {
+ return _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED && !__libcpp_is_constant_evaluated();
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_new(size_type __current_size) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + capacity() + 1, data() + __current_size + 1);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_delete() const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + size() + 1, data() + capacity() + 1);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_increase(size_type __n) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + size() + 1, data() + size() + 1 + __n);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_shrink(size_type __old_size) const _NOEXCEPT {
+ if (!__libcpp_is_constant_evaluated() && (__asan_short_string_is_annotated() || __is_long()))
+ __annotate_contiguous_container(data() + __old_size + 1, data() + size() + 1);
+ }
+
template <size_type __a> static
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
size_type __align_it(size_type __s) _NOEXCEPT
@@ -1968,6 +2038,7 @@ private:
}
else
{
+ __annotate_delete();
allocator_type __a = __str.__alloc();
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
__begin_lifetime(__allocation.ptr, __allocation.count);
@@ -1977,6 +2048,7 @@ private:
__set_long_pointer(__allocation.ptr);
__set_long_cap(__allocation.count);
__set_long_size(__str.size());
+ __annotate_new(__get_long_size());
}
}
}
@@ -2024,18 +2096,28 @@ private:
// Assigns the value in __s, guaranteed to be __n < __min_cap in length.
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& __assign_short(const value_type* __s, size_type __n) {
+ size_type __old_size = size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __is_long()
? (__set_long_size(__n), __get_long_pointer())
: (__set_short_size(__n), __get_short_pointer());
traits_type::move(std::__to_address(__p), __s, __n);
traits_type::assign(__p[__n], value_type());
+ if (__old_size > __n)
+ __annotate_shrink(__old_size);
return *this;
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string& __null_terminate_at(value_type* __p, size_type __newsz) {
+ size_type __old_size = size();
+ if (__newsz > __old_size)
+ __annotate_increase(__newsz - __old_size);
__set_size(__newsz);
traits_type::assign(__p[__newsz], value_type());
+ if (__old_size > __newsz)
+ __annotate_shrink(__old_size);
return *this;
}
@@ -2142,6 +2224,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s,
}
traits_type::copy(std::__to_address(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2170,6 +2253,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_ty
}
traits_type::copy(std::__to_address(__p), __s, __sz);
traits_type::assign(__p[__sz], value_type());
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2194,6 +2278,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(
__set_long_size(__sz);
}
traits_type::copy(std::__to_address(__p), __s, __sz + 1);
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2223,6 +2308,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c)
}
traits_type::assign(std::__to_address(__p), __n, __c);
traits_type::assign(__p[__n], value_type());
+ __annotate_new(__n);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2249,6 +2335,7 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputItera
}
catch (...)
{
+ __annotate_delete();
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
throw;
@@ -2304,11 +2391,13 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(
}
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 <class _CharT, class _Traits, class _Allocator>
@@ -2325,6 +2414,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
size_type __cap = __old_cap < __ms / 2 - __alignment ?
__recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) :
__ms - 1;
+ __annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2344,6 +2434,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace
__old_sz = __n_copy + __n_add + __sec_cp_sz;
__set_long_size(__old_sz);
traits_type::assign(__p[__old_sz], value_type());
+ __annotate_new(__old_cap + __delta_cap);
}
// __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it
@@ -2366,6 +2457,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_t
size_type __cap = __old_cap < __ms / 2 - __alignment ?
__recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) :
__ms - 1;
+ __annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
@@ -2396,6 +2488,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
__grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__set_long_size(__old_sz - __n_del + __n_add);
+ __annotate_new(__old_sz - __n_del + __n_add);
}
// assign
@@ -2408,10 +2501,15 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(
const value_type* __s, size_type __n) {
size_type __cap = __is_short ? static_cast<size_type>(__min_cap) : __get_long_cap();
if (__n < __cap) {
+ size_type __old_size = __is_short ? __get_short_size() : __get_long_size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer();
__is_short ? __set_short_size(__n) : __set_long_size(__n);
traits_type::copy(std::__to_address(__p), __s, __n);
traits_type::assign(__p[__n], value_type());
+ if (__old_size > __n)
+ __annotate_shrink(__old_size);
} else {
size_type __sz = __is_short ? __get_short_size() : __get_long_size();
__grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s);
@@ -2426,6 +2524,9 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_external(
const value_type* __s, size_type __n) {
size_type __cap = capacity();
if (__cap >= __n) {
+ size_type __old_size = size();
+ if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
value_type* __p = std::__to_address(__get_pointer());
traits_type::move(__p, __s, __n);
return __null_terminate_at(__p, __n);
@@ -2453,11 +2554,15 @@ basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c)
{
size_type __cap = capacity();
+ size_type __old_size = size();
if (__cap < __n)
{
size_type __sz = size();
__grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz);
+ __annotate_increase(__n);
}
+ else if(__n > __old_size)
+ __annotate_increase(__n - __old_size);
value_type* __p = std::__to_address(__get_pointer());
traits_type::assign(__p, __n, __c);
return __null_terminate_at(__p, __n);
@@ -2468,24 +2573,26 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::operator=(value_type __c)
{
- pointer __p;
- if (__is_long())
- {
- __p = __get_long_pointer();
- __set_long_size(1);
- }
- else
- {
- __p = __get_short_pointer();
- __set_short_size(1);
- }
- traits_type::assign(*__p, __c);
- traits_type::assign(*++__p, value_type());
- return *this;
+ pointer __p;
+ size_type __old_size = size();
+ if (__old_size == 0)
+ __annotate_increase(1);
+ if (__is_long()) {
+ __p = __get_long_pointer();
+ __set_long_size(1);
+ } else {
+ __p = __get_short_pointer();
+ __set_short_size(1);
+ }
+ traits_type::assign(*__p, __c);
+ traits_type::assign(*++__p, value_type());
+ if (__old_size > 1)
+ __annotate_shrink(__old_size);
+ return *this;
}
template <class _CharT, class _Traits, class _Allocator>
-_LIBCPP_CONSTEXPR_SINCE_CXX20
+_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
basic_string<_CharT, _Traits, _Allocator>&
basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
{
@@ -2493,7 +2600,12 @@ basic_string<_CharT, _Traits, _Allocator>::operator=(const basic_string& __str)
__copy_assign_alloc(__str);
if (!__is_long()) {
if (!__str.__is_long()) {
+ size_type __old_size = __get_short_size();
+ if (__get_short_size() < __str.__get_short_size())
+ __annotate_increase(__str.__get_short_size() - __get_short_size());
__r_.first() = __str.__r_.first();
+ if (__old_size > __get_short_size())
+ __annotate_shrink(__old_size);
} else {
return __assign_no_alias<true>(__str.data(), __str.size());
}
@@ -2519,7 +2631,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, fa
}
template <class _CharT, class _Traits, class _Allocator>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX20
+inline _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void
basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type)
#if _LIBCPP_STD_VER >= 17
@@ -2528,6 +2640,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
_NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value)
#endif
{
+ __annotate_delete();
if (__is_long()) {
__alloc_traits::deallocate(__alloc(), __get_long_pointer(),
__get_long_cap());
@@ -2538,10 +2651,31 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
}
#endif
}
+ size_type __str_old_size = __str.size();
+ bool __str_was_short = !__str.__is_long();
+
__move_assign_alloc(__str);
__r_.first() = __str.__r_.first();
__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
@@ -2587,6 +2721,7 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _
_LIBCPP_ASSERT_INTERNAL(
__string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial");
+ size_type __old_size = size();
size_type __cap = capacity();
if (__cap < __n) {
// Unlike `append` functions, if the input range points into the string itself, there is no case that the input
@@ -2597,12 +2732,17 @@ basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _
// object itself stays valid even if reallocation happens.
size_type __sz = size();
__grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz);
+ __annotate_increase(__n);
}
+ else if (__n > __old_size)
+ __annotate_increase(__n - __old_size);
pointer __p = __get_pointer();
for (; __first != __last; ++__p, (void) ++__first)
traits_type::assign(*__p, *__first);
traits_type::assign(*__p, value_type());
__set_size(__n);
+ if (__n < __old_size)
+ __annotate_shrink(__old_size);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -2663,6 +2803,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_ty
{
if (__n)
{
+ __annotate_increase(__n);
value_type* __p = std::__to_address(__get_pointer());
traits_type::copy(__p + __sz, __s, __n);
__sz += __n;
@@ -2686,6 +2827,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c)
size_type __sz = size();
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer();
traits_type::assign(std::__to_address(__p) + __sz, __n, __c);
__sz += __n;
@@ -2705,6 +2847,7 @@ basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n)
size_type __sz = size();
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer();
__sz += __n;
__set_size(__sz);
@@ -2733,8 +2876,10 @@ basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
if (__sz == __cap)
{
__grow_by_without_replace(__cap, 1, __sz, __sz, 0);
+ __annotate_increase(1);
__is_short = false; // the string is always long after __grow_by
- }
+ } else
+ __annotate_increase(1);
pointer __p = __get_pointer();
if (__is_short)
{
@@ -2766,6 +2911,7 @@ basic_string<_CharT, _Traits, _Allocator>::append(
{
if (__cap - __sz < __n)
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
+ __annotate_increase(__n);
pointer __p = __get_pointer() + __sz;
for (; __first != __last; ++__p, (void) ++__first)
traits_type::assign(*__p, *__first);
@@ -2831,6 +2977,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_t
{
if (__n)
{
+ __annotate_increase(__n);
value_type* __p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
@@ -2864,6 +3011,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n
value_type* __p;
if (__cap - __sz >= __n)
{
+ __annotate_increase(__n);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __pos;
if (__n_move != 0)
@@ -2972,6 +3120,7 @@ basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, value_ty
}
else
{
+ __annotate_increase(1);
__p = std::__to_address(__get_pointer());
size_type __n_move = __sz - __ip;
if (__n_move != 0)
@@ -3002,6 +3151,8 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
value_type* __p = std::__to_address(__get_pointer());
if (__n1 != __n2)
{
+ if (__n2 > __n1)
+ __annotate_increase(__n2 - __n1);
size_type __n_move = __sz - __pos - __n1;
if (__n_move != 0)
{
@@ -3046,20 +3197,18 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __
__n1 = std::min(__n1, __sz - __pos);
size_type __cap = capacity();
value_type* __p;
- if (__cap - __sz + __n1 >= __n2)
- {
- __p = std::__to_address(__get_pointer());
- if (__n1 != __n2)
- {
- size_type __n_move = __sz - __pos - __n1;
- if (__n_move != 0)
- traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move);
- }
- }
- else
- {
- __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2);
- __p = std::__to_address(__get_long_pointer());
+ if (__cap - __sz + __n1 >= __n2) {
+ __p = std::__to_address(__get_pointer());
+ if (__n1 != __n2) {
+ if (__n2 > __n1)
+ __annotate_increase(__n2 - __n1);
+ size_type __n_move = __sz - __pos - __n1;
+ if (__n_move != 0)
+ traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move);
+ }
+ } else {
+ __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2);
+ __p = std::__to_address(__get_long_pointer());
}
traits_type::assign(__p + __pos, __n2, __c);
return __null_terminate_at(__p, __sz - (__n1 - __n2));
@@ -3187,6 +3336,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT
{
+ size_type __old_size = size();
if (__is_long())
{
traits_type::assign(*__get_long_pointer(), value_type());
@@ -3197,6 +3347,7 @@ basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT
traits_type::assign(*__get_short_pointer(), value_type());
__set_short_size(0);
}
+ __annotate_shrink(__old_size);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -3259,6 +3410,7 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity)
{
+ __annotate_delete();
size_type __cap = capacity();
size_type __sz = size();
@@ -3315,6 +3467,7 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
}
else
__set_short_size(__sz);
+ __annotate_new(__sz);
}
template <class _CharT, class _Traits, class _Allocator>
@@ -3365,8 +3518,16 @@ basic_string<_CharT, _Traits, _Allocator>::swap(basic_string& __str)
__alloc_traits::propagate_on_container_swap::value ||
__alloc_traits::is_always_equal::value ||
__alloc() == __str.__alloc(), "swapping non-equal allocators");
+ if (!__is_long())
+ __annotate_delete();
+ if (this != &__str && !__str.__is_long())
+ __str.__annotate_delete();
std::swap(__r_.first(), __str.__r_.first());
std::__swap_allocator(__alloc(), __str.__alloc());
+ if (!__is_long())
+ __annotate_new(__get_short_size());
+ if (this != &__str && !__str.__is_long())
+ __str.__annotate_new(__str.__get_short_size());
}
// find
@@ -3854,12 +4015,12 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
basic_string<_CharT, _Traits, _Allocator>::__clear_and_shrink() _NOEXCEPT
{
- clear();
- if(__is_long())
- {
- __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
- __r_.first() = __rep();
- }
+ clear();
+ if (__is_long()) {
+ __annotate_delete();
+ __alloc_traits::deallocate(__alloc(), __get_long_pointer(), capacity() + 1);
+ __r_.first() = __rep();
+ }
}
// operator==
@@ -4110,6 +4271,7 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
_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;
}
@@ -4124,10 +4286,12 @@ operator+(const _CharT* __lhs , const basic_string<_CharT,_Traits,_Allocator>& _
_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;
}
@@ -4141,10 +4305,12 @@ operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Allocator>& __rhs)
_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;
}
@@ -4159,10 +4325,12 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT*
_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;
}
@@ -4176,10 +4344,12 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, _CharT __rhs)
_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
index e1d20662e41de..61867cfb087b9 100644
--- 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"
@@ -28,6 +29,7 @@ TEST_CONSTEXPR_CXX20 void test_invariant(S s, test_allocator_statistics& alloc_s
while (s.size() < s.capacity())
s.push_back(typename S::value_type());
assert(s.size() == s.capacity());
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
catch (...) {
@@ -43,10 +45,12 @@ TEST_CONSTEXPR_CXX20 void test_string(const Alloc& a) {
{
S const s((Alloc(a)));
assert(s.capacity() >= 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
{
S const s(3, 'x', Alloc(a));
assert(s.capacity() >= 3);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#if TEST_STD_VER >= 11
// Check that we perform SSO
@@ -54,6 +58,7 @@ TEST_CONSTEXPR_CXX20 void test_string(const Alloc& a) {
S const s;
assert(s.capacity() > 0);
ASSERT_NOEXCEPT(s.capacity());
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#endif
}
@@ -63,18 +68,22 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>());
test_string(test_allocator<char>(3));
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
{
test_allocator_statistics alloc_stats;
typedef std::basic_string<char, std::char_traits<char>, test_allocator<char> > S;
S s((test_allocator<char>(&alloc_stats)));
test_invariant(s, alloc_stats);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
s.assign(10, 'a');
s.erase(5);
test_invariant(s, alloc_stats);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
s.assign(100, 'a');
s.erase(50);
test_invariant(s, alloc_stats);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
return true;
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
index 3a308de9b7569..7fa5cd43b80af 100644
--- 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,31 +15,38 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s) {
s.clear();
assert(s.size() == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
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<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index ecde912dc39f4..009be101c0f9e 100644
--- 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 <class S>
void test(typename S::size_type min_cap, typename S::size_type erased_index) {
@@ -33,6 +34,7 @@ void test(typename S::size_type min_cap, typename S::size_type erased_index) {
assert(s == s0);
assert(s.capacity() <= old_cap);
assert(s.capacity() >= s.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -46,6 +48,7 @@ bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 0000000000000..7b9f7442ff4e2
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.capacity/reserve_size.asan.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <string>
+
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+#include "asan_testing.h"
+
+template <class S>
+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**) {
+ test<std::string>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<std::wstring>();
+#endif
+#if TEST_STD_VER >= 11
+ test<std::u16string>();
+ test<std::u32string>();
+#endif
+#if TEST_STD_VER >= 20
+ test<std::u8string>();
+#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
index bb804bf328b3b..5790a3a1754cd 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -28,6 +29,7 @@ test(typename S::size_type min_cap, typename S::size_type erased_index, typename
s.erase(erased_index);
assert(s.size() == erased_index);
assert(s.capacity() >= min_cap); // Check that we really have at least this capacity.
+ LIBCPP_ASSERT(is_string_asan_correct(s));
#if TEST_STD_VER > 17
typename S::size_type old_cap = s.capacity();
@@ -39,6 +41,7 @@ test(typename S::size_type min_cap, typename S::size_type erased_index, typename
assert(s == s0);
assert(s.capacity() >= res_arg);
assert(s.capacity() >= s.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s));
#if TEST_STD_VER > 17
assert(s.capacity() >= old_cap); // reserve never shrinks as of P0966 (C++20)
#endif
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
index bbe6551a0ff11..00f5cccd30d6b 100644
--- 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 <class S>
constexpr void test_appending(std::size_t k, size_t N, size_t new_capacity) {
@@ -76,11 +77,14 @@ constexpr bool test() {
void test_value_categories() {
std::string s;
s.resize_and_overwrite(10, [](char*&&, std::size_t&&) { return 0; });
+ LIBCPP_ASSERT(is_string_asan_correct(s));
s.resize_and_overwrite(10, [](char* const&, const std::size_t&) { return 0; });
+ LIBCPP_ASSERT(is_string_asan_correct(s));
struct RefQualified {
int operator()(char*, std::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
index 487b12d9df87f..7cf4b7ca3b6ef 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) {
@@ -23,6 +24,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, S expected) {
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) {
@@ -61,6 +63,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 3b6adc0b0afeb..e3b925ca8bcdb 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_type c, S expected) {
@@ -23,6 +24,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_t
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) {
@@ -57,12 +59,23 @@ TEST_CONSTEXPR_CXX20 void test_string() {
'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() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 1efebfc9cea56..57f6b49eaf994 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s) {
assert(s == s0);
assert(s.capacity() <= old_cap);
assert(s.capacity() >= s.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -39,12 +41,18 @@ TEST_CONSTEXPR_CXX20 void test_string() {
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<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index a6b625b7b0e81..dcf697bed752f 100644
--- 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 <class S, class SV>
TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) {
@@ -38,6 +39,7 @@ TEST_CONSTEXPR_CXX20 void test(SV sv, std::size_t pos, std::size_t n) {
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) {
@@ -113,6 +115,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(8));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
#endif
{
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
index 97a0566ba031b..91beac37764db 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test() {
@@ -31,6 +32,7 @@ TEST_CONSTEXPR_CXX20 void test() {
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 @@ TEST_CONSTEXPR_CXX20 void test() {
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));
}
}
@@ -65,6 +68,7 @@ TEST_CONSTEXPR_CXX20 void test2() {
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 @@ TEST_CONSTEXPR_CXX20 void test2() {
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_CONSTEXPR_CXX20 bool test() {
test<std::basic_string<char, std::char_traits<char>, test_allocator<char> > >();
#if TEST_STD_VER >= 11
test2<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test2<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
test2<std::basic_string<char, std::char_traits<char>, explicit_allocator<char> > >();
#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
index e7d18b4ca8717..6b3a665ced447 100644
--- 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 <cassert>
#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 @@ TEST_CONSTEXPR_CXX20 bool test() {
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
index 3cffc82e94835..1019dc8bca5df 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, typename S::value_type s2) {
@@ -24,6 +25,7 @@ TEST_CONSTEXPR_CXX20 void test(S s1, typename S::value_type s2) {
assert(s1.size() == 1);
assert(T::eq(s1[0], s2));
assert(s1.capacity() >= s1.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
template <class S>
@@ -38,6 +40,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 3afe76e88316f..f65f8e97c9824 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1) {
@@ -24,6 +25,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1) {
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));
}
template <class Alloc>
@@ -40,6 +43,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(3));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
#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
index 6b0040376a424..b0045cb4afbba 100644
--- 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 {
@@ -83,6 +84,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, const typename S::allocator_type& a) {
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));
}
template <class Alloc>
@@ -99,6 +102,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(3));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
#endif
#if TEST_STD_VER >= 11
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
index 8d0fcb3c6d294..8d993829f6add 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, const S& s2) {
@@ -23,6 +24,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, const S& s2) {
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 <class S>
@@ -46,6 +49,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
#if TEST_STD_VER >= 11
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
index 3993a40dd5a16..fc263f9820cb5 100644
--- 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
@@ -30,6 +31,7 @@ LIBCPP_STATIC_ASSERT(!std::is_nothrow_default_constructible<
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
index 5b7e8bde2e6e8..e326a71dc7a46 100644
--- 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,6 +18,7 @@
#include "test_macros.h"
#include "test_allocator.h"
#include "min_allocator.h"
+#include "asan_testing.h"
// clang-format off
template <template <class> class Alloc>
@@ -25,11 +26,19 @@ TEST_CONSTEXPR_CXX20 void test_string() {
{
std::basic_string<char, std::char_traits<char>, Alloc<char> > s = {'a', 'b', 'c'};
assert(s == "abc");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
+ {
+ std::basic_string<char, std::char_traits<char>, Alloc<char> > s;
+ s = {'a', 'b', 'c'};
+ assert(s == "abc");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
std::basic_string<wchar_t, std::char_traits<wchar_t>, Alloc<wchar_t> > s = {L'a', L'b', L'c'};
assert(s == L"abc");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#endif
}
@@ -38,6 +47,7 @@ TEST_CONSTEXPR_CXX20 void test_string() {
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::allocator>();
test_string<min_allocator>();
+ test_string<safe_allocator>();
return true;
}
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
index 88597daba121a..90be1cc58857b 100644
--- 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,6 +17,7 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
// clang-format off
template <template <class> class Alloc>
@@ -27,6 +28,16 @@ TEST_CONSTEXPR_CXX20 void test_string() {
S& result = (s = {'a', 'b', 'c'});
assert(s == "abc");
assert(&result == &s);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ LIBCPP_ASSERT(is_string_asan_correct(result));
+ }
+ {
+ typedef std::basic_string<char, std::char_traits<char>, Alloc<char>> 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));
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
@@ -35,6 +46,8 @@ TEST_CONSTEXPR_CXX20 void test_string() {
S& result = (s = {L'a', L'b', L'c'});
assert(s == L"abc");
assert(&result == &s);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ LIBCPP_ASSERT(is_string_asan_correct(result));
}
#endif
}
@@ -43,6 +56,7 @@ TEST_CONSTEXPR_CXX20 void test_string() {
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::allocator>();
test_string<min_allocator>();
+ test_string<safe_allocator>();
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
index 2ef73e5ec8c1a..e14227d1a7717 100644
--- 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
@@ -21,6 +21,7 @@
#include "test_allocator.h"
#include "test_iterators.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class Alloc, class It>
TEST_CONSTEXPR_CXX20 void test(It first, It last) {
@@ -37,6 +38,7 @@ TEST_CONSTEXPR_CXX20 void test(It first, It last) {
}
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc, class It>
@@ -54,6 +56,7 @@ TEST_CONSTEXPR_CXX20 void test(It first, It last, const Alloc& a) {
}
assert(s2.get_allocator() == a);
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc>
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
index 65762ccf89d93..d9176da63d0dc 100644
--- 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<std::basic_string<char16_t>>;
@@ -66,6 +67,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(std::is_same_v<S::allocator_type, std::allocator<char>>, "");
assert(s1.size() == 10);
assert(s1.compare(0, s1.size(), s, s1.size()) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
{
const char* s = "12345678901234";
@@ -76,6 +78,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(std::is_same_v<S::allocator_type, std::allocator<char>>, "");
assert(s1.size() == 10);
assert(s1.compare(0, s1.size(), s, s1.size()) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
@@ -87,6 +90,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(std::is_same_v<S::allocator_type, test_allocator<wchar_t>>, "");
assert(s1.size() == 10);
assert(s1.compare(0, s1.size(), s, s1.size()) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
#endif
{
@@ -98,6 +102,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(std::is_same_v<S::allocator_type, min_allocator<char16_t>>, "");
assert(s1.size() == 10);
assert(s1.compare(0, s1.size(), s, s1.size()) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
{
const char32_t* s = U"12345678901234";
@@ -108,6 +113,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
static_assert(std::is_same_v<S::allocator_type, explicit_allocator<char32_t>>, "");
assert(s1.size() == 10);
assert(s1.compare(0, s1.size(), s, s1.size()) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s1));
}
return true;
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
index f5ffebd35d50e..5d2d774b36063 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s0) {
@@ -28,6 +29,9 @@ TEST_CONSTEXPR_CXX20 void test(S s0) {
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));
}
template <class Alloc>
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
index 0e5c72192adea..7210d67b5cb22 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s0, const typename S::allocator_type& a) {
@@ -28,6 +29,9 @@ TEST_CONSTEXPR_CXX20 void test(S s0, const typename S::allocator_type& a) {
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
index 89cb44d62ef2b..3e42dfcb23d43 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
@@ -28,6 +29,9 @@ TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
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 <class S>
@@ -51,6 +55,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 84a29df5b57bf..d5d5152e11e54 100644
--- 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 <class Alloc, class charT>
TEST_CONSTEXPR_CXX20 void test(const charT* s) {
@@ -31,6 +32,7 @@ TEST_CONSTEXPR_CXX20 void test(const charT* s) {
assert(T::compare(s2.data(), s, n) == 0);
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc, class charT>
@@ -44,6 +46,7 @@ TEST_CONSTEXPR_CXX20 void test(const charT* s, const Alloc& a) {
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 <class Alloc>
@@ -67,6 +70,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test(test_allocator<char>(2));
#if TEST_STD_VER >= 11
test(min_allocator<char>());
+ test(safe_allocator<char>());
#endif
return true;
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
index 4b3027a2aad11..d463763223c90 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, const typename S::value_type* s2) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s1, const typename S::value_type* s2) {
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 <class S>
@@ -48,6 +50,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index e0dab72b5c632..b6ba2be46d18b 100644
--- 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 <class Alloc, class CharT>
TEST_CONSTEXPR_CXX20 void test(const CharT* s, unsigned n) {
@@ -29,6 +30,7 @@ TEST_CONSTEXPR_CXX20 void test(const CharT* s, unsigned n) {
assert(T::compare(s2.data(), s, n) == 0);
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc, class CharT>
@@ -41,6 +43,7 @@ TEST_CONSTEXPR_CXX20 void test(const CharT* s, unsigned n, const Alloc& a) {
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 <class Alloc>
@@ -64,6 +67,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test(test_allocator<char>(2));
#if TEST_STD_VER >= 11
test(min_allocator<char>());
+ test(safe_allocator<char>());
#endif
#if TEST_STD_VER >= 11
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
index 3afbcdffa6bdf..a87e01f0fc088 100644
--- 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 <class Alloc, class charT>
TEST_CONSTEXPR_CXX20 void test(unsigned n, charT c) {
@@ -30,6 +31,7 @@ TEST_CONSTEXPR_CXX20 void test(unsigned n, charT c) {
assert(s2[i] == c);
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc, class charT>
@@ -42,6 +44,7 @@ TEST_CONSTEXPR_CXX20 void test(unsigned n, charT c, const Alloc& a) {
assert(s2[i] == c);
assert(s2.get_allocator() == a);
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
template <class Alloc, class Tp>
@@ -94,6 +97,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(2));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
#endif
return true;
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
index 74fa76a013a69..ad37b50b83ba7 100644
--- 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<std::string_view, std::string const&>::value, "");
static_assert(!std::is_convertible<std::string_view, std::string>::value, "");
@@ -35,6 +36,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv) {
assert(T::compare(s2.data(), sv.data(), sv.size()) == 0);
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
{
S s2;
@@ -44,6 +46,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv) {
assert(T::compare(s2.data(), sv.data(), sv.size()) == 0);
assert(s2.get_allocator() == Alloc());
assert(s2.capacity() >= s2.size());
+ LIBCPP_ASSERT(is_string_asan_correct(s2));
}
}
@@ -58,6 +61,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv, const Alloc& a)
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);
@@ -67,6 +71,7 @@ TEST_CONSTEXPR_CXX20 void test(std::basic_string_view<CharT> sv, const Alloc& a)
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));
}
}
@@ -93,6 +98,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(2));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>());
+ test_string(safe_allocator<char>());
#endif
return true;
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
index 3c88f9e40fc0b..31d2c231e4cb8 100644
--- 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 <class S, class SV>
TEST_CONSTEXPR_CXX20 void test(S s1, SV sv) {
@@ -24,6 +25,7 @@ TEST_CONSTEXPR_CXX20 void test(S s1, SV sv) {
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 <class S>
@@ -48,6 +50,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 693edab76b17b..cafd9674f4898 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos) {
@@ -40,6 +41,7 @@ TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos) {
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) {
@@ -65,6 +67,7 @@ TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos, unsigned n) {
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) {
@@ -90,6 +93,7 @@ TEST_CONSTEXPR_CXX20 void test(S str, unsigned pos, unsigned n, const typename S
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) {
@@ -164,6 +168,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string(test_allocator<char>(3), test_allocator<char>(5));
#if TEST_STD_VER >= 11
test_string(min_allocator<char>(), min_allocator<char>());
+ test_string(safe_allocator<char>(), safe_allocator<char>());
#endif
return true;
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
index 6c5049f16bc61..f1f5828bfe21d 100644
--- 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,6 +18,7 @@
#include "test_macros.h"
#include "min_allocator.h"
#include "nasty_string.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test() {
@@ -26,6 +27,7 @@ TEST_CONSTEXPR_CXX20 void test() {
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 +42,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test<std::u32string>();
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#ifndef TEST_HAS_NO_NASTY_STRING
test<nasty_string>();
#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
index 2982cfe77042c..684661aeab8fc 100644
--- 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,12 +17,14 @@
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S, class It>
TEST_CONSTEXPR_CXX20 void test(S s, It first, It last, S expected) {
s.append(first, last);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -225,6 +227,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index 68f5838ccf2f0..af334eb080c37 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, const typename S::value_type* str, S expected) {
s.append(str);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -43,6 +45,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{ // test appending to self
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
index b98c91cf097b1..93e7500a11967 100644
--- 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,12 +17,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, const typename S::value_type* str, typename S::size_type n, S expected) {
s.append(str, n);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -48,6 +50,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{ // test appending to self
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
index 0b8e5f65c15e9..30a38781bd47e 100644
--- 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;
@@ -61,6 +62,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::value_type c, S expected) {
s.push_back(c);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -74,6 +76,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
{
// https://llvm.org/PR31454
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
index eb0728456df5b..0d0318fc6955f 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_type c, S expected) {
s.append(n, c);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -44,6 +46,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 21f2ff53004d1..79bdb0c04b32f 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, S str, S expected) {
s.append(str);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -51,6 +53,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
#if TEST_STD_VER >= 11
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
index 902d29c53ac69..96ddc53917075 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, S str, typename S::size_type pos, typename S::size_type n, S expected) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, S str, typename S::size_type pos, typename S
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) {
@@ -85,6 +87,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{
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
index a2a954cb94aac..b35f6b9497d03 100644
--- 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 <class S, class SV>
TEST_CONSTEXPR_CXX20 void test(S s, SV sv, typename S::size_type pos, typename S::size_type n, S expected) {
@@ -24,6 +25,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, SV sv, typename S::size_type pos, typename S
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) {
@@ -85,6 +87,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{
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
index ba55f30785e94..484ad723e7c7e 100644
--- 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"
template <class S>
TEST_CONSTEXPR_CXX20 void test_string() {
S s("123");
s.assign({'a', 'b', 'c'});
assert(s == "abc");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
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
index b2ca4fb5ddd93..c183def9ee75f 100644
--- 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,12 +17,14 @@
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S, class It>
TEST_CONSTEXPR_CXX20 void test(S s, It first, It last, S expected) {
s.assign(first, last);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -171,6 +173,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index 11e12c318a2e8..0619c91d59e25 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, const typename S::value_type* str, S expected) {
s.assign(str);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -43,6 +45,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{ // test assignment to self
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
index 2738a9a6ffad5..3fed2c7ee9ba6 100644
--- 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,12 +17,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, const typename S::value_type* str, typename S::size_type n, S expected) {
s.assign(str, n);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -48,6 +50,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{ // test assign to self
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
index b52c66103395f..3c7651135f1aa 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type n, typename S::value_type c, S expected) {
s.assign(n, c);
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -44,6 +46,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index f39b7f66c4b18..8b310630bf07a 100644
--- 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 <class S>
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 <class S>
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
index 9448452bafad9..1cd2368b2a6b3 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, S str, typename S::size_type pos, typename S::size_type n, S expected) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, S str, typename S::size_type pos, typename S
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) {
@@ -85,6 +87,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{
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
index e1904baeb9033..bf9eefb90c1ff 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S str, typename S::value_type* s, typename S::size_type n, typename S::size_type pos) {
@@ -25,6 +26,9 @@ TEST_CONSTEXPR_CXX20 void test(S str, typename S::value_type* s, typename S::siz
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]));
}
@@ -108,6 +112,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 03c5b965537c6..b724973150296 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, S expected) {
@@ -24,6 +25,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, S expected)
assert(s[s.size()] == typename S::value_type());
assert(s == expected);
assert(i - s.begin() == pos);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -46,6 +48,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index f092ad718cdaa..5270335aa9ff3 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, typename S::difference_type n, S expected) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, typename S:
assert(s[s.size()] == typename S::value_type());
assert(s == expected);
assert(i - s.begin() == pos);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -89,6 +91,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 0000000000000..a115d6b1a5e15
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <string>
+
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+#include "asan_testing.h"
+
+template <class CharT>
+void test(const CharT val) {
+ using S = std::basic_string<CharT>;
+
+ 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**) {
+ test<char>('x');
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>(L'x');
+#endif
+#if TEST_STD_VER >= 11
+ test<char16_t>(u'x');
+ test<char32_t>(U'x');
+#endif
+#if TEST_STD_VER >= 20
+ test<char8_t>(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
index 9c63fa47a7e4a..7fc715f9d21da 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, S expected) {
@@ -22,6 +23,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, S expected) {
LIBCPP_ASSERT(s.__invariants());
assert(s[s.size()] == typename S::value_type());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -35,6 +37,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 610256061a5f2..97acffd484e64 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, typename S::size_type n, S expected) {
@@ -27,6 +28,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, typename S::size_
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) {
@@ -180,6 +182,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index bc3ce511ab5c2..f13e0ee37d265 100644
--- 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,9 +16,11 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
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);
@@ -28,6 +30,7 @@ TEST_CONSTEXPR_CXX20 void test(S& s, typename S::const_iterator p, typename S::v
assert(*i == c);
if (sufficient_cap)
assert(i == p);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -53,6 +56,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 876cc9ecd14c6..52594ab7ece53 100644
--- 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
@@ -17,6 +17,7 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test_string() {
@@ -24,11 +25,13 @@ TEST_CONSTEXPR_CXX20 void test_string() {
typename S::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));
}
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
return true;
}
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
index e3d0f1322e85d..060216e7a82b3 100644
--- 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 <class S, class It>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, It first, It last, S expected) {
@@ -25,6 +26,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::difference_type pos, It first, I
LIBCPP_ASSERT(s.__invariants());
assert(i - s.begin() == pos);
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -147,6 +149,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
#endif
#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
index 1e0d16e4cc2e1..6937ccc0d540a 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -24,6 +25,7 @@ test(S s, typename S::difference_type pos, typename S::size_type n, typename S::
LIBCPP_ASSERT(s.__invariants());
assert(i - s.begin() == pos);
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -98,6 +100,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 359fd999598f8..9e2d00279b96d 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, const typename S::value_type* str, S expected) {
@@ -26,6 +27,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, const typename S:
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) {
@@ -128,6 +130,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
{ // test inserting into self
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
index 44f20ff63cc0c..3e581b56a6390 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -27,6 +28,7 @@ test(S s, typename S::size_type pos, const typename S::value_type* str, typename
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) {
@@ -388,6 +390,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
#if TEST_STD_VER > 17
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
index 2396b7e2f54df..f18ef484b5a04 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -27,6 +28,7 @@ test(S s, typename S::size_type pos, typename S::size_type n, typename S::value_
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) {
@@ -129,6 +131,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index 1b908ac464c31..49870ba05e357 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, S str, S expected) {
@@ -26,6 +27,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos, S str, S expected
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) {
@@ -128,6 +130,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
#if TEST_STD_VER >= 11
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
index 1a8f6b35b42c4..2c0579485d0fb 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -29,6 +30,7 @@ test(S s, typename S::size_type pos1, S str, typename S::size_type pos2, typenam
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) {
@@ -1816,6 +1818,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return 0;
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
index 1e03d8c1b6147..a3a23d1ce7716 100644
--- 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,12 +15,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::value_type str, S expected) {
s += str;
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -35,6 +37,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index e7334b96276a5..6e631ab264b47 100644
--- 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,17 +17,20 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test_string() {
S s("123");
s += {'a', 'b', 'c'};
assert(s == "123abc");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
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
index 2d8c535b354c2..32de8bfcc3156 100644
--- 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,12 +15,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, const typename S::value_type* str, S expected) {
s += str;
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -50,6 +52,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index e02ced737ae16..20f0e257663e6 100644
--- 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,12 +16,14 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(S s, S str, S expected) {
s += str;
LIBCPP_ASSERT(s.__invariants());
assert(s == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -51,11 +53,13 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
{ // LWG 2946
std::string s;
s += {"abc", 1};
assert(s.size() == 1);
assert(s == "a");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
#endif
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
index 35db1d6368191..eb0c62a66504c 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size_type n1, S str, S expected) {
@@ -29,6 +30,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size
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 <class S>
@@ -292,6 +294,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 004a519262853..df08ae675a11e 100644
--- 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
@@ -23,6 +23,7 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S, class SV>
TEST_CONSTEXPR_CXX20 void
@@ -49,6 +50,7 @@ test(S s,
SizeT xlen = std::min<SizeT>(n1, old_size - pos1);
SizeT rlen = std::min<SizeT>(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) {
@@ -6279,6 +6281,7 @@ int main(int, char**) {
test<char, std::allocator>();
#if TEST_STD_VER >= 11
test<char, min_allocator>();
+ test<char, safe_allocator>();
#endif
return 0;
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
index a7282615e4855..aefe3ced9765e 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -31,6 +32,7 @@ test(S s, typename S::size_type pos, typename S::size_type n1, const typename S:
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) {
@@ -377,6 +379,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 7ef63bdf313dd..cb01c34e43d4a 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -36,6 +37,7 @@ test(S s,
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) {
@@ -1341,6 +1343,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#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
index 8841318c1d4df..67e9316794225 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void
@@ -36,6 +37,7 @@ test(S s,
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) {
@@ -381,6 +383,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return 0;
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
index fab2beeabd572..47fe7030c83b3 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size_type n1, S str, S expected) {
@@ -30,6 +31,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size
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) {
@@ -385,6 +387,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return 0;
}
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
index 073de60289857..48645f6280990 100644
--- 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
@@ -22,6 +22,7 @@
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void
@@ -41,6 +42,7 @@ test(S s,
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) {
@@ -6099,6 +6101,7 @@ int main(int, char**) {
test<std::string>();
#if TEST_STD_VER >= 11
test<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return 0;
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
index cec8cc0c52dd9..7f17160419065 100644
--- 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 <class S, class SV>
TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size_type n1, SV sv, S expected) {
@@ -30,6 +31,7 @@ TEST_CONSTEXPR_CXX20 void test(S s, typename S::size_type pos1, typename S::size
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) {
@@ -376,6 +378,7 @@ int main(int, char**) {
test<char, std::allocator>();
#if TEST_STD_VER >= 11
test<char, min_allocator>();
+ test<char, safe_allocator>();
#endif
return 0;
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp
new file mode 100644
index 0000000000000..ded4c56d34e48
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_swap/swap.asan.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <string>
+
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+#include "asan_testing.h"
+
+template <class CharT>
+void test(const CharT val) {
+ using S = std::basic_string<CharT>;
+
+ 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**) {
+ test<char>('x');
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>(L'x');
+#endif
+#if TEST_STD_VER >= 11
+ test<char16_t>(u'x');
+ test<char32_t>(U'x');
+#endif
+#if TEST_STD_VER >= 20
+ test<char8_t>(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
index 3d9ec016bcfbd..46f19bb51885d 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
@@ -27,6 +28,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
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 <class S>
@@ -53,6 +56,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
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
index da6fc11c14329..0d637df40662b 100644
--- 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 <class S>
TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
@@ -29,6 +30,8 @@ TEST_CONSTEXPR_CXX20 void test(S s1, S s2) {
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 <class S>
@@ -55,6 +58,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index 82a591e053362..2ca5788e6d8a3 100644
--- 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 <class S>
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
@@ -53,6 +55,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index 66cbac28f9f2c..9c0fb56e1f1c9 100644
--- 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 <class S>
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
@@ -55,6 +57,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index 2802189f843c5..3e1aaebf112eb 100644
--- 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 <class S>
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
@@ -77,6 +79,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
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
index f8ebb98767a83..fcc8ceab87071 100644
--- 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 <class S>
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
@@ -133,6 +135,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char> > >();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char> > >();
#endif
return true;
diff --git a/libcxx/test/support/asan_testing.h b/libcxx/test/support/asan_testing.h
index 5d044374044de..aaddff0879d6c 100644
--- a/libcxx/test/support/asan_testing.h
+++ b/libcxx/test/support/asan_testing.h
@@ -11,26 +11,25 @@
#include "test_macros.h"
#include <vector>
+#include <string>
+#include <memory>
+#include <type_traits>
#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 <typename T, typename Alloc>
-TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &c )
-{
- if (TEST_IS_CONSTANT_EVALUATED)
- return true;
- if (std::is_same<Alloc, std::allocator<T> >::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<T, Alloc>& c) {
+ if (TEST_IS_CONSTANT_EVALUATED)
return true;
+ if (std::is_same<Alloc, std::allocator<T> >::value && c.data() != NULL)
+ return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0;
+ return true;
}
#else
template <typename T, typename Alloc>
-TEST_CONSTEXPR bool is_contiguous_container_asan_correct ( const std::vector<T, Alloc> &)
-{
- return true;
+TEST_CONSTEXPR bool is_contiguous_container_asan_correct(const std::vector<T, Alloc>&) {
+ return true;
}
#endif // TEST_HAS_FEATURE(address_sanitizer)
@@ -56,4 +55,44 @@ TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std:
}
#endif
+#if TEST_HAS_FEATURE(address_sanitizer)
+template <typename S>
+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 <typename ChrT, typename TraitsT, typename Alloc>
+TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>& c) {
+ if (TEST_IS_CONSTANT_EVALUATED)
+ return true;
+ if (c.data() != NULL) {
+ if (!is_string_short(c) || _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED) {
+ if (std::is_same<Alloc, std::allocator<ChrT>>::value)
+ return __sanitizer_verify_contiguous_container(
+ c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) != 0;
+ else
+ return __sanitizer_verify_contiguous_container(
+ c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
+ } else {
+ return __sanitizer_verify_contiguous_container(std::addressof(c), std::addressof(c) + 1, std::addressof(c) + 1) !=
+ 0;
+ }
+ }
+ return true;
+}
+#else
+# include <string>
+template <typename ChrT, typename TraitsT, typename Alloc>
+TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>&) {
+ return true;
+}
+#endif // TEST_HAS_FEATURE(address_sanitizer)
#endif // ASAN_TESTING_H
>From 81d9af46b51a140a39660b410d089b7c8605c004 Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Tue, 5 Dec 2023 06:05:29 +0100
Subject: [PATCH 2/8] Refactor: remove duplicated code with
`[[__maybe_unused__]]`
This commit refactors the ASan annotation function to reduce unnecessary code duplication.
Suggested here: https://github.com/llvm/llvm-project/issues/73043
Related PR: https://github.com/llvm/llvm-project/pull/74023
---
libcxx/include/string | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index 93725c2acc619..ea4955674f374 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1898,18 +1898,15 @@ private:
{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 {
+ [[__maybe_unused__]] const void* __old_mid, [[__maybe_unused__]] const void* __new_mid) const {
+#ifndef _LIBCPP_HAS_NO_ASAN
const void* __begin = data();
const void* __end = data() + capacity() + 1;
if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same<allocator_type, __default_allocator_type>::value)
__sanitizer_annotate_contiguous_container(__begin, __end, __old_mid, __new_mid);
- }
-#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 __asan_short_string_is_annotated() const _NOEXCEPT {
>From 54baf85ea39075994fe42d1b0b4427661036083b Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Wed, 6 Dec 2023 03:55:02 +0100
Subject: [PATCH 3/8] Address code review feedback for existing code
Requested changes for existing code.
Additional changes related to dylibs in the next commit.
This commit extends a few more tests to cover long strings in more situations.
---
libcxx/include/string | 5 +-
.../reserve_size.asan.pass.cpp | 17 +++----
.../string.capacity/shrink_to_fit.pass.cpp | 4 +-
.../string.cons/brace_assignment.pass.cpp | 12 +++++
.../string.cons/initializer_list.pass.cpp | 6 ---
.../string_erase/pop_back.asan.pass.cpp | 50 -------------------
.../string_erase/pop_back.pass.cpp | 2 +
.../initializer_list.pass.cpp | 8 +++
.../string_swap/swap.asan.pass.cpp | 4 ++
.../string_swap/swap.pass.cpp | 5 ++
libcxx/test/support/asan_testing.h | 22 ++++----
11 files changed, 52 insertions(+), 83 deletions(-)
delete mode 100644 libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp
diff --git a/libcxx/include/string b/libcxx/include/string
index ea4955674f374..f0941e6b6b9fb 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -937,9 +937,8 @@ public:
_NOEXCEPT
# endif
// 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 only the short string case).
+ // does not work consistently during initialization of __r_, so we instead unpoison __str's memory manually first.
+ // __str's memory needs to be unpoisoned only in the case where it's a short string.
: __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) {
__str.__r_.first() = __rep();
}
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
index 7b9f7442ff4e2..d35a5bcefc46a 100644
--- 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
@@ -8,6 +8,9 @@
// <string>
+// This test verifies that the ASan annotations for basic_string objects remain accurate
+// after invoking basic_string::reserve(size_type __requested_capacity).
+// Different types are used to confirm that ASan works correctly with types of different sizes.
#include <string>
#include <cassert>
@@ -22,25 +25,19 @@ void test() {
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();
+
+ short_s1.reserve(0x1);
+ long_s1.reserve(0x1);
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);
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
index 57f6b49eaf994..293e8cb967f38 100644
--- 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
@@ -43,8 +43,8 @@ TEST_CONSTEXPR_CXX20 void test_string() {
test(s);
s.assign(100, 'a');
- for (int i = 0; i < 90; ++i)
- s.erase(1);
+ for (int i = 0; i <= 90; ++i)
+ s.erase(91 - 2 * (i / 2));
test(s);
}
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
index 6b3a665ced447..6773aa1c28d0a 100644
--- 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
@@ -34,6 +34,18 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(s == "ab");
LIBCPP_ASSERT(is_string_asan_correct(s));
}
+ {
+ std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!";
+ s = {"abc", 2};
+ assert(s == "ab");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
+ {
+ std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!";
+ s = {"abc", 0};
+ assert(s == "");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
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
index e326a71dc7a46..a8b57b32e3629 100644
--- 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
@@ -28,12 +28,6 @@ TEST_CONSTEXPR_CXX20 void test_string() {
assert(s == "abc");
LIBCPP_ASSERT(is_string_asan_correct(s));
}
- {
- std::basic_string<char, std::char_traits<char>, Alloc<char> > s;
- s = {'a', 'b', 'c'};
- assert(s == "abc");
- LIBCPP_ASSERT(is_string_asan_correct(s));
- }
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
std::basic_string<wchar_t, std::char_traits<wchar_t>, Alloc<wchar_t> > s = {L'a', L'b', L'c'};
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
deleted file mode 100644
index a115d6b1a5e15..0000000000000
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_erase/pop_back.asan.pass.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// <string>
-
-#include <string>
-#include <cassert>
-
-#include "test_macros.h"
-#include "asan_testing.h"
-
-template <class CharT>
-void test(const CharT val) {
- using S = std::basic_string<CharT>;
-
- 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**) {
- test<char>('x');
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- test<wchar_t>(L'x');
-#endif
-#if TEST_STD_VER >= 11
- test<char16_t>(u'x');
- test<char32_t>(U'x');
-#endif
-#if TEST_STD_VER >= 20
- test<char8_t>(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
index 7fc715f9d21da..f52512231e094 100644
--- 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
@@ -31,6 +31,8 @@ TEST_CONSTEXPR_CXX20 void test_string() {
test(S("abcde"), S("abcd"));
test(S("abcdefghij"), S("abcdefghi"));
test(S("abcdefghijklmnopqrst"), S("abcdefghijklmnopqrs"));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrstabcdefghijklmnopqrstabcdefghijklmnopqrst"),
+ S("abcdefghijklmnopqrstabcdefghijklmnopqrstabcdefghijklmnopqrstabcdefghijklmnopqrs"));
}
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
index 6e631ab264b47..a853a255dab36 100644
--- 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
@@ -25,6 +25,14 @@ TEST_CONSTEXPR_CXX20 void test_string() {
s += {'a', 'b', 'c'};
assert(s == "123abc");
LIBCPP_ASSERT(is_string_asan_correct(s));
+
+ s += {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'};
+ assert(s == "123abcxxxxxxxxxxxxxxxx");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+
+ s += {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'};
+ assert(s == "123abcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
TEST_CONSTEXPR_CXX20 bool test() {
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
index ded4c56d34e48..a3466e76a5f5f 100644
--- 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
@@ -8,6 +8,10 @@
// <string>
+// This test validates that ASan annotations are correctly updated after swaps.
+// This test meticulously interchanges objects that store data both within their internal memory (Short
+// String Optimization) and in external buffers (non-SSO).
+
#include <string>
#include <cassert>
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
index 46f19bb51885d..16bdac1c4dcc6 100644
--- 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
@@ -50,6 +50,11 @@ TEST_CONSTEXPR_CXX20 void test_string() {
test(S("abcdefghijklmnopqrst"), S("12345"));
test(S("abcdefghijklmnopqrst"), S("1234567890"));
test(S("abcdefghijklmnopqrst"), S("12345678901234567890"));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrst"), S(""));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrst"), S("12345"));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrst"), S("1234567890"));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrst"), S("12345678901234567890"));
+ test(S("abcdefghijklmnopqrstabcdefghijklmnopqrst"), S("12345678901234567890abcdefghijklmnopqrst"));
}
TEST_CONSTEXPR_CXX20 bool test() {
diff --git a/libcxx/test/support/asan_testing.h b/libcxx/test/support/asan_testing.h
index aaddff0879d6c..2dfec5c42b00b 100644
--- a/libcxx/test/support/asan_testing.h
+++ b/libcxx/test/support/asan_testing.h
@@ -73,20 +73,18 @@ template <typename ChrT, typename TraitsT, typename Alloc>
TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>& c) {
if (TEST_IS_CONSTANT_EVALUATED)
return true;
- if (c.data() != NULL) {
- if (!is_string_short(c) || _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED) {
- if (std::is_same<Alloc, std::allocator<ChrT>>::value)
- return __sanitizer_verify_contiguous_container(
- c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) != 0;
- else
- return __sanitizer_verify_contiguous_container(
- c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
- } else {
- return __sanitizer_verify_contiguous_container(std::addressof(c), std::addressof(c) + 1, std::addressof(c) + 1) !=
+
+ if (!is_string_short(c) || _LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED) {
+ if (std::is_same<Alloc, std::allocator<ChrT>>::value)
+ return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) !=
0;
- }
+ else
+ return __sanitizer_verify_contiguous_container(
+ c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
+ } else {
+ return __sanitizer_verify_contiguous_container(std::addressof(c), std::addressof(c) + 1, std::addressof(c) + 1) !=
+ 0;
}
- return true;
}
#else
# include <string>
>From 7250595613d2177c83f5a80b390ab33a4a4f6c8b Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Wed, 6 Dec 2023 09:07:34 +0100
Subject: [PATCH 4/8] Add flag informing about dylib ASan instrumentation and
guard string annotations
* CMake files are updated to automatically add the `_LIBCPP_INSTRUMENTED_WITH_ASAN`
macro to `__config_site`. This macro is used to inform the compiler (in header files)
that the library has been built with ASan and is instrumented for memory safety checks.
* The `-D_LIBCPP_INSTRUMENTED_WITH_ASAN` flag is added to the libc++ compilation
command when building with ASan. This flag ensures that basic_string annotations
are included in the binary, which are needed for ASan to track memory usage
correctly.
* The string file is updated to use string annotations from headers if and only
if the code is compiled with `-fsanitize=address` and the dylib is compiled
with ASan (so, `_LIBCPP_INSTRUMENTED_WITH_ASAN` is defined). This ensures that
the string annotations are only included when they are supported.
---
libcxx/CMakeLists.txt | 19 +++++++++++++++++++
libcxx/include/__config_site.in | 1 +
libcxx/include/string | 4 ++--
libcxxabi/CMakeLists.txt | 7 +++++++
4 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 31fc9cec1c57f..8e97792f0f9a6 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -543,6 +543,18 @@ function(cxx_add_basic_build_flags target)
# library.
target_compile_definitions(${target} PRIVATE -D_LIBCPP_BUILDING_LIBRARY)
+ # Define _LIBCPP_INSTRUMENTED_WITH_ASAN while building the library with ASan.
+ # Normally, the _LIBCPP_INSTRUMENTED_WITH_ASAN flag is used to keep information whether
+ # dylibs are built with AddressSanitizer. However, when building libc++,
+ # this flag needs to be defined so that the resulting dylib has all ASan functionalities normally guarded by this flag.
+ # If the _LIBCPP_INSTRUMENTED_WITH_ASAN flag is not defined, then parts of the ASan instrumentation code in libc++
+ # will not be compiled into it resulting in true positives.
+ # For context, read: https://github.com/llvm/llvm-project/pull/72677#pullrequestreview-1765402800
+ string(FIND "${LLVM_USE_SANITIZER}" "Address" building_with_asan)
+ if (NOT "${building_with_asan}" STREQUAL "-1")
+ target_compile_definitions(${target} PRIVATE -D_LIBCPP_INSTRUMENTED_WITH_ASAN)
+ endif()
+
# Make sure the library can be build without transitive includes. This makes
# it easier to upgrade the library to a newer language standard without build
# errors.
@@ -642,6 +654,13 @@ get_sanitizer_flags(SANITIZER_FLAGS "${LLVM_USE_SANITIZER}")
add_library(cxx-sanitizer-flags INTERFACE)
target_compile_options(cxx-sanitizer-flags INTERFACE ${SANITIZER_FLAGS})
+# _LIBCPP_INSTRUMENTED_WITH_ASAN informs that library was built with ASan.
+string(FIND "${LLVM_USE_SANITIZER}" "Address" building_with_asan)
+if (NOT "${building_with_asan}" STREQUAL "-1")
+ set(LIBCPP_SANITIZER_DEFINES "#define _LIBCPP_INSTRUMENTED_WITH_ASAN 1")
+ config_define(${LIBCPP_SANITIZER_DEFINES} _LIBCPP_SANITIZER_DEFINES)
+endif()
+
# Link system libraries =======================================================
function(cxx_link_system_libraries target)
if (NOT MSVC)
diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index 6cade6f10d8ac..b0193760142c7 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -45,6 +45,7 @@
#endif
@_LIBCPP_ABI_DEFINES@
+ at _LIBCPP_SANITIZER_DEFINES@
@_LIBCPP_EXTRA_SITE_DEFINES@
#ifdef __clang__
diff --git a/libcxx/include/string b/libcxx/include/string
index f0941e6b6b9fb..c86e7883c8c57 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -649,7 +649,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
-#ifndef _LIBCPP_HAS_NO_ASAN
+#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
# define _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS __attribute__((__no_sanitize__("address")))
// This macro disables AddressSanitizer (ASan) instrumentation for a specific function,
// allowing memory accesses that would normally trigger ASan errors to proceed without crashing.
@@ -1899,7 +1899,7 @@ private:
// The following functions are no-ops outside of AddressSanitizer mode.
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(
[[__maybe_unused__]] const void* __old_mid, [[__maybe_unused__]] const void* __new_mid) const {
-#ifndef _LIBCPP_HAS_NO_ASAN
+#if !defined(_LIBCPP_HAS_NO_ASAN) && defined(_LIBCPP_INSTRUMENTED_WITH_ASAN)
const void* __begin = data();
const void* __end = data() + capacity() + 1;
if (!__libcpp_is_constant_evaluated() && __begin != nullptr && is_same<allocator_type, __default_allocator_type>::value)
diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt
index efe830bd2ad66..b5415294b0cfe 100644
--- a/libcxxabi/CMakeLists.txt
+++ b/libcxxabi/CMakeLists.txt
@@ -269,6 +269,13 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY)
# it is being built as part of libcxx.
add_definitions(-D_LIBCPP_BUILDING_LIBRARY)
+# To ensure that all ASan functionalities are built into the binary.
+# For context, read: https://github.com/llvm/llvm-project/pull/72677#pullrequestreview-1765402800
+string(FIND "${LLVM_USE_SANITIZER}" "Address" building_with_asan)
+if (NOT "${building_with_asan}" STREQUAL "-1")
+ add_definitions(-D_LIBCPP_INSTRUMENTED_WITH_ASAN)
+endif()
+
# Get feature flags.
add_compile_flags_if_supported(-fstrict-aliasing)
>From f0adcf2ce71541cf6829f716cb5bd07ccb05fcf0 Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Fri, 8 Dec 2023 12:22:51 +0100
Subject: [PATCH 5/8] Add missing annotations checks
Some files are missing annotations checks, this commit adds those checks.
---
.../strings/basic.string/string.capacity/clear.pass.cpp | 1 +
.../string.capacity/resize_and_overwrite.pass.cpp | 2 ++
.../basic.string/string.capacity/shrink_to_fit.pass.cpp | 7 ++++---
.../strings/basic.string/string.cons/from_range.pass.cpp | 3 +++
.../string.cons/from_range_deduction.pass.cpp | 3 +++
.../basic.string/string.cons/substr_rvalue.pass.cpp | 9 +++++++++
.../string.modifiers/string_append/append_range.pass.cpp | 5 +++++
.../string.modifiers/string_assign/assign_range.pass.cpp | 5 +++++
.../iter_iter_iter.infinite_recursion.pass.cpp | 2 ++
.../string.ops/string_substr/substr.pass.cpp | 4 ++++
.../string.ops/string_substr/substr_rvalue.pass.cpp | 3 +++
11 files changed, 41 insertions(+), 3 deletions(-)
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
index 7fa5cd43b80af..643ea4a3bdad4 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/clear.pass.cpp
@@ -34,6 +34,7 @@ TEST_CONSTEXPR_CXX20 void test_string() {
s.erase(5);
LIBCPP_ASSERT(is_string_asan_correct(s));
test(s);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
s.assign(100, 'a');
s.erase(50);
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
index 00f5cccd30d6b..edc8b67808b85 100644
--- 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
@@ -38,6 +38,7 @@ constexpr void test_appending(std::size_t k, size_t N, size_t new_capacity) {
const S expected = S(k, 'a') + S(N - k, 'b');
assert(s == expected);
assert(s.c_str()[N] == '\0');
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class S>
@@ -56,6 +57,7 @@ constexpr void test_truncating(std::size_t o, size_t N) {
const S expected = S(N - 1, 'a') + S(1, 'b');
assert(s == expected);
assert(s.c_str()[N] == '\0');
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
template <class String>
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
index 293e8cb967f38..26b177be2f767 100644
--- 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
@@ -43,9 +43,10 @@ TEST_CONSTEXPR_CXX20 void test_string() {
test(s);
s.assign(100, 'a');
- for (int i = 0; i <= 90; ++i)
- s.erase(91 - 2 * (i / 2));
- test(s);
+ for (int i = 0; i <= 9; ++i) {
+ s.erase(90 - 10 * i);
+ test(s);
+ }
}
TEST_CONSTEXPR_CXX20 bool test() {
diff --git a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
index 3ae5b74a3504a..7f33237de4631 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp
@@ -19,6 +19,7 @@
#include "../../../containers/from_range_helpers.h"
#include "../../../containers/sequences/from_range_sequence_containers.h"
#include "test_macros.h"
+#include "asan_testing.h"
template <class Container, class Range, class Alloc>
concept StringHasFromRangeAllocCtr =
@@ -70,6 +71,7 @@ constexpr void test_with_input(std::vector<char> input) {
LIBCPP_ASSERT(c.__invariants());
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
assert(std::ranges::equal(in, c));
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
{ // (range, allocator)
@@ -80,6 +82,7 @@ constexpr void test_with_input(std::vector<char> input) {
assert(c.get_allocator() == alloc);
assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end())));
assert(std::ranges::equal(in, c));
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
}
diff --git a/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp
index b2dab03506f03..83c3dfdfa79dd 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/from_range_deduction.pass.cpp
@@ -26,6 +26,7 @@
#include "deduction_guides_sfinae_checks.h"
#include "test_allocator.h"
+#include "asan_testing.h"
int main(int, char**) {
using Char = char16_t;
@@ -33,12 +34,14 @@ int main(int, char**) {
{
std::basic_string c(std::from_range, std::array<Char, 0>());
static_assert(std::is_same_v<decltype(c), std::basic_string<Char>>);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
{
using Alloc = test_allocator<Char>;
std::basic_string c(std::from_range, std::array<Char, 0>(), Alloc());
static_assert(std::is_same_v<decltype(c), std::basic_string<Char, std::char_traits<Char>, Alloc>>);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
// Note: defining `value_type` is a workaround because one of the deduction guides will end up instantiating
diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
index 272ce339f3adc..a9b07a6eb1aa4 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
@@ -23,6 +23,7 @@
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"
+#include "asan_testing.h"
#define STR(string) MAKE_CSTRING(typename S::value_type, string)
@@ -39,6 +40,8 @@ constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) {
LIBCPP_ASSERT(orig.empty());
LIBCPP_ASSERT(substr.__invariants());
assert(substr == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(orig));
+ LIBCPP_ASSERT(is_string_asan_correct(substr));
}
template <class S>
@@ -65,6 +68,8 @@ test_string_pos_alloc(S orig, typename S::size_type pos, const typename S::alloc
LIBCPP_ASSERT(substr.__invariants());
assert(substr == expected);
assert(substr.get_allocator() == alloc);
+ LIBCPP_ASSERT(is_string_asan_correct(orig));
+ LIBCPP_ASSERT(is_string_asan_correct(substr));
}
template <class S>
@@ -95,6 +100,8 @@ constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::
LIBCPP_ASSERT(orig.empty());
LIBCPP_ASSERT(substr.__invariants());
assert(substr == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(orig));
+ LIBCPP_ASSERT(is_string_asan_correct(substr));
}
template <class S>
@@ -122,6 +129,8 @@ constexpr void test_string_pos_n_alloc(
LIBCPP_ASSERT(substr.__invariants());
assert(substr == expected);
assert(substr.get_allocator() == alloc);
+ LIBCPP_ASSERT(is_string_asan_correct(orig));
+ LIBCPP_ASSERT(is_string_asan_correct(substr));
}
template <class S>
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/append_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/append_range.pass.cpp
index d88e9f9573600..9e06aa4aaa790 100644
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_append/append_range.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_append/append_range.pass.cpp
@@ -15,6 +15,7 @@
#include "../../../../containers/sequences/insert_range_sequence_containers.h"
#include "test_macros.h"
+#include "asan_testing.h"
// Tested cases:
// - different kinds of insertions (appending an {empty/one-element/mid-sized/long range} into an
@@ -43,9 +44,13 @@ int main(int, char**) {
std::string c;
static_assert(std::is_lvalue_reference_v<decltype(c.append_range(FullContainer_Begin_EmptyRange<char>.input))>);
assert(&c.append_range(FullContainer_Begin_EmptyRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.append_range(FullContainer_Begin_OneElementRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.append_range(FullContainer_Begin_MidRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.append_range(FullContainer_Begin_LongRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
// Note: `test_append_range_exception_safety_throwing_copy` doesn't apply because copying chars cannot throw.
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/assign_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/assign_range.pass.cpp
index d51326f383304..fd060b351a6cf 100644
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/assign_range.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_assign/assign_range.pass.cpp
@@ -15,6 +15,7 @@
#include "../../../../containers/sequences/insert_range_sequence_containers.h"
#include "test_macros.h"
+#include "asan_testing.h"
// Tested cases:
// - different kinds of assignments (assigning an {empty/one-element/mid-sized/long range} to an
@@ -43,9 +44,13 @@ int main(int, char**) {
std::string c;
static_assert(std::is_lvalue_reference_v<decltype(c.assign_range(FullContainer_Begin_EmptyRange<char>.input))>);
assert(&c.assign_range(FullContainer_Begin_EmptyRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.assign_range(FullContainer_Begin_OneElementRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.assign_range(FullContainer_Begin_MidRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
assert(&c.assign_range(FullContainer_Begin_LongRange<char>.input) == &c);
+ LIBCPP_ASSERT(is_string_asan_correct(c));
}
// Note: `test_assign_range_exception_safety_throwing_copy` doesn't apply because copying chars cannot throw.
diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.infinite_recursion.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.infinite_recursion.pass.cpp
index e40528e516531..b7b70fa9118c6 100644
--- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.infinite_recursion.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.infinite_recursion.pass.cpp
@@ -16,6 +16,7 @@
#include <string>
#include "test_macros.h"
+#include "asan_testing.h"
struct char_ascii {
char char_;
@@ -95,5 +96,6 @@ int main(int, char**) {
str.insert(str.begin(), &ch, &ch + 1);
assert(str.size() == 1);
assert(str[0].char_ == 'A');
+ LIBCPP_ASSERT(is_string_asan_correct(str));
return 0;
}
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
index 83cfa8737408c..6430310fcfc96 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
@@ -19,6 +19,7 @@
#include "test_allocator.h"
#include "test_macros.h"
#include "min_allocator.h"
+#include "asan_testing.h"
template <class S>
TEST_CONSTEXPR_CXX20 void test(const S& s, typename S::size_type pos, typename S::size_type n) {
@@ -29,6 +30,8 @@ TEST_CONSTEXPR_CXX20 void test(const S& s, typename S::size_type pos, typename S
typename S::size_type rlen = std::min(n, s.size() - pos);
assert(str.size() == rlen);
assert(S::traits_type::compare(s.data() + pos, str.data(), rlen) == 0);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ LIBCPP_ASSERT(is_string_asan_correct(str));
}
#ifndef TEST_HAS_NO_EXCEPTIONS
else if (!TEST_IS_CONSTANT_EVALUATED) {
@@ -108,6 +111,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
test_string<std::string>();
#if TEST_STD_VER >= 11
test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
+ test_string<std::basic_string<char, std::char_traits<char>, safe_allocator<char>>>();
#endif
return true;
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
index c3c6c3f56b919..596eb923db310 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
@@ -20,6 +20,7 @@
#include "make_string.h"
#include "min_allocator.h"
#include "test_allocator.h"
+#include "asan_testing.h"
#define STR(string) MAKE_CSTRING(typename S::value_type, string)
@@ -32,6 +33,8 @@ constexpr void test(S orig, typename S::size_type pos, typename S::size_type n,
LIBCPP_ASSERT(orig.__invariants());
LIBCPP_ASSERT(str.__invariants());
assert(str == expected);
+ LIBCPP_ASSERT(is_string_asan_correct(orig));
+ LIBCPP_ASSERT(is_string_asan_correct(str));
}
template <class S>
>From c4dcdfe4b9a35ea2882b701ae0fdccbe441b0309 Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Fri, 8 Dec 2023 12:28:04 +0100
Subject: [PATCH 6/8] Additional test cases
This commit adds a few test cases to check ASan annotations for SSO/no-SSO.
---
.../string.cons/brace_assignment.pass.cpp | 12 ++++++++++++
.../string.cons/initializer_list.pass.cpp | 10 ++++++++++
.../string.cons/initializer_list_assignment.pass.cpp | 9 +++++++++
.../string_assign/initializer_list.pass.cpp | 10 ++++++++++
.../string_insert/iter_initializer_list.pass.cpp | 5 +++++
.../string_op_plus_equal/initializer_list.pass.cpp | 6 ++++++
6 files changed, 52 insertions(+)
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
index 6773aa1c28d0a..49a90872c56fa 100644
--- 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
@@ -34,6 +34,18 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(s == "ab");
LIBCPP_ASSERT(is_string_asan_correct(s));
}
+ {
+ std::string s = "hello world";
+ s = {"It'sALongString!NoSSO!qwertyuiop", 30};
+ assert(s == "It'sALongString!NoSSO!qwertyui");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
+ {
+ std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!";
+ s = {"It'sALongString!NoSSO!qwertyuiop", 30};
+ assert(s == "It'sALongString!NoSSO!qwertyui");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
{
std::string s = "Hello world! Hello world! Hello world! Hello world! Hello world!";
s = {"abc", 2};
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
index a8b57b32e3629..ebdcc523f055d 100644
--- 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
@@ -28,12 +28,22 @@ TEST_CONSTEXPR_CXX20 void test_string() {
assert(s == "abc");
LIBCPP_ASSERT(is_string_asan_correct(s));
}
+ {
+ std::basic_string<char, std::char_traits<char>, Alloc<char> > 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', 'a'};
+ assert(s == "aaaaaaaaaaaaaaaaaaaaaaaaa");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
{
std::basic_string<wchar_t, std::char_traits<wchar_t>, Alloc<wchar_t> > s = {L'a', L'b', L'c'};
assert(s == L"abc");
LIBCPP_ASSERT(is_string_asan_correct(s));
}
+ {
+ std::basic_string<wchar_t, std::char_traits<wchar_t>, Alloc<wchar_t> > s = {L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a'};
+ assert(s == L"aaaaaaaaaaaaaaaaaaaaaaaaa");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ }
#endif
}
// clang-format on
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
index 90be1cc58857b..a3491696a4fc8 100644
--- 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
@@ -49,6 +49,15 @@ TEST_CONSTEXPR_CXX20 void test_string() {
LIBCPP_ASSERT(is_string_asan_correct(s));
LIBCPP_ASSERT(is_string_asan_correct(result));
}
+ {
+ typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, Alloc<wchar_t>> S;
+ S s;
+ S& result = (s = {L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a', L'a'});
+ assert(s == L"aaaaaaaaaaaaaaaaaaaaaaaaa");
+ assert(&result == &s);
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+ LIBCPP_ASSERT(is_string_asan_correct(result));
+ }
#endif
}
// clang-format on
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
index 484ad723e7c7e..47a59e8997e62 100644
--- 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
@@ -22,9 +22,19 @@
template <class S>
TEST_CONSTEXPR_CXX20 void test_string() {
S s("123");
+
+ s.assign({'a', 'b'});
+ assert(s == "ab");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
+
s.assign({'a', 'b', 'c'});
assert(s == "abc");
LIBCPP_ASSERT(is_string_asan_correct(s));
+
+ s.assign({'a', '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 == "aaaaaaaaaaaaaaaaaaaaaaaaa");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
TEST_CONSTEXPR_CXX20 bool test() {
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
index 52594ab7ece53..769bd7c4274ff 100644
--- 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
@@ -26,6 +26,11 @@ TEST_CONSTEXPR_CXX20 void test_string() {
assert(i - s.begin() == 3);
assert(s == "123abc456");
LIBCPP_ASSERT(is_string_asan_correct(s));
+ typename S::iterator j = s.insert(s.begin() + 6, {'a', '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(j - s.begin() == 6);
+ assert(s == "123abcaaaaaaaaaaaaaaaaaaaaaaaaa456");
+ 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
index a853a255dab36..165fb2f96313b 100644
--- 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
@@ -33,6 +33,12 @@ TEST_CONSTEXPR_CXX20 void test_string() {
s += {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'};
assert(s == "123abcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
LIBCPP_ASSERT(is_string_asan_correct(s));
+
+ s += {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
+ 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x',
+ 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'};
+ assert(s == "123abcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+ LIBCPP_ASSERT(is_string_asan_correct(s));
}
TEST_CONSTEXPR_CXX20 bool test() {
>From 47a5481e64df6b351e058a02d92515a14108e19f Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Mon, 11 Dec 2023 10:22:14 +0100
Subject: [PATCH 7/8] [ASan] Annotations fix
Resolved an issue with ASan annotations that was causing failure of `substr_rvalue` tests.
---
libcxx/include/string | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index c86e7883c8c57..92085aed89de3 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1368,12 +1368,22 @@ public:
void __move_assign(basic_string&& __str, size_type __pos, size_type __len) {
// Pilfer the allocation from __str.
_LIBCPP_ASSERT_INTERNAL(__alloc() == __str.__alloc(), "__move_assign called with wrong allocator");
+ size_type __old_sz = __str.size();
__r_.first() = __str.__r_.first();
+ if (!__str.__is_long())
+ __str.__annotate_delete();
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
_Traits::move(data(), data() + __pos, __len);
__set_size(__len);
_Traits::assign(data()[__len], value_type());
+
+ if (!__is_long()) {
+ __annotate_new(__len);
+ } else if(__old_sz > __len) {
+ __annotate_shrink(__old_sz);
+ }
}
#endif
@@ -2350,7 +2360,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init(_ForwardIterator __first, _For
template <class _CharT, class _Traits, class _Allocator>
template <class _InputIterator, class _Sentinel>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(
_InputIterator __first, _Sentinel __last, size_type __sz) {
if (__libcpp_is_constant_evaluated())
>From ad29f03a52c7e700198d796cbbc8d6190f3623c6 Mon Sep 17 00:00:00 2001
From: Advenam Tacet <advenam.tacet at trailofbits.com>
Date: Mon, 11 Dec 2023 12:25:30 +0100
Subject: [PATCH 8/8] [ASan] SSO annotations fixes and refactor
This commit fixes issues related to annotations and instrumentation, causing problems only with SSO annotations.
First, it fixes an issue where `_LIBCPP_STRING_INTERNAL_MEMORY_ACCESS` doesn't work in `basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, true_type)``.
Second, it adds missing SSO annotations and refactors annotations around `__uninitialized_size_tag`.
To reproduce the errors in this commit, change `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED` to true. This flag will be changed to true (and probably deleted) soon.
---
libcxx/include/string | 40 +++++++++++++++++++++-------------------
1 file changed, 21 insertions(+), 19 deletions(-)
diff --git a/libcxx/include/string b/libcxx/include/string
index 92085aed89de3..ddfd22656c102 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -874,6 +874,7 @@ private:
__set_long_pointer(__allocation);
__set_long_size(__size);
}
+ __annotate_new(__size);
}
template <class _Iter, class _Sent>
@@ -896,7 +897,9 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string()
_NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
- : __r_(__value_init_tag(), __default_init_tag()) {}
+ : __r_(__value_init_tag(), __default_init_tag()) {
+ __annotate_new(0);
+ }
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
@@ -904,7 +907,9 @@ public:
#else
_NOEXCEPT
#endif
- : __r_(__value_init_tag(), __a) {}
+ : __r_(__value_init_tag(), __a) {
+ __annotate_new(0);
+ }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string(const basic_string& __str)
: __r_(__default_init_tag(), __alloc_traits::select_on_container_copy_construction(__str.__alloc())) {
@@ -941,6 +946,9 @@ public:
// __str's memory needs to be unpoisoned only in the case where it's a short string.
: __r_( ( (__str.__is_long() ? 0 : (__str.__annotate_delete(), 0)), std::move(__str.__r_)) ) {
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
+ if(!__is_long())
+ __annotate_new(size());
}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
@@ -951,11 +959,13 @@ public:
else {
if (__libcpp_is_constant_evaluated())
__r_.first() = __rep();
- __r_.first() = __str.__r_.first();
- if (!__str.__is_long()) {
+ if (!__str.__is_long())
__str.__annotate_delete();
- }
+ __r_.first() = __str.__r_.first();
__str.__r_.first() = __rep();
+ __str.__annotate_new(0);
+ if(!__is_long() && this != &__str)
+ __annotate_new(size());
}
}
#endif // _LIBCPP_CXX03_LANG
@@ -1121,7 +1131,7 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
operator __self_view() const _NOEXCEPT { return __self_view(data(), size()); }
- _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const basic_string& __str);
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string& operator=(const basic_string& __str);
template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value &&
!__is_same_uncvref<_Tp, basic_string>::value, int> = 0>
@@ -1131,7 +1141,7 @@ public:
}
#ifndef _LIBCPP_CXX03_LANG
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS basic_string&
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string&
operator=(basic_string&& __str) _NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)) {
__move_assign(__str, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>());
return *this;
@@ -2067,7 +2077,7 @@ private:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void __move_assign(basic_string& __str, false_type)
_NOEXCEPT_(__alloc_traits::is_always_equal::value);
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS
void __move_assign(basic_string& __str, true_type)
#if _LIBCPP_STD_VER >= 17
_NOEXCEPT;
@@ -2330,6 +2340,7 @@ template <class _InputIterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator __first, _Sentinel __last) {
__r_.first() = __rep();
+ __annotate_new(0);
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try
@@ -2397,7 +2408,6 @@ void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(
}
catch (...)
{
- __annotate_delete();
if (__is_long())
__alloc_traits::deallocate(__alloc(), __get_long_pointer(), __get_long_cap());
throw;
@@ -2654,6 +2664,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
if (!is_nothrow_move_assignable<allocator_type>::value) {
__set_short_size(0);
traits_type::assign(__get_short_pointer()[0], value_type());
+ __annotate_new(0);
}
#endif
}
@@ -2680,7 +2691,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr
// 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.
+ // If it is long string, delete was never called on original __str's buffer.
__annotate_new(__get_short_size());
}
@@ -4277,7 +4288,6 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs,
_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;
}
@@ -4292,12 +4302,10 @@ operator+(const _CharT* __lhs , const basic_string<_CharT,_Traits,_Allocator>& _
_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;
}
@@ -4311,12 +4319,10 @@ operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Allocator>& __rhs)
_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;
}
@@ -4331,12 +4337,10 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT*
_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;
}
@@ -4350,12 +4354,10 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, _CharT __rhs)
_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;
}
More information about the libcxx-commits
mailing list