1 // RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=cplusplus.InnerPointer \
2 // RUN: -Wno-dangling -Wno-dangling-field -Wno-return-stack-address \
3 // RUN: %s -analyzer-output=text -verify
4
5 #include "Inputs/system-header-simulator-cxx.h"
6 namespace std {
7
8 template <typename T>
9 void func_ref(T &a);
10
11 template <typename T>
12 void func_const_ref(const T &a);
13
14 template <typename T>
15 void func_value(T a);
16
17 string my_string = "default";
18 void default_arg(int a = 42, string &b = my_string);
19
20 } // end namespace std
21
consume(const char *)22 void consume(const char *) {}
consume(const wchar_t *)23 void consume(const wchar_t *) {}
consume(const char16_t *)24 void consume(const char16_t *) {}
consume(const char32_t *)25 void consume(const char32_t *) {}
26
27 //=--------------------------------------=//
28 // `std::string` member functions //
29 //=--------------------------------------=//
30
deref_after_scope_char(bool cond)31 void deref_after_scope_char(bool cond) {
32 const char *c, *d;
33 {
34 std::string s;
35 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
36 d = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
37 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
38 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
39 std::string s;
40 const char *c2 = s.c_str();
41 if (cond) {
42 // expected-note@-1 {{Assuming 'cond' is true}}
43 // expected-note@-2 {{Taking true branch}}
44 // expected-note@-3 {{Assuming 'cond' is false}}
45 // expected-note@-4 {{Taking false branch}}
46 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
47 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
48 } else {
49 consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}}
50 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
51 }
52 }
53
deref_after_scope_char_data_non_const()54 void deref_after_scope_char_data_non_const() {
55 char *c;
56 {
57 std::string s;
58 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
59 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
60 std::string s;
61 char *c2 = s.data();
62 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
63 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
64 }
65
deref_after_scope_wchar_t(bool cond)66 void deref_after_scope_wchar_t(bool cond) {
67 const wchar_t *c, *d;
68 {
69 std::wstring s;
70 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
71 d = s.data(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
72 } // expected-note {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
73 // expected-note@-1 {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
74 std::wstring s;
75 const wchar_t *c2 = s.c_str();
76 if (cond) {
77 // expected-note@-1 {{Assuming 'cond' is true}}
78 // expected-note@-2 {{Taking true branch}}
79 // expected-note@-3 {{Assuming 'cond' is false}}
80 // expected-note@-4 {{Taking false branch}}
81 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
82 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
83 } else {
84 consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}}
85 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
86 }
87 }
88
deref_after_scope_char16_t_cstr()89 void deref_after_scope_char16_t_cstr() {
90 const char16_t *c16;
91 {
92 std::u16string s16;
93 c16 = s16.c_str(); // expected-note {{Pointer to inner buffer of 'std::u16string' obtained here}}
94 } // expected-note {{Inner buffer of 'std::u16string' deallocated by call to destructor}}
95 std::u16string s16;
96 const char16_t *c16_2 = s16.c_str();
97 consume(c16); // expected-warning {{Inner pointer of container used after re/deallocation}}
98 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
99 }
100
deref_after_scope_char32_t_data()101 void deref_after_scope_char32_t_data() {
102 const char32_t *c32;
103 {
104 std::u32string s32;
105 c32 = s32.data(); // expected-note {{Pointer to inner buffer of 'std::u32string' obtained here}}
106 } // expected-note {{Inner buffer of 'std::u32string' deallocated by call to destructor}}
107 std::u32string s32;
108 const char32_t *c32_2 = s32.data();
109 consume(c32); // expected-warning {{Inner pointer of container used after re/deallocation}}
110 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
111 }
112
multiple_symbols(bool cond)113 void multiple_symbols(bool cond) {
114 const char *c1, *d1;
115 {
116 std::string s1;
117 c1 = s1.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
118 d1 = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
119 const char *local = s1.c_str();
120 consume(local); // no-warning
121 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
122 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
123 std::string s2;
124 const char *c2 = s2.c_str();
125 if (cond) {
126 // expected-note@-1 {{Assuming 'cond' is true}}
127 // expected-note@-2 {{Taking true branch}}
128 // expected-note@-3 {{Assuming 'cond' is false}}
129 // expected-note@-4 {{Taking false branch}}
130 consume(c1); // expected-warning {{Inner pointer of container used after re/deallocation}}
131 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
132 } else {
133 consume(d1); // expected-warning {{Inner pointer of container used after re/deallocation}}
134 } // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
135 }
136
deref_after_scope_ok(bool cond)137 void deref_after_scope_ok(bool cond) {
138 const char *c, *d;
139 std::string s;
140 {
141 c = s.c_str();
142 d = s.data();
143 }
144 if (cond)
145 consume(c); // no-warning
146 else
147 consume(d); // no-warning
148 }
149
deref_after_equals()150 void deref_after_equals() {
151 const char *c;
152 std::string s = "hello";
153 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
154 s = "world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator='}}
155 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
156 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
157 }
158
deref_after_plus_equals()159 void deref_after_plus_equals() {
160 const char *c;
161 std::string s = "hello";
162 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
163 s += " world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator+='}}
164 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
165 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
166 }
167
deref_after_clear()168 void deref_after_clear() {
169 const char *c;
170 std::string s;
171 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
172 s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
173 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
174 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
175 }
176
deref_after_append()177 void deref_after_append() {
178 const char *c;
179 std::string s = "hello";
180 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
181 s.append(2, 'x'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'append'}}
182 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
183 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
184 }
185
deref_after_assign()186 void deref_after_assign() {
187 const char *c;
188 std::string s;
189 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
190 s.assign(4, 'a'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'assign'}}
191 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
192 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
193 }
194
deref_after_erase()195 void deref_after_erase() {
196 const char *c;
197 std::string s = "hello";
198 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
199 s.erase(0, 2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'erase'}}
200 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
201 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
202 }
203
deref_after_insert()204 void deref_after_insert() {
205 const char *c;
206 std::string s = "ello";
207 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
208 s.insert(0, 1, 'h'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'insert'}}
209 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
210 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
211 }
212
deref_after_replace()213 void deref_after_replace() {
214 const char *c;
215 std::string s = "hello world";
216 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
217 s.replace(6, 5, "string"); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'replace'}}
218 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
219 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
220 }
221
deref_after_pop_back()222 void deref_after_pop_back() {
223 const char *c;
224 std::string s;
225 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
226 s.pop_back(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'pop_back'}}
227 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
228 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
229 }
230
deref_after_push_back()231 void deref_after_push_back() {
232 const char *c;
233 std::string s;
234 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
235 s.push_back('c'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'push_back'}}
236 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
237 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
238 }
239
deref_after_reserve()240 void deref_after_reserve() {
241 const char *c;
242 std::string s;
243 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
244 s.reserve(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'reserve'}}
245 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
246 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
247 }
248
deref_after_resize()249 void deref_after_resize() {
250 const char *c;
251 std::string s;
252 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
253 s.resize(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'resize'}}
254 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
255 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
256 }
257
deref_after_shrink_to_fit()258 void deref_after_shrink_to_fit() {
259 const char *c;
260 std::string s;
261 c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
262 s.shrink_to_fit(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'shrink_to_fit'}}
263 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
264 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
265 }
266
deref_after_swap()267 void deref_after_swap() {
268 const char *c;
269 std::string s1, s2;
270 c = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
271 s1.swap(s2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'swap'}}
272 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
273 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
274 }
275
276 struct S {
277 std::string s;
nameS278 const char *name() {
279 return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
280 // expected-note@-1 {{Pointer to inner buffer of 'std::string' obtained here}}
281 }
clearS282 void clear() {
283 s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
284 }
~SS285 ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
286 };
287
cleared_through_method()288 void cleared_through_method() {
289 S x;
290 const char *c = x.name(); // expected-note {{Calling 'S::name'}}
291 // expected-note@-1 {{Returning from 'S::name'}}
292 x.clear(); // expected-note {{Calling 'S::clear'}}
293 // expected-note@-1 {{Returning; inner buffer was reallocated}}
294 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
295 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
296 }
297
destroyed_through_method()298 void destroyed_through_method() {
299 S y;
300 const char *c = y.name(); // expected-note {{Calling 'S::name'}}
301 // expected-note@-1 {{Returning from 'S::name'}}
302 y.~S(); // expected-note {{Calling '~S'}}
303 // expected-note@-1 {{Returning; inner buffer was deallocated}}
304 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
305 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
306 }
307
308 //=---------------------------=//
309 // Other STL functions //
310 //=---------------------------=//
311
STL_func_ref()312 void STL_func_ref() {
313 const char *c;
314 std::string s;
315 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
316 std::func_ref(s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
317 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
318 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
319 }
320
STL_func_const_ref()321 void STL_func_const_ref() {
322 const char *c;
323 std::string s;
324 c = s.c_str();
325 std::func_const_ref(s);
326 consume(c); // no-warning
327 }
328
STL_func_value()329 void STL_func_value() {
330 const char *c;
331 std::string s;
332 c = s.c_str();
333 std::func_value(s);
334 consume(c); // no-warning
335 }
336
func_ptr_known()337 void func_ptr_known() {
338 const char *c;
339 std::string s;
340 void (*func_ptr)(std::string &) = std::func_ref<std::string>;
341 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
342 func_ptr(s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
343 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
344 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
345 }
346
func_ptr_unknown(void (* func_ptr)(std::string &))347 void func_ptr_unknown(void (*func_ptr)(std::string &)) {
348 const char *c;
349 std::string s;
350 c = s.c_str();
351 func_ptr(s);
352 consume(c); // no-warning
353 }
354
func_default_arg()355 void func_default_arg() {
356 const char *c;
357 std::string s;
358 c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
359 default_arg(3, s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'default_arg'}}
360 consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
361 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
362 }
363
364 struct T {
to_stringT365 std::string to_string() { return s; }
366 private:
367 std::string s;
368 };
369
escape_via_return_temp()370 const char *escape_via_return_temp() {
371 T x;
372 return x.to_string().c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
373 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
374 // expected-warning@-2 {{Inner pointer of container used after re/deallocation}}
375 // expected-note@-3 {{Inner pointer of container used after re/deallocation}}
376 }
377
escape_via_return_local()378 const char *escape_via_return_local() {
379 std::string s;
380 return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
381 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
382 // expected-warning@-2 {{Inner pointer of container used after re/deallocation}}
383 // expected-note@-3 {{Inner pointer of container used after re/deallocation}}
384 }
385
386
387 char *c();
388 class A {};
389
no_CXXRecordDecl()390 void no_CXXRecordDecl() {
391 A a, *b;
392 *(void **)&b = c() + 1;
393 *b = a; // no-crash
394 }
395
checkReference(std::string & s)396 void checkReference(std::string &s) {
397 const char *c = s.c_str();
398 }
399