diff options
| author | Reka Kovacs <rekanikolett@gmail.com> | 2018-07-19 15:10:06 +0000 |
|---|---|---|
| committer | Reka Kovacs <rekanikolett@gmail.com> | 2018-07-19 15:10:06 +0000 |
| commit | c18ecc8489201b363fde22b5af1051f9ddd1dd50 (patch) | |
| tree | 15f545f5123618deb9f0f0e5832fea5bbe1e4553 /clang/test | |
| parent | a2b553b4c9f48f0f2e2bb76d55d5a1407bc56eae (diff) | |
| download | bcm5719-llvm-c18ecc8489201b363fde22b5af1051f9ddd1dd50.tar.gz bcm5719-llvm-c18ecc8489201b363fde22b5af1051f9ddd1dd50.zip | |
[analyzer] Add support for more basic_string API in
DanglingInternalBufferChecker.
A pointer referring to the elements of a basic_string may be invalidated
by calling a non-const member function, except operator[], at, front,
back, begin, rbegin, end, and rend. The checker now warns if the pointer
is used after such operations.
Differential Revision: https://reviews.llvm.org/D49360
llvm-svn: 337463
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/Analysis/dangling-internal-buffer.cpp | 260 |
1 files changed, 200 insertions, 60 deletions
diff --git a/clang/test/Analysis/dangling-internal-buffer.cpp b/clang/test/Analysis/dangling-internal-buffer.cpp index f77229c6304..fa8d5e154b9 100644 --- a/clang/test/Analysis/dangling-internal-buffer.cpp +++ b/clang/test/Analysis/dangling-internal-buffer.cpp @@ -2,13 +2,35 @@ namespace std { -template< typename CharT > +typedef int size_type; + +template <typename CharT> class basic_string { public: + basic_string(); + basic_string(const CharT *s); + ~basic_string(); + void clear(); + + basic_string &operator=(const basic_string &str); + basic_string &operator+=(const basic_string &str); + const CharT *c_str() const; const CharT *data() const; CharT *data(); + + 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); }; typedef basic_string<char> string; @@ -23,73 +45,70 @@ void consume(const wchar_t *) {} void consume(const char16_t *) {} void consume(const char32_t *) {} -void deref_after_scope_char_cstr() { - const char *c; +void deref_after_scope_char(bool cond) { + const char *c, *d; { std::string s; - c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} + 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::string s; const char *c2 = s.c_str(); - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} -} - -void deref_after_scope_char_data() { - const char *c; - { - std::string s; - c = s.data(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} - std::string s; - const char *c2 = s.data(); - consume(c); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + 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}} + } } void deref_after_scope_char_data_non_const() { char *c; { std::string s; - c = s.data(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} + c = s.data(); // expected-note {{Dangling inner pointer obtained here}} + } // expected-note {{Inner pointer invalidated by call to destructor}} std::string s; char *c2 = s.data(); consume(c); // expected-warning {{Use of memory after it is freed}} // expected-note@-1 {{Use of memory after it is freed}} } - -void deref_after_scope_wchar_t_cstr() { - const wchar_t *w; +void deref_after_scope_wchar_t(bool cond) { + const wchar_t *c, *d; { - std::wstring ws; - w = ws.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} - std::wstring ws; - const wchar_t *w2 = ws.c_str(); - consume(w); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} -} - -void deref_after_scope_wchar_t_data() { - const wchar_t *w; - { - std::wstring ws; - w = ws.data(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} - std::wstring ws; - const wchar_t *w2 = ws.data(); - consume(w); // expected-warning {{Use of memory after it is freed}} - // expected-note@-1 {{Use of memory after it is freed}} + 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}} + } } void deref_after_scope_char16_t_cstr() { const char16_t *c16; { std::u16string s16; - c16 = s16.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} + c16 = s16.c_str(); // expected-note {{Dangling inner pointer obtained here}} + } // expected-note {{Inner pointer invalidated by call to destructor}} std::u16string s16; const char16_t *c16_2 = s16.c_str(); consume(c16); // expected-warning {{Use of memory after it is freed}} @@ -100,8 +119,8 @@ void deref_after_scope_char32_t_data() { const char32_t *c32; { std::u32string s32; - c32 = s32.data(); // expected-note {{Pointer to dangling buffer was obtained here}} - } // expected-note {{Internal buffer is released because the object was destroyed}} + c32 = s32.data(); // expected-note {{Dangling inner pointer obtained here}} + } // expected-note {{Inner pointer invalidated by call to destructor}} std::u32string s32; const char32_t *c32_2 = s32.data(); consume(c32); // expected-warning {{Use of memory after it is freed}} @@ -112,12 +131,12 @@ void multiple_symbols(bool cond) { const char *c1, *d1; { std::string s1; - c1 = s1.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} - d1 = s1.data(); // expected-note {{Pointer to dangling buffer was obtained here}} + c1 = s1.c_str(); // expected-note {{Dangling inner pointer obtained here}} + d1 = s1.data(); // expected-note {{Dangling inner pointer obtained here}} const char *local = s1.c_str(); consume(local); // no-warning - } // expected-note {{Internal buffer is released because the object was destroyed}} - // expected-note@-1 {{Internal buffer is released because the object was destroyed}} + } // expected-note {{Inner pointer invalidated by call to destructor}} + // expected-note@-1 {{Inner pointer invalidated by call to destructor}} std::string s2; const char *c2 = s2.c_str(); if (cond) { @@ -129,23 +148,144 @@ void multiple_symbols(bool cond) { // expected-note@-1 {{Use of memory after it is freed}} } else { consume(d1); // expected-warning {{Use of memory after it is freed}} - } // expected-note@-1 {{Use of memory after it is freed}} + } // expected-note@-1 {{Use of memory after it is freed}} +} + +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}} } -void deref_after_scope_cstr_ok() { +void deref_after_clear() { const char *c; std::string s; - { - c = s.c_str(); - } - consume(c); // no-warning + 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}} } -void deref_after_scope_data_ok() { +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() { const char *c; std::string s; + 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}} +} + +void deref_after_scope_ok(bool cond) { + const char *c, *d; + std::string s; { - c = s.data(); + c = s.c_str(); + d = s.data(); } - consume(c); // no-warning + if (cond) + consume(c); // no-warning + else + consume(d); // no-warning } |

