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