diff options
| author | Reka Kovacs <rekanikolett@gmail.com> | 2018-07-07 20:29:24 +0000 | 
|---|---|---|
| committer | Reka Kovacs <rekanikolett@gmail.com> | 2018-07-07 20:29:24 +0000 | 
| commit | bd516a61b4c94421472c87b3f2775499f8818b56 (patch) | |
| tree | c4e8f06dca21908b8f692baca49b3378caadd030 | |
| parent | 2a4344537c7450283152061c9b0535e171d14f51 (diff) | |
| download | bcm5719-llvm-bd516a61b4c94421472c87b3f2775499f8818b56.tar.gz bcm5719-llvm-bd516a61b4c94421472c87b3f2775499f8818b56.zip  | |
[analyzer] Add support for data() in DanglingInternalBufferChecker.
DanglingInternalBufferChecker now tracks use-after-free problems related
to the incorrect usage of std::basic_string::data().
Differential Revision: https://reviews.llvm.org/D48532
llvm-svn: 336497
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp | 11 | ||||
| -rw-r--r-- | clang/test/Analysis/dangling-internal-buffer.cpp | 62 | 
2 files changed, 59 insertions, 14 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp index 3716f8b3e20..fe575cc5fca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp @@ -24,15 +24,16 @@  using namespace clang;  using namespace ento; -// FIXME: c_str() may be called on a string object many times, so it should -// have a list of symbols associated with it. +// FIXME: member functions that return a pointer to the container's internal +// buffer may be called on the object many times, so the object's memory +// region should have a list of pointer symbols associated with it.  REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)  namespace {  class DanglingInternalBufferChecker      : public Checker<check::DeadSymbols, check::PostCall> { -  CallDescription CStrFn; +  CallDescription CStrFn, DataFn;  public:    class DanglingBufferBRVisitor : public BugReporterVisitor { @@ -67,7 +68,7 @@ public:      }    }; -  DanglingInternalBufferChecker() : CStrFn("c_str") {} +  DanglingInternalBufferChecker() : CStrFn("c_str"), DataFn("data") {}    /// Record the connection between the symbol returned by c_str() and the    /// corresponding string object region in the ProgramState. Mark the symbol @@ -97,7 +98,7 @@ void DanglingInternalBufferChecker::checkPostCall(const CallEvent &Call,    ProgramStateRef State = C.getState(); -  if (Call.isCalled(CStrFn)) { +  if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {      SVal RawPtr = Call.getReturnValue();      if (!RawPtr.isUnknown()) {        State = State->set<RawPtrMap>(TypedR, RawPtr.getAsSymbol()); diff --git a/clang/test/Analysis/dangling-internal-buffer.cpp b/clang/test/Analysis/dangling-internal-buffer.cpp index c4228f4e32d..d5a8940bae0 100644 --- a/clang/test/Analysis/dangling-internal-buffer.cpp +++ b/clang/test/Analysis/dangling-internal-buffer.cpp @@ -7,6 +7,8 @@ class basic_string {  public:    ~basic_string();    const CharT *c_str() const; +  const CharT *data() const; +  CharT *data();  };  typedef basic_string<char> string; @@ -21,59 +23,92 @@ void consume(const wchar_t *) {}  void consume(const char16_t *) {}  void consume(const char32_t *) {} -void deref_after_scope_char() { +void deref_after_scope_char_cstr() {    const char *c;    {      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}} +  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_char2() { +void deref_after_scope_char_data() {    const char *c;    {      std::string s; -    c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} +    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.c_str(); +  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}} +} + +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}} +  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() { + +void deref_after_scope_wchar_t_cstr() {    const wchar_t *w;    {      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}}  } -void deref_after_scope_char16_t() { +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}} +  std::u16string s16; +  const char16_t *c16_2 = s16.c_str();    consume(c16); // expected-warning {{Use of memory after it is freed}}    // expected-note@-1 {{Use of memory after it is freed}}  } -void deref_after_scope_char32_t() { +void deref_after_scope_char32_t_data() {    const char32_t *c32;    {      std::u32string s32; -    c32 = s32.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}} +    c32 = s32.data(); // expected-note {{Pointer to dangling buffer was obtained here}}    } // expected-note {{Internal buffer is released because the object was destroyed}} +  std::u32string s32; +  const char32_t *c32_2 = s32.data();    consume(c32); // expected-warning {{Use of memory after it is freed}}    // expected-note@-1 {{Use of memory after it is freed}}  } -void deref_after_scope_ok() { +void deref_after_scope_cstr_ok() {    const char *c;    std::string s;    { @@ -81,3 +116,12 @@ void deref_after_scope_ok() {    }    consume(c); // no-warning  } + +void deref_after_scope_data_ok() { +  const char *c; +  std::string s; +  { +    c = s.data(); +  } +  consume(c); // no-warning +}  | 

