r339489 - [analyzer] InnerPointerChecker: improve warning messages and notes.

Reka Kovacs via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 10 16:56:57 PDT 2018


Author: rkovacs
Date: Fri Aug 10 16:56:57 2018
New Revision: 339489

URL: http://llvm.org/viewvc/llvm-project?rev=339489&view=rev
Log:
[analyzer] InnerPointerChecker: improve warning messages and notes.

Differential Revision: https://reviews.llvm.org/D49570

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/test/Analysis/inner-pointer.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h?rev=339489&r1=339488&r2=339489&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h Fri Aug 10 16:56:57 2018
@@ -26,6 +26,11 @@ ProgramStateRef markReleased(ProgramStat
 /// AF_InnerBuffer symbols.
 std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym);
 
+/// 'Sym' represents a pointer to the inner buffer of a container object.
+/// This function looks up the memory region of that object in
+/// DanglingInternalBufferChecker's program state map.
+const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym);
+
 } // end namespace allocation_state
 
 } // end namespace ento

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp?rev=339489&r1=339488&r2=339489&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Fri Aug 10 16:56:57 2018
@@ -279,6 +279,28 @@ void InnerPointerChecker::checkDeadSymbo
   C.addTransition(State);
 }
 
+namespace clang {
+namespace ento {
+namespace allocation_state {
+
+std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
+  return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
+}
+
+const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
+  RawPtrMapTy Map = State->get<RawPtrMap>();
+  for (const auto Entry : Map) {
+    if (Entry.second.contains(Sym)) {
+      return Entry.first;
+    }
+  }
+  return nullptr;
+}
+
+} // end namespace allocation_state
+} // end namespace ento
+} // end namespace clang
+
 std::shared_ptr<PathDiagnosticPiece>
 InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
                                                       const ExplodedNode *PrevN,
@@ -292,27 +314,21 @@ InnerPointerChecker::InnerPointerBRVisit
   if (!S)
     return nullptr;
 
+  const MemRegion *ObjRegion =
+      allocation_state::getContainerObjRegion(N->getState(), PtrToBuf);
+  const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
+  QualType ObjTy = TypedRegion->getValueType();
+
   SmallString<256> Buf;
   llvm::raw_svector_ostream OS(Buf);
-  OS << "Dangling inner pointer obtained here";
+  OS << "Pointer to inner buffer of '" << ObjTy.getAsString()
+     << "' obtained here";
   PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
                              N->getLocationContext());
   return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
                                                     nullptr);
 }
 
-namespace clang {
-namespace ento {
-namespace allocation_state {
-
-std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
-  return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
-}
-
-} // end namespace allocation_state
-} // end namespace ento
-} // end namespace clang
-
 void ento::registerInnerPointerChecker(CheckerManager &Mgr) {
   registerInnerPointerCheckerAux(Mgr);
   Mgr.registerChecker<InnerPointerChecker>();

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=339489&r1=339488&r2=339489&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Fri Aug 10 16:56:57 2018
@@ -1996,15 +1996,20 @@ void MallocChecker::ReportUseAfterFree(C
       BT_UseFree[*CheckKind].reset(new BugType(
           CheckNames[*CheckKind], "Use-after-free", categories::MemoryError));
 
+    AllocationFamily AF =
+        C.getState()->get<RegionState>(Sym)->getAllocationFamily();
+
     auto R = llvm::make_unique<BugReport>(*BT_UseFree[*CheckKind],
-                                         "Use of memory after it is freed", N);
+        AF == AF_InnerBuffer
+              ? "Inner pointer of container used after re/deallocation"
+              : "Use of memory after it is freed",
+        N);
 
     R->markInteresting(Sym);
     R->addRange(Range);
     R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
 
-    const RefState *RS = C.getState()->get<RegionState>(Sym);
-    if (RS->getAllocationFamily() == AF_InnerBuffer)
+    if (AF == AF_InnerBuffer)
       R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
 
     C.emitReport(std::move(R));
@@ -2944,13 +2949,22 @@ std::shared_ptr<PathDiagnosticPiece> Mal
         case AF_CXXNewArray:
         case AF_IfNameIndex:
           Msg = "Memory is released";
+          StackHint = new StackHintGeneratorForSymbol(Sym,
+                                              "Returning; memory was released");
           break;
         case AF_InnerBuffer: {
-          OS << "Inner pointer invalidated by call to ";
+          const MemRegion *ObjRegion =
+              allocation_state::getContainerObjRegion(statePrev, Sym);
+          const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
+          QualType ObjTy = TypedRegion->getValueType();
+          OS << "Inner buffer of '" << ObjTy.getAsString() << "' ";
+
           if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {
-            OS << "destructor";
+            OS << "deallocated by call to destructor";
+            StackHint = new StackHintGeneratorForSymbol(Sym,
+                                      "Returning; inner buffer was deallocated");
           } else {
-            OS << "'";
+            OS << "reallocated by call to '";
             const Stmt *S = RS->getStmt();
             if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
               OS << MemCallE->getMethodDecl()->getNameAsString();
@@ -2963,6 +2977,8 @@ std::shared_ptr<PathDiagnosticPiece> Mal
               OS << (D ? D->getNameAsString() : "unknown");
             }
             OS << "'";
+            StackHint = new StackHintGeneratorForSymbol(Sym,
+                                      "Returning; inner buffer was reallocated");
           }
           Msg = OS.str();
           break;
@@ -2970,8 +2986,6 @@ std::shared_ptr<PathDiagnosticPiece> Mal
         case AF_None:
           llvm_unreachable("Unhandled allocation family!");
       }
-      StackHint = new StackHintGeneratorForSymbol(Sym,
-                                             "Returning; memory was released");
 
       // See if we're releasing memory while inlining a destructor
       // (or one of its callees). This turns on various common

Modified: cfe/trunk/test/Analysis/inner-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inner-pointer.cpp?rev=339489&r1=339488&r2=339489&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/inner-pointer.cpp (original)
+++ cfe/trunk/test/Analysis/inner-pointer.cpp Fri Aug 10 16:56:57 2018
@@ -65,10 +65,10 @@ void deref_after_scope_char(bool cond) {
   const char *c, *d;
   {
     std::string 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 at -1 {{Inner pointer invalidated by call to destructor}}
+    c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+    d = s.data();  // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  }                // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
+  // expected-note at -1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
   std::string s;
   const char *c2 = s.c_str();
   if (cond) {
@@ -76,11 +76,11 @@ void deref_after_scope_char(bool cond) {
     // expected-note at -2 {{Taking true branch}}
     // expected-note at -3 {{Assuming 'cond' is 0}}
     // expected-note at -4 {{Taking false branch}}
-    consume(c); // expected-warning {{Use of memory after it is freed}}
-    // expected-note at -1 {{Use of memory after it is freed}}
+    consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
+    // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
   } else {
-    consume(d); // expected-warning {{Use of memory after it is freed}}
-    // expected-note at -1 {{Use of memory after it is freed}}
+    consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}}
+    // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
   }
 }
 
@@ -88,22 +88,22 @@ void deref_after_scope_char_data_non_con
   char *c;
   {
     std::string s;
-    c = s.data(); // expected-note {{Dangling inner pointer obtained here}}
-  }               // expected-note {{Inner pointer invalidated by call to destructor}}
+    c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  }               // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
   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}}
+  consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void deref_after_scope_wchar_t(bool cond) {
   const wchar_t *c, *d;
   {
     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 at -1 {{Inner pointer invalidated by call to destructor}}
+    c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
+    d = s.data();  // expected-note {{Pointer to inner buffer of 'std::wstring' obtained here}}
+  }                // expected-note {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
+  // expected-note at -1 {{Inner buffer of 'std::wstring' deallocated by call to destructor}}
   std::wstring s;
   const wchar_t *c2 = s.c_str();
   if (cond) {
@@ -111,11 +111,11 @@ void deref_after_scope_wchar_t(bool cond
     // expected-note at -2 {{Taking true branch}}
     // expected-note at -3 {{Assuming 'cond' is 0}}
     // expected-note at -4 {{Taking false branch}}
-    consume(c); // expected-warning {{Use of memory after it is freed}}
-    // expected-note at -1 {{Use of memory after it is freed}}
+    consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
+    // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
   } else {
-    consume(d); // expected-warning {{Use of memory after it is freed}}
-    // expected-note at -1 {{Use of memory after it is freed}}
+    consume(d); // expected-warning {{Inner pointer of container used after re/deallocation}}
+    // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
   }
 }
 
@@ -123,36 +123,36 @@ void deref_after_scope_char16_t_cstr() {
   const char16_t *c16;
   {
     std::u16string s16;
-    c16 = s16.c_str(); // expected-note {{Dangling inner pointer obtained here}}
-  }                    // expected-note {{Inner pointer invalidated by call to destructor}}
+    c16 = s16.c_str(); // expected-note {{Pointer to inner buffer of 'std::u16string' obtained here}}
+  }                    // expected-note {{Inner buffer of 'std::u16string' deallocated 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}}
-  // expected-note at -1 {{Use of memory after it is freed}}
+  consume(c16); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void deref_after_scope_char32_t_data() {
   const char32_t *c32;
   {
     std::u32string s32;
-    c32 = s32.data(); // expected-note {{Dangling inner pointer obtained here}}
-  }                   // expected-note {{Inner pointer invalidated by call to destructor}}
+    c32 = s32.data(); // expected-note {{Pointer to inner buffer of 'std::u32string' obtained here}}
+  }                   // expected-note {{Inner buffer of 'std::u32string' deallocated 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}}
-  // expected-note at -1 {{Use of memory after it is freed}}
+  consume(c32); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void multiple_symbols(bool cond) {
   const char *c1, *d1;
   {
     std::string s1;
-    c1 = s1.c_str(); // expected-note {{Dangling inner pointer obtained here}}
-    d1 = s1.data();  // expected-note {{Dangling inner pointer obtained here}}
+    c1 = s1.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+    d1 = s1.data();  // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
     const char *local = s1.c_str();
     consume(local); // no-warning
-  }                 // expected-note {{Inner pointer invalidated by call to destructor}}
-  // expected-note at -1 {{Inner pointer invalidated by call to destructor}}
+  }                 // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
+  // expected-note at -1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
   std::string s2;
   const char *c2 = s2.c_str();
   if (cond) {
@@ -160,11 +160,11 @@ void multiple_symbols(bool cond) {
     // expected-note at -2 {{Taking true branch}}
     // expected-note at -3 {{Assuming 'cond' is 0}}
     // expected-note at -4 {{Taking false branch}}
-    consume(c1); // expected-warning {{Use of memory after it is freed}}
-    // expected-note at -1 {{Use of memory after it is freed}}
+    consume(c1); // expected-warning {{Inner pointer of container used after re/deallocation}}
+    // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
   } else {
-    consume(d1); // expected-warning {{Use of memory after it is freed}}
-  }              // expected-note at -1 {{Use of memory after it is freed}}
+    consume(d1); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  }              // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void deref_after_scope_ok(bool cond) {
@@ -183,127 +183,159 @@ void deref_after_scope_ok(bool cond) {
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s = "world";   // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator='}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.data();  // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s += " world"; // expected-note {{Inner buffer of 'std::string' reallocated by call to 'operator+='}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void deref_after_clear() {
   const char *c;
   std::string s;
-  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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.clear();     // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str();    // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.append(2, 'x'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'append'}}
+  consume(c);       // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.data();     // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.assign(4, 'a'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'assign'}}
+  consume(c);       // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.erase(0, 2); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'erase'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str();       // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.insert(0, 1, 'h'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'insert'}}
+  consume(c);          // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str();             // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.replace(6, 5, "string"); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'replace'}}
+  consume(c);                // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.pop_back();  // expected-note {{Inner buffer of 'std::string' reallocated by call to 'pop_back'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.data();     // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.push_back('c'); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'push_back'}}
+  consume(c);       // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.reserve(5);  // expected-note {{Inner buffer of 'std::string' reallocated by call to 'reserve'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.resize(5);  // expected-note {{Inner buffer of 'std::string' reallocated by call to 'resize'}}
+  consume(c);   // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s.data();      // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s.shrink_to_fit(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'shrink_to_fit'}}
+  consume(c);        // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 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 at -1 {{Use of memory after it is freed}}
+  c = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  s1.swap(s2);   // expected-note {{Inner buffer of 'std::string' reallocated by call to 'swap'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
+}
+
+struct S {
+  std::string s;
+  const char *name() {
+    return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+                      // expected-note at -1 {{Pointer to inner buffer of 'std::string' obtained here}}
+  }
+  void clear() {
+    s.clear(); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'clear'}}
+  }
+  ~S() {} // expected-note {{Inner buffer of 'std::string' deallocated by call to destructor}}
+};
+
+void cleared_through_method() {
+  S x;
+  const char *c = x.name(); // expected-note {{Calling 'S::name'}}
+                            // expected-note at -1 {{Returning from 'S::name'}}
+  x.clear(); // expected-note {{Calling 'S::clear'}}
+             // expected-note at -1 {{Returning; inner buffer was reallocated}}
+  consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
+}
+
+void destroyed_through_method() {
+  S y;
+  const char *c = y.name(); // expected-note {{Calling 'S::name'}}
+                            // expected-note at -1 {{Returning from 'S::name'}}
+  y.~S(); // expected-note {{Calling '~S'}}
+          // expected-note at -1 {{Returning; inner buffer was deallocated}}
+  consume(c); // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 //=---------------------------=//
@@ -313,10 +345,10 @@ void deref_after_swap() {
 void STL_func_ref() {
   const char *c;
   std::string s;
-  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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str();    // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  std::func_ref(s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
+  consume(c);       // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void STL_func_const_ref() {
@@ -339,10 +371,10 @@ 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  func_ptr(s);   // expected-note {{Inner buffer of 'std::string' reallocated by call to 'func_ref'}}
+  consume(c);    // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
 void func_ptr_unknown(void (*func_ptr)(std::string &)) {
@@ -356,32 +388,32 @@ void func_ptr_unknown(void (*func_ptr)(s
 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 at -1 {{Use of memory after it is freed}}
+  c = s.c_str();     // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  default_arg(3, s); // expected-note {{Inner buffer of 'std::string' reallocated by call to 'default_arg'}}
+  consume(c);        // expected-warning {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 }
 
-struct S {
+struct T {
   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 at -1 {{Inner pointer invalidated by call to destructor}}
-  // expected-warning at -2 {{Use of memory after it is freed}}
-  // expected-note at -3 {{Use of memory after it is freed}}
+  T x;
+  return x.to_string().c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+  // expected-note at -1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
+  // expected-warning at -2 {{Inner pointer of container used after re/deallocation}}
+  // expected-note at -3 {{Inner pointer of container used after re/deallocation}}
 }
 
 const char *escape_via_return_local() {
   std::string s;
-  return s.c_str(); // expected-note {{Dangling inner pointer obtained here}}
-                    // expected-note at -1 {{Inner pointer invalidated by call to destructor}}
-} // expected-warning {{Use of memory after it is freed}}
-// expected-note at -1 {{Use of memory after it is freed}}
+  return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' obtained here}}
+                    // expected-note at -1 {{Inner buffer of 'std::string' deallocated by call to destructor}}
+} // expected-warning {{Inner pointer of container used after re/deallocation}}
+// expected-note at -1 {{Inner pointer of container used after re/deallocation}}
 
 
 char *c();




More information about the cfe-commits mailing list