[analyzer] Add support for data() in DanglingInternalBufferChecker.
authorReka Kovacs <rekanikolett@gmail.com>
Sat, 7 Jul 2018 20:29:24 +0000 (20:29 +0000)
committerReka Kovacs <rekanikolett@gmail.com>
Sat, 7 Jul 2018 20:29:24 +0000 (20:29 +0000)
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

clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
clang/test/Analysis/dangling-internal-buffer.cpp

index 3716f8b..fe575cc 100644 (file)
 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());
index c4228f4..d5a8940 100644 (file)
@@ -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
+}