[clang] 703a1b8 - [analyzer][MallocChecker][NFC] Split checkPostCall up, deploy CallDescriptionMap

Kirstóf Umann via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 30 07:02:11 PDT 2020


Author: Louis Dionne
Date: 2020-03-30T16:01:58+02:00
New Revision: 703a1b8caf09a5262a45c2179b8131922f71cf25

URL: https://github.com/llvm/llvm-project/commit/703a1b8caf09a5262a45c2179b8131922f71cf25
DIFF: https://github.com/llvm/llvm-project/commit/703a1b8caf09a5262a45c2179b8131922f71cf25.diff

LOG: [analyzer][MallocChecker][NFC] Split checkPostCall up, deploy CallDescriptionMap

Since its important to know whether a function frees memory (even if its a
reallocating function!), I used two CallDescriptionMaps to merge all
CallDescriptions into it. MemFunctionInfoTy no longer makes sense, it may never
have, but for now, it would be more of a distraction then anything else.

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

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 32a500ffd102..52786bcaf072 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -62,16 +62,19 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <climits>
+#include <functional>
 #include <utility>
 
 using namespace clang;
 using namespace ento;
+using namespace std::placeholders;
 
 //===----------------------------------------------------------------------===//
 // The types of allocation we're modeling. This is used to check whether a
@@ -93,8 +96,6 @@ enum AllocationFamily {
   AF_InnerBuffer
 };
 
-struct MemFunctionInfoTy;
-
 } // end of anonymous namespace
 
 /// Print names of allocators and deallocators.
@@ -263,47 +264,6 @@ struct ReallocPair {
 
 REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
 
-//===----------------------------------------------------------------------===//
-// Kinds of memory operations, information about resource managing functions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-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;
-
-  CallDescription CD_alloca{{"alloca"}, 1}, CD_win_alloca{{"_alloca"}, 1},
-      CD_malloc{{"malloc"}, 1}, CD_BSD_malloc{{"malloc"}, 3},
-      CD_free{{"free"}, 1}, CD_realloc{{"realloc"}, 2},
-      CD_calloc{{"calloc"}, 2}, CD_valloc{{"valloc"}, 1},
-      CD_reallocf{{"reallocf"}, 2}, CD_strndup{{"strndup"}, 2},
-      CD_strdup{{"strdup"}, 1}, CD_win_strdup{{"_strdup"}, 1},
-      CD_kmalloc{{"kmalloc"}, 2}, CD_if_nameindex{{"if_nameindex"}, 1},
-      CD_if_freenameindex{{"if_freenameindex"}, 1}, CD_wcsdup{{"wcsdup"}, 1},
-      CD_win_wcsdup{{"_wcsdup"}, 1}, CD_kfree{{"kfree"}, 1},
-      CD_g_malloc{{"g_malloc"}, 1}, CD_g_malloc0{{"g_malloc0"}, 1},
-      CD_g_realloc{{"g_realloc"}, 2}, CD_g_try_malloc{{"g_try_malloc"}, 1},
-      CD_g_try_malloc0{{"g_try_malloc0"}, 1},
-      CD_g_try_realloc{{"g_try_realloc"}, 2}, CD_g_free{{"g_free"}, 1},
-      CD_g_memdup{{"g_memdup"}, 2}, CD_g_malloc_n{{"g_malloc_n"}, 2},
-      CD_g_malloc0_n{{"g_malloc0_n"}, 2}, CD_g_realloc_n{{"g_realloc_n"}, 3},
-      CD_g_try_malloc_n{{"g_try_malloc_n"}, 2},
-      CD_g_try_malloc0_n{{"g_try_malloc0_n"}, 2},
-      CD_g_try_realloc_n{{"g_try_realloc_n"}, 3};
-
-  bool isMemFunction(const CallEvent &Call) const;
-  bool isCMemFunction(const CallEvent &Call) const;
-  bool isCMemFreeFunction(const CallEvent &Call) const;
-  bool isCMemAllocFunction(const CallEvent &Call) const;
-};
-} // end of anonymous namespace
-
 /// Tells if the callee is one of the builtin new/delete operators, including
 /// placement operators and other standard overloads.
 static bool isStandardNewDelete(const FunctionDecl *FD);
@@ -327,7 +287,11 @@ class MallocChecker
                      check::PreStmt<CXXDeleteExpr>, check::PostStmt<BlockExpr>,
                      check::PostObjCMessage, check::Location, eval::Assume> {
 public:
-  MemFunctionInfoTy MemFunctionInfo;
+  /// 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;
 
   /// Many checkers are essentially built into this one, so enabling them will
   /// make MallocChecker perform additional modeling and reporting.
@@ -387,6 +351,81 @@ class MallocChecker
   mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
   mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
 
+#define CHECK_FN(NAME)                                                         \
+  void NAME(CheckerContext &C, const CallExpr *CE, ProgramStateRef State) const;
+
+  CHECK_FN(checkFree)
+  CHECK_FN(checkIfNameIndex)
+  CHECK_FN(checkBasicAlloc)
+  CHECK_FN(checkKernelMalloc)
+  CHECK_FN(checkCalloc)
+  CHECK_FN(checkAlloca)
+  CHECK_FN(checkStrdup)
+  CHECK_FN(checkIfFreeNameIndex)
+  CHECK_FN(checkCXXNewOrCXXDelete)
+  CHECK_FN(checkGMalloc0)
+  CHECK_FN(checkGMemdup)
+  CHECK_FN(checkGMallocN)
+  CHECK_FN(checkGMallocN0)
+  CHECK_FN(checkReallocN)
+  CHECK_FN(checkOwnershipAttr)
+
+  void checkRealloc(CheckerContext &C, const CallExpr *CE,
+                    ProgramStateRef State, bool ShouldFreeOnFail) const;
+
+  using CheckFn =
+      std::function<void(const MallocChecker *, CheckerContext &C,
+                         const CallExpr *CE, ProgramStateRef State)>;
+
+  const CallDescriptionMap<CheckFn> FreeingMemFnMap{
+      {{"free", 1}, &MallocChecker::checkFree},
+      {{"if_freenameindex", 1}, &MallocChecker::checkIfFreeNameIndex},
+      {{"kfree", 1}, &MallocChecker::checkFree},
+      {{"g_free", 1}, &MallocChecker::checkFree},
+  };
+
+  bool isFreeingCall(const CallEvent &Call) const;
+
+  CallDescriptionMap<CheckFn> AllocatingMemFnMap{
+      {{"alloca", 1}, &MallocChecker::checkAlloca},
+      {{"_alloca", 1}, &MallocChecker::checkAlloca},
+      {{"malloc", 1}, &MallocChecker::checkBasicAlloc},
+      {{"malloc", 3}, &MallocChecker::checkKernelMalloc},
+      {{"calloc", 2}, &MallocChecker::checkCalloc},
+      {{"valloc", 1}, &MallocChecker::checkBasicAlloc},
+      {{CDF_MaybeBuiltin, "strndup", 2}, &MallocChecker::checkStrdup},
+      {{CDF_MaybeBuiltin, "strdup", 1}, &MallocChecker::checkStrdup},
+      {{"_strdup", 1}, &MallocChecker::checkStrdup},
+      {{"kmalloc", 2}, &MallocChecker::checkKernelMalloc},
+      {{"if_nameindex", 1}, &MallocChecker::checkIfNameIndex},
+      {{CDF_MaybeBuiltin, "wcsdup", 1}, &MallocChecker::checkStrdup},
+      {{CDF_MaybeBuiltin, "_wcsdup", 1}, &MallocChecker::checkStrdup},
+      {{"g_malloc", 1}, &MallocChecker::checkBasicAlloc},
+      {{"g_malloc0", 1}, &MallocChecker::checkGMalloc0},
+      {{"g_try_malloc", 1}, &MallocChecker::checkBasicAlloc},
+      {{"g_try_malloc0", 1}, &MallocChecker::checkGMalloc0},
+      {{"g_memdup", 2}, &MallocChecker::checkGMemdup},
+      {{"g_malloc_n", 2}, &MallocChecker::checkGMallocN},
+      {{"g_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
+      {{"g_try_malloc_n", 2}, &MallocChecker::checkGMallocN},
+      {{"g_try_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
+  };
+
+  CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
+      {{"realloc", 2},
+       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
+      {{"reallocf", 2},
+       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},
+      {{"g_realloc", 2},
+       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
+      {{"g_try_realloc", 2},
+       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
+      {{"g_realloc_n", 3}, &MallocChecker::checkReallocN},
+      {{"g_try_realloc_n", 3}, &MallocChecker::checkReallocN},
+  };
+
+  bool isMemCall(const CallEvent &Call) const;
+
   // TODO: Remove mutable by moving the initializtaion to the registry function.
   mutable Optional<uint64_t> KernelZeroFlagVal;
 
@@ -822,28 +861,31 @@ class StopTrackingCallback final : public SymbolVisitor {
 };
 } // end anonymous namespace
 
-//===----------------------------------------------------------------------===//
-// Methods of MemFunctionInfoTy.
-//===----------------------------------------------------------------------===//
+static bool isStandardNewDelete(const FunctionDecl *FD) {
+  if (!FD)
+    return false;
 
-bool MemFunctionInfoTy::isMemFunction(const CallEvent &Call) const {
-  return isCMemFunction(Call) || isStandardNewDelete(Call);
-}
+  OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+  if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
+      Kind != OO_Array_Delete)
+    return false;
 
-bool MemFunctionInfoTy::isCMemFunction(const CallEvent &Call) const {
-  return isCMemFreeFunction(Call) || isCMemAllocFunction(Call);
+  // This is standard if and only if it's not defined in a user file.
+  SourceLocation L = FD->getLocation();
+  // If the header for operator delete is not included, it's still defined
+  // in an invalid source location. Check to make sure we don't crash.
+  return !L.isValid() ||
+         FD->getASTContext().getSourceManager().isInSystemHeader(L);
 }
 
-bool MemFunctionInfoTy::isCMemFreeFunction(const CallEvent &Call) const {
-  if (Call.isCalled(CD_free, CD_realloc, CD_reallocf, CD_g_free, CD_kfree))
-    return true;
+//===----------------------------------------------------------------------===//
+// Methods of MallocChecker and MallocBugVisitor.
+//===----------------------------------------------------------------------===//
 
-  if (Call.isCalled(CD_if_freenameindex))
+bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
+  if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
     return true;
 
-  if (!ShouldIncludeOwnershipAnnotatedFunctions)
-    return false;
-
   const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());
   if (Func && Func->hasAttrs()) {
     for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
@@ -855,60 +897,21 @@ bool MemFunctionInfoTy::isCMemFreeFunction(const CallEvent &Call) const {
   return false;
 }
 
-bool MemFunctionInfoTy::isCMemAllocFunction(const CallEvent &Call) const {
-  if (Call.isCalled(CD_malloc, CD_realloc, CD_reallocf, CD_calloc, CD_valloc,
-                    CD_strdup, CD_win_strdup, CD_strndup, CD_wcsdup,
-                    CD_win_wcsdup, CD_kmalloc, CD_g_malloc, CD_g_malloc0,
-                    CD_g_realloc, CD_g_try_malloc, CD_g_try_malloc0,
-                    CD_g_try_realloc, CD_g_memdup, CD_g_malloc_n,
-                    CD_g_malloc0_n, CD_g_realloc_n, CD_g_try_malloc_n,
-                    CD_g_try_malloc0_n, CD_g_try_realloc_n))
-    return true;
-
-  if (Call.isCalled(CD_if_nameindex))
-    return true;
-
-  if (Call.isCalled(CD_alloca, CD_win_alloca))
+bool MallocChecker::isMemCall(const CallEvent &Call) const {
+  if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
+      ReallocatingMemFnMap.lookup(Call))
     return true;
 
   if (!ShouldIncludeOwnershipAnnotatedFunctions)
     return false;
 
   const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());
-  if (Func && Func->hasAttrs()) {
-    for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
-      OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
-      if (OwnKind == OwnershipAttr::Returns)
-        return true;
-    }
-  }
-
-  return false;
-}
-
-static bool isStandardNewDelete(const FunctionDecl *FD) {
-  if (!FD)
-    return false;
-
-  OverloadedOperatorKind Kind = FD->getOverloadedOperator();
-  if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
-      Kind != OO_Array_Delete)
-    return false;
-
-  // This is standard if and only if it's not defined in a user file.
-  SourceLocation L = FD->getLocation();
-  // If the header for operator delete is not included, it's still defined
-  // in an invalid source location. Check to make sure we don't crash.
-  return !L.isValid() ||
-         FD->getASTContext().getSourceManager().isInSystemHeader(L);
+  return Func && Func->hasAttr<OwnershipAttr>();
 }
 
-//===----------------------------------------------------------------------===//
-// Methods of MallocChecker and MallocBugVisitor.
-//===----------------------------------------------------------------------===//
-
-llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
-  const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const {
+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:
   //
   // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);
@@ -996,173 +999,169 @@ SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
   return TotalSize;
 }
 
-void MallocChecker::checkPostCall(const CallEvent &Call,
-                                  CheckerContext &C) const {
-  if (C.wasInlined)
-    return;
+void MallocChecker::checkBasicAlloc(CheckerContext &C, const CallExpr *CE,
+                                    ProgramStateRef State) const {
+  State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  C.addTransition(State);
+}
 
-  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
-  if (!CE)
-    return;
+void MallocChecker::checkKernelMalloc(CheckerContext &C, const CallExpr *CE,
+                                      ProgramStateRef State) const {
+  llvm::Optional<ProgramStateRef> MaybeState =
+      performKernelMalloc(CE, C, State);
+  if (MaybeState.hasValue())
+    State = MaybeState.getValue();
+  else
+    State =
+        MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc);
+  C.addTransition(State);
+}
 
-  const FunctionDecl *FD = C.getCalleeDecl(CE);
-  if (!FD)
+void MallocChecker::checkRealloc(CheckerContext &C, const CallExpr *CE,
+                                 ProgramStateRef State,
+                                 bool ShouldFreeOnFail) const {
+  State = ReallocMemAux(C, CE, ShouldFreeOnFail, State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkCalloc(CheckerContext &C, const CallExpr *CE,
+                                ProgramStateRef State) const {
+  State = CallocMem(C, CE, State);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkFree(CheckerContext &C, const CallExpr *CE,
+                              ProgramStateRef State) const {
+  bool IsKnownToBeAllocatedMemory = false;
+  if (suppressDeallocationsInSuspiciousContexts(CE, C))
     return;
+  State =
+      FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, AF_Malloc);
+  C.addTransition(State);
+}
 
-  ProgramStateRef State = C.getState();
+void MallocChecker::checkAlloca(CheckerContext &C, const CallExpr *CE,
+                                ProgramStateRef State) const {
+  State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkStrdup(CheckerContext &C, const CallExpr *CE,
+                                ProgramStateRef State) const {
+  State = MallocUpdateRefState(C, CE, State, AF_Malloc);
+
+  C.addTransition(State);
+}
+
+void MallocChecker::checkIfNameIndex(CheckerContext &C, const CallExpr *CE,
+                                     ProgramStateRef State) const {
+  // Should we model this 
diff erently? We can allocate a fixed number of
+  // elements with zeros in the last one.
+  State =
+      MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State, AF_IfNameIndex);
+
+  C.addTransition(State);
+}
+
+void MallocChecker::checkIfFreeNameIndex(CheckerContext &C, const CallExpr *CE,
+                                         ProgramStateRef State) const {
   bool IsKnownToBeAllocatedMemory = false;
+  State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+                     AF_IfNameIndex);
+  C.addTransition(State);
+}
 
-  if (FD->getKind() == Decl::Function) {
-    if (Call.isCalled(MemFunctionInfo.CD_malloc, MemFunctionInfo.CD_BSD_malloc,
-                      MemFunctionInfo.CD_g_malloc,
-                      MemFunctionInfo.CD_g_try_malloc)) {
-      switch (CE->getNumArgs()) {
-      default:
-        return;
-      case 1:
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                             AF_Malloc);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case 2:
-        llvm_unreachable("There shouldn't be a 2-argument malloc!");
-        break;
-      case 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,
-                               AF_Malloc);
-        break;
-      }
-    } else if (Call.isCalled(MemFunctionInfo.CD_kmalloc)) {
-      if (CE->getNumArgs() < 1)
-        return;
-      llvm::Optional<ProgramStateRef> MaybeState =
-          performKernelMalloc(CE, C, State);
-      if (MaybeState.hasValue())
-        State = MaybeState.getValue();
-      else
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                             AF_Malloc);
-    } else if (Call.isCalled(MemFunctionInfo.CD_valloc)) {
-      if (CE->getNumArgs() < 1)
-        return;
-      State =
-          MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_realloc,
-                             MemFunctionInfo.CD_g_realloc,
-                             MemFunctionInfo.CD_g_try_realloc)) {
-      State =
-          ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_reallocf)) {
-      State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_calloc)) {
-      State = CallocMem(C, CE, State);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_free, MemFunctionInfo.CD_g_free,
-                             MemFunctionInfo.CD_kfree)) {
-      if (suppressDeallocationsInSuspiciousContexts(CE, C))
-        return;
+void MallocChecker::checkCXXNewOrCXXDelete(CheckerContext &C,
+                                           const CallExpr *CE,
+                                           ProgramStateRef State) const {
+  bool IsKnownToBeAllocatedMemory = false;
 
-      State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
-                         AF_Malloc);
-    } else if (Call.isCalled(
-                   MemFunctionInfo.CD_strdup, MemFunctionInfo.CD_win_strdup,
-                   MemFunctionInfo.CD_wcsdup, MemFunctionInfo.CD_win_wcsdup)) {
-      State = MallocUpdateRefState(C, CE, State, AF_Malloc);
-    } else if (Call.isCalled(MemFunctionInfo.CD_strndup)) {
-      State = MallocUpdateRefState(C, CE, State, AF_Malloc);
-    } else if (Call.isCalled(MemFunctionInfo.CD_alloca,
-                             MemFunctionInfo.CD_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 (isStandardNewDelete(FD)) {
-      // 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:
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                             AF_CXXNew);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case OO_Array_New:
-        State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
-                             AF_CXXNewArray);
-        State = ProcessZeroAllocCheck(C, CE, 0, State);
-        break;
-      case OO_Delete:
-        State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
-                           AF_CXXNew);
-        break;
-      case OO_Array_Delete:
-        State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
-                           AF_CXXNewArray);
-        break;
-      default:
-        llvm_unreachable("not a new/delete operator");
-      }
-    } else if (Call.isCalled(MemFunctionInfo.CD_if_nameindex)) {
-      // Should we model this 
diff erently? 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 (Call.isCalled(MemFunctionInfo.CD_if_freenameindex)) {
-      State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
-                         AF_IfNameIndex);
-    } else if (Call.isCalled(MemFunctionInfo.CD_g_malloc0,
-                             MemFunctionInfo.CD_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, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_g_memdup)) {
-      if (CE->getNumArgs() < 2)
-        return;
-      State =
-          MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_g_malloc_n,
-                             MemFunctionInfo.CD_g_try_malloc_n,
-                             MemFunctionInfo.CD_g_malloc0_n,
-                             MemFunctionInfo.CD_g_try_malloc0_n)) {
-      if (CE->getNumArgs() < 2)
-        return;
-      SVal Init = UndefinedVal();
-      if (Call.isCalled(MemFunctionInfo.CD_g_malloc0_n,
-                        MemFunctionInfo.CD_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, AF_Malloc);
-      State = ProcessZeroAllocCheck(C, CE, 0, State);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-    } else if (Call.isCalled(MemFunctionInfo.CD_g_realloc_n,
-                             MemFunctionInfo.CD_g_try_realloc_n)) {
-      if (CE->getNumArgs() < 3)
-        return;
-      State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc,
-                            /*SuffixWithN*/ true);
-      State = ProcessZeroAllocCheck(C, CE, 1, State);
-      State = ProcessZeroAllocCheck(C, CE, 2, State);
-    }
+  const FunctionDecl *FD = C.getCalleeDecl(CE);
+  // 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:
+    State =
+        MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_CXXNew);
+    State = ProcessZeroAllocCheck(C, CE, 0, State);
+    break;
+  case OO_Array_New:
+    State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+                         AF_CXXNewArray);
+    State = ProcessZeroAllocCheck(C, CE, 0, State);
+    break;
+  case OO_Delete:
+    State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+                       AF_CXXNew);
+    break;
+  case OO_Array_Delete:
+    State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory,
+                       AF_CXXNewArray);
+    break;
+  default:
+    llvm_unreachable("not a new/delete operator");
   }
 
-  if (MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions ||
+  C.addTransition(State);
+}
+
+void MallocChecker::checkGMalloc0(CheckerContext &C, const CallExpr *CE,
+                                  ProgramStateRef State) const {
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
+  State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkGMemdup(CheckerContext &C, const CallExpr *CE,
+                                 ProgramStateRef State) const {
+  State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkGMallocN(CheckerContext &C, const CallExpr *CE,
+                                  ProgramStateRef State) const {
+  SVal Init = UndefinedVal();
+  SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
+  State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkGMallocN0(CheckerContext &C, const CallExpr *CE,
+                                   ProgramStateRef State) const {
+  SValBuilder &SB = C.getSValBuilder();
+  SVal Init = SB.makeZeroVal(SB.getContext().CharTy);
+  SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
+  State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc);
+  State = ProcessZeroAllocCheck(C, CE, 0, State);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkReallocN(CheckerContext &C, const CallExpr *CE,
+                                  ProgramStateRef State) const {
+  State = ReallocMemAux(C, CE, /*ShouldFreeOnFail=*/false, State, AF_Malloc,
+                        /*SuffixWithN=*/true);
+  State = ProcessZeroAllocCheck(C, CE, 1, State);
+  State = ProcessZeroAllocCheck(C, CE, 2, State);
+  C.addTransition(State);
+}
+
+void MallocChecker::checkOwnershipAttr(CheckerContext &C, const CallExpr *CE,
+                                       ProgramStateRef State) const {
+  const FunctionDecl *FD = C.getCalleeDecl(CE);
+  if (ShouldIncludeOwnershipAnnotatedFunctions ||
       ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
     // Check all the attributes, if there are any.
     // There can be multiple of these attributes.
@@ -1182,6 +1181,44 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
   C.addTransition(State);
 }
 
+void MallocChecker::checkPostCall(const CallEvent &Call,
+                                  CheckerContext &C) const {
+  if (C.wasInlined)
+    return;
+
+  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+  if (!CE)
+    return;
+
+  const FunctionDecl *FD = C.getCalleeDecl(CE);
+  if (!FD)
+    return;
+
+  ProgramStateRef State = C.getState();
+
+  if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
+    (*Callback)(this, C, CE, State);
+    return;
+  }
+
+  if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
+    (*Callback)(this, C, CE, State);
+    return;
+  }
+
+  if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
+    (*Callback)(this, C, CE, State);
+    return;
+  }
+
+  if (isStandardNewDelete(Call)) {
+    checkCXXNewOrCXXDelete(C, CE, State);
+    return;
+  }
+
+  checkOwnershipAttr(C, CE, State);
+}
+
 // Performs a 0-sized allocations check.
 ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
     CheckerContext &C, const Expr *E, const unsigned IndexOfSizeArg,
@@ -1448,8 +1485,7 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
   if (!State)
     return nullptr;
 
-  if (Att->getModule()->getName() !=
-      MemFunctionInfo.CD_malloc.getFunctionName())
+  if (Att->getModule()->getName() != "malloc")
     return nullptr;
 
   OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
@@ -1545,8 +1581,7 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
   if (!State)
     return nullptr;
 
-  if (Att->getModule()->getName() !=
-      MemFunctionInfo.CD_malloc.getFunctionName())
+  if (Att->getModule()->getName() != "malloc")
     return nullptr;
 
   bool IsKnownToBeAllocated = false;
@@ -2597,8 +2632,7 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
     if (!FD)
       return;
 
-    if (ChecksEnabled[CK_MallocChecker] &&
-        (MemFunctionInfo.isCMemFreeFunction(Call)))
+    if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))
       return;
   }
 
@@ -2897,7 +2931,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
 
   // If it's one of the allocation functions we can reason about, we model
   // its behavior explicitly.
-  if (MemFunctionInfo.isMemFunction(*Call))
+  if (isMemCall(*Call))
     return false;
 
   // If it's not a system call, assume it frees memory.
@@ -3315,7 +3349,7 @@ void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
 
 void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
   auto *checker = mgr.registerChecker<MallocChecker>();
-  checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions =
+  checker->ShouldIncludeOwnershipAnnotatedFunctions =
       mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic");
 }
 


        


More information about the cfe-commits mailing list