This revision was automatically updated to reflect the committed changes.
Closed by commit rL337559: [analyzer] Rename DanglingInternalBufferChecker to 
InnerPointerChecker. (authored by rkovacs, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D49553?vs=156291&id=156491#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D49553

Files:
  cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
  cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
  cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
  cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
  cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
  cfe/trunk/test/Analysis/inner-pointer.cpp

Index: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -300,16 +300,15 @@
 
 let ParentPackage = CplusplusAlpha in {
 
-def DanglingInternalBufferChecker : Checker<"DanglingInternalBuffer">,
-  HelpText<"Check for internal raw pointers of C++ standard library containers "
-           "used after deallocation">,
-  DescFile<"DanglingInternalBufferChecker.cpp">;
-
 def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
   HelpText<"Reports destructions of polymorphic objects with a non-virtual "
            "destructor in their base class">,
   DescFile<"DeleteWithNonVirtualDtorChecker.cpp">;
 
+def InnerPointerChecker : Checker<"InnerPointer">,
+  HelpText<"Check for inner pointers of C++ containers used after re/deallocation">,
+  DescFile<"InnerPointerChecker.cpp">;
+
 def IteratorRangeChecker : Checker<"IteratorRange">,
   HelpText<"Check for iterators used outside their valid ranges">,
   DescFile<"IteratorChecker.cpp">;
Index: cfe/trunk/test/Analysis/inner-pointer.cpp
===================================================================
--- cfe/trunk/test/Analysis/inner-pointer.cpp
+++ cfe/trunk/test/Analysis/inner-pointer.cpp
@@ -0,0 +1,291 @@
+//RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.InnerPointer %s -analyzer-output=text -verify
+
+namespace std {
+
+typedef int size_type;
+
+template <typename CharT>
+class basic_string {
+public:
+  basic_string();
+  basic_string(const CharT *s);
+
+  ~basic_string();
+  void clear();
+
+  basic_string &operator=(const basic_string &str);
+  basic_string &operator+=(const basic_string &str);
+
+  const CharT *c_str() const;
+  const CharT *data() const;
+  CharT *data();
+
+  basic_string &append(size_type count, CharT ch);
+  basic_string &assign(size_type count, CharT ch);
+  basic_string &erase(size_type index, size_type count);
+  basic_string &insert(size_type index, size_type count, CharT ch);
+  basic_string &replace(size_type pos, size_type count, const basic_string &str);
+  void pop_back();
+  void push_back(CharT ch);
+  void reserve(size_type new_cap);
+  void resize(size_type count);
+  void shrink_to_fit();
+  void swap(basic_string &other);
+};
+
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+typedef basic_string<char16_t> u16string;
+typedef basic_string<char32_t> u32string;
+
+} // end namespace std
+
+void consume(const char *) {}
+void consume(const wchar_t *) {}
+void consume(const char16_t *) {}
+void consume(const char32_t *) {}
+
+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@-1 {{Inner pointer invalidated 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}}
+  } else {
+    consume(d); // 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 {{Dangling inner pointer obtained here}}
+  }               // expected-note {{Inner pointer invalidated 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}}
+}
+
+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}}
+  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}}
+  } else {
+    consume(d); // 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_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}}
+  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_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}}
+  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 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}}
+    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}}
+  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}}
+  } else {
+    consume(d1); // expected-warning {{Use of memory after it is freed}}
+  }              // expected-note@-1 {{Use of memory after it is freed}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+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}}
+}
+
+void deref_after_scope_ok(bool cond) {
+  const char *c, *d;
+  std::string s;
+  {
+    c = s.c_str();
+    d = s.data();
+  }
+  if (cond)
+    consume(c); // no-warning
+  else
+    consume(d); // no-warning
+}
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
@@ -23,8 +23,8 @@
 
 /// This function provides an additional visitor that augments the bug report
 /// with information relevant to memory errors caused by the misuse of
-/// AF_InternalBuffer symbols.
-std::unique_ptr<BugReporterVisitor> getDanglingBufferBRVisitor(SymbolRef Sym);
+/// AF_InnerBuffer symbols.
+std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym);
 
 } // end namespace allocation_state
 
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -27,7 +27,6 @@
   CloneChecker.cpp
   ConversionChecker.cpp
   CXXSelfAssignmentChecker.cpp
-  DanglingInternalBufferChecker.cpp
   DeadStoresChecker.cpp
   DebugCheckers.cpp
   DeleteWithNonVirtualDtorChecker.cpp
@@ -42,6 +41,7 @@
   GenericTaintChecker.cpp
   GTestChecker.cpp
   IdenticalExprChecker.cpp
+  InnerPointerChecker.cpp
   IteratorChecker.cpp
   IvarInvalidationChecker.cpp
   LLVMConventionsChecker.cpp
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -0,0 +1,252 @@
+//=== InnerPointerChecker.cpp -------------------------------------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a check that marks a raw pointer to a C++ container's
+// inner buffer released when the object is destroyed. This information can
+// be used by MallocChecker to detect use-after-free problems.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AllocationState.h"
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+using PtrSet = llvm::ImmutableSet<SymbolRef>;
+
+// Associate container objects with a set of raw pointer symbols.
+REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
+
+// This is a trick to gain access to PtrSet's Factory.
+namespace clang {
+namespace ento {
+template <>
+struct ProgramStateTrait<PtrSet> : public ProgramStatePartialTrait<PtrSet> {
+  static void *GDMIndex() {
+    static int Index = 0;
+    return &Index;
+  }
+};
+} // end namespace ento
+} // end namespace clang
+
+namespace {
+
+class InnerPointerChecker
+    : public Checker<check::DeadSymbols, check::PostCall> {
+
+  CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
+      InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
+      ShrinkToFitFn, SwapFn;
+
+public:
+  class InnerPointerBRVisitor : public BugReporterVisitor {
+    SymbolRef PtrToBuf;
+
+  public:
+    InnerPointerBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}
+
+    static void *getTag() {
+      static int Tag = 0;
+      return &Tag;
+    }
+
+    void Profile(llvm::FoldingSetNodeID &ID) const override {
+      ID.AddPointer(getTag());
+    }
+
+    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+                                                   const ExplodedNode *PrevN,
+                                                   BugReporterContext &BRC,
+                                                   BugReport &BR) override;
+
+    // FIXME: Scan the map once in the visitor's constructor and do a direct
+    // lookup by region.
+    bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
+      RawPtrMapTy Map = State->get<RawPtrMap>();
+      for (const auto Entry : Map) {
+        if (Entry.second.contains(Sym))
+          return true;
+      }
+      return false;
+    }
+  };
+
+  InnerPointerChecker()
+      : AppendFn("append"), AssignFn("assign"), ClearFn("clear"),
+        CStrFn("c_str"), DataFn("data"), EraseFn("erase"), InsertFn("insert"),
+        PopBackFn("pop_back"), PushBackFn("push_back"), ReplaceFn("replace"),
+        ReserveFn("reserve"), ResizeFn("resize"),
+        ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {}
+
+  /// Check whether the function called on the container object is a
+  /// member function that potentially invalidates pointers referring
+  /// to the objects's internal buffer.
+  bool mayInvalidateBuffer(const CallEvent &Call) const;
+
+  /// Record the connection between the symbol returned by c_str() and the
+  /// corresponding string object region in the ProgramState. Mark the symbol
+  /// released if the string object is destroyed.
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+
+  /// Clean up the ProgramState map.
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+};
+
+} // end anonymous namespace
+
+// [string.require]
+//
+// "References, pointers, and iterators referring to the elements of a
+// basic_string sequence may be invalidated by the following uses of that
+// basic_string object:
+//
+// -- TODO: As an argument to any standard library function taking a reference
+// to non-const basic_string as an argument. For example, as an argument to
+// non-member functions swap(), operator>>(), and getline(), or as an argument
+// to basic_string::swap().
+//
+// -- Calling non-const member functions, except operator[], at, front, back,
+// begin, rbegin, end, and rend."
+//
+bool InnerPointerChecker::mayInvalidateBuffer(const CallEvent &Call) const {
+  if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
+    OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator();
+    if (Opc == OO_Equal || Opc == OO_PlusEqual)
+      return true;
+    return false;
+  }
+  return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
+          Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
+          Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
+          Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
+          Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
+          Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
+          Call.isCalled(SwapFn));
+}
+
+void InnerPointerChecker::checkPostCall(const CallEvent &Call,
+                                        CheckerContext &C) const {
+  const auto *ICall = dyn_cast<CXXInstanceCall>(&Call);
+  if (!ICall)
+    return;
+
+  SVal Obj = ICall->getCXXThisVal();
+  const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(Obj.getAsRegion());
+  if (!ObjRegion)
+    return;
+
+  auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
+  if (TypeDecl->getName() != "basic_string")
+    return;
+
+  ProgramStateRef State = C.getState();
+
+  if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
+    SVal RawPtr = Call.getReturnValue();
+    if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
+      // Start tracking this raw pointer by adding it to the set of symbols
+      // associated with this container object in the program state map.
+      PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
+      const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
+      PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
+      assert(C.wasInlined || !Set.contains(Sym));
+      Set = F.add(Set, Sym);
+      State = State->set<RawPtrMap>(ObjRegion, Set);
+      C.addTransition(State);
+    }
+    return;
+  }
+
+  if (mayInvalidateBuffer(Call)) {
+    if (const PtrSet *PS = State->get<RawPtrMap>(ObjRegion)) {
+      // Mark all pointer symbols associated with the deleted object released.
+      const Expr *Origin = Call.getOriginExpr();
+      for (const auto Symbol : *PS) {
+        // NOTE: `Origin` may be null, and will be stored so in the symbol's
+        // `RefState` in MallocChecker's `RegionState` program state map.
+        State = allocation_state::markReleased(State, Symbol, Origin);
+      }
+      State = State->remove<RawPtrMap>(ObjRegion);
+      C.addTransition(State);
+      return;
+    }
+  }
+}
+
+void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+                                           CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
+  RawPtrMapTy RPM = State->get<RawPtrMap>();
+  for (const auto Entry : RPM) {
+    if (!SymReaper.isLiveRegion(Entry.first)) {
+      // Due to incomplete destructor support, some dead regions might
+      // remain in the program state map. Clean them up.
+      State = State->remove<RawPtrMap>(Entry.first);
+    }
+    if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
+      PtrSet CleanedUpSet = *OldSet;
+      for (const auto Symbol : Entry.second) {
+        if (!SymReaper.isLive(Symbol))
+          CleanedUpSet = F.remove(CleanedUpSet, Symbol);
+      }
+      State = CleanedUpSet.isEmpty()
+                  ? State->remove<RawPtrMap>(Entry.first)
+                  : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
+    }
+  }
+  C.addTransition(State);
+}
+
+std::shared_ptr<PathDiagnosticPiece>
+InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
+                                                      const ExplodedNode *PrevN,
+                                                      BugReporterContext &BRC,
+                                                      BugReport &BR) {
+
+  if (!isSymbolTracked(N->getState(), PtrToBuf) ||
+      isSymbolTracked(PrevN->getState(), PtrToBuf))
+    return nullptr;
+
+  const Stmt *S = PathDiagnosticLocation::getStmt(N);
+  if (!S)
+    return nullptr;
+
+  SmallString<256> Buf;
+  llvm::raw_svector_ostream OS(Buf);
+  OS << "Dangling inner pointer 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) {
+  registerNewDeleteChecker(Mgr);
+  Mgr.registerChecker<InnerPointerChecker>();
+}
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -47,7 +47,7 @@
   AF_CXXNewArray,
   AF_IfNameIndex,
   AF_Alloca,
-  AF_InternalBuffer
+  AF_InnerBuffer
 };
 
 class RefState {
@@ -485,7 +485,7 @@
                         (!SPrev || !SPrev->isReleased());
       assert(!IsReleased ||
              (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
-             (!Stmt && S->getAllocationFamily() == AF_InternalBuffer));
+             (!Stmt && S->getAllocationFamily() == AF_InnerBuffer));
       return IsReleased;
     }
 
@@ -1473,7 +1473,7 @@
     case AF_CXXNew: os << "'new'"; return;
     case AF_CXXNewArray: os << "'new[]'"; return;
     case AF_IfNameIndex: os << "'if_nameindex()'"; return;
-    case AF_InternalBuffer: os << "container-specific allocator"; return;
+    case AF_InnerBuffer: os << "container-specific allocator"; return;
     case AF_Alloca:
     case AF_None: llvm_unreachable("not a deallocation expression");
   }
@@ -1486,7 +1486,7 @@
     case AF_CXXNew: os << "'delete'"; return;
     case AF_CXXNewArray: os << "'delete[]'"; return;
     case AF_IfNameIndex: os << "'if_freenameindex()'"; return;
-    case AF_InternalBuffer: os << "container-specific deallocator"; return;
+    case AF_InnerBuffer: os << "container-specific deallocator"; return;
     case AF_Alloca:
     case AF_None: llvm_unreachable("suspicious argument");
   }
@@ -1662,8 +1662,8 @@
   }
   case AF_CXXNew:
   case AF_CXXNewArray:
-  // FIXME: Add new CheckKind for AF_InternalBuffer.
-  case AF_InternalBuffer: {
+  // FIXME: Add new CheckKind for AF_InnerBuffer.
+  case AF_InnerBuffer: {
     if (IsALeakCheck) {
       if (ChecksEnabled[CK_NewDeleteLeaksChecker])
         return CK_NewDeleteLeaksChecker;
@@ -1995,8 +1995,8 @@
     R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
 
     const RefState *RS = C.getState()->get<RegionState>(Sym);
-    if (RS->getAllocationFamily() == AF_InternalBuffer)
-      R->addVisitor(allocation_state::getDanglingBufferBRVisitor(Sym));
+    if (RS->getAllocationFamily() == AF_InnerBuffer)
+      R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
 
     C.emitReport(std::move(R));
   }
@@ -2870,7 +2870,7 @@
   const Stmt *S = PathDiagnosticLocation::getStmt(N);
   // When dealing with containers, we sometimes want to give a note
   // even if the statement is missing.
-  if (!S && (!RS || RS->getAllocationFamily() != AF_InternalBuffer))
+  if (!S && (!RS || RS->getAllocationFamily() != AF_InnerBuffer))
     return nullptr;
 
   const LocationContext *CurrentLC = N->getLocationContext();
@@ -2903,7 +2903,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";
@@ -2919,7 +2919,7 @@
         case AF_IfNameIndex:
           Msg = "Memory is released";
           break;
-        case AF_InternalBuffer: {
+        case AF_InnerBuffer: {
           OS << "Inner pointer invalidated by call to ";
           if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {
             OS << "destructor";
@@ -3011,7 +3011,7 @@
   // Generate the extra diagnostic.
   PathDiagnosticLocation Pos;
   if (!S) {
-    assert(RS->getAllocationFamily() == AF_InternalBuffer);
+    assert(RS->getAllocationFamily() == AF_InnerBuffer);
     auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
     if (!PostImplCall)
       return nullptr;
@@ -3055,7 +3055,7 @@
 
 ProgramStateRef
 markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
-  AllocationFamily Family = AF_InternalBuffer;
+  AllocationFamily Family = AF_InnerBuffer;
   return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
 }
 
Index: cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
===================================================================
--- cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
+++ cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
@@ -1,291 +0,0 @@
-//RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.DanglingInternalBuffer %s -analyzer-output=text -verify
-
-namespace std {
-
-typedef int size_type;
-
-template <typename CharT>
-class basic_string {
-public:
-  basic_string();
-  basic_string(const CharT *s);
-
-  ~basic_string();
-  void clear();
-
-  basic_string &operator=(const basic_string &str);
-  basic_string &operator+=(const basic_string &str);
-
-  const CharT *c_str() const;
-  const CharT *data() const;
-  CharT *data();
-
-  basic_string &append(size_type count, CharT ch);
-  basic_string &assign(size_type count, CharT ch);
-  basic_string &erase(size_type index, size_type count);
-  basic_string &insert(size_type index, size_type count, CharT ch);
-  basic_string &replace(size_type pos, size_type count, const basic_string &str);
-  void pop_back();
-  void push_back(CharT ch);
-  void reserve(size_type new_cap);
-  void resize(size_type count);
-  void shrink_to_fit();
-  void swap(basic_string &other);
-};
-
-typedef basic_string<char> string;
-typedef basic_string<wchar_t> wstring;
-typedef basic_string<char16_t> u16string;
-typedef basic_string<char32_t> u32string;
-
-} // end namespace std
-
-void consume(const char *) {}
-void consume(const wchar_t *) {}
-void consume(const char16_t *) {}
-void consume(const char32_t *) {}
-
-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@-1 {{Inner pointer invalidated 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}}
-  } else {
-    consume(d); // 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 {{Dangling inner pointer obtained here}}
-  }               // expected-note {{Inner pointer invalidated 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}}
-}
-
-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}}
-  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}}
-  } else {
-    consume(d); // 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_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}}
-  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_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}}
-  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 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}}
-    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}}
-  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}}
-  } else {
-    consume(d1); // expected-warning {{Use of memory after it is freed}}
-  }              // expected-note@-1 {{Use of memory after it is freed}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-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}}
-}
-
-void deref_after_scope_ok(bool cond) {
-  const char *c, *d;
-  std::string s;
-  {
-    c = s.c_str();
-    d = s.data();
-  }
-  if (cond)
-    consume(c); // no-warning
-  else
-    consume(d); // no-warning
-}
Index: cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
@@ -1,253 +0,0 @@
-//=== DanglingInternalBufferChecker.cpp ---------------------------*- C++ -*--//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a check that marks a raw pointer to a C++ container's
-// inner buffer released when the object is destroyed. This information can
-// be used by MallocChecker to detect use-after-free problems.
-//
-//===----------------------------------------------------------------------===//
-
-#include "AllocationState.h"
-#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-using namespace clang;
-using namespace ento;
-
-using PtrSet = llvm::ImmutableSet<SymbolRef>;
-
-// Associate container objects with a set of raw pointer symbols.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
-
-// This is a trick to gain access to PtrSet's Factory.
-namespace clang {
-namespace ento {
-template <>
-struct ProgramStateTrait<PtrSet> : public ProgramStatePartialTrait<PtrSet> {
-  static void *GDMIndex() {
-    static int Index = 0;
-    return &Index;
-  }
-};
-} // end namespace ento
-} // end namespace clang
-
-namespace {
-
-class DanglingInternalBufferChecker
-    : public Checker<check::DeadSymbols, check::PostCall> {
-
-  CallDescription AppendFn, AssignFn, ClearFn, CStrFn, DataFn, EraseFn,
-      InsertFn, PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
-      ShrinkToFitFn, SwapFn;
-
-public:
-  class DanglingBufferBRVisitor : public BugReporterVisitor {
-    SymbolRef PtrToBuf;
-
-  public:
-    DanglingBufferBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}
-
-    static void *getTag() {
-      static int Tag = 0;
-      return &Tag;
-    }
-
-    void Profile(llvm::FoldingSetNodeID &ID) const override {
-      ID.AddPointer(getTag());
-    }
-
-    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
-                                                   const ExplodedNode *PrevN,
-                                                   BugReporterContext &BRC,
-                                                   BugReport &BR) override;
-
-    // FIXME: Scan the map once in the visitor's constructor and do a direct
-    // lookup by region.
-    bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
-      RawPtrMapTy Map = State->get<RawPtrMap>();
-      for (const auto Entry : Map) {
-        if (Entry.second.contains(Sym))
-          return true;
-      }
-      return false;
-    }
-  };
-
-  DanglingInternalBufferChecker()
-      : AppendFn("append"), AssignFn("assign"), ClearFn("clear"),
-        CStrFn("c_str"), DataFn("data"), EraseFn("erase"), InsertFn("insert"),
-        PopBackFn("pop_back"), PushBackFn("push_back"), ReplaceFn("replace"),
-        ReserveFn("reserve"), ResizeFn("resize"),
-        ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {}
-
-  /// Check whether the function called on the container object is a
-  /// member function that potentially invalidates pointers referring
-  /// to the objects's internal buffer.
-  bool mayInvalidateBuffer(const CallEvent &Call) const;
-
-  /// Record the connection between the symbol returned by c_str() and the
-  /// corresponding string object region in the ProgramState. Mark the symbol
-  /// released if the string object is destroyed.
-  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-
-  /// Clean up the ProgramState map.
-  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
-};
-
-} // end anonymous namespace
-
-// [string.require]
-//
-// "References, pointers, and iterators referring to the elements of a
-// basic_string sequence may be invalidated by the following uses of that
-// basic_string object:
-//
-// -- TODO: As an argument to any standard library function taking a reference
-// to non-const basic_string as an argument. For example, as an argument to
-// non-member functions swap(), operator>>(), and getline(), or as an argument
-// to basic_string::swap().
-//
-// -- Calling non-const member functions, except operator[], at, front, back,
-// begin, rbegin, end, and rend."
-//
-bool DanglingInternalBufferChecker::mayInvalidateBuffer(
-    const CallEvent &Call) const {
-  if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
-    OverloadedOperatorKind Opc = MemOpCall->getOriginExpr()->getOperator();
-    if (Opc == OO_Equal || Opc == OO_PlusEqual)
-      return true;
-    return false;
-  }
-  return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
-          Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
-          Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
-          Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
-          Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
-          Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
-          Call.isCalled(SwapFn));
-}
-
-void DanglingInternalBufferChecker::checkPostCall(const CallEvent &Call,
-                                                  CheckerContext &C) const {
-  const auto *ICall = dyn_cast<CXXInstanceCall>(&Call);
-  if (!ICall)
-    return;
-
-  SVal Obj = ICall->getCXXThisVal();
-  const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(Obj.getAsRegion());
-  if (!ObjRegion)
-    return;
-
-  auto *TypeDecl = ObjRegion->getValueType()->getAsCXXRecordDecl();
-  if (TypeDecl->getName() != "basic_string")
-    return;
-
-  ProgramStateRef State = C.getState();
-
-  if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
-    SVal RawPtr = Call.getReturnValue();
-    if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
-      // Start tracking this raw pointer by adding it to the set of symbols
-      // associated with this container object in the program state map.
-      PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
-      const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
-      PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
-      assert(C.wasInlined || !Set.contains(Sym));
-      Set = F.add(Set, Sym);
-      State = State->set<RawPtrMap>(ObjRegion, Set);
-      C.addTransition(State);
-    }
-    return;
-  }
-
-  if (mayInvalidateBuffer(Call)) {
-    if (const PtrSet *PS = State->get<RawPtrMap>(ObjRegion)) {
-      // Mark all pointer symbols associated with the deleted object released.
-      const Expr *Origin = Call.getOriginExpr();
-      for (const auto Symbol : *PS) {
-        // NOTE: `Origin` may be null, and will be stored so in the symbol's
-        // `RefState` in MallocChecker's `RegionState` program state map.
-        State = allocation_state::markReleased(State, Symbol, Origin);
-      }
-      State = State->remove<RawPtrMap>(ObjRegion);
-      C.addTransition(State);
-      return;
-    }
-  }
-}
-
-void DanglingInternalBufferChecker::checkDeadSymbols(SymbolReaper &SymReaper,
-                                                     CheckerContext &C) const {
-  ProgramStateRef State = C.getState();
-  PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
-  RawPtrMapTy RPM = State->get<RawPtrMap>();
-  for (const auto Entry : RPM) {
-    if (!SymReaper.isLiveRegion(Entry.first)) {
-      // Due to incomplete destructor support, some dead regions might
-      // remain in the program state map. Clean them up.
-      State = State->remove<RawPtrMap>(Entry.first);
-    }
-    if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) {
-      PtrSet CleanedUpSet = *OldSet;
-      for (const auto Symbol : Entry.second) {
-        if (!SymReaper.isLive(Symbol))
-          CleanedUpSet = F.remove(CleanedUpSet, Symbol);
-      }
-      State = CleanedUpSet.isEmpty()
-                  ? State->remove<RawPtrMap>(Entry.first)
-                  : State->set<RawPtrMap>(Entry.first, CleanedUpSet);
-    }
-  }
-  C.addTransition(State);
-}
-
-std::shared_ptr<PathDiagnosticPiece>
-DanglingInternalBufferChecker::DanglingBufferBRVisitor::VisitNode(
-    const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
-    BugReport &BR) {
-
-  if (!isSymbolTracked(N->getState(), PtrToBuf) ||
-      isSymbolTracked(PrevN->getState(), PtrToBuf))
-    return nullptr;
-
-  const Stmt *S = PathDiagnosticLocation::getStmt(N);
-  if (!S)
-    return nullptr;
-
-  SmallString<256> Buf;
-  llvm::raw_svector_ostream OS(Buf);
-  OS << "Dangling inner pointer 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>();
-}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to