xref: /llvm-project/libcxx/test/libcxx/containers/strings/basic.string/asan_vector_integration.pass.cpp (revision 1a96179596099b8a3839050dbff02bfed94502e5)
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 // REQUIRES: asan
10 // UNSUPPORTED: c++03
11 
12 #include <cassert>
13 #include <string>
14 #include <vector>
15 #include <array>
16 #include "test_macros.h"
17 #include "asan_testing.h"
18 #include "min_allocator.h"
19 
20 // This tests exists to check if strings work well with vector, as those
21 // may be partialy annotated, we cannot simply call
22 // is_contiguous_container_asan_correct, as it assumes that
23 // object memory inside is not annotated, so we check everything in a more careful way.
24 
25 template <typename D>
verify_inside(D const & d)26 void verify_inside(D const& d) {
27   for (size_t i = 0; i < d.size(); ++i) {
28     assert(is_string_asan_correct(d[i]));
29   }
30 }
31 
32 template <typename S, size_t N>
get_s(char c)33 S get_s(char c) {
34   S s;
35   for (size_t i = 0; i < N; ++i)
36     s.push_back(c);
37 
38   return s;
39 }
40 
41 template <class C, class S>
test_string()42 void test_string() {
43   size_t const N = sizeof(S) < 256 ? (4096 / sizeof(S)) : 16;
44 
45   {
46     C d1a(1), d1b(N), d1c(N + 1), d1d(5 * N);
47     verify_inside(d1a);
48     verify_inside(d1b);
49     verify_inside(d1c);
50     verify_inside(d1d);
51   }
52   {
53     C d2;
54     for (size_t i = 0; i < 3 * N + 2; ++i) {
55       d2.push_back(get_s<S, 1>(i % 10 + 'a'));
56       verify_inside(d2);
57       d2.push_back(get_s<S, 28>(i % 10 + 'b'));
58       verify_inside(d2);
59 
60       d2.erase(d2.cbegin());
61       verify_inside(d2);
62     }
63   }
64   {
65     C d3;
66     for (size_t i = 0; i < 3 * N + 2; ++i) {
67       d3.push_back(get_s<S, 1>(i % 10 + 'a'));
68       verify_inside(d3);
69       d3.push_back(get_s<S, 28>(i % 10 + 'b'));
70       verify_inside(d3);
71 
72       d3.pop_back();
73       verify_inside(d3);
74     }
75   }
76   {
77     C d4;
78     for (size_t i = 0; i < 3 * N + 2; ++i) {
79       // When there is no SSO, all elements inside should not be poisoned,
80       // so we can verify vector poisoning.
81       d4.push_back(get_s<S, 33>(i % 10 + 'a'));
82       verify_inside(d4);
83       assert(is_contiguous_container_asan_correct(d4));
84       d4.push_back(get_s<S, 28>(i % 10 + 'b'));
85       verify_inside(d4);
86       assert(is_contiguous_container_asan_correct(d4));
87     }
88   }
89   {
90     C d5;
91     for (size_t i = 0; i < 3 * N + 2; ++i) {
92       // In d4 we never had poisoned memory inside vector.
93       // Here we start with SSO, so part of the inside of the container,
94       // will be poisoned.
95       d5.push_back(S());
96       verify_inside(d5);
97     }
98     for (size_t i = 0; i < d5.size(); ++i) {
99       // We change the size to have long string.
100       // Memory owne by vector should not be poisoned by string.
101       d5[i].resize(100);
102       verify_inside(d5);
103     }
104 
105     assert(is_contiguous_container_asan_correct(d5));
106 
107     d5.erase(d5.begin() + 2);
108     verify_inside(d5);
109 
110     d5.erase(d5.end() - 2);
111     verify_inside(d5);
112 
113     assert(is_contiguous_container_asan_correct(d5));
114   }
115   {
116     C d6a;
117     assert(is_contiguous_container_asan_correct(d6a));
118 
119     C d6b(N + 2, get_s<S, 100>('a'));
120     d6b.push_back(get_s<S, 101>('b'));
121     while (!d6b.empty()) {
122       d6b.pop_back();
123       assert(is_contiguous_container_asan_correct(d6b));
124     }
125 
126     C d6c(N + 2, get_s<S, 102>('c'));
127     while (!d6c.empty()) {
128       d6c.pop_back();
129       assert(is_contiguous_container_asan_correct(d6c));
130     }
131   }
132   {
133     C d7(9 * N + 2);
134 
135     d7.insert(d7.begin() + 1, S());
136     verify_inside(d7);
137 
138     d7.insert(d7.end() - 3, S());
139     verify_inside(d7);
140 
141     d7.insert(d7.begin() + 2 * N, get_s<S, 1>('a'));
142     verify_inside(d7);
143 
144     d7.insert(d7.end() - 2 * N, get_s<S, 1>('b'));
145     verify_inside(d7);
146 
147     d7.insert(d7.begin() + 2 * N, 3 * N, get_s<S, 1>('c'));
148     verify_inside(d7);
149 
150     // It may not be short for big element types, but it will be checked correctly:
151     d7.insert(d7.end() - 2 * N, 3 * N, get_s<S, 2>('d'));
152     verify_inside(d7);
153 
154     d7.erase(d7.begin() + 2);
155     verify_inside(d7);
156 
157     d7.erase(d7.end() - 2);
158     verify_inside(d7);
159   }
160 }
161 
162 template <class S>
test_container()163 void test_container() {
164   test_string<std::vector<S, std::allocator<S>>, S>();
165   test_string<std::vector<S, min_allocator<S>>, S>();
166   test_string<std::vector<S, safe_allocator<S>>, S>();
167 }
168 
main(int,char **)169 int main(int, char**) {
170   // Those tests support only types based on std::basic_string.
171   test_container<std::string>();
172   test_container<std::wstring>();
173 #if TEST_STD_VER >= 11
174   test_container<std::u16string>();
175   test_container<std::u32string>();
176 #endif
177 #if TEST_STD_VER >= 20
178   test_container<std::u8string>();
179 #endif
180 
181   return 0;
182 }
183