440 lines · cpp
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 -verify4 5#include "Inputs/system-header-simulator-cxx.h"6namespace std {7 8template <typename T>9void func_ref(T &a);10 11template <typename T>12void func_const_ref(const T &a);13 14template <typename T>15void func_value(T a);16 17string my_string = "default";18void default_arg(int a = 42, string &b = my_string);19 20template <class T>21T *addressof(T &arg);22 23template <class T>24T *__addressof(T &arg);25 26char *data(std::string &c);27 28} // end namespace std29 30void consume(const char *) {}31void consume(const wchar_t *) {}32void consume(const char16_t *) {}33void consume(const char32_t *) {}34 35//=--------------------------------------=//36// `std::string` member functions //37//=--------------------------------------=//38 39void 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 62void 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 74void 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 97void 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 109void 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 121void 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-warning129 } // 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 145void 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-warning154 else155 consume(d); // no-warning156}157 158void 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 167void 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 176void 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 185void 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 194void 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 203void 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 212void 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 221void 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 230void 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 239void 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 248void 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 257void 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 266void 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 275void 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 284void 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 293struct 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 305void 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 315void 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 329void 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 338void 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-warning344}345 346void 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-warning352}353 354void 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 364void 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-warning370}371 372void 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 381void func_addressof() {382 const char *c;383 std::string s;384 c = s.c_str();385 (void)addressof(s);386 consume(c); // no-warning387}388 389void func_AddressofFn_() {390 const char *c;391 std::string s;392 c = s.c_str();393 (void)std::__addressof(s);394 consume(c); // no-warning395}396 397void func_std_data() {398 const char *c;399 std::string s;400 c = std::data(s);401 consume(c); // no-warning402}403 404struct T {405 std::string to_string() { return s; }406 407private:408 std::string s;409};410 411const 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 419const 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 428char *c();429class A {};430 431void no_CXXRecordDecl() {432 A a, *b;433 *(void **)&b = c() + 1;434 *b = a; // no-crash435}436 437void checkReference(std::string &s) {438 const char *c = s.c_str();439}440