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