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