r336497 - [analyzer] Add support for data() in DanglingInternalBufferChecker.

Reka Kovacs via cfe-commits cfe-commits at lists.llvm.org
Sat Jul 7 13:29:24 PDT 2018


Author: rkovacs
Date: Sat Jul  7 13:29:24 2018
New Revision: 336497

URL: http://llvm.org/viewvc/llvm-project?rev=336497&view=rev
Log:
[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

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
    cfe/trunk/test/Analysis/dangling-internal-buffer.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp?rev=336497&r1=336496&r2=336497&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp Sat Jul  7 13:29:24 2018
@@ -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::chec
 
   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());

Modified: cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dangling-internal-buffer.cpp?rev=336497&r1=336496&r2=336497&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dangling-internal-buffer.cpp (original)
+++ cfe/trunk/test/Analysis/dangling-internal-buffer.cpp Sat Jul  7 13:29:24 2018
@@ -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 at -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 at -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 at -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 at -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 at -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 at -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 at -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
+}




More information about the cfe-commits mailing list