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