Clang Project

clang_source_code/test/Analysis/inner-pointer.cpp
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"
5namespace std {
6
7template <typename T>
8void func_ref(T &a);
9
10template <typename T>
11void func_const_ref(const T &a);
12
13template <typename T>
14void func_value(T a);
15
16string my_string = "default";
17void default_arg(int a = 42, string &b = my_string);
18
19} // end namespace std
20
21void consume(const char *) {}
22void consume(const wchar_t *) {}
23void consume(const char16_t *) {}
24void consume(const char32_t *) {}
25
26//=--------------------------------------=//
27//     `std::string` member functions     //
28//=--------------------------------------=//
29
30void 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 not equal to 0}}
42    // expected-note@-2 {{Taking true branch}}
43    // expected-note@-3 {{Assuming 'cond' is 0}}
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
53void 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
65void 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 not equal to 0}}
77    // expected-note@-2 {{Taking true branch}}
78    // expected-note@-3 {{Assuming 'cond' is 0}}
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
88void 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
100void 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
112void 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 not equal to 0}}
126    // expected-note@-2 {{Taking true branch}}
127    // expected-note@-3 {{Assuming 'cond' is 0}}
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
136void 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
149void 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
158void 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
167void 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
176void 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
185void 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
194void 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
203void 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
212void 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
221void 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
230void 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
239void 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
248void 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
257void 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
266void 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
275struct 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
287void 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
297void 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
311void 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
320void 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
328void 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
336void 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
346void 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
354void 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
363struct T {
364  std::string to_string() { return s; }
365private:
366  std::string s;
367};
368
369const 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
377const 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
386char *c();
387class A {};
388
389void no_CXXRecordDecl() {
390  A a, *b;
391  *(void **)&b = c() + 1;
392  *b = a; // no-crash
393}
394
395void checkReference(std::string &s) {
396  const char *c = s.c_str();
397}
398