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