2018-08-01 04:27:11 +08:00
|
|
|
//RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer %s -analyzer-output=text -verify
|
2018-06-09 21:03:49 +08:00
|
|
|
|
|
|
|
namespace std {
|
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
typedef int size_type;
|
|
|
|
|
|
|
|
template <typename CharT>
|
2018-06-09 21:03:49 +08:00
|
|
|
class basic_string {
|
|
|
|
public:
|
2018-07-19 23:10:06 +08:00
|
|
|
basic_string();
|
|
|
|
basic_string(const CharT *s);
|
|
|
|
|
2018-06-09 21:03:49 +08:00
|
|
|
~basic_string();
|
2018-07-19 23:10:06 +08:00
|
|
|
void clear();
|
|
|
|
|
|
|
|
basic_string &operator=(const basic_string &str);
|
|
|
|
basic_string &operator+=(const basic_string &str);
|
|
|
|
|
2018-07-08 03:27:18 +08:00
|
|
|
const CharT *c_str() const;
|
2018-07-08 04:29:24 +08:00
|
|
|
const CharT *data() const;
|
|
|
|
CharT *data();
|
2018-07-19 23:10:06 +08:00
|
|
|
|
|
|
|
basic_string &append(size_type count, CharT ch);
|
|
|
|
basic_string &assign(size_type count, CharT ch);
|
|
|
|
basic_string &erase(size_type index, size_type count);
|
|
|
|
basic_string &insert(size_type index, size_type count, CharT ch);
|
|
|
|
basic_string &replace(size_type pos, size_type count, const basic_string &str);
|
|
|
|
void pop_back();
|
|
|
|
void push_back(CharT ch);
|
|
|
|
void reserve(size_type new_cap);
|
|
|
|
void resize(size_type count);
|
|
|
|
void shrink_to_fit();
|
|
|
|
void swap(basic_string &other);
|
2018-06-09 21:03:49 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef basic_string<char> string;
|
|
|
|
typedef basic_string<wchar_t> wstring;
|
|
|
|
typedef basic_string<char16_t> u16string;
|
|
|
|
typedef basic_string<char32_t> u32string;
|
|
|
|
|
2018-07-30 23:43:45 +08:00
|
|
|
template <typename T>
|
|
|
|
void func_ref(T &a);
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void func_const_ref(const T &a);
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void func_value(T a);
|
|
|
|
|
|
|
|
string my_string = "default";
|
|
|
|
void default_arg(int a = 42, string &b = my_string);
|
|
|
|
|
2018-06-09 21:03:49 +08:00
|
|
|
} // end namespace std
|
|
|
|
|
|
|
|
void consume(const char *) {}
|
|
|
|
void consume(const wchar_t *) {}
|
|
|
|
void consume(const char16_t *) {}
|
|
|
|
void consume(const char32_t *) {}
|
|
|
|
|
2018-07-30 23:43:45 +08:00
|
|
|
//=--------------------------------------=//
|
|
|
|
// `std::string` member functions //
|
|
|
|
//=--------------------------------------=//
|
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
void deref_after_scope_char(bool cond) {
|
|
|
|
const char *c, *d;
|
2018-06-09 21:03:49 +08:00
|
|
|
{
|
|
|
|
std::string s;
|
2018-07-19 23:10:06 +08:00
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
d = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
|
|
|
// expected-note@-1 {{Inner pointer invalidated by call to destructor}}
|
2018-07-08 04:29:24 +08:00
|
|
|
std::string s;
|
|
|
|
const char *c2 = s.c_str();
|
2018-07-19 23:10:06 +08:00
|
|
|
if (cond) {
|
|
|
|
// expected-note@-1 {{Assuming 'cond' is not equal to 0}}
|
|
|
|
// expected-note@-2 {{Taking true branch}}
|
|
|
|
// expected-note@-3 {{Assuming 'cond' is 0}}
|
|
|
|
// expected-note@-4 {{Taking false branch}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
} else {
|
|
|
|
consume(d); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
2018-07-08 04:29:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_scope_char_data_non_const() {
|
|
|
|
char *c;
|
|
|
|
{
|
|
|
|
std::string s;
|
2018-07-19 23:10:06 +08:00
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
2018-07-08 04:29:24 +08:00
|
|
|
std::string s;
|
|
|
|
char *c2 = s.data();
|
2018-06-09 21:03:49 +08:00
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
void deref_after_scope_wchar_t(bool cond) {
|
|
|
|
const wchar_t *c, *d;
|
2018-06-09 21:03:49 +08:00
|
|
|
{
|
2018-07-19 23:10:06 +08:00
|
|
|
std::wstring s;
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
d = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
|
|
|
// expected-note@-1 {{Inner pointer invalidated by call to destructor}}
|
|
|
|
std::wstring s;
|
|
|
|
const wchar_t *c2 = s.c_str();
|
|
|
|
if (cond) {
|
|
|
|
// expected-note@-1 {{Assuming 'cond' is not equal to 0}}
|
|
|
|
// expected-note@-2 {{Taking true branch}}
|
|
|
|
// expected-note@-3 {{Assuming 'cond' is 0}}
|
|
|
|
// expected-note@-4 {{Taking false branch}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
} else {
|
|
|
|
consume(d); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
2018-06-09 21:03:49 +08:00
|
|
|
}
|
|
|
|
|
2018-07-08 04:29:24 +08:00
|
|
|
void deref_after_scope_char16_t_cstr() {
|
2018-06-09 21:03:49 +08:00
|
|
|
const char16_t *c16;
|
|
|
|
{
|
|
|
|
std::u16string s16;
|
2018-07-19 23:10:06 +08:00
|
|
|
c16 = s16.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
2018-07-08 04:29:24 +08:00
|
|
|
std::u16string s16;
|
|
|
|
const char16_t *c16_2 = s16.c_str();
|
2018-06-09 21:03:49 +08:00
|
|
|
consume(c16); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
2018-07-08 04:29:24 +08:00
|
|
|
void deref_after_scope_char32_t_data() {
|
2018-06-09 21:03:49 +08:00
|
|
|
const char32_t *c32;
|
|
|
|
{
|
|
|
|
std::u32string s32;
|
2018-07-19 23:10:06 +08:00
|
|
|
c32 = s32.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
2018-07-08 04:29:24 +08:00
|
|
|
std::u32string s32;
|
|
|
|
const char32_t *c32_2 = s32.data();
|
2018-06-09 21:03:49 +08:00
|
|
|
consume(c32); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
2018-07-12 03:08:02 +08:00
|
|
|
void multiple_symbols(bool cond) {
|
|
|
|
const char *c1, *d1;
|
|
|
|
{
|
|
|
|
std::string s1;
|
2018-07-19 23:10:06 +08:00
|
|
|
c1 = s1.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
d1 = s1.data(); // expected-note {{Dangling inner pointer obtained here}}
|
2018-07-12 03:08:02 +08:00
|
|
|
const char *local = s1.c_str();
|
|
|
|
consume(local); // no-warning
|
2018-07-19 23:10:06 +08:00
|
|
|
} // expected-note {{Inner pointer invalidated by call to destructor}}
|
|
|
|
// expected-note@-1 {{Inner pointer invalidated by call to destructor}}
|
2018-07-12 03:08:02 +08:00
|
|
|
std::string s2;
|
|
|
|
const char *c2 = s2.c_str();
|
|
|
|
if (cond) {
|
|
|
|
// expected-note@-1 {{Assuming 'cond' is not equal to 0}}
|
|
|
|
// expected-note@-2 {{Taking true branch}}
|
|
|
|
// expected-note@-3 {{Assuming 'cond' is 0}}
|
|
|
|
// expected-note@-4 {{Taking false branch}}
|
|
|
|
consume(c1); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
} else {
|
|
|
|
consume(d1); // expected-warning {{Use of memory after it is freed}}
|
2018-07-19 23:10:06 +08:00
|
|
|
} // expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
2018-07-30 23:43:45 +08:00
|
|
|
void deref_after_scope_ok(bool cond) {
|
|
|
|
const char *c, *d;
|
|
|
|
std::string s;
|
|
|
|
{
|
|
|
|
c = s.c_str();
|
|
|
|
d = s.data();
|
|
|
|
}
|
|
|
|
if (cond)
|
|
|
|
consume(c); // no-warning
|
|
|
|
else
|
|
|
|
consume(d); // no-warning
|
|
|
|
}
|
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
void deref_after_equals() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "hello";
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s = "world"; // expected-note {{Inner pointer invalidated by call to 'operator='}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_plus_equals() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "hello";
|
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s += " world"; // expected-note {{Inner pointer invalidated by call to 'operator+='}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
2018-07-12 03:08:02 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
void deref_after_clear() {
|
2018-06-09 21:03:49 +08:00
|
|
|
const char *c;
|
|
|
|
std::string s;
|
2018-07-19 23:10:06 +08:00
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.clear(); // expected-note {{Inner pointer invalidated by call to 'clear'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_append() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "hello";
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.append(2, 'x'); // expected-note {{Inner pointer invalidated by call to 'append'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_assign() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.assign(4, 'a'); // expected-note {{Inner pointer invalidated by call to 'assign'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_erase() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "hello";
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.erase(0, 2); // expected-note {{Inner pointer invalidated by call to 'erase'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
2018-06-09 21:03:49 +08:00
|
|
|
}
|
2018-07-08 04:29:24 +08:00
|
|
|
|
2018-07-19 23:10:06 +08:00
|
|
|
void deref_after_insert() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "ello";
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.insert(0, 1, 'h'); // expected-note {{Inner pointer invalidated by call to 'insert'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_replace() {
|
|
|
|
const char *c;
|
|
|
|
std::string s = "hello world";
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.replace(6, 5, "string"); // expected-note {{Inner pointer invalidated by call to 'replace'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_pop_back() {
|
2018-07-08 04:29:24 +08:00
|
|
|
const char *c;
|
|
|
|
std::string s;
|
2018-07-19 23:10:06 +08:00
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.pop_back(); // expected-note {{Inner pointer invalidated by call to 'pop_back'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_push_back() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.push_back('c'); // expected-note {{Inner pointer invalidated by call to 'push_back'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_reserve() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.reserve(5); // expected-note {{Inner pointer invalidated by call to 'reserve'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_resize() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.resize(5); // expected-note {{Inner pointer invalidated by call to 'resize'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_shrink_to_fit() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s.shrink_to_fit(); // expected-note {{Inner pointer invalidated by call to 'shrink_to_fit'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deref_after_swap() {
|
|
|
|
const char *c;
|
|
|
|
std::string s1, s2;
|
|
|
|
c = s1.data(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
s1.swap(s2); // expected-note {{Inner pointer invalidated by call to 'swap'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
2018-07-30 23:43:45 +08:00
|
|
|
//=---------------------------=//
|
|
|
|
// Other STL functions //
|
|
|
|
//=---------------------------=//
|
|
|
|
|
|
|
|
void STL_func_ref() {
|
|
|
|
const char *c;
|
2018-07-19 23:10:06 +08:00
|
|
|
std::string s;
|
2018-07-30 23:43:45 +08:00
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
std::func_ref(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void STL_func_const_ref() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.c_str();
|
|
|
|
std::func_const_ref(s);
|
|
|
|
consume(c); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void STL_func_value() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.c_str();
|
|
|
|
std::func_value(s);
|
|
|
|
consume(c); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void func_ptr_known() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
void (*func_ptr)(std::string &) = std::func_ref<std::string>;
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
func_ptr(s); // expected-note {{Inner pointer invalidated by call to 'func_ref'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void func_ptr_unknown(void (*func_ptr)(std::string &)) {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.c_str();
|
|
|
|
func_ptr(s);
|
|
|
|
consume(c); // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void func_default_arg() {
|
|
|
|
const char *c;
|
|
|
|
std::string s;
|
|
|
|
c = s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
default_arg(3, s); // expected-note {{Inner pointer invalidated by call to 'default_arg'}}
|
|
|
|
consume(c); // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
2018-07-08 04:29:24 +08:00
|
|
|
}
|
2018-08-03 07:02:08 +08:00
|
|
|
|
|
|
|
struct S {
|
|
|
|
std::string to_string() { return s; }
|
|
|
|
private:
|
|
|
|
std::string s;
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *escape_via_return_temp() {
|
|
|
|
S x;
|
|
|
|
return x.to_string().c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
// expected-note@-1 {{Inner pointer invalidated by call to destructor}}
|
|
|
|
// expected-warning@-2 {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-3 {{Use of memory after it is freed}}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *escape_via_return_local() {
|
|
|
|
std::string s;
|
|
|
|
return s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
|
|
|
|
// expected-note@-1 {{Inner pointer invalidated by call to destructor}}
|
|
|
|
} // expected-warning {{Use of memory after it is freed}}
|
|
|
|
// expected-note@-1 {{Use of memory after it is freed}}
|
2018-08-04 04:42:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
char *c();
|
|
|
|
class A {};
|
|
|
|
|
|
|
|
void no_CXXRecordDecl() {
|
|
|
|
A a, *b;
|
|
|
|
*(void **)&b = c() + 1;
|
|
|
|
*b = a; // no-crash
|
|
|
|
}
|