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