rnkovacs created this revision.
rnkovacs added reviewers: NoQ, dcoughlin, xazax.hun, george.karpenkov.
Herald added subscribers: mikhail.ramalho, a.sidorin, dkrupp, szepet, 
baloghadamsoftware, whisperity.

Following the discussion at https://reviews.llvm.org/D49360.
Added two more test cases that show "returning"-type-of notes as well.


Repository:
  rC Clang

https://reviews.llvm.org/D49570

Files:
  lib/StaticAnalyzer/Checkers/AllocationState.h
  lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
  lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  test/Analysis/dangling-internal-buffer.cpp

Index: test/Analysis/dangling-internal-buffer.cpp
===================================================================
--- test/Analysis/dangling-internal-buffer.cpp
+++ test/Analysis/dangling-internal-buffer.cpp
@@ -49,232 +49,264 @@
   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@-1 {{Inner pointer invalidated by call to destructor}}
+    c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+    d = s.data();  // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  }                // expected-note {{Inner buffer deallocated by call to destructor}}
+  // expected-note@-1 {{Inner buffer deallocated by call to destructor}}
   std::string s;
   const char *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}}
+    consume(c); // expected-warning {{Deallocated pointer returned to the caller}}
+    // expected-note@-1 {{Deallocated pointer returned to the caller}}
   } else {
-    consume(d); // expected-warning {{Use of memory after it is freed}}
-    // expected-note@-1 {{Use of memory after it is freed}}
+    consume(d); // expected-warning {{Deallocated pointer returned to the caller}}
+    // expected-note@-1 {{Deallocated pointer returned to the caller}}
   }
 }
 
 void deref_after_scope_char_data_non_const() {
   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' object obtained here}}
+  }               // expected-note {{Inner buffer 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@-1 {{Use of memory after it is freed}}
+  consume(c); // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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@-1 {{Inner pointer invalidated by call to destructor}}
+    c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::wstring' object obtained here}}
+    d = s.data();  // expected-note {{Pointer to inner buffer of 'std::wstring' object obtained here}}
+  }                // expected-note {{Inner buffer deallocated by call to destructor}}
+  // expected-note@-1 {{Inner buffer deallocated 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}}
+    consume(c); // expected-warning {{Deallocated pointer returned to the caller}}
+    // expected-note@-1 {{Deallocated pointer returned to the caller}}
   } else {
-    consume(d); // expected-warning {{Use of memory after it is freed}}
-    // expected-note@-1 {{Use of memory after it is freed}}
+    consume(d); // expected-warning {{Deallocated pointer returned to the caller}}
+    // expected-note@-1 {{Deallocated pointer returned to the caller}}
   }
 }
 
 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' object obtained here}}
+  }                    // expected-note {{Inner buffer 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@-1 {{Use of memory after it is freed}}
+  consume(c16); // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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' object obtained here}}
+  }                   // expected-note {{Inner buffer 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@-1 {{Use of memory after it is freed}}
+  consume(c32); // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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' object obtained here}}
+    d1 = s1.data();  // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
     const char *local = s1.c_str();
     consume(local); // no-warning
-  }                 // expected-note {{Inner pointer invalidated by call to destructor}}
-  // expected-note@-1 {{Inner pointer invalidated by call to destructor}}
+  }                 // expected-note {{Inner buffer deallocated by call to destructor}}
+  // expected-note@-1 {{Inner buffer deallocated by call to destructor}}
   std::string s2;
   const char *c2 = s2.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(c1); // expected-warning {{Use of memory after it is freed}}
-    // expected-note@-1 {{Use of memory after it is freed}}
+    consume(c1); // expected-warning {{Deallocated pointer returned to the caller}}
+    // expected-note@-1 {{Deallocated pointer returned to the caller}}
   } else {
-    consume(d1); // expected-warning {{Use of memory after it is freed}}
-  }              // expected-note@-1 {{Use of memory after it is freed}}
+    consume(d1); // expected-warning {{Deallocated pointer returned to the caller}}
+  }              // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s = "world";   // expected-note {{Inner buffer reallocated by call to 'operator='}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.data();  // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s += " world"; // expected-note {{Inner buffer reallocated by call to 'operator+='}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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@-1 {{Use of memory after it is freed}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.clear();     // expected-note {{Inner buffer reallocated by call to 'clear'}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str();    // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.append(2, 'x'); // expected-note {{Inner buffer reallocated by call to 'append'}}
+  consume(c);       // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.data();     // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.assign(4, 'a'); // expected-note {{Inner buffer reallocated by call to 'assign'}}
+  consume(c);       // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.erase(0, 2); // expected-note {{Inner buffer reallocated by call to 'erase'}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str();       // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.insert(0, 1, 'h'); // expected-note {{Inner buffer reallocated by call to 'insert'}}
+  consume(c);          // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str();             // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.replace(6, 5, "string"); // expected-note {{Inner buffer reallocated by call to 'replace'}}
+  consume(c);                // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.pop_back();  // expected-note {{Inner buffer reallocated by call to 'pop_back'}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.data();     // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.push_back('c'); // expected-note {{Inner buffer reallocated by call to 'push_back'}}
+  consume(c);       // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.reserve(5);  // expected-note {{Inner buffer reallocated by call to 'reserve'}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.data(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.resize(5);  // expected-note {{Inner buffer reallocated by call to 'resize'}}
+  consume(c);   // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s.data();      // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s.shrink_to_fit(); // expected-note {{Inner buffer reallocated by call to 'shrink_to_fit'}}
+  consume(c);        // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 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}}
+  c = s1.data(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+  s1.swap(s2);   // expected-note {{Inner buffer reallocated by call to 'swap'}}
+  consume(c);    // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
+}
+
+struct S {
+  std::string s;
+  const char *name() {
+    return s.c_str(); // expected-note {{Pointer to inner buffer of 'std::string' object obtained here}}
+                      // expected-note@-1 {{Pointer to inner buffer of 'std::string' object obtained here}}
+  }
+  void clear() {
+    s.clear(); // expected-note {{Inner buffer reallocated by call to 'clear'}}
+  }
+  ~S() {} // expected-note {{Inner buffer deallocated by call to destructor on 'std::string' object}}
+};
+
+void cleared_through_method() {
+  S x;
+  const char *c = x.name(); // expected-note {{Calling 'S::name'}}
+                            // expected-note@-1 {{Returning from 'S::name'}}
+  x.clear(); // expected-note {{Calling 'S::clear'}}
+             // expected-note@-1 {{Returning; inner buffer was reallocated}}
+  consume(c); // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
+}
+
+void destroyed_through_method() {
+  S y;
+  const char *c = y.name(); // expected-note {{Calling 'S::name'}}
+                            // expected-note@-1 {{Returning from 'S::name'}}
+  y.~S(); // expected-note {{Calling '~S'}}
+          // expected-note@-1 {{Returning; inner buffer was deallocated}}
+  consume(c); // expected-warning {{Deallocated pointer returned to the caller}}
+  // expected-note@-1 {{Deallocated pointer returned to the caller}}
 }
 
 void deref_after_scope_ok(bool cond) {
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1987,15 +1987,18 @@
       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_InternalBuffer ? "Deallocated pointer returned to the caller"
+                                : "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_InternalBuffer)
+    if (AF == AF_InternalBuffer)
       R->addVisitor(allocation_state::getDanglingBufferBRVisitor(Sym));
 
     C.emitReport(std::move(R));
@@ -2903,7 +2906,7 @@
   StackHintGeneratorForSymbol *StackHint = nullptr;
   SmallString<256> Buf;
   llvm::raw_svector_ostream OS(Buf);
-  
+
   if (Mode == Normal) {
     if (isAllocated(RS, RSPrev, S)) {
       Msg = "Memory is allocated";
@@ -2918,29 +2921,41 @@
         case AF_CXXNewArray:
         case AF_IfNameIndex:
           Msg = "Memory is released";
+          StackHint = new StackHintGeneratorForSymbol(Sym,
+                                              "Returning; memory was released");
           break;
         case AF_InternalBuffer: {
-          OS << "Inner pointer invalidated by call to ";
+          OS << "Inner buffer ";
           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();
             } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
               OS << OpCallE->getDirectCallee()->getNameAsString();
             }
             OS << "'";
+            StackHint = new StackHintGeneratorForSymbol(Sym,
+                                      "Returning; inner buffer was reallocated");
           }
+
+          // Find the type of the container object.
+          const MemRegion *ObjRegion =
+              allocation_state::getContainerObjRegion(statePrev, Sym);
+          const auto *TypedRegion = dyn_cast<TypedValueRegion>(ObjRegion);
+          QualType ObjTy = TypedRegion->getValueType();
+          OS << " on '" << ObjTy.getAsString() << "' object";
+
           Msg = OS.str();
           break;
         }
         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
Index: lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
+++ lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
@@ -212,6 +212,29 @@
   C.addTransition(State);
 }
 
+namespace clang {
+namespace ento {
+namespace allocation_state {
+
+std::unique_ptr<BugReporterVisitor> getDanglingBufferBRVisitor(SymbolRef Sym) {
+  return llvm::make_unique<
+      DanglingInternalBufferChecker::DanglingBufferBRVisitor>(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>
 DanglingInternalBufferChecker::DanglingBufferBRVisitor::VisitNode(
     const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
@@ -225,28 +248,21 @@
   if (!S)
     return nullptr;
 
+  const MemRegion *ObjRegion =
+      allocation_state::getContainerObjRegion(N->getState(), PtrToBuf);
+  const auto *TypedRegion = dyn_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()
+     << "' object 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> getDanglingBufferBRVisitor(SymbolRef Sym) {
-  return llvm::make_unique<
-      DanglingInternalBufferChecker::DanglingBufferBRVisitor>(Sym);
-}
-
-} // end namespace allocation_state
-} // end namespace ento
-} // end namespace clang
-
 void ento::registerDanglingInternalBufferChecker(CheckerManager &Mgr) {
   registerNewDeleteChecker(Mgr);
   Mgr.registerChecker<DanglingInternalBufferChecker>();
Index: lib/StaticAnalyzer/Checkers/AllocationState.h
===================================================================
--- lib/StaticAnalyzer/Checkers/AllocationState.h
+++ lib/StaticAnalyzer/Checkers/AllocationState.h
@@ -26,6 +26,11 @@
 /// AF_InternalBuffer symbols.
 std::unique_ptr<BugReporterVisitor> getDanglingBufferBRVisitor(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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D49570: [analyzer]... Reka Kovacs via Phabricator via cfe-commits

Reply via email to