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 30 void consume(const char *) {} 31 void consume(const wchar_t *) {} 32 void consume(const char16_t *) {} 33 void consume(const char32_t *) {} 34 35 //=--------------------------------------=// 36 // `std::string` member functions // 37 //=--------------------------------------=// 38 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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; 295 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 } 299 void clear() { 300 s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}} 301 } 302 ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}} 303 }; 304 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 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 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 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 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 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 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 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 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 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 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 { 405 std::string to_string() { return s; } 406 407 private: 408 std::string s; 409 }; 410 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 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 431 void no_CXXRecordDecl() { 432 A a, *b; 433 *(void **)&b = c() + 1; 434 *b = a; // no-crash 435 } 436 437 void checkReference(std::string &s) { 438 const char *c = s.c_str(); 439 } 440