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
5 #include "Inputs/system-header-simulator-cxx.h"
12 void func_const_ref(const T
&a
);
17 string my_string
= "default";
18 void default_arg(int a
= 42, string
&b
= my_string
);
24 T
*__addressof(T
&arg
);
26 char *data(std::string
&c
);
28 } // end namespace std
30 void consume(const char *) {}
31 void consume(const wchar_t *) {}
32 void consume(const char16_t
*) {}
33 void consume(const char32_t
*) {}
35 //=--------------------------------------=//
36 // `std::string` member functions //
37 //=--------------------------------------=//
39 void deref_after_scope_char(bool cond
) {
43 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
44 d
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
45 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
46 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
48 const char *c2
= s
.c_str();
50 // expected-note@-1 {{Assuming 'cond' is true}}
51 // expected-note@-2 {{Taking true branch}}
52 // expected-note@-3 {{Assuming 'cond' is false}}
53 // expected-note@-4 {{Taking false branch}}
54 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
55 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
57 consume(d
); // expected-warning {{Inner pointer of container used after re/deallocation}}
58 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
62 void deref_after_scope_char_data_non_const() {
66 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
67 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
70 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
71 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
74 void deref_after_scope_wchar_t(bool cond
) {
78 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
79 d
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
80 } // expected-note {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
81 // expected-note@-1 {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
83 const wchar_t *c2
= s
.c_str();
85 // expected-note@-1 {{Assuming 'cond' is true}}
86 // expected-note@-2 {{Taking true branch}}
87 // expected-note@-3 {{Assuming 'cond' is false}}
88 // expected-note@-4 {{Taking false branch}}
89 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
90 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
92 consume(d
); // expected-warning {{Inner pointer of container used after re/deallocation}}
93 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
97 void deref_after_scope_char16_t_cstr() {
101 c16
= s16
.c_str(); // expected-note {{Pointer to inner buffer of 'std::u16string' obtained here}}
102 } // expected-note {{Inner buffer of 'std::u16string' deallocated by call to destructor}}
104 const char16_t
*c16_2
= s16
.c_str();
105 consume(c16
); // expected-warning {{Inner pointer of container used after re/deallocation}}
106 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
109 void deref_after_scope_char32_t_data() {
113 c32
= s32
.data(); // expected-note {{Pointer to inner buffer of 'std::u32string' obtained here}}
114 } // expected-note {{Inner buffer of 'std::u32string' deallocated by call to destructor}}
116 const char32_t
*c32_2
= s32
.data();
117 consume(c32
); // expected-warning {{Inner pointer of container used after re/deallocation}}
118 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
121 void multiple_symbols(bool cond
) {
125 c1
= s1
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
126 d1
= s1
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
127 const char *local
= s1
.c_str();
128 consume(local
); // no-warning
129 } // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
130 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
132 const char *c2
= s2
.c_str();
134 // expected-note@-1 {{Assuming 'cond' is true}}
135 // expected-note@-2 {{Taking true branch}}
136 // expected-note@-3 {{Assuming 'cond' is false}}
137 // expected-note@-4 {{Taking false branch}}
138 consume(c1
); // expected-warning {{Inner pointer of container used after re/deallocation}}
139 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
141 consume(d1
); // expected-warning {{Inner pointer of container used after re/deallocation}}
142 } // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
145 void deref_after_scope_ok(bool cond
) {
153 consume(c
); // no-warning
155 consume(d
); // no-warning
158 void deref_after_equals() {
160 std::string s
= "hello";
161 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
162 s
= "world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator='}}
163 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
164 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
167 void deref_after_plus_equals() {
169 std::string s
= "hello";
170 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
171 s
+= " world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator+='}}
172 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
173 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
176 void deref_after_clear() {
179 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
180 s
.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
181 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
182 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
185 void deref_after_append() {
187 std::string s
= "hello";
188 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
189 s
.append(2, 'x'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'append'}}
190 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
191 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
194 void deref_after_assign() {
197 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
198 s
.assign(4, 'a'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'assign'}}
199 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
200 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
203 void deref_after_erase() {
205 std::string s
= "hello";
206 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
207 s
.erase(0, 2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'erase'}}
208 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
209 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
212 void deref_after_insert() {
214 std::string s
= "ello";
215 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
216 s
.insert(0, 1, 'h'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'insert'}}
217 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
218 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
221 void deref_after_replace() {
223 std::string s
= "hello world";
224 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
225 s
.replace(6, 5, "string"); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'replace'}}
226 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
227 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
230 void deref_after_pop_back() {
233 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
234 s
.pop_back(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'pop_back'}}
235 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
236 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
239 void deref_after_push_back() {
242 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
243 s
.push_back('c'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'push_back'}}
244 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
245 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
248 void deref_after_reserve() {
251 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
252 s
.reserve(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'reserve'}}
253 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
254 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
257 void deref_after_resize() {
260 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
261 s
.resize(5); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'resize'}}
262 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
263 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
266 void deref_after_shrink_to_fit() {
269 c
= s
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
270 s
.shrink_to_fit(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'shrink_to_fit'}}
271 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
272 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
275 void deref_after_swap() {
278 c
= s1
.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
279 s1
.swap(s2
); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'swap'}}
280 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
281 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
284 void deref_after_std_data() {
287 c
= std::data(s
); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
288 s
.push_back('c'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'push_back'}}
289 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
290 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
296 return s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
297 // expected-note@-1 {{Pointer to inner buffer of 'std::string' obtained here}}
300 s
.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
302 ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
305 void cleared_through_method() {
307 const char *c
= x
.name(); // expected-note {{Calling 'S::name'}}
308 // expected-note@-1 {{Returning from 'S::name'}}
309 x
.clear(); // expected-note {{Calling 'S::clear'}}
310 // expected-note@-1 {{Returning; inner buffer was reallocated}}
311 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
312 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
315 void destroyed_through_method() {
317 const char *c
= y
.name(); // expected-note {{Calling 'S::name'}}
318 // expected-note@-1 {{Returning from 'S::name'}}
319 y
.~S(); // expected-note {{Calling '~S'}}
320 // expected-note@-1 {{Returning; inner buffer was deallocated}}
321 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
322 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
325 //=---------------------------=//
326 // Other STL functions //
327 //=---------------------------=//
329 void STL_func_ref() {
332 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
333 std::func_ref(s
); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
334 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
335 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
338 void STL_func_const_ref() {
342 std::func_const_ref(s
);
343 consume(c
); // no-warning
346 void STL_func_value() {
351 consume(c
); // no-warning
354 void func_ptr_known() {
357 void (*func_ptr
)(std::string
&) = std::func_ref
<std::string
>;
358 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
359 func_ptr(s
); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
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}}
364 void func_ptr_unknown(void (*func_ptr
)(std::string
&)) {
369 consume(c
); // no-warning
372 void func_default_arg() {
375 c
= s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
376 default_arg(3, s
); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'default_arg'}}
377 consume(c
); // expected-warning {{Inner pointer of container used after re/deallocation}}
378 // expected-note@-1 {{Inner pointer of container used after re/deallocation}}
381 void func_addressof() {
386 consume(c
); // no-warning
389 void func_AddressofFn_() {
393 (void)std::__addressof(s
);
394 consume(c
); // no-warning
397 void func_std_data() {
401 consume(c
); // no-warning
405 std::string
to_string() { return s
; }
411 const char *escape_via_return_temp() {
413 return x
.to_string().c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
414 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
415 // expected-warning@-2 {{Inner pointer of container used after re/deallocation}}
416 // expected-note@-3 {{Inner pointer of container used after re/deallocation}}
419 const char *escape_via_return_local() {
421 return s
.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
422 // expected-note@-1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
423 // expected-warning@-2 {{Inner pointer of container used after re/deallocation}}
424 // expected-note@-3 {{Inner pointer of container used after re/deallocation}}
431 void no_CXXRecordDecl() {
433 *(void **)&b
= c() + 1;
437 void checkReference(std::string
&s
) {
438 const char *c
= s
.c_str();