xref: /llvm-project/clang/test/Analysis/inner-pointer.cpp (revision cf7cd664f3fd212c0f1e4a83fd2fe96902569d20)
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 template <class T>
21 T *addressof(T &arg);
22 
23 template <class T>
24 T *__addressof(T &arg);
25 
26 char *data(std::string &c);
27 
28 } // end namespace std
29 
consume(const char *)30 void consume(const char *) {}
consume(const wchar_t *)31 void consume(const wchar_t *) {}
consume(const char16_t *)32 void consume(const char16_t *) {}
consume(const char32_t *)33 void consume(const char32_t *) {}
34 
35 //=--------------------------------------=//
36 //     `std::string` member functions     //
37 //=--------------------------------------=//
38 
deref_after_scope_char(bool cond)39 void deref_after_scope_char(bool cond) {
40   const char *c, *d;
41   {
42     std::string s;
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}}
47   std::string s;
48   const char *c2 = s.c_str();
49   if (cond) {
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}}
56   } else {
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}}
59   }
60 }
61 
deref_after_scope_char_data_non_const()62 void deref_after_scope_char_data_non_const() {
63   char *c;
64   {
65     std::string s;
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}}
68   std::string s;
69   char *c2 = s.data();
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}}
72 }
73 
deref_after_scope_wchar_t(bool cond)74 void deref_after_scope_wchar_t(bool cond) {
75   const wchar_t *c, *d;
76   {
77     std::wstring s;
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}}
82   std::wstring s;
83   const wchar_t *c2 = s.c_str();
84   if (cond) {
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}}
91   } else {
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}}
94   }
95 }
96 
deref_after_scope_char16_t_cstr()97 void deref_after_scope_char16_t_cstr() {
98   const char16_t *c16;
99   {
100     std::u16string s16;
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}}
103   std::u16string s16;
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}}
107 }
108 
deref_after_scope_char32_t_data()109 void deref_after_scope_char32_t_data() {
110   const char32_t *c32;
111   {
112     std::u32string s32;
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}}
115   std::u32string s32;
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}}
119 }
120 
multiple_symbols(bool cond)121 void multiple_symbols(bool cond) {
122   const char *c1, *d1;
123   {
124     std::string s1;
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}}
131   std::string s2;
132   const char *c2 = s2.c_str();
133   if (cond) {
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}}
140   } else {
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}}
143 }
144 
deref_after_scope_ok(bool cond)145 void deref_after_scope_ok(bool cond) {
146   const char *c, *d;
147   std::string s;
148   {
149     c = s.c_str();
150     d = s.data();
151   }
152   if (cond)
153     consume(c); // no-warning
154   else
155     consume(d); // no-warning
156 }
157 
deref_after_equals()158 void deref_after_equals() {
159   const char *c;
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}}
165 }
166 
deref_after_plus_equals()167 void deref_after_plus_equals() {
168   const char *c;
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}}
174 }
175 
deref_after_clear()176 void deref_after_clear() {
177   const char *c;
178   std::string s;
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}}
183 }
184 
deref_after_append()185 void deref_after_append() {
186   const char *c;
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}}
192 }
193 
deref_after_assign()194 void deref_after_assign() {
195   const char *c;
196   std::string s;
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}}
201 }
202 
deref_after_erase()203 void deref_after_erase() {
204   const char *c;
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}}
210 }
211 
deref_after_insert()212 void deref_after_insert() {
213   const char *c;
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}}
219 }
220 
deref_after_replace()221 void deref_after_replace() {
222   const char *c;
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}}
228 }
229 
deref_after_pop_back()230 void deref_after_pop_back() {
231   const char *c;
232   std::string s;
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}}
237 }
238 
deref_after_push_back()239 void deref_after_push_back() {
240   const char *c;
241   std::string s;
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}}
246 }
247 
deref_after_reserve()248 void deref_after_reserve() {
249   const char *c;
250   std::string s;
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}}
255 }
256 
deref_after_resize()257 void deref_after_resize() {
258   const char *c;
259   std::string s;
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}}
264 }
265 
deref_after_shrink_to_fit()266 void deref_after_shrink_to_fit() {
267   const char *c;
268   std::string s;
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}}
273 }
274 
deref_after_swap()275 void deref_after_swap() {
276   const char *c;
277   std::string s1, s2;
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}}
282 }
283 
deref_after_std_data()284 void deref_after_std_data() {
285   const char *c;
286   std::string s;
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}}
291 }
292 
293 struct S {
294   std::string s;
nameS295   const char *name() {
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}}
298   }
clearS299   void clear() {
300     s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
301   }
~SS302   ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
303 };
304 
cleared_through_method()305 void cleared_through_method() {
306   S x;
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}}
313 }
314 
destroyed_through_method()315 void destroyed_through_method() {
316   S y;
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}}
323 }
324 
325 //=---------------------------=//
326 //     Other STL functions     //
327 //=---------------------------=//
328 
STL_func_ref()329 void STL_func_ref() {
330   const char *c;
331   std::string s;
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}}
336 }
337 
STL_func_const_ref()338 void STL_func_const_ref() {
339   const char *c;
340   std::string s;
341   c = s.c_str();
342   std::func_const_ref(s);
343   consume(c); // no-warning
344 }
345 
STL_func_value()346 void STL_func_value() {
347   const char *c;
348   std::string s;
349   c = s.c_str();
350   std::func_value(s);
351   consume(c); // no-warning
352 }
353 
func_ptr_known()354 void func_ptr_known() {
355   const char *c;
356   std::string s;
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}}
362 }
363 
func_ptr_unknown(void (* func_ptr)(std::string &))364 void func_ptr_unknown(void (*func_ptr)(std::string &)) {
365   const char *c;
366   std::string s;
367   c = s.c_str();
368   func_ptr(s);
369   consume(c); // no-warning
370 }
371 
func_default_arg()372 void func_default_arg() {
373   const char *c;
374   std::string s;
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}}
379 }
380 
func_addressof()381 void func_addressof() {
382   const char *c;
383   std::string s;
384   c = s.c_str();
385   (void)addressof(s);
386   consume(c); // no-warning
387 }
388 
func_AddressofFn_()389 void func_AddressofFn_() {
390   const char *c;
391   std::string s;
392   c = s.c_str();
393   (void)std::__addressof(s);
394   consume(c); // no-warning
395 }
396 
func_std_data()397 void func_std_data() {
398   const char *c;
399   std::string s;
400   c = std::data(s);
401   consume(c); // no-warning
402 }
403 
404 struct T {
to_stringT405   std::string to_string() { return s; }
406 
407 private:
408   std::string s;
409 };
410 
escape_via_return_temp()411 const char *escape_via_return_temp() {
412   T x;
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}}
417 }
418 
escape_via_return_local()419 const char *escape_via_return_local() {
420   std::string s;
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}}
425 }
426 
427 
428 char *c();
429 class A {};
430 
no_CXXRecordDecl()431 void no_CXXRecordDecl() {
432   A a, *b;
433   *(void **)&b = c() + 1;
434   *b = a; // no-crash
435 }
436 
checkReference(std::string & s)437 void checkReference(std::string &s) {
438   const char *c = s.c_str();
439 }
440