r349344 - Revert rC349281 '[analyzer][MallocChecker][NFC] Document and reorganize some functions'

Kristof Umann via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 17 04:25:48 PST 2018


Author: szelethus
Date: Mon Dec 17 04:25:48 2018
New Revision: 349344

URL: http://llvm.org/viewvc/llvm-project?rev=349344&view=rev
Log:
Revert rC349281 '[analyzer][MallocChecker][NFC] Document and reorganize some functions'

Accidentally commited earlier with the same commit title, but really it
should've been
"Revert rC349283 '[analyzer][MallocChecker] Improve warning messages on double-delete errors'"

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=349344&r1=349343&r2=349344&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Mon Dec 17 04:25:48 2018
@@ -7,41 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file defines a variety of memory management related checkers, such as
-// leak, double free, and use-after-free.
-//
-// The following checkers are defined here:
-//
-//   * MallocChecker
-//       Despite its name, it models all sorts of memory allocations and
-//       de- or reallocation, including but not limited to malloc, free,
-//       relloc, new, delete. It also reports on a variety of memory misuse
-//       errors.
-//       Many other checkers interact very closely with this checker, in fact,
-//       most are merely options to this one. Other checkers may register
-//       MallocChecker, but do not enable MallocChecker's reports (more details
-//       to follow around its field, ChecksEnabled).
-//       It also has a boolean "Optimistic" checker option, which if set to true
-//       will cause the checker to model user defined memory management related
-//       functions annotated via the attribute ownership_takes, ownership_holds
-//       and ownership_returns.
-//
-//   * NewDeleteChecker
-//       Enables the modeling of new, new[], delete, delete[] in MallocChecker,
-//       and checks for related double-free and use-after-free errors.
-//
-//   * NewDeleteLeaksChecker
-//       Checks for leaks related to new, new[], delete, delete[].
-//       Depends on NewDeleteChecker.
-//
-//   * MismatchedDeallocatorChecker
-//       Enables checking whether memory is deallocated with the correspending
-//       allocation function in MallocChecker, such as malloc() allocated
-//       regions are only freed by free(), new by delete, new[] by delete[].
-//
-//  InnerPointerChecker interacts very closely with MallocChecker, but unlike
-//  the above checkers, it has it's own file, hence the many InnerPointerChecker
-//  related headers and non-static functions.
+// This file defines malloc/free checker, which checks for potential memory
+// leaks, double free, and use-after-free problems.
 //
 //===----------------------------------------------------------------------===//
 
@@ -70,10 +37,6 @@
 using namespace clang;
 using namespace ento;
 
-//===----------------------------------------------------------------------===//
-// The types of allocation we're modeling.
-//===----------------------------------------------------------------------===//
-
 namespace {
 
 // Used to check correspondence between allocators and deallocators.
@@ -87,59 +50,28 @@ enum AllocationFamily {
   AF_InnerBuffer
 };
 
-struct MemFunctionInfoTy;
-
-} // end of anonymous namespace
-
-/// Determine family of a deallocation expression.
-static AllocationFamily getAllocationFamily(
-    const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C, const Stmt *S);
-
-/// Print names of allocators and deallocators.
-///
-/// \returns true on success.
-static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
-                                  const Expr *E);
-
-/// Print expected name of an allocator based on the deallocator's
-/// family derived from the DeallocExpr.
-static void printExpectedAllocName(raw_ostream &os,
-                                   const MemFunctionInfoTy  &MemFunctionInfo,
-                                   CheckerContext &C, const Expr *E);
-
-/// Print expected name of a deallocator based on the allocator's
-/// family.
-static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
-
-//===----------------------------------------------------------------------===//
-// The state of a symbol, in terms of memory management.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
 class RefState {
-  enum Kind {
-    // Reference to allocated memory.
-    Allocated,
-    // Reference to zero-allocated memory.
-    AllocatedOfSizeZero,
-    // Reference to released/freed memory.
-    Released,
-    // The responsibility for freeing resources has transferred from
-    // this reference. A relinquished symbol should not be freed.
-    Relinquished,
-    // We are no longer guaranteed to have observed all manipulations
-    // of this pointer/memory. For example, it could have been
-    // passed as a parameter to an opaque function.
-    Escaped
+  enum Kind { // Reference to allocated memory.
+              Allocated,
+              // Reference to zero-allocated memory.
+              AllocatedOfSizeZero,
+              // Reference to released/freed memory.
+              Released,
+              // The responsibility for freeing resources has transferred from
+              // this reference. A relinquished symbol should not be freed.
+              Relinquished,
+              // We are no longer guaranteed to have observed all manipulations
+              // of this pointer/memory. For example, it could have been
+              // passed as a parameter to an opaque function.
+              Escaped
   };
 
   const Stmt *S;
+  unsigned K : 3; // Kind enum, but stored as a bitfield.
+  unsigned Family : 29; // Rest of 32-bit word, currently just an allocation
+                        // family.
 
-  Kind K : 3;
-  AllocationFamily Family : 3;
-
-  RefState(Kind k, const Stmt *s, AllocationFamily family)
+  RefState(Kind k, const Stmt *s, unsigned family)
     : S(s), K(k), Family(family) {
     assert(family != AF_None);
   }
@@ -150,7 +82,7 @@ public:
   bool isRelinquished() const { return K == Relinquished; }
   bool isEscaped() const { return K == Escaped; }
   AllocationFamily getAllocationFamily() const {
-    return Family;
+    return (AllocationFamily)Family;
   }
   const Stmt *getStmt() const { return S; }
 
@@ -158,17 +90,17 @@ public:
     return K == X.K && S == X.S && Family == X.Family;
   }
 
-  static RefState getAllocated(AllocationFamily family, const Stmt *s) {
+  static RefState getAllocated(unsigned family, const Stmt *s) {
     return RefState(Allocated, s, family);
   }
   static RefState getAllocatedOfSizeZero(const RefState *RS) {
     return RefState(AllocatedOfSizeZero, RS->getStmt(),
                     RS->getAllocationFamily());
   }
-  static RefState getReleased(AllocationFamily family, const Stmt *s) {
+  static RefState getReleased(unsigned family, const Stmt *s) {
     return RefState(Released, s, family);
   }
-  static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
+  static RefState getRelinquished(unsigned family, const Stmt *s) {
     return RefState(Relinquished, s, family);
   }
   static RefState getEscaped(const RefState *RS) {
@@ -181,8 +113,8 @@ public:
     ID.AddInteger(Family);
   }
 
-  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
-    switch (K) {
+  void dump(raw_ostream &OS) const {
+    switch (static_cast<Kind>(K)) {
 #define CASE(ID) case ID: OS << #ID; break;
     CASE(Allocated)
     CASE(AllocatedOfSizeZero)
@@ -195,61 +127,23 @@ public:
   LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
 };
 
-} // end of anonymous namespace
-
-REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
-
-/// Check if the memory associated with this symbol was released.
-static bool isReleased(SymbolRef Sym, CheckerContext &C);
-
-/// Update the RefState to reflect the new memory allocation.
-/// The optional \p RetVal parameter specifies the newly allocated pointer
-/// value; if unspecified, the value of expression \p E is used.
-static ProgramStateRef
-MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
-                     AllocationFamily Family = AF_Malloc,
-                     Optional<SVal> RetVal = None);
-
-//===----------------------------------------------------------------------===//
-// The modeling of memory reallocation.
-//
-// The terminology 'toPtr' and 'fromPtr' will be used:
-//   toPtr = realloc(fromPtr, 20);
-//===----------------------------------------------------------------------===//
-
-REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
-
-namespace {
-
-/// The state of 'fromPtr' after reallocation is known to have failed.
-enum OwnershipAfterReallocKind {
-  // The symbol needs to be freed (e.g.: realloc)
-  OAR_ToBeFreedAfterFailure,
-  // The symbol has been freed (e.g.: reallocf)
-  OAR_FreeOnFailure,
-  // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where
-  // 'fromPtr' was allocated:
-  //    void Haha(int *ptr) {
-  //      ptr = realloc(ptr, 67);
-  //      // ...
-  //    }
-  // ).
-  OAR_DoNotTrackAfterFailure
+enum ReallocPairKind {
+  RPToBeFreedAfterFailure,
+  // The symbol has been freed when reallocation failed.
+  RPIsFreeOnFailure,
+  // The symbol does not need to be freed after reallocation fails.
+  RPDoNotTrackAfterFailure
 };
 
-/// Stores information about the 'fromPtr' symbol after reallocation.
-///
-/// This is important because realloc may fail, and that needs special modeling.
-/// Whether reallocation failed or not will not be known until later, so we'll
-/// store whether upon failure 'fromPtr' will be freed, or needs to be freed
-/// later, etc.
+/// \class ReallocPair
+/// Stores information about the symbol being reallocated by a call to
+/// 'realloc' to allow modeling failed reallocation later in the path.
 struct ReallocPair {
-
-  // The 'fromPtr'.
+  // The symbol which realloc reallocated.
   SymbolRef ReallocatedSym;
-  OwnershipAfterReallocKind Kind;
+  ReallocPairKind Kind;
 
-  ReallocPair(SymbolRef S, OwnershipAfterReallocKind K) :
+  ReallocPair(SymbolRef S, ReallocPairKind K) :
     ReallocatedSym(S), Kind(K) {}
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(Kind);
@@ -261,75 +155,7 @@ struct ReallocPair {
   }
 };
 
-} // end of anonymous namespace
-
-REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
-
-//===----------------------------------------------------------------------===//
-// Kinds of memory operations, information about resource managing functions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-enum class MemoryOperationKind {
-  MOK_Allocate,
-  MOK_Free,
-  MOK_Any
-};
-
-struct MemFunctionInfoTy {
-  /// The value of the MallocChecker:Optimistic is stored in this variable.
-  ///
-  /// In pessimistic mode, the checker assumes that it does not know which
-  /// functions might free the memory.
-  /// In optimistic mode, the checker assumes that all user-defined functions
-  /// which might free a pointer are annotated.
-  DefaultBool ShouldIncludeOwnershipAnnotatedFunctions;
-
-  // TODO: Change these to CallDescription, and get rid of lazy initialization.
-  mutable IdentifierInfo *II_alloca = nullptr, *II_win_alloca = nullptr,
-                         *II_malloc = nullptr, *II_free = nullptr,
-                         *II_realloc = nullptr, *II_calloc = nullptr,
-                         *II_valloc = nullptr, *II_reallocf = nullptr,
-                         *II_strndup = nullptr, *II_strdup = nullptr,
-                         *II_win_strdup = nullptr, *II_kmalloc = nullptr,
-                         *II_if_nameindex = nullptr,
-                         *II_if_freenameindex = nullptr, *II_wcsdup = nullptr,
-                         *II_win_wcsdup = nullptr, *II_g_malloc = nullptr,
-                         *II_g_malloc0 = nullptr, *II_g_realloc = nullptr,
-                         *II_g_try_malloc = nullptr,
-                         *II_g_try_malloc0 = nullptr,
-                         *II_g_try_realloc = nullptr, *II_g_free = nullptr,
-                         *II_g_memdup = nullptr, *II_g_malloc_n = nullptr,
-                         *II_g_malloc0_n = nullptr, *II_g_realloc_n = nullptr,
-                         *II_g_try_malloc_n = nullptr,
-                         *II_g_try_malloc0_n = nullptr,
-                         *II_g_try_realloc_n = nullptr;
-
-  void initIdentifierInfo(ASTContext &C) const;
-
-  ///@{
-  /// Check if this is one of the functions which can allocate/reallocate
-  /// memory pointed to by one of its arguments.
-  bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
-  bool isCMemFunction(const FunctionDecl *FD,
-                      ASTContext &C,
-                      AllocationFamily Family,
-                      MemoryOperationKind MemKind) const;
-
-  /// Tells if the callee is one of the builtin new/delete operators, including
-  /// placement operators and other standard overloads.
-  bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
-  ///@}
-};
-
-} // end of anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Definition of the MallocChecker class.
-//===----------------------------------------------------------------------===//
-
-namespace {
+typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo;
 
 class MallocChecker : public Checker<check::DeadSymbols,
                                      check::PointerEscape,
@@ -344,16 +170,26 @@ class MallocChecker : public Checker<che
                                      check::PostStmt<BlockExpr>,
                                      check::PostObjCMessage,
                                      check::Location,
-                                     eval::Assume> {
+                                     eval::Assume>
+{
 public:
-  MemFunctionInfoTy MemFunctionInfo;
+  MallocChecker()
+      : II_alloca(nullptr), II_win_alloca(nullptr), II_malloc(nullptr),
+        II_free(nullptr), II_realloc(nullptr), II_calloc(nullptr),
+        II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
+        II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
+        II_if_nameindex(nullptr), II_if_freenameindex(nullptr),
+        II_wcsdup(nullptr), II_win_wcsdup(nullptr), II_g_malloc(nullptr),
+        II_g_malloc0(nullptr), II_g_realloc(nullptr), II_g_try_malloc(nullptr),
+        II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
+        II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
+        II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
+        II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
+        II_g_try_realloc_n(nullptr) {}
 
-  /// Many checkers are essentially built into this one, so enabling them will
-  /// make MallocChecker perform additional modeling and reporting.
+  /// In pessimistic mode, the checker assumes that it does not know which
+  /// functions might free the memory.
   enum CheckKind {
-    /// When a subchecker is enabled but MallocChecker isn't, model memory
-    /// management but do not emit warnings emitted with MallocChecker only
-    /// enabled.
     CK_MallocChecker,
     CK_NewDeleteChecker,
     CK_NewDeleteLeaksChecker,
@@ -362,7 +198,13 @@ public:
     CK_NumCheckKinds
   };
 
-  using LeakInfo = std::pair<const ExplodedNode*, const MemRegion*>;
+  enum class MemoryOperationKind {
+    MOK_Allocate,
+    MOK_Free,
+    MOK_Any
+  };
+
+  DefaultBool IsOptimistic;
 
   DefaultBool ChecksEnabled[CK_NumCheckKinds];
   CheckName CheckNames[CK_NumCheckKinds];
@@ -405,74 +247,71 @@ private:
   mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
   mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
   mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
-
-  // TODO: Remove mutable by moving the initializtaion to the registry function.
+  mutable IdentifierInfo *II_alloca, *II_win_alloca, *II_malloc, *II_free,
+                         *II_realloc, *II_calloc, *II_valloc, *II_reallocf,
+                         *II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
+                         *II_if_nameindex, *II_if_freenameindex, *II_wcsdup,
+                         *II_win_wcsdup, *II_g_malloc, *II_g_malloc0,
+                         *II_g_realloc, *II_g_try_malloc, *II_g_try_malloc0,
+                         *II_g_try_realloc, *II_g_free, *II_g_memdup,
+                         *II_g_malloc_n, *II_g_malloc0_n, *II_g_realloc_n,
+                         *II_g_try_malloc_n, *II_g_try_malloc0_n,
+                         *II_g_try_realloc_n;
   mutable Optional<uint64_t> KernelZeroFlagVal;
 
+  void initIdentifierInfo(ASTContext &C) const;
+
+  /// Determine family of a deallocation expression.
+  AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const;
+
+  /// Print names of allocators and deallocators.
+  ///
+  /// \returns true on success.
+  bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+                             const Expr *E) const;
+
+  /// Print expected name of an allocator based on the deallocator's
+  /// family derived from the DeallocExpr.
+  void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+                              const Expr *DeallocExpr) const;
+  /// Print expected name of a deallocator based on the allocator's
+  /// family.
+  void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const;
+
+  ///@{
+  /// Check if this is one of the functions which can allocate/reallocate memory
+  /// pointed to by one of its arguments.
+  bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
+  bool isCMemFunction(const FunctionDecl *FD,
+                      ASTContext &C,
+                      AllocationFamily Family,
+                      MemoryOperationKind MemKind) const;
+  bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
+  ///@}
+
   /// Process C++ operator new()'s allocation, which is the part of C++
   /// new-expression that goes before the constructor.
   void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C,
                             SVal Target) const;
 
   /// Perform a zero-allocation check.
-  ///
-  /// \param [in] E The expression that allocates memory.
-  /// \param [in] IndexOfSizeArg Index of the argument that specifies the size
-  ///   of the memory that needs to be allocated. E.g. for malloc, this would be
-  ///   0.
-  /// \param [in] RetVal Specifies the newly allocated pointer value;
-  ///   if unspecified, the value of expression \p E is used.
-  static ProgramStateRef ProcessZeroAllocCheck(CheckerContext &C, const Expr *E,
-                                               const unsigned IndexOfSizeArg,
-                                               ProgramStateRef State,
-                                               Optional<SVal> RetVal = None);
+  /// The optional \p RetVal parameter specifies the newly allocated pointer
+  /// value; if unspecified, the value of expression \p E is used.
+  ProgramStateRef ProcessZeroAllocation(CheckerContext &C, const Expr *E,
+                                        const unsigned AllocationSizeArg,
+                                        ProgramStateRef State,
+                                        Optional<SVal> RetVal = None) const;
 
-  /// Model functions with the ownership_returns attribute.
-  ///
-  /// User-defined function may have the ownership_returns attribute, which
-  /// annotates that the function returns with an object that was allocated on
-  /// the heap, and passes the ownertship to the callee.
-  ///
-  ///   void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);
-  ///
-  /// It has two parameters:
-  ///   - first: name of the resource (e.g. 'malloc')
-  ///   - (OPTIONAL) second: size of the allocated region
-  ///
-  /// \param [in] CE The expression that allocates memory.
-  /// \param [in] Att The ownership_returns attribute.
-  /// \param [in] State The \c ProgramState right before allocation.
-  /// \returns The ProgramState right after allocation.
   ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
                                        const CallExpr *CE,
                                        const OwnershipAttr* Att,
                                        ProgramStateRef State) const;
-
-  /// Models memory allocation.
-  ///
-  /// \param [in] CE The expression that allocates memory.
-  /// \param [in] SizeEx Size of the memory that needs to be allocated.
-  /// \param [in] Init The value the allocated memory needs to be initialized.
-  /// with. For example, \c calloc initializes the allocated memory to 0,
-  /// malloc leaves it undefined.
-  /// \param [in] State The \c ProgramState right before allocation.
-  /// \returns The ProgramState right after allocation.
   static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
                                       const Expr *SizeEx, SVal Init,
                                       ProgramStateRef State,
                                       AllocationFamily Family = AF_Malloc);
-
-  /// Models memory allocation.
-  ///
-  /// \param [in] CE The expression that allocates memory.
-  /// \param [in] Size Size of the memory that needs to be allocated.
-  /// \param [in] Init The value the allocated memory needs to be initialized.
-  /// with. For example, \c calloc initializes the allocated memory to 0,
-  /// malloc leaves it undefined.
-  /// \param [in] State The \c ProgramState right before allocation.
-  /// \returns The ProgramState right after allocation.
   static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
-                                      SVal Size, SVal Init,
+                                      SVal SizeEx, SVal Init,
                                       ProgramStateRef State,
                                       AllocationFamily Family = AF_Malloc);
 
@@ -485,124 +324,49 @@ private:
   performKernelMalloc(const CallExpr *CE, CheckerContext &C,
                       const ProgramStateRef &State) const;
 
-  /// Model functions with the ownership_takes and ownership_holds attributes.
-  ///
-  /// User-defined function may have the ownership_takes and/or ownership_holds
-  /// attributes, which annotates that the function frees the memory passed as a
-  /// parameter.
-  ///
-  ///   void __attribute((ownership_takes(malloc, 1))) my_free(void *);
-  ///   void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
-  ///
-  /// They have two parameters:
-  ///   - first: name of the resource (e.g. 'malloc')
-  ///   - second: index of the parameter the attribute applies to
-  ///
-  /// \param [in] CE The expression that frees memory.
-  /// \param [in] Att The ownership_takes or ownership_holds attribute.
-  /// \param [in] State The \c ProgramState right before allocation.
-  /// \returns The ProgramState right after deallocation.
+  /// Update the RefState to reflect the new memory allocation.
+  /// The optional \p RetVal parameter specifies the newly allocated pointer
+  /// value; if unspecified, the value of expression \p E is used.
+  static ProgramStateRef
+  MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
+                       AllocationFamily Family = AF_Malloc,
+                       Optional<SVal> RetVal = None);
+
   ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
                               const OwnershipAttr* Att,
                               ProgramStateRef State) const;
-
-  /// Models memory deallocation.
-  ///
-  /// \param [in] CE The expression that frees memory.
-  /// \param [in] State The \c ProgramState right before allocation.
-  /// \param [in] Num Index of the argument that needs to be freed. This is
-  ///   normally 0, but for custom free functions it may be different.
-  /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
-  ///   attribute.
-  /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
-  ///   to have been allocated, or in other words, the symbol to be freed was
-  ///   registered as allocated by this checker. In the following case, \c ptr
-  ///   isn't known to be allocated.
-  ///      void Haha(int *ptr) {
-  ///        ptr = realloc(ptr, 67);
-  ///        // ...
-  ///      }
-  /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
-  ///   we're modeling returns with Null on failure.
-  /// \returns The ProgramState right after deallocation.
   ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
-                             ProgramStateRef State, unsigned Num,
+                             ProgramStateRef state, unsigned Num,
                              bool Hold,
-                             bool &IsKnownToBeAllocated,
+                             bool &ReleasedAllocated,
                              bool ReturnsNullOnFailure = false) const;
-
-  /// Models memory deallocation.
-  ///
-  /// \param [in] ArgExpr The variable who's pointee needs to be freed.
-  /// \param [in] ParentExpr The expression that frees the memory.
-  /// \param [in] State The \c ProgramState right before allocation.
-  ///   normally 0, but for custom free functions it may be different.
-  /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
-  ///   attribute.
-  /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
-  ///   to have been allocated, or in other words, the symbol to be freed was
-  ///   registered as allocated by this checker. In the following case, \c ptr
-  ///   isn't known to be allocated.
-  ///      void Haha(int *ptr) {
-  ///        ptr = realloc(ptr, 67);
-  ///        // ...
-  ///      }
-  /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
-  ///   we're modeling returns with Null on failure.
-  /// \returns The ProgramState right after deallocation.
-  ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
+  ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg,
                              const Expr *ParentExpr,
                              ProgramStateRef State,
                              bool Hold,
-                             bool &IsKnownToBeAllocated,
+                             bool &ReleasedAllocated,
                              bool ReturnsNullOnFailure = false) const;
 
-  // TODO: Needs some refactoring, as all other deallocation modeling
-  // functions are suffering from out parameters and messy code due to how
-  // realloc is handled.
-  //
-  /// Models memory reallocation.
-  ///
-  /// \param [in] CE The expression that reallocated memory
-  /// \param [in] FreesMemOnFailure Whether if reallocation fails, the supplied
-  ///   memory should be freed.
-  /// \param [in] State The \c ProgramState right before reallocation.
-  /// \param [in] SuffixWithN Whether the reallocation function we're modeling
-  ///   has an '_n' suffix, such as g_realloc_n.
-  /// \returns The ProgramState right after reallocation.
   ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
-                                bool ShouldFreeOnFail,
+                                bool FreesMemOnFailure,
                                 ProgramStateRef State,
                                 bool SuffixWithN = false) const;
-
-  /// Evaluates the buffer size that needs to be allocated.
-  ///
-  /// \param [in] Blocks The amount of blocks that needs to be allocated.
-  /// \param [in] BlockBytes The size of a block.
-  /// \returns The symbolic value of \p Blocks * \p BlockBytes.
   static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
                                    const Expr *BlockBytes);
-
-  /// Models zero initialized array allocation.
-  ///
-  /// \param [in] CE The expression that reallocated memory
-  /// \param [in] State The \c ProgramState right before reallocation.
-  /// \returns The ProgramState right after allocation.
   static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
                                    ProgramStateRef State);
 
-  /// If in \p S  \p Sym is used, check whether \p Sym was already freed.
+  /// Check if the memory associated with this symbol was released.
+  bool isReleased(SymbolRef Sym, CheckerContext &C) const;
+
   bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
 
-  /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero
-  /// sized memory region.
   void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
                              const Stmt *S) const;
 
-  /// If in \p S \p Sym is being freed, check whether \p Sym was already freed.
   bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
 
-  /// Check if the function is known to free memory, or if it is
+  /// Check if the function is known free memory, or if it is
   /// "interesting" and should be modeled explicitly.
   ///
   /// \param [out] EscapingSymbol A function might not free memory in general,
@@ -616,12 +380,12 @@ private:
                                    ProgramStateRef State,
                                    SymbolRef &EscapingSymbol) const;
 
-  /// Implementation of the checkPointerEscape callbacks.
+  // Implementation of the checkPointerEscape callbacks.
   ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
-                                        const InvalidatedSymbols &Escaped,
-                                        const CallEvent *Call,
-                                        PointerEscapeKind Kind,
-                                        bool IsConstPointerEscape) const;
+                                  const InvalidatedSymbols &Escaped,
+                                  const CallEvent *Call,
+                                  PointerEscapeKind Kind,
+                                  bool(*CheckRefState)(const RefState*)) const;
 
   // Implementation of the checkPreStmt and checkEndFunction callbacks.
   void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
@@ -640,7 +404,6 @@ private:
   ///@}
   static bool SummarizeValue(raw_ostream &os, SVal V);
   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
-
   void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
                      const Expr *DeallocExpr) const;
   void ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
@@ -666,149 +429,143 @@ private:
 
   /// Find the location of the allocation for Sym on the path leading to the
   /// exploded node N.
-  static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
-                                    CheckerContext &C);
-
+  LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+                             CheckerContext &C) const;
 
   void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
-};
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Definition of MallocBugVisitor.
-//===----------------------------------------------------------------------===//
-
-/// The bug visitor which allows us to print extra diagnostics along the
-/// BugReport path. For example, showing the allocation site of the leaked
-/// region.
-class MallocBugVisitor final : public BugReporterVisitor {
-protected:
-  enum NotificationMode {
-    Normal,
-    ReallocationFailed
-  };
-
-  // The allocated region symbol tracked by the main analysis.
-  SymbolRef Sym;
-
-  // The mode we are in, i.e. what kind of diagnostics will be emitted.
-  NotificationMode Mode;
 
-  // A symbol from when the primary region should have been reallocated.
-  SymbolRef FailedReallocSymbol;
+  /// The bug visitor which allows us to print extra diagnostics along the
+  /// BugReport path. For example, showing the allocation site of the leaked
+  /// region.
+  class MallocBugVisitor final : public BugReporterVisitor {
+  protected:
+    enum NotificationMode {
+      Normal,
+      ReallocationFailed
+    };
+
+    // The allocated region symbol tracked by the main analysis.
+    SymbolRef Sym;
+
+    // The mode we are in, i.e. what kind of diagnostics will be emitted.
+    NotificationMode Mode;
+
+    // A symbol from when the primary region should have been reallocated.
+    SymbolRef FailedReallocSymbol;
+
+    // A C++ destructor stack frame in which memory was released. Used for
+    // miscellaneous false positive suppression.
+    const StackFrameContext *ReleaseDestructorLC;
 
-  // A C++ destructor stack frame in which memory was released. Used for
-  // miscellaneous false positive suppression.
-  const StackFrameContext *ReleaseDestructorLC;
+    bool IsLeak;
 
-  bool IsLeak;
-
-public:
-  MallocBugVisitor(SymbolRef S, bool isLeak = false)
-      : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
-        ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
-
-  static void *getTag() {
-    static int Tag = 0;
-    return &Tag;
-  }
-
-  void Profile(llvm::FoldingSetNodeID &ID) const override {
-    ID.AddPointer(getTag());
-    ID.AddPointer(Sym);
-  }
-
-  /// Did not track -> allocated. Other state (released) -> allocated.
-  static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
-                                 const Stmt *Stmt) {
-    return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
-            (RSCurr && (RSCurr->isAllocated() ||
-                        RSCurr->isAllocatedOfSizeZero())) &&
-            (!RSPrev || !(RSPrev->isAllocated() ||
-                         RSPrev->isAllocatedOfSizeZero())));
-  }
-
-  /// Did not track -> released. Other state (allocated) -> released.
-  /// The statement associated with the release might be missing.
-  static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
-                                const Stmt *Stmt) {
-    bool IsReleased = (RSCurr && RSCurr->isReleased()) &&
-                      (!RSPrev || !RSPrev->isReleased());
-    assert(!IsReleased ||
-           (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
-           (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
-    return IsReleased;
-  }
-
-  /// Did not track -> relinquished. Other state (allocated) -> relinquished.
-  static inline bool isRelinquished(const RefState *RSCurr,
-                                    const RefState *RSPrev,
-                                    const Stmt *Stmt) {
-    return (Stmt && (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) ||
-                     isa<ObjCPropertyRefExpr>(Stmt)) &&
-            (RSCurr && RSCurr->isRelinquished()) &&
-            (!RSPrev || !RSPrev->isRelinquished()));
-  }
-
-  /// If the expression is not a call, and the state change is
-  /// released -> allocated, it must be the realloc return value
-  /// check. If we have to handle more cases here, it might be cleaner just
-  /// to track this extra bit in the state itself.
-  static inline bool hasReallocFailed(const RefState *RSCurr,
-                                      const RefState *RSPrev,
-                                      const Stmt *Stmt) {
-    return ((!Stmt || !isa<CallExpr>(Stmt)) &&
-            (RSCurr && (RSCurr->isAllocated() ||
-                        RSCurr->isAllocatedOfSizeZero())) &&
-            (RSPrev && !(RSPrev->isAllocated() ||
-                        RSPrev->isAllocatedOfSizeZero())));
-  }
-
-  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
-                                                 BugReporterContext &BRC,
-                                                 BugReport &BR) override;
-
-  std::shared_ptr<PathDiagnosticPiece>
-  getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
-             BugReport &BR) override {
-    if (!IsLeak)
-      return nullptr;
-
-    PathDiagnosticLocation L =
-      PathDiagnosticLocation::createEndOfPath(EndPathNode,
-                                              BRC.getSourceManager());
-    // Do not add the statement itself as a range in case of leak.
-    return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
-                                                       false);
-  }
-
-private:
-  class StackHintGeneratorForReallocationFailed
-      : public StackHintGeneratorForSymbol {
   public:
-    StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
-      : StackHintGeneratorForSymbol(S, M) {}
+    MallocBugVisitor(SymbolRef S, bool isLeak = false)
+        : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
+          ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
+
+    static void *getTag() {
+      static int Tag = 0;
+      return &Tag;
+    }
+
+    void Profile(llvm::FoldingSetNodeID &ID) const override {
+      ID.AddPointer(getTag());
+      ID.AddPointer(Sym);
+    }
+
+    inline bool isAllocated(const RefState *S, const RefState *SPrev,
+                            const Stmt *Stmt) {
+      // Did not track -> allocated. Other state (released) -> allocated.
+      return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
+              (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
+              (!SPrev || !(SPrev->isAllocated() ||
+                           SPrev->isAllocatedOfSizeZero())));
+    }
+
+    inline bool isReleased(const RefState *S, const RefState *SPrev,
+                           const Stmt *Stmt) {
+      // Did not track -> released. Other state (allocated) -> released.
+      // The statement associated with the release might be missing.
+      bool IsReleased = (S && S->isReleased()) &&
+                        (!SPrev || !SPrev->isReleased());
+      assert(!IsReleased ||
+             (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
+             (!Stmt && S->getAllocationFamily() == AF_InnerBuffer));
+      return IsReleased;
+    }
+
+    inline bool isRelinquished(const RefState *S, const RefState *SPrev,
+                               const Stmt *Stmt) {
+      // Did not track -> relinquished. Other state (allocated) -> relinquished.
+      return (Stmt && (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) ||
+                                              isa<ObjCPropertyRefExpr>(Stmt)) &&
+              (S && S->isRelinquished()) &&
+              (!SPrev || !SPrev->isRelinquished()));
+    }
+
+    inline bool isReallocFailedCheck(const RefState *S, const RefState *SPrev,
+                                     const Stmt *Stmt) {
+      // If the expression is not a call, and the state change is
+      // released -> allocated, it must be the realloc return value
+      // check. If we have to handle more cases here, it might be cleaner just
+      // to track this extra bit in the state itself.
+      return ((!Stmt || !isa<CallExpr>(Stmt)) &&
+              (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
+              (SPrev && !(SPrev->isAllocated() ||
+                          SPrev->isAllocatedOfSizeZero())));
+    }
+
+    std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+                                                   BugReporterContext &BRC,
+                                                   BugReport &BR) override;
+
+    std::shared_ptr<PathDiagnosticPiece>
+    getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
+               BugReport &BR) override {
+      if (!IsLeak)
+        return nullptr;
 
-    std::string getMessageForArg(const Expr *ArgE,
-                                 unsigned ArgIndex) override {
-      // Printed parameters start at 1, not 0.
-      ++ArgIndex;
+      PathDiagnosticLocation L =
+        PathDiagnosticLocation::createEndOfPath(EndPathNode,
+                                                BRC.getSourceManager());
+      // Do not add the statement itself as a range in case of leak.
+      return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
+                                                         false);
+    }
+
+  private:
+    class StackHintGeneratorForReallocationFailed
+        : public StackHintGeneratorForSymbol {
+    public:
+      StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
+        : StackHintGeneratorForSymbol(S, M) {}
+
+      std::string getMessageForArg(const Expr *ArgE,
+                                   unsigned ArgIndex) override {
+        // Printed parameters start at 1, not 0.
+        ++ArgIndex;
 
-      SmallString<200> buf;
-      llvm::raw_svector_ostream os(buf);
+        SmallString<200> buf;
+        llvm::raw_svector_ostream os(buf);
 
-      os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
-         << " parameter failed";
+        os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+           << " parameter failed";
 
-      return os.str();
-    }
+        return os.str();
+      }
 
-    std::string getMessageForReturn(const CallExpr *CallExpr) override {
-      return "Reallocation of returned value failed";
-    }
+      std::string getMessageForReturn(const CallExpr *CallExpr) override {
+        return "Reallocation of returned value failed";
+      }
+    };
   };
 };
+} // end anonymous namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
+REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
+REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
 
 // A map from the freed symbol to the symbol representing the return value of
 // the free function.
@@ -828,11 +585,7 @@ public:
 };
 } // end anonymous namespace
 
-//===----------------------------------------------------------------------===//
-// Methods of MemFunctionInfoTy.
-//===----------------------------------------------------------------------===//
-
-void MemFunctionInfoTy::initIdentifierInfo(ASTContext &Ctx) const {
+void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
   if (II_malloc)
     return;
   II_alloca = &Ctx.Idents.get("alloca");
@@ -871,8 +624,7 @@ void MemFunctionInfoTy::initIdentifierIn
   II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");
 }
 
-bool MemFunctionInfoTy::isMemFunction(const FunctionDecl *FD,
-                                      ASTContext &C) const {
+bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
   if (isCMemFunction(FD, C, AF_Malloc, MemoryOperationKind::MOK_Any))
     return true;
 
@@ -888,10 +640,10 @@ bool MemFunctionInfoTy::isMemFunction(co
   return false;
 }
 
-bool MemFunctionInfoTy::isCMemFunction(const FunctionDecl *FD,
-                                       ASTContext &C,
-                                       AllocationFamily Family,
-                                       MemoryOperationKind MemKind) const {
+bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
+                                   ASTContext &C,
+                                   AllocationFamily Family,
+                                   MemoryOperationKind MemKind) const {
   if (!FD)
     return false;
 
@@ -944,7 +696,7 @@ bool MemFunctionInfoTy::isCMemFunction(c
   if (Family != AF_Malloc)
     return false;
 
-  if (ShouldIncludeOwnershipAnnotatedFunctions && FD->hasAttrs()) {
+  if (IsOptimistic && FD->hasAttrs()) {
     for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
       OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
       if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
@@ -959,7 +711,10 @@ bool MemFunctionInfoTy::isCMemFunction(c
 
   return false;
 }
-bool MemFunctionInfoTy::isStandardNewDelete(const FunctionDecl *FD,
+
+// Tells if the callee is one of the builtin new/delete operators, including
+// placement operators and other standard overloads.
+bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
                                         ASTContext &C) const {
   if (!FD)
     return false;
@@ -976,10 +731,6 @@ bool MemFunctionInfoTy::isStandardNewDel
   return !L.isValid() || C.getSourceManager().isInSystemHeader(L);
 }
 
-//===----------------------------------------------------------------------===//
-// Methods of MallocChecker and MallocBugVisitor.
-//===----------------------------------------------------------------------===//
-
 llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
   const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const {
   // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
@@ -1078,35 +829,28 @@ void MallocChecker::checkPostStmt(const
     return;
 
   ProgramStateRef State = C.getState();
-  bool IsKnownToBeAllocatedMemory = false;
+  bool ReleasedAllocatedMemory = false;
 
   if (FD->getKind() == Decl::Function) {
-    MemFunctionInfo.initIdentifierInfo(C.getASTContext());
+    initIdentifierInfo(C.getASTContext());
     IdentifierInfo *FunI = FD->getIdentifier();
 
-    if (FunI == MemFunctionInfo.II_malloc ||
-        FunI == MemFunctionInfo.II_g_malloc ||
-        FunI == MemFunctionInfo.II_g_try_malloc) {
-      switch(CE->getNumArgs()) {
-      default:
+    if (FunI == II_malloc || FunI == II_g_malloc || FunI == II_g_try_malloc) {
+      if (CE->getNumArgs() < 1)
         return;
-      case 1:
+      if (CE->getNumArgs() < 3) {
         State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case 2:
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-        break;
-      case 3:
+        if (CE->getNumArgs() == 1)
+          State = ProcessZeroAllocation(C, CE, 0, State);
+      } else if (CE->getNumArgs() == 3) {
         llvm::Optional<ProgramStateRef> MaybeState =
           performKernelMalloc(CE, C, State);
         if (MaybeState.hasValue())
           State = MaybeState.getValue();
         else
           State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-        break;
       }
-    } else if (FunI == MemFunctionInfo.II_kmalloc) {
+    } else if (FunI == II_kmalloc) {
       if (CE->getNumArgs() < 1)
         return;
       llvm::Optional<ProgramStateRef> MaybeState =
@@ -1115,112 +859,97 @@ void MallocChecker::checkPostStmt(const
         State = MaybeState.getValue();
       else
         State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-    } else if (FunI == MemFunctionInfo.II_valloc) {
+    } else if (FunI == II_valloc) {
       if (CE->getNumArgs() < 1)
         return;
       State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-    } else if (FunI == MemFunctionInfo.II_realloc ||
-               FunI == MemFunctionInfo.II_g_realloc ||
-               FunI == MemFunctionInfo.II_g_try_realloc) {
-      State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/false, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (FunI == MemFunctionInfo.II_reallocf) {
-      State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/true, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (FunI == MemFunctionInfo.II_calloc) {
+      State = ProcessZeroAllocation(C, CE, 0, State);
+    } else if (FunI == II_realloc || FunI == II_g_realloc ||
+               FunI == II_g_try_realloc) {
+      State = ReallocMemAux(C, CE, false, State);
+      State = ProcessZeroAllocation(C, CE, 1, State);
+    } else if (FunI == II_reallocf) {
+      State = ReallocMemAux(C, CE, true, State);
+      State = ProcessZeroAllocation(C, CE, 1, State);
+    } else if (FunI == II_calloc) {
       State = CallocMem(C, CE, State);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (FunI == MemFunctionInfo.II_free ||
-               FunI == MemFunctionInfo.II_g_free) {
-      State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
-    } else if (FunI == MemFunctionInfo.II_strdup ||
-               FunI == MemFunctionInfo.II_win_strdup ||
-               FunI == MemFunctionInfo.II_wcsdup ||
-               FunI == MemFunctionInfo.II_win_wcsdup) {
+      State = ProcessZeroAllocation(C, CE, 0, State);
+      State = ProcessZeroAllocation(C, CE, 1, State);
+    } else if (FunI == II_free || FunI == II_g_free) {
+      State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+    } else if (FunI == II_strdup || FunI == II_win_strdup ||
+               FunI == II_wcsdup || FunI == II_win_wcsdup) {
       State = MallocUpdateRefState(C, CE, State);
-    } else if (FunI == MemFunctionInfo.II_strndup) {
+    } else if (FunI == II_strndup) {
       State = MallocUpdateRefState(C, CE, State);
-    } else if (FunI == MemFunctionInfo.II_alloca ||
-               FunI == MemFunctionInfo.II_win_alloca) {
+    } else if (FunI == II_alloca || FunI == II_win_alloca) {
       if (CE->getNumArgs() < 1)
         return;
       State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
                            AF_Alloca);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-    } else if (MemFunctionInfo.isStandardNewDelete(FD, C.getASTContext())) {
+      State = ProcessZeroAllocation(C, CE, 0, State);
+    } else if (isStandardNewDelete(FD, C.getASTContext())) {
       // Process direct calls to operator new/new[]/delete/delete[] functions
       // as distinct from new/new[]/delete/delete[] expressions that are
       // processed by the checkPostStmt callbacks for CXXNewExpr and
       // CXXDeleteExpr.
-      switch(FD->getOverloadedOperator()) {
-      case OO_New:
+      OverloadedOperatorKind K = FD->getOverloadedOperator();
+      if (K == OO_New) {
         State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
                              AF_CXXNew);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case OO_Array_New:
+        State = ProcessZeroAllocation(C, CE, 0, State);
+      }
+      else if (K == OO_Array_New) {
         State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
                              AF_CXXNewArray);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case OO_Delete:
-      case OO_Array_Delete:
-        State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
-        break;
-      default:
-        llvm_unreachable("not a new/delete operator");
+        State = ProcessZeroAllocation(C, CE, 0, State);
       }
-    } else if (FunI == MemFunctionInfo.II_if_nameindex) {
+      else if (K == OO_Delete || K == OO_Array_Delete)
+        State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+      else
+        llvm_unreachable("not a new/delete operator");
+    } else if (FunI == II_if_nameindex) {
       // Should we model this differently? We can allocate a fixed number of
       // elements with zeros in the last one.
       State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
                            AF_IfNameIndex);
-    } else if (FunI == MemFunctionInfo.II_if_freenameindex) {
-      State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
-    } else if (FunI == MemFunctionInfo.II_g_malloc0 ||
-               FunI == MemFunctionInfo.II_g_try_malloc0) {
+    } else if (FunI == II_if_freenameindex) {
+      State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+    } else if (FunI == II_g_malloc0 || FunI == II_g_try_malloc0) {
       if (CE->getNumArgs() < 1)
         return;
       SValBuilder &svalBuilder = C.getSValBuilder();
       SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
       State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-    } else if (FunI == MemFunctionInfo.II_g_memdup) {
+      State = ProcessZeroAllocation(C, CE, 0, State);
+    } else if (FunI == II_g_memdup) {
       if (CE->getNumArgs() < 2)
         return;
       State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (FunI == MemFunctionInfo.II_g_malloc_n ||
-               FunI == MemFunctionInfo.II_g_try_malloc_n ||
-               FunI == MemFunctionInfo.II_g_malloc0_n ||
-               FunI == MemFunctionInfo.II_g_try_malloc0_n) {
+      State = ProcessZeroAllocation(C, CE, 1, State);
+    } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
+               FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
       if (CE->getNumArgs() < 2)
         return;
       SVal Init = UndefinedVal();
-      if (FunI == MemFunctionInfo.II_g_malloc0_n ||
-          FunI == MemFunctionInfo.II_g_try_malloc0_n) {
+      if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
         SValBuilder &SB = C.getSValBuilder();
         Init = SB.makeZeroVal(SB.getContext().CharTy);
       }
       SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
       State = MallocMemAux(C, CE, TotalSize, Init, State);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (FunI == MemFunctionInfo.II_g_realloc_n ||
-               FunI == MemFunctionInfo.II_g_try_realloc_n) {
+      State = ProcessZeroAllocation(C, CE, 0, State);
+      State = ProcessZeroAllocation(C, CE, 1, State);
+    } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) {
       if (CE->getNumArgs() < 3)
         return;
-      State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/false, State,
-                            /*SuffixWithN*/true);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-      State = ProcessZeroAllocCheck(C, CE, 2, State);
+      State = ReallocMemAux(C, CE, false, State, true);
+      State = ProcessZeroAllocation(C, CE, 1, State);
+      State = ProcessZeroAllocation(C, CE, 2, State);
     }
   }
 
-  if (MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions ||
-      ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
+  if (IsOptimistic || ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
     // Check all the attributes, if there are any.
     // There can be multiple of these attributes.
     if (FD->hasAttrs())
@@ -1240,9 +969,9 @@ void MallocChecker::checkPostStmt(const
 }
 
 // Performs a 0-sized allocations check.
-ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
-    CheckerContext &C, const Expr *E, const unsigned IndexOfSizeArg,
-    ProgramStateRef State, Optional<SVal> RetVal) {
+ProgramStateRef MallocChecker::ProcessZeroAllocation(
+    CheckerContext &C, const Expr *E, const unsigned AllocationSizeArg,
+    ProgramStateRef State, Optional<SVal> RetVal) const {
   if (!State)
     return nullptr;
 
@@ -1252,7 +981,7 @@ ProgramStateRef MallocChecker::ProcessZe
   const Expr *Arg = nullptr;
 
   if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
-    Arg = CE->getArg(IndexOfSizeArg);
+    Arg = CE->getArg(AllocationSizeArg);
   }
   else if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
     if (NE->isArray())
@@ -1314,9 +1043,7 @@ static QualType getDeepPointeeType(QualT
   return Result;
 }
 
-/// \returns true if the constructor invoked by \p NE has an argument of a
-/// pointer/reference to a record type.
-static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) {
+static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
 
   const CXXConstructExpr *ConstructE = NE->getConstructExpr();
   if (!ConstructE)
@@ -1346,17 +1073,11 @@ static bool hasNonTrivialConstructorCall
 void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
                                          CheckerContext &C,
                                          SVal Target) const {
-  if (!MemFunctionInfo.isStandardNewDelete(NE->getOperatorNew(),
-                                           C.getASTContext()))
+  if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
     return;
 
   ParentMap &PM = C.getLocationContext()->getParentMap();
-
-  // Non-trivial constructors have a chance to escape 'this', but marking all
-  // invocations of trivial constructors as escaped would cause too great of
-  // reduction of true positives, so let's just do that for constructors that
-  // have an argument of a pointer-to-record type.
-  if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE))
+  if (!PM.isConsumedExpr(NE) && treatUnusedNewEscaped(NE))
     return;
 
   ProgramStateRef State = C.getState();
@@ -1367,7 +1088,7 @@ void MallocChecker::processNewAllocation
   State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
                                                            : AF_CXXNew, Target);
   State = addExtentSize(C, NE, State, Target);
-  State = ProcessZeroAllocCheck(C, NE, 0, State, Target);
+  State = ProcessZeroAllocation(C, NE, 0, State, Target);
   C.addTransition(State);
 }
 
@@ -1436,14 +1157,13 @@ void MallocChecker::checkPreStmt(const C
     if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
       checkUseAfterFree(Sym, C, DE->getArgument());
 
-  if (!MemFunctionInfo.isStandardNewDelete(DE->getOperatorDelete(),
-                                           C.getASTContext()))
+  if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext()))
     return;
 
   ProgramStateRef State = C.getState();
-  bool IsKnownToBeAllocated;
+  bool ReleasedAllocated;
   State = FreeMemAux(C, DE->getArgument(), DE, State,
-                     /*Hold*/false, IsKnownToBeAllocated);
+                     /*Hold*/false, ReleasedAllocated);
 
   C.addTransition(State);
 }
@@ -1483,10 +1203,10 @@ void MallocChecker::checkPostObjCMessage
     if (!*FreeWhenDone)
       return;
 
-  bool IsKnownToBeAllocatedMemory;
+  bool ReleasedAllocatedMemory;
   ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0),
                                      Call.getOriginExpr(), C.getState(),
-                                     /*Hold=*/true, IsKnownToBeAllocatedMemory,
+                                     /*Hold=*/true, ReleasedAllocatedMemory,
                                      /*RetNullOnFailure=*/true);
 
   C.addTransition(State);
@@ -1499,7 +1219,7 @@ MallocChecker::MallocMemReturnsAttr(Chec
   if (!State)
     return nullptr;
 
-  if (Att->getModule() != MemFunctionInfo.II_malloc)
+  if (Att->getModule() != II_malloc)
     return nullptr;
 
   OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
@@ -1565,9 +1285,11 @@ ProgramStateRef MallocChecker::MallocMem
   return MallocUpdateRefState(C, CE, State, Family);
 }
 
-static ProgramStateRef
-MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
-                     AllocationFamily Family, Optional<SVal> RetVal) {
+ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
+                                                    const Expr *E,
+                                                    ProgramStateRef State,
+                                                    AllocationFamily Family,
+                                                    Optional<SVal> RetVal) {
   if (!State)
     return nullptr;
 
@@ -1595,15 +1317,15 @@ ProgramStateRef MallocChecker::FreeMemAt
   if (!State)
     return nullptr;
 
-  if (Att->getModule() != MemFunctionInfo.II_malloc)
+  if (Att->getModule() != II_malloc)
     return nullptr;
 
-  bool IsKnownToBeAllocated = false;
+  bool ReleasedAllocated = false;
 
   for (const auto &Arg : Att->args()) {
     ProgramStateRef StateI = FreeMemAux(
         C, CE, State, Arg.getASTIndex(),
-        Att->getOwnKind() == OwnershipAttr::Holds, IsKnownToBeAllocated);
+        Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated);
     if (StateI)
       State = StateI;
   }
@@ -1615,7 +1337,7 @@ ProgramStateRef MallocChecker::FreeMemAu
                                           ProgramStateRef State,
                                           unsigned Num,
                                           bool Hold,
-                                          bool &IsKnownToBeAllocated,
+                                          bool &ReleasedAllocated,
                                           bool ReturnsNullOnFailure) const {
   if (!State)
     return nullptr;
@@ -1624,7 +1346,7 @@ ProgramStateRef MallocChecker::FreeMemAu
     return nullptr;
 
   return FreeMemAux(C, CE->getArg(Num), CE, State, Hold,
-                    IsKnownToBeAllocated, ReturnsNullOnFailure);
+                    ReleasedAllocated, ReturnsNullOnFailure);
 }
 
 /// Checks if the previous call to free on the given symbol failed - if free
@@ -1642,9 +1364,8 @@ static bool didPreviousFreeFail(ProgramS
   return false;
 }
 
-static AllocationFamily getAllocationFamily(
-  const MemFunctionInfoTy  &MemFunctionInfo, CheckerContext &C, const Stmt *S) {
-
+AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
+                                                    const Stmt *S) const {
   if (!S)
     return AF_None;
 
@@ -1656,10 +1377,10 @@ static AllocationFamily getAllocationFam
 
     ASTContext &Ctx = C.getASTContext();
 
-    if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any))
+    if (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any))
       return AF_Malloc;
 
-    if (MemFunctionInfo.isStandardNewDelete(FD, Ctx)) {
+    if (isStandardNewDelete(FD, Ctx)) {
       OverloadedOperatorKind Kind = FD->getOverloadedOperator();
       if (Kind == OO_New || Kind == OO_Delete)
         return AF_CXXNew;
@@ -1667,12 +1388,10 @@ static AllocationFamily getAllocationFam
         return AF_CXXNewArray;
     }
 
-    if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex,
-                                       MemoryOperationKind::MOK_Any))
+    if (isCMemFunction(FD, Ctx, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
       return AF_IfNameIndex;
 
-    if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Alloca,
-                                       MemoryOperationKind::MOK_Any))
+    if (isCMemFunction(FD, Ctx, AF_Alloca, MemoryOperationKind::MOK_Any))
       return AF_Alloca;
 
     return AF_None;
@@ -1690,8 +1409,8 @@ static AllocationFamily getAllocationFam
   return AF_None;
 }
 
-static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
-                                  const Expr *E) {
+bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+                                          const Expr *E) const {
   if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
     // FIXME: This doesn't handle indirect calls.
     const FunctionDecl *FD = CE->getDirectCallee();
@@ -1730,10 +1449,9 @@ static bool printAllocDeallocName(raw_os
   return false;
 }
 
-static void printExpectedAllocName(raw_ostream &os,
-                                   const MemFunctionInfoTy  &MemFunctionInfo,
-                                   CheckerContext &C, const Expr *E) {
-  AllocationFamily Family = getAllocationFamily(MemFunctionInfo, C, E);
+void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+                                           const Expr *E) const {
+  AllocationFamily Family = getAllocationFamily(C, E);
 
   switch(Family) {
     case AF_Malloc: os << "malloc()"; return;
@@ -1746,7 +1464,8 @@ static void printExpectedAllocName(raw_o
   }
 }
 
-static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
+void MallocChecker::printExpectedDeallocName(raw_ostream &os,
+                                             AllocationFamily Family) const {
   switch(Family) {
     case AF_Malloc: os << "free()"; return;
     case AF_CXXNew: os << "'delete'"; return;
@@ -1763,7 +1482,7 @@ ProgramStateRef MallocChecker::FreeMemAu
                                           const Expr *ParentExpr,
                                           ProgramStateRef State,
                                           bool Hold,
-                                          bool &IsKnownToBeAllocated,
+                                          bool &ReleasedAllocated,
                                           bool ReturnsNullOnFailure) const {
 
   if (!State)
@@ -1837,9 +1556,6 @@ ProgramStateRef MallocChecker::FreeMemAu
   const RefState *RsBase = State->get<RegionState>(SymBase);
   SymbolRef PreviousRetStatusSymbol = nullptr;
 
-  IsKnownToBeAllocated = RsBase && (RsBase->isAllocated() ||
-                                    RsBase->isAllocatedOfSizeZero());
-
   if (RsBase) {
 
     // Memory returned by alloca() shouldn't be freed.
@@ -1862,8 +1578,7 @@ ProgramStateRef MallocChecker::FreeMemAu
 
       // Check if an expected deallocation function matches the real one.
       bool DeallocMatchesAlloc =
-        RsBase->getAllocationFamily() ==
-                            getAllocationFamily(MemFunctionInfo, C, ParentExpr);
+        RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
       if (!DeallocMatchesAlloc) {
         ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
                                 ParentExpr, RsBase, SymBase, Hold);
@@ -1889,6 +1604,9 @@ ProgramStateRef MallocChecker::FreeMemAu
     return nullptr;
   }
 
+  ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
+                                              RsBase->isAllocatedOfSizeZero());
+
   // Clean out the info on previous call to free return info.
   State = State->remove<FreeReturnValue>(SymBase);
 
@@ -1904,7 +1622,7 @@ ProgramStateRef MallocChecker::FreeMemAu
   }
 
   AllocationFamily Family = RsBase ? RsBase->getAllocationFamily()
-                          : getAllocationFamily(MemFunctionInfo, C, ParentExpr);
+                                   : getAllocationFamily(C, ParentExpr);
   // Normal free.
   if (Hold)
     return State->set<RegionState>(SymBase,
@@ -1954,8 +1672,8 @@ Optional<MallocChecker::CheckKind>
 MallocChecker::getCheckIfTracked(CheckerContext &C,
                                  const Stmt *AllocDeallocStmt,
                                  bool IsALeakCheck) const {
-  return getCheckIfTracked(
-      getAllocationFamily(MemFunctionInfo, C, AllocDeallocStmt), IsALeakCheck);
+  return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt),
+                           IsALeakCheck);
 }
 
 Optional<MallocChecker::CheckKind>
@@ -2093,7 +1811,7 @@ void MallocChecker::ReportBadFree(Checke
     else
       os << "not memory allocated by ";
 
-    printExpectedAllocName(os, MemFunctionInfo, C, DeallocExpr);
+    printExpectedAllocName(os, C, DeallocExpr);
 
     auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], os.str(), N);
     R->markInteresting(MR);
@@ -2400,7 +2118,7 @@ void MallocChecker::ReportFunctionPointe
 
 ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
                                              const CallExpr *CE,
-                                             bool ShouldFreeOnFail,
+                                             bool FreesOnFail,
                                              ProgramStateRef State,
                                              bool SuffixWithN) const {
   if (!State)
@@ -2465,32 +2183,33 @@ ProgramStateRef MallocChecker::ReallocMe
   if (!FromPtr || !ToPtr)
     return nullptr;
 
-  bool IsKnownToBeAllocated = false;
+  bool ReleasedAllocated = false;
 
   // If the size is 0, free the memory.
   if (SizeIsZero)
-    // The semantics of the return value are:
-    // If size was equal to 0, either NULL or a pointer suitable to be passed
-    // to free() is returned. We just free the input pointer and do not add
-    // any constrains on the output pointer.
     if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0,
-                                               false, IsKnownToBeAllocated))
+                                               false, ReleasedAllocated)){
+      // The semantics of the return value are:
+      // If size was equal to 0, either NULL or a pointer suitable to be passed
+      // to free() is returned. We just free the input pointer and do not add
+      // any constrains on the output pointer.
       return stateFree;
+    }
 
   // Default behavior.
   if (ProgramStateRef stateFree =
-        FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) {
+        FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
 
     ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
                                                 UnknownVal(), stateFree);
     if (!stateRealloc)
       return nullptr;
 
-    OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
-    if (ShouldFreeOnFail)
-      Kind = OAR_FreeOnFailure;
-    else if (!IsKnownToBeAllocated)
-      Kind = OAR_DoNotTrackAfterFailure;
+    ReallocPairKind Kind = RPToBeFreedAfterFailure;
+    if (FreesOnFail)
+      Kind = RPIsFreeOnFailure;
+    else if (!ReleasedAllocated)
+      Kind = RPDoNotTrackAfterFailure;
 
     // Record the info about the reallocated symbol so that we could properly
     // process failed reallocation.
@@ -2518,9 +2237,9 @@ ProgramStateRef MallocChecker::CallocMem
   return MallocMemAux(C, CE, TotalSize, zeroVal, State);
 }
 
-MallocChecker::LeakInfo
+LeakInfo
 MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
-                                 CheckerContext &C) {
+                                 CheckerContext &C) const {
   const LocationContext *LeakContext = N->getLocationContext();
   // Walk the ExplodedGraph backwards and find the first node that referred to
   // the tracked symbol.
@@ -2701,10 +2420,9 @@ void MallocChecker::checkPreCall(const C
 
     ASTContext &Ctx = C.getASTContext();
     if (ChecksEnabled[CK_MallocChecker] &&
-        (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc,
-                                        MemoryOperationKind::MOK_Free) ||
-         MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex,
-                                        MemoryOperationKind::MOK_Free)))
+        (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
+         isCMemFunction(FD, Ctx, AF_IfNameIndex,
+                        MemoryOperationKind::MOK_Free)))
       return;
   }
 
@@ -2807,7 +2525,7 @@ void MallocChecker::checkPostStmt(const
   C.addTransition(state);
 }
 
-static bool isReleased(SymbolRef Sym, CheckerContext &C) {
+bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
   assert(Sym);
   const RefState *RS = C.getState()->get<RegionState>(Sym);
   return (RS && RS->isReleased());
@@ -2883,17 +2601,13 @@ ProgramStateRef MallocChecker::evalAssum
     SymbolRef ReallocSym = I.getData().ReallocatedSym;
     if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
       if (RS->isReleased()) {
-        switch(I.getData().Kind) {
-        case OAR_ToBeFreedAfterFailure:
+        if (I.getData().Kind == RPToBeFreedAfterFailure)
           state = state->set<RegionState>(ReallocSym,
               RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
-          break;
-        case OAR_DoNotTrackAfterFailure:
+        else if (I.getData().Kind == RPDoNotTrackAfterFailure)
           state = state->remove<RegionState>(ReallocSym);
-          break;
-        default:
-          assert(I.getData().Kind == OAR_FreeOnFailure);
-        }
+        else
+          assert(I.getData().Kind == RPIsFreeOnFailure);
       }
     }
     state = state->remove<ReallocPairs>(I.getKey());
@@ -2976,7 +2690,7 @@ bool MallocChecker::mayFreeAnyEscapedMem
 
   // If it's one of the allocation functions we can reason about, we model
   // its behavior explicitly.
-  if (MemFunctionInfo.isMemFunction(FD, ASTC))
+  if (isMemFunction(FD, ASTC))
     return false;
 
   // If it's not a system call, assume it frees memory.
@@ -3068,6 +2782,10 @@ bool MallocChecker::mayFreeAnyEscapedMem
   return false;
 }
 
+static bool retTrue(const RefState *RS) {
+  return true;
+}
+
 static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
   return (RS->getAllocationFamily() == AF_CXXNewArray ||
           RS->getAllocationFamily() == AF_CXXNew);
@@ -3077,25 +2795,22 @@ ProgramStateRef MallocChecker::checkPoin
                                              const InvalidatedSymbols &Escaped,
                                              const CallEvent *Call,
                                              PointerEscapeKind Kind) const {
-  return checkPointerEscapeAux(State, Escaped, Call, Kind,
-                               /*IsConstPointerEscape*/ false);
+  return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue);
 }
 
 ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
                                               const InvalidatedSymbols &Escaped,
                                               const CallEvent *Call,
                                               PointerEscapeKind Kind) const {
-  // If a const pointer escapes, it may not be freed(), but it could be deleted.
   return checkPointerEscapeAux(State, Escaped, Call, Kind,
-                               /*IsConstPointerEscape*/ true);
+                               &checkIfNewOrNewArrayFamily);
 }
 
-ProgramStateRef MallocChecker::checkPointerEscapeAux(
-                                              ProgramStateRef State,
+ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
                                               const InvalidatedSymbols &Escaped,
                                               const CallEvent *Call,
                                               PointerEscapeKind Kind,
-                                              bool IsConstPointerEscape) const {
+                                  bool(*CheckRefState)(const RefState*)) const {
   // If we know that the call does not free memory, or we want to process the
   // call later, keep tracking the top level arguments.
   SymbolRef EscapingSymbol = nullptr;
@@ -3115,11 +2830,10 @@ ProgramStateRef MallocChecker::checkPoin
       continue;
 
     if (const RefState *RS = State->get<RegionState>(sym)) {
-      if ((RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
-        if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS)) {
-          State = State->remove<RegionState>(sym);
-          State = State->set<RegionState>(sym, RefState::getEscaped(RS));
-        }
+      if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
+          CheckRefState(RS)) {
+        State = State->remove<RegionState>(sym);
+        State = State->set<RegionState>(sym, RefState::getEscaped(RS));
       }
     }
   }
@@ -3131,8 +2845,9 @@ static SymbolRef findFailedReallocSymbol
   ReallocPairsTy currMap = currState->get<ReallocPairs>();
   ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
 
-  for (const ReallocPairsTy::value_type &Pair : prevMap) {
-    SymbolRef sym = Pair.first;
+  for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end();
+       I != E; ++I) {
+    SymbolRef sym = I.getKey();
     if (!currMap.lookup(sym))
       return sym;
   }
@@ -3153,19 +2868,19 @@ static bool isReferenceCountingPointerDe
   return false;
 }
 
-std::shared_ptr<PathDiagnosticPiece> MallocBugVisitor::VisitNode(
+std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
     const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) {
 
   ProgramStateRef state = N->getState();
   ProgramStateRef statePrev = N->getFirstPred()->getState();
 
-  const RefState *RSCurr = state->get<RegionState>(Sym);
+  const RefState *RS = state->get<RegionState>(Sym);
   const RefState *RSPrev = statePrev->get<RegionState>(Sym);
 
   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 && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
+  if (!S && (!RS || RS->getAllocationFamily() != AF_InnerBuffer))
     return nullptr;
 
   const LocationContext *CurrentLC = N->getLocationContext();
@@ -3200,12 +2915,12 @@ std::shared_ptr<PathDiagnosticPiece> Mal
   llvm::raw_svector_ostream OS(Buf);
 
   if (Mode == Normal) {
-    if (isAllocated(RSCurr, RSPrev, S)) {
+    if (isAllocated(RS, RSPrev, S)) {
       Msg = "Memory is allocated";
       StackHint = new StackHintGeneratorForSymbol(Sym,
                                                   "Returned allocated memory");
-    } else if (isReleased(RSCurr, RSPrev, S)) {
-      const auto Family = RSCurr->getAllocationFamily();
+    } else if (isReleased(RS, RSPrev, S)) {
+      const auto Family = RS->getAllocationFamily();
       switch (Family) {
         case AF_Alloca:
         case AF_Malloc:
@@ -3229,7 +2944,7 @@ std::shared_ptr<PathDiagnosticPiece> Mal
                                       "Returning; inner buffer was deallocated");
           } else {
             OS << "reallocated by call to '";
-            const Stmt *S = RSCurr->getStmt();
+            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)) {
@@ -3280,10 +2995,10 @@ std::shared_ptr<PathDiagnosticPiece> Mal
           }
         }
       }
-    } else if (isRelinquished(RSCurr, RSPrev, S)) {
+    } else if (isRelinquished(RS, RSPrev, S)) {
       Msg = "Memory ownership is transferred";
       StackHint = new StackHintGeneratorForSymbol(Sym, "");
-    } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
+    } else if (isReallocFailedCheck(RS, RSPrev, S)) {
       Mode = ReallocationFailed;
       Msg = "Reallocation failed";
       StackHint = new StackHintGeneratorForReallocationFailed(Sym,
@@ -3320,7 +3035,7 @@ std::shared_ptr<PathDiagnosticPiece> Mal
   // Generate the extra diagnostic.
   PathDiagnosticLocation Pos;
   if (!S) {
-    assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
+    assert(RS->getAllocationFamily() == AF_InnerBuffer);
     auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
     if (!PostImplCall)
       return nullptr;
@@ -3375,11 +3090,8 @@ markReleased(ProgramStateRef State, Symb
 void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
   registerCStringCheckerBasic(mgr);
   MallocChecker *checker = mgr.registerChecker<MallocChecker>();
-
-  checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions =
-      mgr.getAnalyzerOptions().getCheckerBooleanOption(
-                                                  "Optimistic", false, checker);
-
+  checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
+      "Optimistic", false, checker);
   checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
   checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
       mgr.getCurrentCheckName();
@@ -3397,25 +3109,21 @@ void ento::registerNewDeleteLeaksChecker
 // Intended to be used in InnerPointerChecker to register the part of
 // MallocChecker connected to it.
 void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
-  registerCStringCheckerBasic(mgr);
-  MallocChecker *checker = mgr.registerChecker<MallocChecker>();
-
-  checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions =
-      mgr.getAnalyzerOptions().getCheckerBooleanOption(
-                                                  "Optimistic", false, checker);
-
-  checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
-  checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
-      mgr.getCurrentCheckName();
+    registerCStringCheckerBasic(mgr);
+    MallocChecker *checker = mgr.registerChecker<MallocChecker>();
+    checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
+        "Optimistic", false, checker);
+    checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
+    checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
+        mgr.getCurrentCheckName();
 }
 
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &mgr) {                             \
     registerCStringCheckerBasic(mgr);                                          \
     MallocChecker *checker = mgr.registerChecker<MallocChecker>();             \
-    checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions =        \
-        mgr.getAnalyzerOptions().getCheckerBooleanOption(                      \
-                                                 "Optimistic", false, checker);\
+    checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(  \
+        "Optimistic", false, checker);                                         \
     checker->ChecksEnabled[MallocChecker::CK_##name] = true;                   \
     checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
   }




More information about the cfe-commits mailing list