1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10 11 // <string> 12 13 // template<class Operation> 14 // void resize_and_overwrite(size_type n, Operation op) 15 16 #include <algorithm> 17 #include <cassert> 18 #include <memory> 19 #include <string> 20 21 #include "make_string.h" 22 #include "test_macros.h" 23 #include "asan_testing.h" 24 25 template <class S> 26 constexpr void test_appending(std::size_t k, size_t N, size_t new_capacity) { 27 assert(N > k); 28 assert(new_capacity >= N); 29 auto s = S(k, 'a'); 30 s.resize_and_overwrite(new_capacity, [&](auto* p, auto n) { 31 assert(n == new_capacity); 32 LIBCPP_ASSERT(s.size() == new_capacity); 33 LIBCPP_ASSERT(std::to_address(s.begin()) == p); 34 assert(std::all_of(p, p + k, [](const auto ch) { return ch == 'a'; })); 35 std::fill(p + k, p + n, 'b'); 36 p[n] = 'c'; // will be overwritten 37 return N; 38 }); 39 const S expected = S(k, 'a') + S(N - k, 'b'); 40 assert(s == expected); 41 assert(s.c_str()[N] == '\0'); 42 LIBCPP_ASSERT(is_string_asan_correct(s)); 43 } 44 45 template <class S> 46 constexpr void test_truncating(std::size_t o, size_t N) { 47 assert(N < o); 48 auto s = S(o, 'a'); 49 s.resize_and_overwrite(N, [&](auto* p, auto n) { 50 assert(n == N); 51 LIBCPP_ASSERT(s.size() == n); 52 LIBCPP_ASSERT(std::to_address(s.begin()) == p); 53 assert(std::all_of(p, p + n, [](auto ch) { return ch == 'a'; })); 54 p[n - 1] = 'b'; 55 p[n] = 'c'; // will be overwritten 56 return n; 57 }); 58 const S expected = S(N - 1, 'a') + S(1, 'b'); 59 assert(s == expected); 60 assert(s.c_str()[N] == '\0'); 61 LIBCPP_ASSERT(is_string_asan_correct(s)); 62 } 63 64 template <class String> 65 constexpr bool test() { 66 test_appending<String>(10, 15, 15); 67 test_appending<String>(10, 15, 20); 68 test_appending<String>(10, 40, 40); 69 test_appending<String>(10, 40, 50); 70 test_appending<String>(30, 35, 35); 71 test_appending<String>(30, 35, 45); 72 test_appending<String>(10, 15, 30); 73 test_truncating<String>(15, 10); 74 test_truncating<String>(40, 35); 75 test_truncating<String>(40, 10); 76 77 return true; 78 } 79 80 void test_value_categories() { 81 std::string s; 82 s.resize_and_overwrite(10, [](char*&&, std::size_t&&) { return 0; }); 83 LIBCPP_ASSERT(is_string_asan_correct(s)); 84 s.resize_and_overwrite(10, [](char* const&, const std::size_t&) { return 0; }); 85 LIBCPP_ASSERT(is_string_asan_correct(s)); 86 struct RefQualified { 87 int operator()(char*, std::size_t) && { return 0; } 88 }; 89 s.resize_and_overwrite(10, RefQualified{}); 90 LIBCPP_ASSERT(is_string_asan_correct(s)); 91 } 92 93 int main(int, char**) { 94 test<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>(); 95 test<std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>>(); 96 test<std::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t>>>(); 97 test<std::basic_string<char32_t, std::char_traits<char32_t>, std::allocator<char32_t>>>(); 98 99 static_assert(test<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>()); 100 static_assert(test<std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>>()); 101 static_assert(test<std::basic_string<char16_t, std::char_traits<char16_t>, std::allocator<char16_t>>>()); 102 static_assert(test<std::basic_string<char32_t, std::char_traits<char32_t>, std::allocator<char32_t>>>()); 103 104 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 105 test<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>(); 106 static_assert(test<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>()); 107 #endif 108 return 0; 109 } 110