brintos

brintos / llvm-project-archived public Read only

0
0
Text · 156.9 KiB · ec7ef23 Raw
4231 lines · cpp
1//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines checkers that report memory management errors such as10// leak, double free, and use-after-free.11//12// The logic for modeling memory allocations is implemented in the checker13// family which is called 'MallocChecker' for historical reasons. (This name is14// inaccurate, something like 'DynamicMemory' would be more precise.)15//16// The reports produced by this backend are exposed through several frontends:17//  *   MallocChecker: reports all misuse of dynamic memory allocated by18//      malloc, related functions (like calloc, realloc etc.) and the functions19//      annotated by ownership_returns. (Here the name "MallocChecker" is20//      reasonably accurate; don't confuse this checker frontend with the whole21//      misnamed family.)22//  *   NewDeleteChecker: reports most misuse (anything but memory leaks) of23//      memory managed by the C++ operators new and new[].24//  *   NewDeleteLeaksChecker: reports leaks of dynamic memory allocated by25//      the C++ operators new and new[].26//  *   MismatchedDeallocatorChecker: reports situations where the allocation27//      and deallocation is mismatched, e.g. memory allocated via malloc is28//      passed to operator delete.29//  *   InnerPointerChecker: reports use of pointers to the internal buffer of30//      a std::string instance after operations that invalidate them.31//  *   TaintedAllocChecker: reports situations where the size argument of a32//      memory allocation function or array new operator is tainted (i.e. comes33//      from an untrusted source and can be controlled by an attacker).34//35// In addition to these frontends this file also defines the registration36// functions for "unix.DynamicMemoryModeling". This registers the callbacks of37// the checker family MallocChecker without enabling any of the frontends and38// and handle two checker options which are attached to this "modeling39// checker" because they affect multiple checker frontends.40//41// Note that what the users see as the checker "cplusplus.InnerPointer" is a42// combination of the frontend InnerPointerChecker (within this family) which43// emits the bug reports and a separate checker class (also named44// InnerPointerChecker) which is defined in InnerPointerChecker.cpp and does a45// significant part of the modeling. This cooperation is enabled by several46// non-static helper functions that are defined within this translation unit47// and used in InnerPointerChecker.cpp.48//49//===----------------------------------------------------------------------===//50 51#include "AllocationState.h"52#include "InterCheckerAPI.h"53#include "NoOwnershipChangeVisitor.h"54#include "clang/AST/Attr.h"55#include "clang/AST/DeclCXX.h"56#include "clang/AST/DeclTemplate.h"57#include "clang/AST/Expr.h"58#include "clang/AST/ExprCXX.h"59#include "clang/AST/ParentMap.h"60#include "clang/ASTMatchers/ASTMatchFinder.h"61#include "clang/ASTMatchers/ASTMatchers.h"62#include "clang/Analysis/ProgramPoint.h"63#include "clang/Basic/LLVM.h"64#include "clang/Basic/SourceManager.h"65#include "clang/Basic/TargetInfo.h"66#include "clang/Lex/Lexer.h"67#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"68#include "clang/StaticAnalyzer/Checkers/Taint.h"69#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"70#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"71#include "clang/StaticAnalyzer/Core/Checker.h"72#include "clang/StaticAnalyzer/Core/CheckerManager.h"73#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"74#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"75#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"76#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"77#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"78#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"79#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"80#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"81#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"82#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"83#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"84#include "llvm/ADT/STLExtras.h"85#include "llvm/ADT/SmallVector.h"86#include "llvm/ADT/StringExtras.h"87#include "llvm/Support/Casting.h"88#include "llvm/Support/Compiler.h"89#include "llvm/Support/ErrorHandling.h"90#include "llvm/Support/raw_ostream.h"91#include <functional>92#include <optional>93#include <utility>94 95using namespace clang;96using namespace ento;97using namespace std::placeholders;98 99//===----------------------------------------------------------------------===//100// The types of allocation we're modeling. This is used to check whether a101// dynamically allocated object is deallocated with the correct function, like102// not using operator delete on an object created by malloc(), or alloca regions103// aren't ever deallocated manually.104//===----------------------------------------------------------------------===//105 106namespace {107 108// Used to check correspondence between allocators and deallocators.109enum AllocationFamilyKind {110  AF_None,111  AF_Malloc,112  AF_CXXNew,113  AF_CXXNewArray,114  AF_IfNameIndex,115  AF_Alloca,116  AF_InnerBuffer,117  AF_Custom,118};119 120struct AllocationFamily {121  AllocationFamilyKind Kind;122  std::optional<StringRef> CustomName;123 124  explicit AllocationFamily(AllocationFamilyKind AKind,125                            std::optional<StringRef> Name = std::nullopt)126      : Kind(AKind), CustomName(Name) {127    assert((Kind != AF_Custom || CustomName.has_value()) &&128           "Custom family must specify also the name");129 130    // Preseve previous behavior when "malloc" class means AF_Malloc131    if (Kind == AF_Custom && CustomName.value() == "malloc") {132      Kind = AF_Malloc;133      CustomName = std::nullopt;134    }135  }136 137  bool operator==(const AllocationFamily &Other) const {138    return std::tie(Kind, CustomName) == std::tie(Other.Kind, Other.CustomName);139  }140 141  bool operator!=(const AllocationFamily &Other) const {142    return !(*this == Other);143  }144 145  void Profile(llvm::FoldingSetNodeID &ID) const {146    ID.AddInteger(Kind);147 148    if (Kind == AF_Custom)149      ID.AddString(CustomName.value());150  }151};152 153} // end of anonymous namespace154 155/// Print names of allocators and deallocators.156///157/// \returns true on success.158static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);159 160/// Print expected name of an allocator based on the deallocator's family161/// derived from the DeallocExpr.162static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);163 164/// Print expected name of a deallocator based on the allocator's165/// family.166static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);167 168//===----------------------------------------------------------------------===//169// The state of a symbol, in terms of memory management.170//===----------------------------------------------------------------------===//171 172namespace {173 174class RefState {175  enum Kind {176    // Reference to allocated memory.177    Allocated,178    // Reference to zero-allocated memory.179    AllocatedOfSizeZero,180    // Reference to released/freed memory.181    Released,182    // The responsibility for freeing resources has transferred from183    // this reference. A relinquished symbol should not be freed.184    Relinquished,185    // We are no longer guaranteed to have observed all manipulations186    // of this pointer/memory. For example, it could have been187    // passed as a parameter to an opaque function.188    Escaped189  };190 191  const Stmt *S;192 193  Kind K;194  AllocationFamily Family;195 196  RefState(Kind k, const Stmt *s, AllocationFamily family)197      : S(s), K(k), Family(family) {198    assert(family.Kind != AF_None);199  }200 201public:202  bool isAllocated() const { return K == Allocated; }203  bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }204  bool isReleased() const { return K == Released; }205  bool isRelinquished() const { return K == Relinquished; }206  bool isEscaped() const { return K == Escaped; }207  AllocationFamily getAllocationFamily() const { return Family; }208  const Stmt *getStmt() const { return S; }209 210  bool operator==(const RefState &X) const {211    return K == X.K && S == X.S && Family == X.Family;212  }213 214  static RefState getAllocated(AllocationFamily family, const Stmt *s) {215    return RefState(Allocated, s, family);216  }217  static RefState getAllocatedOfSizeZero(const RefState *RS) {218    return RefState(AllocatedOfSizeZero, RS->getStmt(),219                    RS->getAllocationFamily());220  }221  static RefState getReleased(AllocationFamily family, const Stmt *s) {222    return RefState(Released, s, family);223  }224  static RefState getRelinquished(AllocationFamily family, const Stmt *s) {225    return RefState(Relinquished, s, family);226  }227  static RefState getEscaped(const RefState *RS) {228    return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());229  }230 231  void Profile(llvm::FoldingSetNodeID &ID) const {232    ID.AddInteger(K);233    ID.AddPointer(S);234    Family.Profile(ID);235  }236 237  LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {238    switch (K) {239#define CASE(ID) case ID: OS << #ID; break;240    CASE(Allocated)241    CASE(AllocatedOfSizeZero)242    CASE(Released)243    CASE(Relinquished)244    CASE(Escaped)245    }246  }247 248  LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }249};250 251} // end of anonymous namespace252 253REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)254 255/// Check if the memory associated with this symbol was released.256static bool isReleased(SymbolRef Sym, CheckerContext &C);257 258/// Update the RefState to reflect the new memory allocation.259/// The optional \p RetVal parameter specifies the newly allocated pointer260/// value; if unspecified, the value of expression \p E is used.261static ProgramStateRef262MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,263                     AllocationFamily Family,264                     std::optional<SVal> RetVal = std::nullopt);265 266//===----------------------------------------------------------------------===//267// The modeling of memory reallocation.268//269// The terminology 'toPtr' and 'fromPtr' will be used:270//   toPtr = realloc(fromPtr, 20);271//===----------------------------------------------------------------------===//272 273REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)274 275namespace {276 277/// The state of 'fromPtr' after reallocation is known to have failed.278enum OwnershipAfterReallocKind {279  // The symbol needs to be freed (e.g.: realloc)280  OAR_ToBeFreedAfterFailure,281  // The symbol has been freed (e.g.: reallocf)282  OAR_FreeOnFailure,283  // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where284  // 'fromPtr' was allocated:285  //    void Haha(int *ptr) {286  //      ptr = realloc(ptr, 67);287  //      // ...288  //    }289  // ).290  OAR_DoNotTrackAfterFailure291};292 293/// Stores information about the 'fromPtr' symbol after reallocation.294///295/// This is important because realloc may fail, and that needs special modeling.296/// Whether reallocation failed or not will not be known until later, so we'll297/// store whether upon failure 'fromPtr' will be freed, or needs to be freed298/// later, etc.299struct ReallocPair {300 301  // The 'fromPtr'.302  SymbolRef ReallocatedSym;303  OwnershipAfterReallocKind Kind;304 305  ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)306      : ReallocatedSym(S), Kind(K) {}307  void Profile(llvm::FoldingSetNodeID &ID) const {308    ID.AddInteger(Kind);309    ID.AddPointer(ReallocatedSym);310  }311  bool operator==(const ReallocPair &X) const {312    return ReallocatedSym == X.ReallocatedSym &&313           Kind == X.Kind;314  }315};316 317} // end of anonymous namespace318 319REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)320 321static bool isStandardNew(const FunctionDecl *FD);322static bool isStandardNew(const CallEvent &Call) {323  if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))324    return false;325  return isStandardNew(cast<FunctionDecl>(Call.getDecl()));326}327 328static bool isStandardDelete(const FunctionDecl *FD);329static bool isStandardDelete(const CallEvent &Call) {330  if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))331    return false;332  return isStandardDelete(cast<FunctionDecl>(Call.getDecl()));333}334 335/// Tells if the callee is one of the builtin new/delete operators, including336/// placement operators and other standard overloads.337template <typename T> static bool isStandardNewDelete(const T &FD) {338  return isStandardDelete(FD) || isStandardNew(FD);339}340 341namespace {342 343//===----------------------------------------------------------------------===//344// Utility classes that provide access to the bug types and can model that some345// of the bug types are shared by multiple checker frontends.346//===----------------------------------------------------------------------===//347 348#define BUGTYPE_PROVIDER(NAME, DEF)                                            \349  struct NAME : virtual public CheckerFrontend {                               \350    BugType NAME##Bug{this, DEF, categories::MemoryError};                     \351  };352 353BUGTYPE_PROVIDER(DoubleFree, "Double free")354 355struct Leak : virtual public CheckerFrontend {356  // Leaks should not be reported if they are post-dominated by a sink:357  // (1) Sinks are higher importance bugs.358  // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending359  //     with __noreturn functions such as assert() or exit(). We choose not360  //     to report leaks on such paths.361  BugType LeakBug{this, "Memory leak", categories::MemoryError,362                  /*SuppressOnSink=*/true};363};364 365BUGTYPE_PROVIDER(UseFree, "Use-after-free")366BUGTYPE_PROVIDER(BadFree, "Bad free")367BUGTYPE_PROVIDER(FreeAlloca, "Free 'alloca()'")368BUGTYPE_PROVIDER(MismatchedDealloc, "Bad deallocator")369BUGTYPE_PROVIDER(OffsetFree, "Offset free")370BUGTYPE_PROVIDER(UseZeroAllocated, "Use of zero allocated")371 372#undef BUGTYPE_PROVIDER373 374template <typename... BT_PROVIDERS>375struct DynMemFrontend : virtual public CheckerFrontend, public BT_PROVIDERS... {376  template <typename T> const T *getAs() const {377    if constexpr (std::is_same_v<T, CheckerFrontend> ||378                  (std::is_same_v<T, BT_PROVIDERS> || ...))379      return static_cast<const T *>(this);380    return nullptr;381  }382};383 384//===----------------------------------------------------------------------===//385// Definition of the MallocChecker class.386//===----------------------------------------------------------------------===//387 388class MallocChecker389    : public CheckerFamily<390          check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,391          check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,392          check::PostCall, eval::Call, check::NewAllocator,393          check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,394          eval::Assume> {395public:396  /// In pessimistic mode, the checker assumes that it does not know which397  /// functions might free the memory.398  /// In optimistic mode, the checker assumes that all user-defined functions399  /// which might free a pointer are annotated.400  bool ShouldIncludeOwnershipAnnotatedFunctions = false;401 402  bool ShouldRegisterNoOwnershipChangeVisitor = false;403 404  // This checker family implements many bug types and frontends, and several405  // bug types are shared between multiple frontends, so most of the frontends406  // are declared with the helper class DynMemFrontend.407  // FIXME: There is no clear reason for separating NewDelete vs NewDeleteLeaks408  // while e.g. MallocChecker covers both non-leak and leak bugs together. It409  // would be nice to redraw the boundaries between the frontends in a more410  // logical way.411  DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,412                 UseZeroAllocated>413      MallocChecker;414  DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>415      NewDeleteChecker;416  DynMemFrontend<Leak> NewDeleteLeaksChecker;417  DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;418  DynMemFrontend<UseFree> InnerPointerChecker;419  // This last frontend is associated with a single bug type which is not used420  // elsewhere and has a different bug category, so it's declared separately.421  CheckerFrontendWithBugType TaintedAllocChecker{"Tainted Memory Allocation",422                                                 categories::TaintedData};423 424  using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;425 426  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;427  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;428  bool evalCall(const CallEvent &Call, CheckerContext &C) const;429 430  ProgramStateRef431  handleSmartPointerConstructorArguments(const CallEvent &Call,432                                         ProgramStateRef State) const;433  ProgramStateRef handleSmartPointerRelatedCalls(const CallEvent &Call,434                                                 CheckerContext &C,435                                                 ProgramStateRef State) const;436  void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;437  void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;438  void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;439  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;440  void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;441  void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;442  ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,443                            bool Assumption) const;444  void checkLocation(SVal l, bool isLoad, const Stmt *S,445                     CheckerContext &C) const;446 447  ProgramStateRef checkPointerEscape(ProgramStateRef State,448                                    const InvalidatedSymbols &Escaped,449                                    const CallEvent *Call,450                                    PointerEscapeKind Kind) const;451  ProgramStateRef checkConstPointerEscape(ProgramStateRef State,452                                          const InvalidatedSymbols &Escaped,453                                          const CallEvent *Call,454                                          PointerEscapeKind Kind) const;455 456  void printState(raw_ostream &Out, ProgramStateRef State,457                  const char *NL, const char *Sep) const override;458 459  StringRef getDebugTag() const override { return "MallocChecker"; }460 461private:462#define CHECK_FN(NAME)                                                         \463  void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C)   \464      const;465 466  CHECK_FN(checkFree)467  CHECK_FN(checkIfNameIndex)468  CHECK_FN(checkBasicAlloc)469  CHECK_FN(checkKernelMalloc)470  CHECK_FN(checkCalloc)471  CHECK_FN(checkAlloca)472  CHECK_FN(checkStrdup)473  CHECK_FN(checkIfFreeNameIndex)474  CHECK_FN(checkCXXNewOrCXXDelete)475  CHECK_FN(checkGMalloc0)476  CHECK_FN(checkGMemdup)477  CHECK_FN(checkGMallocN)478  CHECK_FN(checkGMallocN0)479  CHECK_FN(preGetDelimOrGetLine)480  CHECK_FN(checkGetDelimOrGetLine)481  CHECK_FN(checkReallocN)482  CHECK_FN(checkOwnershipAttr)483 484  void checkRealloc(ProgramStateRef State, const CallEvent &Call,485                    CheckerContext &C, bool ShouldFreeOnFail) const;486 487  using CheckFn =488      std::function<void(const class MallocChecker *, ProgramStateRef State,489                         const CallEvent &Call, CheckerContext &C)>;490 491  const CallDescriptionMap<CheckFn> PreFnMap{492      // NOTE: the following CallDescription also matches the C++ standard493      // library function std::getline(); the callback will filter it out.494      {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},495      {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},496  };497 498  const CallDescriptionMap<CheckFn> PostFnMap{499      // NOTE: the following CallDescription also matches the C++ standard500      // library function std::getline(); the callback will filter it out.501      {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},502      {{CDM::CLibrary, {"getdelim"}, 4},503       &MallocChecker::checkGetDelimOrGetLine},504  };505 506  const CallDescriptionMap<CheckFn> FreeingMemFnMap{507      {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},508      {{CDM::CLibrary, {"if_freenameindex"}, 1},509       &MallocChecker::checkIfFreeNameIndex},510      {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},511      {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},512  };513 514  bool isFreeingCall(const CallEvent &Call) const;515  static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);516  static bool isFreeingOwnershipAttrCall(const CallEvent &Call);517  static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);518  static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);519 520  friend class NoMemOwnershipChangeVisitor;521 522  CallDescriptionMap<CheckFn> AllocaMemFnMap{523      {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},524      {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},525      // The line for "alloca" also covers "__builtin_alloca", but the526      // _with_align variant must be listed separately because it takes an527      // extra argument:528      {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},529       &MallocChecker::checkAlloca},530  };531 532  CallDescriptionMap<CheckFn> AllocatingMemFnMap{533      {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},534      {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},535      {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},536      {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},537      {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},538      {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},539      {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},540      {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},541      {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},542      {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},543      {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},544      {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},545      {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},546      {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},547      {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},548      {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},549      {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},550      {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},551      {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},552      {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},553  };554 555  CallDescriptionMap<CheckFn> ReallocatingMemFnMap{556      {{CDM::CLibrary, {"realloc"}, 2},557       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},558      {{CDM::CLibrary, {"reallocf"}, 2},559       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},560      {{CDM::CLibrary, {"g_realloc"}, 2},561       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},562      {{CDM::CLibrary, {"g_try_realloc"}, 2},563       std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},564      {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},565      {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},566  };567 568  bool isMemCall(const CallEvent &Call) const;569  bool hasOwnershipReturns(const CallEvent &Call) const;570  bool hasOwnershipTakesHolds(const CallEvent &Call) const;571  void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C,572                      llvm::ArrayRef<SymbolRef> TaintedSyms,573                      AllocationFamily Family) const;574 575  void checkTaintedness(CheckerContext &C, const CallEvent &Call,576                        const SVal SizeSVal, ProgramStateRef State,577                        AllocationFamily Family) const;578 579  // TODO: Remove mutable by moving the initializtaion to the registry function.580  mutable std::optional<uint64_t> KernelZeroFlagVal;581 582  using KernelZeroSizePtrValueTy = std::optional<int>;583  /// Store the value of macro called `ZERO_SIZE_PTR`.584  /// The value is initialized at first use, before first use the outer585  /// Optional is empty, afterwards it contains another Optional that indicates586  /// if the macro value could be determined, and if yes the value itself.587  mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;588 589  /// Process C++ operator new()'s allocation, which is the part of C++590  /// new-expression that goes before the constructor.591  [[nodiscard]] ProgramStateRef592  processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,593                       AllocationFamily Family) const;594 595  /// Perform a zero-allocation check.596  ///597  /// \param [in] Call The expression that allocates memory.598  /// \param [in] IndexOfSizeArg Index of the argument that specifies the size599  ///   of the memory that needs to be allocated. E.g. for malloc, this would be600  ///   0.601  /// \param [in] RetVal Specifies the newly allocated pointer value;602  ///   if unspecified, the value of expression \p E is used.603  [[nodiscard]] static ProgramStateRef604  ProcessZeroAllocCheck(CheckerContext &C, const CallEvent &Call,605                        const unsigned IndexOfSizeArg, ProgramStateRef State,606                        std::optional<SVal> RetVal = std::nullopt);607 608  /// Model functions with the ownership_returns attribute.609  ///610  /// User-defined function may have the ownership_returns attribute, which611  /// annotates that the function returns with an object that was allocated on612  /// the heap, and passes the ownertship to the callee.613  ///614  ///   void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);615  ///616  /// It has two parameters:617  ///   - first: name of the resource (e.g. 'malloc')618  ///   - (OPTIONAL) second: size of the allocated region619  ///620  /// \param [in] Call The expression that allocates memory.621  /// \param [in] Att The ownership_returns attribute.622  /// \param [in] State The \c ProgramState right before allocation.623  /// \returns The ProgramState right after allocation.624  [[nodiscard]] ProgramStateRef625  MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,626                       const OwnershipAttr *Att, ProgramStateRef State) const;627  /// Models memory allocation.628  ///629  /// \param [in] C Checker context.630  /// \param [in] Call The expression that allocates memory.631  /// \param [in] State The \c ProgramState right before allocation.632  /// \param [in] isAlloca Is the allocation function alloca-like633  /// \returns The ProgramState with returnValue bound634  [[nodiscard]] ProgramStateRef MallocBindRetVal(CheckerContext &C,635                                                 const CallEvent &Call,636                                                 ProgramStateRef State,637                                                 bool isAlloca) const;638 639  /// Models memory allocation.640  ///641  /// \param [in] Call The expression that allocates memory.642  /// \param [in] SizeEx Size of the memory that needs to be allocated.643  /// \param [in] Init The value the allocated memory needs to be initialized.644  /// with. For example, \c calloc initializes the allocated memory to 0,645  /// malloc leaves it undefined.646  /// \param [in] State The \c ProgramState right before allocation.647  /// \returns The ProgramState right after allocation.648  [[nodiscard]] ProgramStateRef649  MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,650               SVal Init, ProgramStateRef State, AllocationFamily Family) const;651 652  /// Models memory allocation.653  ///654  /// \param [in] Call The expression that allocates memory.655  /// \param [in] Size Size of the memory that needs to be allocated.656  /// \param [in] Init The value the allocated memory needs to be initialized.657  /// with. For example, \c calloc initializes the allocated memory to 0,658  /// malloc leaves it undefined.659  /// \param [in] State The \c ProgramState right before allocation.660  /// \returns The ProgramState right after allocation.661  [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C,662                                             const CallEvent &Call, SVal Size,663                                             SVal Init, ProgramStateRef State,664                                             AllocationFamily Family) const;665 666  // Check if this malloc() for special flags. At present that means M_ZERO or667  // __GFP_ZERO (in which case, treat it like calloc).668  [[nodiscard]] std::optional<ProgramStateRef>669  performKernelMalloc(const CallEvent &Call, CheckerContext &C,670                      const ProgramStateRef &State) const;671 672  /// Model functions with the ownership_takes and ownership_holds attributes.673  ///674  /// User-defined function may have the ownership_takes and/or ownership_holds675  /// attributes, which annotates that the function frees the memory passed as a676  /// parameter.677  ///678  ///   void __attribute((ownership_takes(malloc, 1))) my_free(void *);679  ///   void __attribute((ownership_holds(malloc, 1))) my_hold(void *);680  ///681  /// They have two parameters:682  ///   - first: name of the resource (e.g. 'malloc')683  ///   - second: index of the parameter the attribute applies to684  ///685  /// \param [in] Call The expression that frees memory.686  /// \param [in] Att The ownership_takes or ownership_holds attribute.687  /// \param [in] State The \c ProgramState right before allocation.688  /// \returns The ProgramState right after deallocation.689  [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,690                                            const CallEvent &Call,691                                            const OwnershipAttr *Att,692                                            ProgramStateRef State) const;693 694  /// Models memory deallocation.695  ///696  /// \param [in] Call The expression that frees memory.697  /// \param [in] State The \c ProgramState right before allocation.698  /// \param [in] Num Index of the argument that needs to be freed. This is699  ///   normally 0, but for custom free functions it may be different.700  /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds701  ///   attribute.702  /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known703  ///   to have been allocated, or in other words, the symbol to be freed was704  ///   registered as allocated by this checker. In the following case, \c ptr705  ///   isn't known to be allocated.706  ///      void Haha(int *ptr) {707  ///        ptr = realloc(ptr, 67);708  ///        // ...709  ///      }710  /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function711  ///   we're modeling returns with Null on failure.712  /// \returns The ProgramState right after deallocation.713  [[nodiscard]] ProgramStateRef714  FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,715             unsigned Num, bool Hold, bool &IsKnownToBeAllocated,716             AllocationFamily Family, bool ReturnsNullOnFailure = false) const;717 718  /// Models memory deallocation.719  ///720  /// \param [in] ArgExpr The variable who's pointee needs to be freed.721  /// \param [in] Call The expression that frees the memory.722  /// \param [in] State The \c ProgramState right before allocation.723  ///   normally 0, but for custom free functions it may be different.724  /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds725  ///   attribute.726  /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known727  ///   to have been allocated, or in other words, the symbol to be freed was728  ///   registered as allocated by this checker. In the following case, \c ptr729  ///   isn't known to be allocated.730  ///      void Haha(int *ptr) {731  ///        ptr = realloc(ptr, 67);732  ///        // ...733  ///      }734  /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function735  ///   we're modeling returns with Null on failure.736  /// \param [in] ArgValOpt Optional value to use for the argument instead of737  /// the one obtained from ArgExpr.738  /// \returns The ProgramState right after deallocation.739  [[nodiscard]] ProgramStateRef740  FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,741             ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,742             AllocationFamily Family, bool ReturnsNullOnFailure = false,743             std::optional<SVal> ArgValOpt = {}) const;744 745  // TODO: Needs some refactoring, as all other deallocation modeling746  // functions are suffering from out parameters and messy code due to how747  // realloc is handled.748  //749  /// Models memory reallocation.750  ///751  /// \param [in] Call The expression that reallocated memory752  /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied753  ///   memory should be freed.754  /// \param [in] State The \c ProgramState right before reallocation.755  /// \param [in] SuffixWithN Whether the reallocation function we're modeling756  ///   has an '_n' suffix, such as g_realloc_n.757  /// \returns The ProgramState right after reallocation.758  [[nodiscard]] ProgramStateRef759  ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,760                ProgramStateRef State, AllocationFamily Family,761                bool SuffixWithN = false) const;762 763  /// Evaluates the buffer size that needs to be allocated.764  ///765  /// \param [in] Blocks The amount of blocks that needs to be allocated.766  /// \param [in] BlockBytes The size of a block.767  /// \returns The symbolic value of \p Blocks * \p BlockBytes.768  [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,769                                                 const Expr *Blocks,770                                                 const Expr *BlockBytes);771 772  /// Models zero initialized array allocation.773  ///774  /// \param [in] Call The expression that reallocated memory775  /// \param [in] State The \c ProgramState right before reallocation.776  /// \returns The ProgramState right after allocation.777  [[nodiscard]] ProgramStateRef CallocMem(CheckerContext &C,778                                          const CallEvent &Call,779                                          ProgramStateRef State) const;780 781  /// See if deallocation happens in a suspicious context. If so, escape the782  /// pointers that otherwise would have been deallocated and return true.783  bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,784                                                 CheckerContext &C) const;785 786  /// If in \p S  \p Sym is used, check whether \p Sym was already freed.787  bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;788 789  /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero790  /// sized memory region.791  void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,792                             const Stmt *S) const;793 794  /// Check if the function is known to free memory, or if it is795  /// "interesting" and should be modeled explicitly.796  ///797  /// \param [out] EscapingSymbol A function might not free memory in general,798  ///   but could be known to free a particular symbol. In this case, false is799  ///   returned and the single escaping symbol is returned through the out800  ///   parameter.801  ///802  /// We assume that pointers do not escape through calls to system functions803  /// not handled by this checker.804  bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,805                                   ProgramStateRef State,806                                   SymbolRef &EscapingSymbol) const;807 808  /// Implementation of the checkPointerEscape callbacks.809  [[nodiscard]] ProgramStateRef810  checkPointerEscapeAux(ProgramStateRef State,811                        const InvalidatedSymbols &Escaped,812                        const CallEvent *Call, PointerEscapeKind Kind,813                        bool IsConstPointerEscape) const;814 815  // Implementation of the checkPreStmt and checkEndFunction callbacks.816  void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;817 818  ///@{819  /// Returns a pointer to the checker frontend corresponding to the given820  /// family or symbol. The template argument T may be either CheckerFamily or821  /// a BUGTYPE_PROVIDER class; in the latter case the query is restricted to822  /// frontends that descend from that PROVIDER class (i.e. can emit that bug823  /// type). Note that this may return a frontend which is disabled.824  template <class T>825  const T *getRelevantFrontendAs(AllocationFamily Family) const;826 827  template <class T>828  const T *getRelevantFrontendAs(CheckerContext &C, SymbolRef Sym) const;829  ///@}830  static bool SummarizeValue(raw_ostream &os, SVal V);831  static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,832                              const MemRegion *MR);833 834  void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,835                            const Expr *DeallocExpr,836                            AllocationFamily Family) const;837 838  void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,839                        SourceRange Range) const;840 841  void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,842                               const Expr *DeallocExpr, const RefState *RS,843                               SymbolRef Sym, bool OwnershipTransferred) const;844 845  void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,846                        const Expr *DeallocExpr, AllocationFamily Family,847                        const Expr *AllocExpr = nullptr) const;848 849  void HandleUseAfterFree(CheckerContext &C, SourceRange Range,850                          SymbolRef Sym) const;851 852  void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,853                        SymbolRef Sym, SymbolRef PrevSym) const;854 855  void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,856                          SymbolRef Sym) const;857 858  void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,859                             const Expr *FreeExpr,860                             AllocationFamily Family) const;861 862  /// Find the location of the allocation for Sym on the path leading to the863  /// exploded node N.864  static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,865                                    CheckerContext &C);866 867  void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;868 869  /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`.870  bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,871                          SVal ArgVal) const;872};873} // end anonymous namespace874 875//===----------------------------------------------------------------------===//876// Definition of NoOwnershipChangeVisitor.877//===----------------------------------------------------------------------===//878 879namespace {880class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor {881protected:882  /// Syntactically checks whether the callee is a deallocating function. Since883  /// we have no path-sensitive information on this call (we would need a884  /// CallEvent instead of a CallExpr for that), its possible that a885  /// deallocation function was called indirectly through a function pointer,886  /// but we are not able to tell, so this is a best effort analysis.887  /// See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in888  /// clang/test/Analysis/NewDeleteLeaks.cpp.889  bool isFreeingCallAsWritten(const CallExpr &Call) const {890    const auto *MallocChk = static_cast<const MallocChecker *>(&Checker);891    if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) ||892        MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))893      return true;894 895    if (const auto *Func =896            llvm::dyn_cast_or_null<FunctionDecl>(Call.getCalleeDecl()))897      return MallocChecker::isFreeingOwnershipAttrCall(Func);898 899    return false;900  }901 902  bool hasResourceStateChanged(ProgramStateRef CallEnterState,903                               ProgramStateRef CallExitEndState) final {904    return CallEnterState->get<RegionState>(Sym) !=905           CallExitEndState->get<RegionState>(Sym);906  }907 908  /// Heuristically guess whether the callee intended to free memory. This is909  /// done syntactically, because we are trying to argue about alternative910  /// paths of execution, and as a consequence we don't have path-sensitive911  /// information.912  bool doesFnIntendToHandleOwnership(const Decl *Callee,913                                     ASTContext &ACtx) final {914    const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);915 916    // Given that the stack frame was entered, the body should always be917    // theoretically obtainable. In case of body farms, the synthesized body918    // is not attached to declaration, thus triggering the '!FD->hasBody()'919    // branch. That said, would a synthesized body ever intend to handle920    // ownership? As of today they don't. And if they did, how would we921    // put notes inside it, given that it doesn't match any source locations?922    if (!FD || !FD->hasBody())923      return false;924    using namespace clang::ast_matchers;925 926    auto Matches = match(findAll(stmt(anyOf(cxxDeleteExpr().bind("delete"),927                                            callExpr().bind("call")))),928                         *FD->getBody(), ACtx);929    for (BoundNodes Match : Matches) {930      if (Match.getNodeAs<CXXDeleteExpr>("delete"))931        return true;932 933      if (const auto *Call = Match.getNodeAs<CallExpr>("call"))934        if (isFreeingCallAsWritten(*Call))935          return true;936    }937    // TODO: Ownership might change with an attempt to store the allocated938    // memory, not only through deallocation. Check for attempted stores as939    // well.940    return false;941  }942 943  PathDiagnosticPieceRef emitNote(const ExplodedNode *N) final {944    PathDiagnosticLocation L = PathDiagnosticLocation::create(945        N->getLocation(),946        N->getState()->getStateManager().getContext().getSourceManager());947    return std::make_shared<PathDiagnosticEventPiece>(948        L, "Returning without deallocating memory or storing the pointer for "949           "later deallocation");950  }951 952public:953  NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)954      : NoOwnershipChangeVisitor(Sym, Checker) {}955 956  void Profile(llvm::FoldingSetNodeID &ID) const override {957    static int Tag = 0;958    ID.AddPointer(&Tag);959    ID.AddPointer(Sym);960  }961};962 963} // end anonymous namespace964 965//===----------------------------------------------------------------------===//966// Definition of MallocBugVisitor.967//===----------------------------------------------------------------------===//968 969namespace {970/// The bug visitor which allows us to print extra diagnostics along the971/// BugReport path. For example, showing the allocation site of the leaked972/// region.973class MallocBugVisitor final : public BugReporterVisitor {974protected:975  enum NotificationMode { Normal, ReallocationFailed };976 977  // The allocated region symbol tracked by the main analysis.978  SymbolRef Sym;979 980  // The mode we are in, i.e. what kind of diagnostics will be emitted.981  NotificationMode Mode;982 983  // A symbol from when the primary region should have been reallocated.984  SymbolRef FailedReallocSymbol;985 986  // A release function stack frame in which memory was released. Used for987  // miscellaneous false positive suppression.988  const StackFrameContext *ReleaseFunctionLC;989 990  bool IsLeak;991 992public:993  MallocBugVisitor(SymbolRef S, bool isLeak = false)994      : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),995        ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}996 997  static void *getTag() {998    static int Tag = 0;999    return &Tag;1000  }1001 1002  void Profile(llvm::FoldingSetNodeID &ID) const override {1003    ID.AddPointer(getTag());1004    ID.AddPointer(Sym);1005  }1006 1007  /// Did not track -> allocated. Other state (released) -> allocated.1008  static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,1009                                 const Stmt *Stmt) {1010    return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&1011            (RSCurr &&1012             (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&1013            (!RSPrev ||1014             !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));1015  }1016 1017  /// Did not track -> released. Other state (allocated) -> released.1018  /// The statement associated with the release might be missing.1019  static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,1020                                const Stmt *Stmt) {1021    bool IsReleased =1022        (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());1023    assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||1024           (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));1025    return IsReleased;1026  }1027 1028  /// Did not track -> relinquished. Other state (allocated) -> relinquished.1029  static inline bool isRelinquished(const RefState *RSCurr,1030                                    const RefState *RSPrev, const Stmt *Stmt) {1031    return (1032        isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&1033        (RSCurr && RSCurr->isRelinquished()) &&1034        (!RSPrev || !RSPrev->isRelinquished()));1035  }1036 1037  /// If the expression is not a call, and the state change is1038  /// released -> allocated, it must be the realloc return value1039  /// check. If we have to handle more cases here, it might be cleaner just1040  /// to track this extra bit in the state itself.1041  static inline bool hasReallocFailed(const RefState *RSCurr,1042                                      const RefState *RSPrev,1043                                      const Stmt *Stmt) {1044    return ((!isa_and_nonnull<CallExpr>(Stmt)) &&1045            (RSCurr &&1046             (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&1047            (RSPrev &&1048             !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));1049  }1050 1051  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,1052                                   BugReporterContext &BRC,1053                                   PathSensitiveBugReport &BR) override;1054 1055  PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,1056                                    const ExplodedNode *EndPathNode,1057                                    PathSensitiveBugReport &BR) override {1058    if (!IsLeak)1059      return nullptr;1060 1061    PathDiagnosticLocation L = BR.getLocation();1062    // Do not add the statement itself as a range in case of leak.1063    return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),1064                                                      false);1065  }1066 1067private:1068  class StackHintGeneratorForReallocationFailed1069      : public StackHintGeneratorForSymbol {1070  public:1071    StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)1072        : StackHintGeneratorForSymbol(S, M) {}1073 1074    std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {1075      // Printed parameters start at 1, not 0.1076      ++ArgIndex;1077 1078      SmallString<200> buf;1079      llvm::raw_svector_ostream os(buf);1080 1081      os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)1082         << " parameter failed";1083 1084      return std::string(os.str());1085    }1086 1087    std::string getMessageForReturn(const CallExpr *CallExpr) override {1088      return "Reallocation of returned value failed";1089    }1090  };1091};1092} // end anonymous namespace1093 1094// A map from the freed symbol to the symbol representing the return value of1095// the free function.1096REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)1097 1098namespace {1099class StopTrackingCallback final : public SymbolVisitor {1100  ProgramStateRef state;1101 1102public:1103  StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}1104  ProgramStateRef getState() const { return state; }1105 1106  bool VisitSymbol(SymbolRef sym) override {1107    state = state->remove<RegionState>(sym);1108    return true;1109  }1110};1111 1112/// EscapeTrackedCallback - A SymbolVisitor that marks allocated symbols as1113/// escaped.1114///1115/// This visitor is used to suppress false positive leak reports when smart1116/// pointers are nested in temporary objects passed by value to functions. When1117/// the analyzer can't see the destructor calls for temporary objects, it may1118/// incorrectly report leaks for memory that will be properly freed by the smart1119/// pointer destructors.1120///1121/// The visitor traverses reachable symbols from a given set of memory regions1122/// (typically smart pointer field regions) and marks any allocated symbols as1123/// escaped. Escaped symbols are not reported as leaks by checkDeadSymbols.1124class EscapeTrackedCallback final : public SymbolVisitor {1125  ProgramStateRef State;1126 1127  explicit EscapeTrackedCallback(ProgramStateRef S) : State(std::move(S)) {}1128 1129public:1130  bool VisitSymbol(SymbolRef Sym) override {1131    if (const RefState *RS = State->get<RegionState>(Sym)) {1132      if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {1133        State = State->set<RegionState>(Sym, RefState::getEscaped(RS));1134      }1135    }1136    return true;1137  }1138 1139  /// Escape tracked regions reachable from the given roots.1140  static ProgramStateRef1141  EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,1142                                    ProgramStateRef State) {1143    if (Roots.empty())1144      return State;1145 1146    // scanReachableSymbols is expensive, so we use a single visitor for all1147    // roots1148    SmallVector<const MemRegion *, 10> Regions;1149    EscapeTrackedCallback Visitor(State);1150    for (const MemRegion *R : Roots) {1151      Regions.push_back(R);1152    }1153    State->scanReachableSymbols(Regions, Visitor);1154    return Visitor.State;1155  }1156 1157  friend class SymbolVisitor;1158};1159} // end anonymous namespace1160 1161static bool isStandardNew(const FunctionDecl *FD) {1162  if (!FD)1163    return false;1164 1165  OverloadedOperatorKind Kind = FD->getOverloadedOperator();1166  if (Kind != OO_New && Kind != OO_Array_New)1167    return false;1168 1169  // This is standard if and only if it's not defined in a user file.1170  SourceLocation L = FD->getLocation();1171  // If the header for operator delete is not included, it's still defined1172  // in an invalid source location. Check to make sure we don't crash.1173  return !L.isValid() ||1174         FD->getASTContext().getSourceManager().isInSystemHeader(L);1175}1176 1177static bool isStandardDelete(const FunctionDecl *FD) {1178  if (!FD)1179    return false;1180 1181  OverloadedOperatorKind Kind = FD->getOverloadedOperator();1182  if (Kind != OO_Delete && Kind != OO_Array_Delete)1183    return false;1184 1185  bool HasBody = FD->hasBody(); // Prefer using the definition.1186 1187  // This is standard if and only if it's not defined in a user file.1188  SourceLocation L = FD->getLocation();1189 1190  // If the header for operator delete is not included, it's still defined1191  // in an invalid source location. Check to make sure we don't crash.1192  const auto &SM = FD->getASTContext().getSourceManager();1193  return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));1194}1195 1196//===----------------------------------------------------------------------===//1197// Methods of MallocChecker and MallocBugVisitor.1198//===----------------------------------------------------------------------===//1199 1200bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) {1201  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());1202 1203  return Func && isFreeingOwnershipAttrCall(Func);1204}1205 1206bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {1207  if (Func->hasAttrs()) {1208    for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {1209      OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();1210      if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)1211        return true;1212    }1213  }1214  return false;1215}1216 1217bool MallocChecker::isFreeingCall(const CallEvent &Call) const {1218  if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))1219    return true;1220 1221  return isFreeingOwnershipAttrCall(Call);1222}1223 1224bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) {1225  const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());1226 1227  return Func && isAllocatingOwnershipAttrCall(Func);1228}1229 1230bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) {1231  for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {1232    if (I->getOwnKind() == OwnershipAttr::Returns)1233      return true;1234  }1235 1236  return false;1237}1238 1239bool MallocChecker::isMemCall(const CallEvent &Call) const {1240  if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||1241      AllocaMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))1242    return true;1243 1244  if (!ShouldIncludeOwnershipAnnotatedFunctions)1245    return false;1246 1247  const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());1248  return Func && Func->hasAttr<OwnershipAttr>();1249}1250 1251std::optional<ProgramStateRef>1252MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,1253                                   const ProgramStateRef &State) const {1254  // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:1255  //1256  // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);1257  //1258  // One of the possible flags is M_ZERO, which means 'give me back an1259  // allocation which is already zeroed', like calloc.1260 1261  // 2-argument kmalloc(), as used in the Linux kernel:1262  //1263  // void *kmalloc(size_t size, gfp_t flags);1264  //1265  // Has the similar flag value __GFP_ZERO.1266 1267  // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some1268  // code could be shared.1269 1270  ASTContext &Ctx = C.getASTContext();1271  llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();1272 1273  if (!KernelZeroFlagVal) {1274    switch (OS) {1275    case llvm::Triple::FreeBSD:1276      KernelZeroFlagVal = 0x0100;1277      break;1278    case llvm::Triple::NetBSD:1279      KernelZeroFlagVal = 0x0002;1280      break;1281    case llvm::Triple::OpenBSD:1282      KernelZeroFlagVal = 0x0008;1283      break;1284    case llvm::Triple::Linux:1285      // __GFP_ZERO1286      KernelZeroFlagVal = 0x8000;1287      break;1288    default:1289      // FIXME: We need a more general way of getting the M_ZERO value.1290      // See also: O_CREAT in UnixAPIChecker.cpp.1291 1292      // Fall back to normal malloc behavior on platforms where we don't1293      // know M_ZERO.1294      return std::nullopt;1295    }1296  }1297 1298  // We treat the last argument as the flags argument, and callers fall-back to1299  // normal malloc on a None return. This works for the FreeBSD kernel malloc1300  // as well as Linux kmalloc.1301  if (Call.getNumArgs() < 2)1302    return std::nullopt;1303 1304  const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);1305  const SVal V = C.getSVal(FlagsEx);1306  if (!isa<NonLoc>(V)) {1307    // The case where 'V' can be a location can only be due to a bad header,1308    // so in this case bail out.1309    return std::nullopt;1310  }1311 1312  NonLoc Flags = V.castAs<NonLoc>();1313  NonLoc ZeroFlag = C.getSValBuilder()1314                        .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())1315                        .castAs<NonLoc>();1316  SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,1317                                                      Flags, ZeroFlag,1318                                                      FlagsEx->getType());1319  if (MaskedFlagsUC.isUnknownOrUndef())1320    return std::nullopt;1321  DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();1322 1323  // Check if maskedFlags is non-zero.1324  ProgramStateRef TrueState, FalseState;1325  std::tie(TrueState, FalseState) = State->assume(MaskedFlags);1326 1327  // If M_ZERO is set, treat this like calloc (initialized).1328  if (TrueState && !FalseState) {1329    SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);1330    return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,1331                        AllocationFamily(AF_Malloc));1332  }1333 1334  return std::nullopt;1335}1336 1337SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,1338                                         const Expr *BlockBytes) {1339  SValBuilder &SB = C.getSValBuilder();1340  SVal BlocksVal = C.getSVal(Blocks);1341  SVal BlockBytesVal = C.getSVal(BlockBytes);1342  ProgramStateRef State = C.getState();1343  SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,1344                                SB.getContext().getCanonicalSizeType());1345  return TotalSize;1346}1347 1348void MallocChecker::checkBasicAlloc(ProgramStateRef State,1349                                    const CallEvent &Call,1350                                    CheckerContext &C) const {1351  State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,1352                       AllocationFamily(AF_Malloc));1353  State = ProcessZeroAllocCheck(C, Call, 0, State);1354  C.addTransition(State);1355}1356 1357void MallocChecker::checkKernelMalloc(ProgramStateRef State,1358                                      const CallEvent &Call,1359                                      CheckerContext &C) const {1360  std::optional<ProgramStateRef> MaybeState =1361      performKernelMalloc(Call, C, State);1362  if (MaybeState)1363    State = *MaybeState;1364  else1365    State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,1366                         AllocationFamily(AF_Malloc));1367  C.addTransition(State);1368}1369 1370static bool isStandardRealloc(const CallEvent &Call) {1371  const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());1372  assert(FD);1373  ASTContext &AC = FD->getASTContext();1374  return AC.hasSameType(FD->getDeclaredReturnType(), AC.VoidPtrTy) &&1375         AC.hasSameType(FD->getParamDecl(0)->getType(), AC.VoidPtrTy) &&1376         AC.hasSameType(FD->getParamDecl(1)->getType(), AC.getSizeType());1377}1378 1379static bool isGRealloc(const CallEvent &Call) {1380  const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());1381  assert(FD);1382  ASTContext &AC = FD->getASTContext();1383 1384  return AC.hasSameType(FD->getDeclaredReturnType(), AC.VoidPtrTy) &&1385         AC.hasSameType(FD->getParamDecl(0)->getType(), AC.VoidPtrTy) &&1386         AC.hasSameType(FD->getParamDecl(1)->getType(), AC.UnsignedLongTy);1387}1388 1389void MallocChecker::checkRealloc(ProgramStateRef State, const CallEvent &Call,1390                                 CheckerContext &C,1391                                 bool ShouldFreeOnFail) const {1392  // Ignore calls to functions whose type does not match the expected type of1393  // either the standard realloc or g_realloc from GLib.1394  // FIXME: Should we perform this kind of checking consistently for each1395  // function? If yes, then perhaps extend the `CallDescription` interface to1396  // handle this.1397  if (!isStandardRealloc(Call) && !isGRealloc(Call))1398    return;1399 1400  State = ReallocMemAux(C, Call, ShouldFreeOnFail, State,1401                        AllocationFamily(AF_Malloc));1402  State = ProcessZeroAllocCheck(C, Call, 1, State);1403  C.addTransition(State);1404}1405 1406void MallocChecker::checkCalloc(ProgramStateRef State, const CallEvent &Call,1407                                CheckerContext &C) const {1408  State = CallocMem(C, Call, State);1409  State = ProcessZeroAllocCheck(C, Call, 0, State);1410  State = ProcessZeroAllocCheck(C, Call, 1, State);1411  C.addTransition(State);1412}1413 1414void MallocChecker::checkFree(ProgramStateRef State, const CallEvent &Call,1415                              CheckerContext &C) const {1416  bool IsKnownToBeAllocatedMemory = false;1417  if (suppressDeallocationsInSuspiciousContexts(Call, C))1418    return;1419  State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,1420                     AllocationFamily(AF_Malloc));1421  C.addTransition(State);1422}1423 1424void MallocChecker::checkAlloca(ProgramStateRef State, const CallEvent &Call,1425                                CheckerContext &C) const {1426  State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,1427                       AllocationFamily(AF_Alloca));1428  State = ProcessZeroAllocCheck(C, Call, 0, State);1429  C.addTransition(State);1430}1431 1432void MallocChecker::checkStrdup(ProgramStateRef State, const CallEvent &Call,1433                                CheckerContext &C) const {1434  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());1435  if (!CE)1436    return;1437  State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,1438                       AllocationFamily(AF_Malloc));1439 1440  C.addTransition(State);1441}1442 1443void MallocChecker::checkIfNameIndex(ProgramStateRef State,1444                                     const CallEvent &Call,1445                                     CheckerContext &C) const {1446  // Should we model this differently? We can allocate a fixed number of1447  // elements with zeros in the last one.1448  State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,1449                       AllocationFamily(AF_IfNameIndex));1450 1451  C.addTransition(State);1452}1453 1454void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,1455                                         const CallEvent &Call,1456                                         CheckerContext &C) const {1457  bool IsKnownToBeAllocatedMemory = false;1458  State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,1459                     AllocationFamily(AF_IfNameIndex));1460  C.addTransition(State);1461}1462 1463static const Expr *getPlacementNewBufferArg(const CallExpr *CE,1464                                            const FunctionDecl *FD) {1465  // Checking for signature:1466  // void* operator new  ( std::size_t count, void* ptr );1467  // void* operator new[]( std::size_t count, void* ptr );1468  if (CE->getNumArgs() != 2 || (FD->getOverloadedOperator() != OO_New &&1469                                FD->getOverloadedOperator() != OO_Array_New))1470    return nullptr;1471  auto BuffType = FD->getParamDecl(1)->getType();1472  if (BuffType.isNull() || !BuffType->isVoidPointerType())1473    return nullptr;1474  return CE->getArg(1);1475}1476 1477void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,1478                                           const CallEvent &Call,1479                                           CheckerContext &C) const {1480  bool IsKnownToBeAllocatedMemory = false;1481  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());1482  if (!CE)1483    return;1484 1485  assert(isStandardNewDelete(Call));1486 1487  // Process direct calls to operator new/new[]/delete/delete[] functions1488  // as distinct from new/new[]/delete/delete[] expressions that are1489  // processed by the checkPostStmt callbacks for CXXNewExpr and1490  // CXXDeleteExpr.1491  const FunctionDecl *FD = C.getCalleeDecl(CE);1492  if (const auto *BufArg = getPlacementNewBufferArg(CE, FD)) {1493    // Placement new does not allocate memory1494    auto RetVal = State->getSVal(BufArg, Call.getLocationContext());1495    State = State->BindExpr(CE, C.getLocationContext(), RetVal);1496    C.addTransition(State);1497    return;1498  }1499 1500  switch (FD->getOverloadedOperator()) {1501  case OO_New:1502    State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,1503                         AllocationFamily(AF_CXXNew));1504    State = ProcessZeroAllocCheck(C, Call, 0, State);1505    break;1506  case OO_Array_New:1507    State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,1508                         AllocationFamily(AF_CXXNewArray));1509    State = ProcessZeroAllocCheck(C, Call, 0, State);1510    break;1511  case OO_Delete:1512    State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,1513                       AllocationFamily(AF_CXXNew));1514    break;1515  case OO_Array_Delete:1516    State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,1517                       AllocationFamily(AF_CXXNewArray));1518    break;1519  default:1520    assert(false && "not a new/delete operator");1521    return;1522  }1523 1524  C.addTransition(State);1525}1526 1527void MallocChecker::checkGMalloc0(ProgramStateRef State, const CallEvent &Call,1528                                  CheckerContext &C) const {1529  SValBuilder &svalBuilder = C.getSValBuilder();1530  SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);1531  State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State,1532                       AllocationFamily(AF_Malloc));1533  State = ProcessZeroAllocCheck(C, Call, 0, State);1534  C.addTransition(State);1535}1536 1537void MallocChecker::checkGMemdup(ProgramStateRef State, const CallEvent &Call,1538                                 CheckerContext &C) const {1539  State = MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State,1540                       AllocationFamily(AF_Malloc));1541  State = ProcessZeroAllocCheck(C, Call, 1, State);1542  C.addTransition(State);1543}1544 1545void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,1546                                  CheckerContext &C) const {1547  SVal Init = UndefinedVal();1548  SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));1549  State = MallocMemAux(C, Call, TotalSize, Init, State,1550                       AllocationFamily(AF_Malloc));1551  State = ProcessZeroAllocCheck(C, Call, 0, State);1552  State = ProcessZeroAllocCheck(C, Call, 1, State);1553  C.addTransition(State);1554}1555 1556void MallocChecker::checkGMallocN0(ProgramStateRef State, const CallEvent &Call,1557                                   CheckerContext &C) const {1558  SValBuilder &SB = C.getSValBuilder();1559  SVal Init = SB.makeZeroVal(SB.getContext().CharTy);1560  SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));1561  State = MallocMemAux(C, Call, TotalSize, Init, State,1562                       AllocationFamily(AF_Malloc));1563  State = ProcessZeroAllocCheck(C, Call, 0, State);1564  State = ProcessZeroAllocCheck(C, Call, 1, State);1565  C.addTransition(State);1566}1567 1568static bool isFromStdNamespace(const CallEvent &Call) {1569  const Decl *FD = Call.getDecl();1570  assert(FD && "a CallDescription cannot match a call without a Decl");1571  return FD->isInStdNamespace();1572}1573 1574void MallocChecker::preGetDelimOrGetLine(ProgramStateRef State,1575                                         const CallEvent &Call,1576                                         CheckerContext &C) const {1577  // Discard calls to the C++ standard library function std::getline(), which1578  // is completely unrelated to the POSIX getline() that we're checking.1579  if (isFromStdNamespace(Call))1580    return;1581 1582  const auto LinePtr = getPointeeVal(Call.getArgSVal(0), State);1583  if (!LinePtr)1584    return;1585 1586  // FreeMemAux takes IsKnownToBeAllocated as an output parameter, and it will1587  // be true after the call if the symbol was registered by this checker.1588  // We do not need this value here, as FreeMemAux will take care1589  // of reporting any violation of the preconditions.1590  bool IsKnownToBeAllocated = false;1591  State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false,1592                     IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,1593                     LinePtr);1594  if (State)1595    C.addTransition(State);1596}1597 1598void MallocChecker::checkGetDelimOrGetLine(ProgramStateRef State,1599                                           const CallEvent &Call,1600                                           CheckerContext &C) const {1601  // Discard calls to the C++ standard library function std::getline(), which1602  // is completely unrelated to the POSIX getline() that we're checking.1603  if (isFromStdNamespace(Call))1604    return;1605 1606  // Handle the post-conditions of getline and getdelim:1607  // Register the new conjured value as an allocated buffer.1608  const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());1609  if (!CE)1610    return;1611 1612  const auto LinePtrOpt = getPointeeVal(Call.getArgSVal(0), State);1613  const auto SizeOpt = getPointeeVal(Call.getArgSVal(1), State);1614  if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||1615      SizeOpt->isUnknownOrUndef())1616    return;1617 1618  const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();1619  const auto Size = SizeOpt->getAs<DefinedSVal>();1620  const MemRegion *LinePtrReg = LinePtr->getAsRegion();1621  if (!LinePtrReg)1622    return;1623 1624  State = setDynamicExtent(State, LinePtrReg, *Size);1625  C.addTransition(MallocUpdateRefState(C, CE, State,1626                                       AllocationFamily(AF_Malloc), *LinePtr));1627}1628 1629void MallocChecker::checkReallocN(ProgramStateRef State, const CallEvent &Call,1630                                  CheckerContext &C) const {1631  State = ReallocMemAux(C, Call, /*ShouldFreeOnFail=*/false, State,1632                        AllocationFamily(AF_Malloc),1633                        /*SuffixWithN=*/true);1634  State = ProcessZeroAllocCheck(C, Call, 1, State);1635  State = ProcessZeroAllocCheck(C, Call, 2, State);1636  C.addTransition(State);1637}1638 1639void MallocChecker::checkOwnershipAttr(ProgramStateRef State,1640                                       const CallEvent &Call,1641                                       CheckerContext &C) const {1642  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());1643  if (!CE)1644    return;1645  const FunctionDecl *FD = C.getCalleeDecl(CE);1646  if (!FD)1647    return;1648  if (ShouldIncludeOwnershipAnnotatedFunctions ||1649      MismatchedDeallocatorChecker.isEnabled()) {1650    // Check all the attributes, if there are any.1651    // There can be multiple of these attributes.1652    if (FD->hasAttrs())1653      for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {1654        switch (I->getOwnKind()) {1655        case OwnershipAttr::Returns:1656          State = MallocMemReturnsAttr(C, Call, I, State);1657          break;1658        case OwnershipAttr::Takes:1659        case OwnershipAttr::Holds:1660          State = FreeMemAttr(C, Call, I, State);1661          break;1662        }1663      }1664  }1665  C.addTransition(State);1666}1667 1668bool MallocChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {1669  if (!Call.getOriginExpr())1670    return false;1671 1672  ProgramStateRef State = C.getState();1673 1674  if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {1675    (*Callback)(this, State, Call, C);1676    return true;1677  }1678 1679  if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {1680    State = MallocBindRetVal(C, Call, State, false);1681    (*Callback)(this, State, Call, C);1682    return true;1683  }1684 1685  if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {1686    State = MallocBindRetVal(C, Call, State, false);1687    (*Callback)(this, State, Call, C);1688    return true;1689  }1690 1691  if (isStandardNew(Call)) {1692    State = MallocBindRetVal(C, Call, State, false);1693    checkCXXNewOrCXXDelete(State, Call, C);1694    return true;1695  }1696 1697  if (isStandardDelete(Call)) {1698    checkCXXNewOrCXXDelete(State, Call, C);1699    return true;1700  }1701 1702  if (const CheckFn *Callback = AllocaMemFnMap.lookup(Call)) {1703    State = MallocBindRetVal(C, Call, State, true);1704    (*Callback)(this, State, Call, C);1705    return true;1706  }1707 1708  if (isFreeingOwnershipAttrCall(Call)) {1709    checkOwnershipAttr(State, Call, C);1710    return true;1711  }1712 1713  if (isAllocatingOwnershipAttrCall(Call)) {1714    State = MallocBindRetVal(C, Call, State, false);1715    checkOwnershipAttr(State, Call, C);1716    return true;1717  }1718 1719  return false;1720}1721 1722// Performs a 0-sized allocations check.1723ProgramStateRef MallocChecker::ProcessZeroAllocCheck(1724    CheckerContext &C, const CallEvent &Call, const unsigned IndexOfSizeArg,1725    ProgramStateRef State, std::optional<SVal> RetVal) {1726  if (!State)1727    return nullptr;1728 1729  const Expr *Arg = nullptr;1730 1731  if (const CallExpr *CE = dyn_cast<CallExpr>(Call.getOriginExpr())) {1732    Arg = CE->getArg(IndexOfSizeArg);1733  } else if (const CXXNewExpr *NE =1734                 dyn_cast<CXXNewExpr>(Call.getOriginExpr())) {1735    if (NE->isArray()) {1736      Arg = *NE->getArraySize();1737    } else {1738      return State;1739    }1740  } else {1741    assert(false && "not a CallExpr or CXXNewExpr");1742    return nullptr;1743  }1744 1745  if (!RetVal)1746    RetVal = State->getSVal(Call.getOriginExpr(), C.getLocationContext());1747 1748  assert(Arg);1749 1750  auto DefArgVal =1751      State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();1752 1753  if (!DefArgVal)1754    return State;1755 1756  // Check if the allocation size is 0.1757  ProgramStateRef TrueState, FalseState;1758  SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();1759  DefinedSVal Zero =1760      SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();1761 1762  std::tie(TrueState, FalseState) =1763      State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));1764 1765  if (TrueState && !FalseState) {1766    SymbolRef Sym = RetVal->getAsLocSymbol();1767    if (!Sym)1768      return State;1769 1770    const RefState *RS = State->get<RegionState>(Sym);1771    if (RS) {1772      if (RS->isAllocated())1773        return TrueState->set<RegionState>(1774            Sym, RefState::getAllocatedOfSizeZero(RS));1775      return State;1776    }1777    // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as1778    // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not1779    // tracked. Add zero-reallocated Sym to the state to catch references1780    // to zero-allocated memory.1781    return TrueState->add<ReallocSizeZeroSymbols>(Sym);1782  }1783 1784  // Assume the value is non-zero going forward.1785  assert(FalseState);1786  return FalseState;1787}1788 1789static QualType getDeepPointeeType(QualType T) {1790  QualType Result = T, PointeeType = T->getPointeeType();1791  while (!PointeeType.isNull()) {1792    Result = PointeeType;1793    PointeeType = PointeeType->getPointeeType();1794  }1795  return Result;1796}1797 1798/// \returns true if the constructor invoked by \p NE has an argument of a1799/// pointer/reference to a record type.1800static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) {1801 1802  const CXXConstructExpr *ConstructE = NE->getConstructExpr();1803  if (!ConstructE)1804    return false;1805 1806  if (!NE->getAllocatedType()->getAsCXXRecordDecl())1807    return false;1808 1809  const CXXConstructorDecl *CtorD = ConstructE->getConstructor();1810 1811  // Iterate over the constructor parameters.1812  for (const auto *CtorParam : CtorD->parameters()) {1813 1814    QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType();1815    if (CtorParamPointeeT.isNull())1816      continue;1817 1818    CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT);1819 1820    if (CtorParamPointeeT->getAsCXXRecordDecl())1821      return true;1822  }1823 1824  return false;1825}1826 1827ProgramStateRef1828MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,1829                                    CheckerContext &C,1830                                    AllocationFamily Family) const {1831  if (!isStandardNewDelete(Call))1832    return nullptr;1833 1834  const CXXNewExpr *NE = Call.getOriginExpr();1835  const ParentMap &PM = C.getLocationContext()->getParentMap();1836  ProgramStateRef State = C.getState();1837 1838  // Non-trivial constructors have a chance to escape 'this', but marking all1839  // invocations of trivial constructors as escaped would cause too great of1840  // reduction of true positives, so let's just do that for constructors that1841  // have an argument of a pointer-to-record type.1842  if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE))1843    return State;1844 1845  // The return value from operator new is bound to a specified initialization1846  // value (if any) and we don't want to loose this value. So we call1847  // MallocUpdateRefState() instead of MallocMemAux() which breaks the1848  // existing binding.1849  SVal Target = Call.getObjectUnderConstruction();1850  if (Call.getOriginExpr()->isArray()) {1851    if (auto SizeEx = NE->getArraySize())1852      checkTaintedness(C, Call, C.getSVal(*SizeEx), State,1853                       AllocationFamily(AF_CXXNewArray));1854  }1855 1856  State = MallocUpdateRefState(C, NE, State, Family, Target);1857  State = ProcessZeroAllocCheck(C, Call, 0, State, Target);1858  return State;1859}1860 1861void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,1862                                      CheckerContext &C) const {1863  if (!C.wasInlined) {1864    ProgramStateRef State = processNewAllocation(1865        Call, C,1866        AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray1867                                                         : AF_CXXNew));1868    C.addTransition(State);1869  }1870}1871 1872static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {1873  // If the first selector piece is one of the names below, assume that the1874  // object takes ownership of the memory, promising to eventually deallocate it1875  // with free().1876  // Ex:  [NSData dataWithBytesNoCopy:bytes length:10];1877  // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)1878  StringRef FirstSlot = Call.getSelector().getNameForSlot(0);1879  return FirstSlot == "dataWithBytesNoCopy" ||1880         FirstSlot == "initWithBytesNoCopy" ||1881         FirstSlot == "initWithCharactersNoCopy";1882}1883 1884static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {1885  Selector S = Call.getSelector();1886 1887  // FIXME: We should not rely on fully-constrained symbols being folded.1888  for (unsigned i = 1; i < S.getNumArgs(); ++i)1889    if (S.getNameForSlot(i) == "freeWhenDone")1890      return !Call.getArgSVal(i).isZeroConstant();1891 1892  return std::nullopt;1893}1894 1895void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,1896                                         CheckerContext &C) const {1897  if (C.wasInlined)1898    return;1899 1900  if (!isKnownDeallocObjCMethodName(Call))1901    return;1902 1903  if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))1904    if (!*FreeWhenDone)1905      return;1906 1907  if (Call.hasNonZeroCallbackArg())1908    return;1909 1910  bool IsKnownToBeAllocatedMemory;1911  ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(),1912                                     /*Hold=*/true, IsKnownToBeAllocatedMemory,1913                                     AllocationFamily(AF_Malloc),1914                                     /*ReturnsNullOnFailure=*/true);1915 1916  C.addTransition(State);1917}1918 1919ProgramStateRef1920MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,1921                                    const OwnershipAttr *Att,1922                                    ProgramStateRef State) const {1923  if (!State)1924    return nullptr;1925 1926  auto attrClassName = Att->getModule()->getName();1927  auto Family = AllocationFamily(AF_Custom, attrClassName);1928 1929  if (!Att->args().empty()) {1930    return MallocMemAux(C, Call,1931                        Call.getArgExpr(Att->args_begin()->getASTIndex()),1932                        UnknownVal(), State, Family);1933  }1934  return MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, Family);1935}1936 1937ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,1938                                                const CallEvent &Call,1939                                                ProgramStateRef State,1940                                                bool isAlloca) const {1941  const Expr *CE = Call.getOriginExpr();1942 1943  // We expect the allocation functions to return a pointer.1944  if (!Loc::isLocType(CE->getType()))1945    return nullptr;1946 1947  unsigned Count = C.blockCount();1948  SValBuilder &SVB = C.getSValBuilder();1949  const LocationContext *LCtx = C.getPredecessor()->getLocationContext();1950  DefinedSVal RetVal =1951      isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)1952               : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,1953                                              CE->getType(), Count);1954  return State->BindExpr(CE, C.getLocationContext(), RetVal);1955}1956 1957ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,1958                                            const CallEvent &Call,1959                                            const Expr *SizeEx, SVal Init,1960                                            ProgramStateRef State,1961                                            AllocationFamily Family) const {1962  if (!State)1963    return nullptr;1964 1965  assert(SizeEx);1966  return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);1967}1968 1969void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,1970                                   CheckerContext &C,1971                                   llvm::ArrayRef<SymbolRef> TaintedSyms,1972                                   AllocationFamily Family) const {1973  if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {1974    auto R =1975        std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);1976    for (const auto *TaintedSym : TaintedSyms) {1977      R->markInteresting(TaintedSym);1978    }1979    C.emitReport(std::move(R));1980  }1981}1982 1983void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,1984                                     const SVal SizeSVal, ProgramStateRef State,1985                                     AllocationFamily Family) const {1986  if (!TaintedAllocChecker.isEnabled())1987    return;1988  std::vector<SymbolRef> TaintedSyms =1989      taint::getTaintedSymbols(State, SizeSVal);1990  if (TaintedSyms.empty())1991    return;1992 1993  SValBuilder &SVB = C.getSValBuilder();1994  QualType SizeTy = SVB.getContext().getSizeType();1995  QualType CmpTy = SVB.getConditionType();1996  // In case the symbol is tainted, we give a warning if the1997  // size is larger than SIZE_MAX/41998  BasicValueFactory &BVF = SVB.getBasicValueFactory();1999  const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);2000  NonLoc MaxLength =2001      SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));2002  std::optional<NonLoc> SizeNL = SizeSVal.getAs<NonLoc>();2003  auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)2004                 .getAs<DefinedOrUnknownSVal>();2005  if (!Cmp)2006    return;2007  auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);2008  if (!StateTooLarge && StateNotTooLarge) {2009    // We can prove that size is not too large so there is no issue.2010    return;2011  }2012 2013  std::string Callee = "Memory allocation function";2014  if (Call.getCalleeIdentifier())2015    Callee = Call.getCalleeIdentifier()->getName().str();2016  reportTaintBug(2017      Callee + " is called with a tainted (potentially attacker controlled) "2018               "value. Make sure the value is bound checked.",2019      State, C, TaintedSyms, Family);2020}2021 2022ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,2023                                            const CallEvent &Call, SVal Size,2024                                            SVal Init, ProgramStateRef State,2025                                            AllocationFamily Family) const {2026  if (!State)2027    return nullptr;2028 2029  const Expr *CE = Call.getOriginExpr();2030 2031  // We expect the malloc functions to return a pointer.2032  // Should have been already checked.2033  assert(Loc::isLocType(CE->getType()) &&2034         "Allocation functions must return a pointer");2035 2036  const LocationContext *LCtx = C.getPredecessor()->getLocationContext();2037  SVal RetVal = State->getSVal(CE, C.getLocationContext());2038 2039  // Fill the region with the initialization value.2040  State = State->bindDefaultInitial(RetVal, Init, LCtx);2041 2042  // If Size is somehow undefined at this point, this line prevents a crash.2043  if (Size.isUndef())2044    Size = UnknownVal();2045 2046  checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));2047 2048  // Set the region's extent.2049  State = setDynamicExtent(State, RetVal.getAsRegion(),2050                           Size.castAs<DefinedOrUnknownSVal>());2051 2052  return MallocUpdateRefState(C, CE, State, Family);2053}2054 2055static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,2056                                            ProgramStateRef State,2057                                            AllocationFamily Family,2058                                            std::optional<SVal> RetVal) {2059  if (!State)2060    return nullptr;2061 2062  // Get the return value.2063  if (!RetVal)2064    RetVal = State->getSVal(E, C.getLocationContext());2065 2066  // We expect the malloc functions to return a pointer.2067  if (!RetVal->getAs<Loc>())2068    return nullptr;2069 2070  SymbolRef Sym = RetVal->getAsLocSymbol();2071 2072  // NOTE: If this was an `alloca()` call, then `RetVal` holds an2073  // `AllocaRegion`, so `Sym` will be a nullpointer because `AllocaRegion`s do2074  // not have an associated symbol. However, this distinct region type means2075  // that we don't need to store anything about them in `RegionState`.2076 2077  if (Sym)2078    return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));2079 2080  return State;2081}2082 2083ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,2084                                           const CallEvent &Call,2085                                           const OwnershipAttr *Att,2086                                           ProgramStateRef State) const {2087  if (!State)2088    return nullptr;2089 2090  auto attrClassName = Att->getModule()->getName();2091  auto Family = AllocationFamily(AF_Custom, attrClassName);2092 2093  bool IsKnownToBeAllocated = false;2094 2095  for (const auto &Arg : Att->args()) {2096    ProgramStateRef StateI =2097        FreeMemAux(C, Call, State, Arg.getASTIndex(),2098                   Att->getOwnKind() == OwnershipAttr::Holds,2099                   IsKnownToBeAllocated, Family);2100    if (StateI)2101      State = StateI;2102  }2103  return State;2104}2105 2106ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,2107                                          const CallEvent &Call,2108                                          ProgramStateRef State, unsigned Num,2109                                          bool Hold, bool &IsKnownToBeAllocated,2110                                          AllocationFamily Family,2111                                          bool ReturnsNullOnFailure) const {2112  if (!State)2113    return nullptr;2114 2115  if (Call.getNumArgs() < (Num + 1))2116    return nullptr;2117 2118  return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,2119                    IsKnownToBeAllocated, Family, ReturnsNullOnFailure);2120}2121 2122/// Checks if the previous call to free on the given symbol failed - if free2123/// failed, returns true. Also, returns the corresponding return value symbol.2124static bool didPreviousFreeFail(ProgramStateRef State,2125                                SymbolRef Sym, SymbolRef &RetStatusSymbol) {2126  const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);2127  if (Ret) {2128    assert(*Ret && "We should not store the null return symbol");2129    ConstraintManager &CMgr = State->getConstraintManager();2130    ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);2131    RetStatusSymbol = *Ret;2132    return FreeFailed.isConstrainedTrue();2133  }2134  return false;2135}2136 2137static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C,2138                                    const Expr *E) {2139  const CallExpr *CE = dyn_cast<CallExpr>(E);2140 2141  if (!CE)2142    return;2143 2144  const FunctionDecl *FD = CE->getDirectCallee();2145  if (!FD)2146    return;2147 2148  // Only one ownership_takes attribute is allowed.2149  for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {2150    if (I->getOwnKind() != OwnershipAttr::Takes)2151      continue;2152 2153    os << ", which takes ownership of '" << I->getModule()->getName() << '\'';2154    break;2155  }2156}2157 2158static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {2159  if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {2160    // FIXME: This doesn't handle indirect calls.2161    const FunctionDecl *FD = CE->getDirectCallee();2162    if (!FD)2163      return false;2164 2165    os << '\'' << *FD;2166 2167    if (!FD->isOverloadedOperator())2168      os << "()";2169 2170    os << '\'';2171    return true;2172  }2173 2174  if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {2175    if (Msg->isInstanceMessage())2176      os << "-";2177    else2178      os << "+";2179    Msg->getSelector().print(os);2180    return true;2181  }2182 2183  if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {2184    os << "'"2185       << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())2186       << "'";2187    return true;2188  }2189 2190  if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {2191    os << "'"2192       << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())2193       << "'";2194    return true;2195  }2196 2197  return false;2198}2199 2200static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {2201 2202  switch (Family.Kind) {2203  case AF_Malloc:2204    os << "'malloc()'";2205    return;2206  case AF_CXXNew:2207    os << "'new'";2208    return;2209  case AF_CXXNewArray:2210    os << "'new[]'";2211    return;2212  case AF_IfNameIndex:2213    os << "'if_nameindex()'";2214    return;2215  case AF_InnerBuffer:2216    os << "container-specific allocator";2217    return;2218  case AF_Custom:2219    os << Family.CustomName.value();2220    return;2221  case AF_Alloca:2222  case AF_None:2223    assert(false && "not a deallocation expression");2224  }2225}2226 2227static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {2228  switch (Family.Kind) {2229  case AF_Malloc:2230    os << "'free()'";2231    return;2232  case AF_CXXNew:2233    os << "'delete'";2234    return;2235  case AF_CXXNewArray:2236    os << "'delete[]'";2237    return;2238  case AF_IfNameIndex:2239    os << "'if_freenameindex()'";2240    return;2241  case AF_InnerBuffer:2242    os << "container-specific deallocator";2243    return;2244  case AF_Custom:2245    os << "function that takes ownership of '" << Family.CustomName.value()2246       << "\'";2247    return;2248  case AF_Alloca:2249  case AF_None:2250    assert(false && "not a deallocation expression");2251  }2252}2253 2254ProgramStateRef2255MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,2256                          const CallEvent &Call, ProgramStateRef State,2257                          bool Hold, bool &IsKnownToBeAllocated,2258                          AllocationFamily Family, bool ReturnsNullOnFailure,2259                          std::optional<SVal> ArgValOpt) const {2260 2261  if (!State)2262    return nullptr;2263 2264  SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr));2265  if (!isa<DefinedOrUnknownSVal>(ArgVal))2266    return nullptr;2267  DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();2268 2269  // Check for null dereferences.2270  if (!isa<Loc>(location))2271    return nullptr;2272 2273  // The explicit NULL case, no operation is performed.2274  ProgramStateRef notNullState, nullState;2275  std::tie(notNullState, nullState) = State->assume(location);2276  if (nullState && !notNullState)2277    return nullptr;2278 2279  // Unknown values could easily be okay2280  // Undefined values are handled elsewhere2281  if (ArgVal.isUnknownOrUndef())2282    return nullptr;2283 2284  const MemRegion *R = ArgVal.getAsRegion();2285  const Expr *ParentExpr = Call.getOriginExpr();2286 2287  // NOTE: We detected a bug, but the checker under whose name we would emit the2288  // error could be disabled. Generally speaking, the MallocChecker family is an2289  // integral part of the Static Analyzer, and disabling any part of it should2290  // only be done under exceptional circumstances, such as frequent false2291  // positives. If this is the case, we can reasonably believe that there are2292  // serious faults in our understanding of the source code, and even if we2293  // don't emit an warning, we should terminate further analysis with a sink2294  // node.2295 2296  // Nonlocs can't be freed, of course.2297  // Non-region locations (labels and fixed addresses) also shouldn't be freed.2298  if (!R) {2299    // Exception:2300    // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source2301    // code. In that case, the ZERO_SIZE_PTR defines a special value used for a2302    // zero-sized memory block which is allowed to be freed, despite not being a2303    // null pointer.2304    if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))2305      HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,2306                           Family);2307    return nullptr;2308  }2309 2310  R = R->StripCasts();2311 2312  // Blocks might show up as heap data, but should not be free()d2313  if (isa<BlockDataRegion>(R)) {2314    HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,2315                         Family);2316    return nullptr;2317  }2318 2319  // Parameters, locals, statics, globals, and memory returned by2320  // __builtin_alloca() shouldn't be freed.2321  if (!R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {2322    // Regions returned by malloc() are represented by SymbolicRegion objects2323    // within HeapSpaceRegion. Of course, free() can work on memory allocated2324    // outside the current function, so UnknownSpaceRegion is also a2325    // possibility here.2326 2327    if (isa<AllocaRegion>(R))2328      HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());2329    else2330      HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,2331                           Family);2332 2333    return nullptr;2334  }2335 2336  const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());2337  // Various cases could lead to non-symbol values here.2338  // For now, ignore them.2339  if (!SrBase)2340    return nullptr;2341 2342  SymbolRef SymBase = SrBase->getSymbol();2343  const RefState *RsBase = State->get<RegionState>(SymBase);2344  SymbolRef PreviousRetStatusSymbol = nullptr;2345 2346  IsKnownToBeAllocated =2347      RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());2348 2349  if (RsBase) {2350 2351    // Memory returned by alloca() shouldn't be freed.2352    if (RsBase->getAllocationFamily().Kind == AF_Alloca) {2353      HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());2354      return nullptr;2355    }2356 2357    // Check for double free first.2358    if ((RsBase->isReleased() || RsBase->isRelinquished()) &&2359        !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {2360      HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),2361                       SymBase, PreviousRetStatusSymbol);2362      return nullptr;2363    }2364 2365    // If the pointer is allocated or escaped, but we are now trying to free it,2366    // check that the call to free is proper.2367    if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||2368        RsBase->isEscaped()) {2369 2370      // Check if an expected deallocation function matches the real one.2371      bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;2372      if (!DeallocMatchesAlloc) {2373        HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,2374                                RsBase, SymBase, Hold);2375        return nullptr;2376      }2377 2378      // Check if the memory location being freed is the actual location2379      // allocated, or an offset.2380      RegionOffset Offset = R->getAsOffset();2381      if (Offset.isValid() &&2382          !Offset.hasSymbolicOffset() &&2383          Offset.getOffset() != 0) {2384        const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());2385        HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,2386                         Family, AllocExpr);2387        return nullptr;2388      }2389    }2390  }2391 2392  if (SymBase->getType()->isFunctionPointerType()) {2393    HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,2394                          Family);2395    return nullptr;2396  }2397 2398  // Clean out the info on previous call to free return info.2399  State = State->remove<FreeReturnValue>(SymBase);2400 2401  // Keep track of the return value. If it is NULL, we will know that free2402  // failed.2403  if (ReturnsNullOnFailure) {2404    SVal RetVal = C.getSVal(ParentExpr);2405    SymbolRef RetStatusSymbol = RetVal.getAsSymbol();2406    if (RetStatusSymbol) {2407      C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);2408      State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);2409    }2410  }2411 2412  // If we don't know anything about this symbol, a free on it may be totally2413  // valid. If this is the case, lets assume that the allocation family of the2414  // freeing function is the same as the symbols allocation family, and go with2415  // that.2416  assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));2417 2418  // Assume that after memory is freed, it contains unknown values. This2419  // conforts languages standards, since reading from freed memory is considered2420  // UB and may result in arbitrary value.2421  State = State->invalidateRegions({location}, Call.getCFGElementRef(),2422                                   C.blockCount(), C.getLocationContext(),2423                                   /*CausesPointerEscape=*/false,2424                                   /*InvalidatedSymbols=*/nullptr);2425 2426  // Normal free.2427  if (Hold)2428    return State->set<RegionState>(SymBase,2429                                   RefState::getRelinquished(Family,2430                                                             ParentExpr));2431 2432  return State->set<RegionState>(SymBase,2433                                 RefState::getReleased(Family, ParentExpr));2434}2435 2436template <class T>2437const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family) const {2438  switch (Family.Kind) {2439  case AF_Malloc:2440  case AF_Alloca:2441  case AF_Custom:2442  case AF_IfNameIndex:2443    return MallocChecker.getAs<T>();2444  case AF_CXXNew:2445  case AF_CXXNewArray: {2446    const T *ND = NewDeleteChecker.getAs<T>();2447    const T *NDL = NewDeleteLeaksChecker.getAs<T>();2448    // Bugs corresponding to C++ new/delete allocations are split between these2449    // two frontends.2450    if constexpr (std::is_same_v<T, CheckerFrontend>) {2451      assert(ND && NDL && "Casting to CheckerFrontend always succeeds");2452      // Prefer NewDelete unless it's disabled and NewDeleteLeaks is enabled.2453      return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;2454    }2455    assert(!(ND && NDL) &&2456           "NewDelete and NewDeleteLeaks must not share a bug type");2457    return ND ? ND : NDL;2458  }2459  case AF_InnerBuffer:2460    return InnerPointerChecker.getAs<T>();2461  case AF_None:2462    assert(false && "no family");2463    return nullptr;2464  }2465  assert(false && "unhandled family");2466  return nullptr;2467}2468template <class T>2469const T *MallocChecker::getRelevantFrontendAs(CheckerContext &C,2470                                              SymbolRef Sym) const {2471  if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))2472    return MallocChecker.getAs<T>();2473 2474  const RefState *RS = C.getState()->get<RegionState>(Sym);2475  assert(RS);2476  return getRelevantFrontendAs<T>(RS->getAllocationFamily());2477}2478 2479bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {2480  if (std::optional<nonloc::ConcreteInt> IntVal =2481          V.getAs<nonloc::ConcreteInt>())2482    os << "an integer (" << IntVal->getValue() << ")";2483  else if (std::optional<loc::ConcreteInt> ConstAddr =2484               V.getAs<loc::ConcreteInt>())2485    os << "a constant address (" << ConstAddr->getValue() << ")";2486  else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())2487    os << "the address of the label '" << Label->getLabel()->getName() << "'";2488  else2489    return false;2490 2491  return true;2492}2493 2494bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,2495                                    const MemRegion *MR) {2496  switch (MR->getKind()) {2497  case MemRegion::FunctionCodeRegionKind: {2498    const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();2499    if (FD)2500      os << "the address of the function '" << *FD << '\'';2501    else2502      os << "the address of a function";2503    return true;2504  }2505  case MemRegion::BlockCodeRegionKind:2506    os << "block text";2507    return true;2508  case MemRegion::BlockDataRegionKind:2509    // FIXME: where the block came from?2510    os << "a block";2511    return true;2512  default: {2513    const MemSpaceRegion *MS = MR->getMemorySpace(State);2514 2515    if (isa<StackLocalsSpaceRegion>(MS)) {2516      const VarRegion *VR = dyn_cast<VarRegion>(MR);2517      const VarDecl *VD;2518      if (VR)2519        VD = VR->getDecl();2520      else2521        VD = nullptr;2522 2523      if (VD)2524        os << "the address of the local variable '" << VD->getName() << "'";2525      else2526        os << "the address of a local stack variable";2527      return true;2528    }2529 2530    if (isa<StackArgumentsSpaceRegion>(MS)) {2531      const VarRegion *VR = dyn_cast<VarRegion>(MR);2532      const VarDecl *VD;2533      if (VR)2534        VD = VR->getDecl();2535      else2536        VD = nullptr;2537 2538      if (VD)2539        os << "the address of the parameter '" << VD->getName() << "'";2540      else2541        os << "the address of a parameter";2542      return true;2543    }2544 2545    if (isa<GlobalsSpaceRegion>(MS)) {2546      const VarRegion *VR = dyn_cast<VarRegion>(MR);2547      const VarDecl *VD;2548      if (VR)2549        VD = VR->getDecl();2550      else2551        VD = nullptr;2552 2553      if (VD) {2554        if (VD->isStaticLocal())2555          os << "the address of the static variable '" << VD->getName() << "'";2556        else2557          os << "the address of the global variable '" << VD->getName() << "'";2558      } else2559        os << "the address of a global variable";2560      return true;2561    }2562 2563    return false;2564  }2565  }2566}2567 2568void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,2569                                         SourceRange Range,2570                                         const Expr *DeallocExpr,2571                                         AllocationFamily Family) const {2572  const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);2573  if (!Frontend)2574    return;2575  if (!Frontend->isEnabled()) {2576    C.addSink();2577    return;2578  }2579 2580  if (ExplodedNode *N = C.generateErrorNode()) {2581    SmallString<100> buf;2582    llvm::raw_svector_ostream os(buf);2583 2584    const MemRegion *MR = ArgVal.getAsRegion();2585    while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))2586      MR = ER->getSuperRegion();2587 2588    os << "Argument to ";2589    if (!printMemFnName(os, C, DeallocExpr))2590      os << "deallocator";2591 2592    os << " is ";2593    bool Summarized =2594        MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);2595    if (Summarized)2596      os << ", which is not memory allocated by ";2597    else2598      os << "not memory allocated by ";2599 2600    printExpectedAllocName(os, Family);2601 2602    auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,2603                                                      os.str(), N);2604    R->markInteresting(MR);2605    R->addRange(Range);2606    C.emitReport(std::move(R));2607  }2608}2609 2610void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,2611                                     SourceRange Range) const {2612  const FreeAlloca *Frontend;2613 2614  if (MallocChecker.isEnabled())2615    Frontend = &MallocChecker;2616  else if (MismatchedDeallocatorChecker.isEnabled())2617    Frontend = &MismatchedDeallocatorChecker;2618  else {2619    C.addSink();2620    return;2621  }2622 2623  if (ExplodedNode *N = C.generateErrorNode()) {2624    auto R = std::make_unique<PathSensitiveBugReport>(2625        Frontend->FreeAllocaBug,2626        "Memory allocated by 'alloca()' should not be deallocated", N);2627    R->markInteresting(ArgVal.getAsRegion());2628    R->addRange(Range);2629    C.emitReport(std::move(R));2630  }2631}2632 2633void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,2634                                            SourceRange Range,2635                                            const Expr *DeallocExpr,2636                                            const RefState *RS, SymbolRef Sym,2637                                            bool OwnershipTransferred) const {2638  if (!MismatchedDeallocatorChecker.isEnabled()) {2639    C.addSink();2640    return;2641  }2642 2643  if (ExplodedNode *N = C.generateErrorNode()) {2644    SmallString<100> buf;2645    llvm::raw_svector_ostream os(buf);2646 2647    const Expr *AllocExpr = cast<Expr>(RS->getStmt());2648    SmallString<20> AllocBuf;2649    llvm::raw_svector_ostream AllocOs(AllocBuf);2650    SmallString<20> DeallocBuf;2651    llvm::raw_svector_ostream DeallocOs(DeallocBuf);2652 2653    if (OwnershipTransferred) {2654      if (printMemFnName(DeallocOs, C, DeallocExpr))2655        os << DeallocOs.str() << " cannot";2656      else2657        os << "Cannot";2658 2659      os << " take ownership of memory";2660 2661      if (printMemFnName(AllocOs, C, AllocExpr))2662        os << " allocated by " << AllocOs.str();2663    } else {2664      os << "Memory";2665      if (printMemFnName(AllocOs, C, AllocExpr))2666        os << " allocated by " << AllocOs.str();2667 2668      os << " should be deallocated by ";2669        printExpectedDeallocName(os, RS->getAllocationFamily());2670 2671        if (printMemFnName(DeallocOs, C, DeallocExpr))2672          os << ", not " << DeallocOs.str();2673 2674        printOwnershipTakesList(os, C, DeallocExpr);2675    }2676 2677    auto R = std::make_unique<PathSensitiveBugReport>(2678        MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);2679    R->markInteresting(Sym);2680    R->addRange(Range);2681    R->addVisitor<MallocBugVisitor>(Sym);2682    C.emitReport(std::move(R));2683  }2684}2685 2686void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,2687                                     SourceRange Range, const Expr *DeallocExpr,2688                                     AllocationFamily Family,2689                                     const Expr *AllocExpr) const {2690  const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);2691  if (!Frontend)2692    return;2693  if (!Frontend->isEnabled()) {2694    C.addSink();2695    return;2696  }2697 2698  ExplodedNode *N = C.generateErrorNode();2699  if (!N)2700    return;2701 2702  SmallString<100> buf;2703  llvm::raw_svector_ostream os(buf);2704  SmallString<20> AllocNameBuf;2705  llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);2706 2707  const MemRegion *MR = ArgVal.getAsRegion();2708  assert(MR && "Only MemRegion based symbols can have offset free errors");2709 2710  RegionOffset Offset = MR->getAsOffset();2711  assert((Offset.isValid() &&2712          !Offset.hasSymbolicOffset() &&2713          Offset.getOffset() != 0) &&2714         "Only symbols with a valid offset can have offset free errors");2715 2716  int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();2717 2718  os << "Argument to ";2719  if (!printMemFnName(os, C, DeallocExpr))2720    os << "deallocator";2721  os << " is offset by "2722     << offsetBytes2723     << " "2724     << ((abs(offsetBytes) > 1) ? "bytes" : "byte")2725     << " from the start of ";2726  if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))2727    os << "memory allocated by " << AllocNameOs.str();2728  else2729    os << "allocated memory";2730 2731  auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,2732                                                    os.str(), N);2733  R->markInteresting(MR->getBaseRegion());2734  R->addRange(Range);2735  C.emitReport(std::move(R));2736}2737 2738void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,2739                                       SymbolRef Sym) const {2740  const UseFree *Frontend = getRelevantFrontendAs<UseFree>(C, Sym);2741  if (!Frontend)2742    return;2743  if (!Frontend->isEnabled()) {2744    C.addSink();2745    return;2746  }2747 2748  if (ExplodedNode *N = C.generateErrorNode()) {2749    AllocationFamily AF =2750        C.getState()->get<RegionState>(Sym)->getAllocationFamily();2751 2752    auto R = std::make_unique<PathSensitiveBugReport>(2753        Frontend->UseFreeBug,2754        AF.Kind == AF_InnerBuffer2755            ? "Inner pointer of container used after re/deallocation"2756            : "Use of memory after it is released",2757        N);2758 2759    R->markInteresting(Sym);2760    R->addRange(Range);2761    R->addVisitor<MallocBugVisitor>(Sym);2762 2763    if (AF.Kind == AF_InnerBuffer)2764      R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));2765 2766    C.emitReport(std::move(R));2767  }2768}2769 2770void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,2771                                     bool Released, SymbolRef Sym,2772                                     SymbolRef PrevSym) const {2773  const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(C, Sym);2774  if (!Frontend)2775    return;2776  if (!Frontend->isEnabled()) {2777    C.addSink();2778    return;2779  }2780 2781  if (ExplodedNode *N = C.generateErrorNode()) {2782    auto R = std::make_unique<PathSensitiveBugReport>(2783        Frontend->DoubleFreeBug,2784        (Released ? "Attempt to release already released memory"2785                  : "Attempt to release non-owned memory"),2786        N);2787    if (Range.isValid())2788      R->addRange(Range);2789    R->markInteresting(Sym);2790    if (PrevSym)2791      R->markInteresting(PrevSym);2792    R->addVisitor<MallocBugVisitor>(Sym);2793    C.emitReport(std::move(R));2794  }2795}2796 2797void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,2798                                       SymbolRef Sym) const {2799  const UseZeroAllocated *Frontend =2800      getRelevantFrontendAs<UseZeroAllocated>(C, Sym);2801  if (!Frontend)2802    return;2803  if (!Frontend->isEnabled()) {2804    C.addSink();2805    return;2806  }2807 2808  if (ExplodedNode *N = C.generateErrorNode()) {2809    auto R = std::make_unique<PathSensitiveBugReport>(2810        Frontend->UseZeroAllocatedBug, "Use of memory allocated with size zero",2811        N);2812 2813    R->addRange(Range);2814    if (Sym) {2815      R->markInteresting(Sym);2816      R->addVisitor<MallocBugVisitor>(Sym);2817    }2818    C.emitReport(std::move(R));2819  }2820}2821 2822void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,2823                                          SourceRange Range,2824                                          const Expr *FreeExpr,2825                                          AllocationFamily Family) const {2826  const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);2827  if (!Frontend)2828    return;2829  if (!Frontend->isEnabled()) {2830    C.addSink();2831    return;2832  }2833 2834  if (ExplodedNode *N = C.generateErrorNode()) {2835    SmallString<100> Buf;2836    llvm::raw_svector_ostream Os(Buf);2837 2838    const MemRegion *MR = ArgVal.getAsRegion();2839    while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))2840      MR = ER->getSuperRegion();2841 2842    Os << "Argument to ";2843    if (!printMemFnName(Os, C, FreeExpr))2844      Os << "deallocator";2845 2846    Os << " is a function pointer";2847 2848    auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,2849                                                      Os.str(), N);2850    R->markInteresting(MR);2851    R->addRange(Range);2852    C.emitReport(std::move(R));2853  }2854}2855 2856ProgramStateRef2857MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,2858                             bool ShouldFreeOnFail, ProgramStateRef State,2859                             AllocationFamily Family, bool SuffixWithN) const {2860  if (!State)2861    return nullptr;2862 2863  const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());2864 2865  if ((SuffixWithN && CE->getNumArgs() < 3) || CE->getNumArgs() < 2)2866    return nullptr;2867 2868  const Expr *arg0Expr = CE->getArg(0);2869  SVal Arg0Val = C.getSVal(arg0Expr);2870  if (!isa<DefinedOrUnknownSVal>(Arg0Val))2871    return nullptr;2872  DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();2873 2874  SValBuilder &svalBuilder = C.getSValBuilder();2875 2876  DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(2877      State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));2878 2879  // Get the size argument.2880  const Expr *Arg1 = CE->getArg(1);2881 2882  // Get the value of the size argument.2883  SVal TotalSize = C.getSVal(Arg1);2884  if (SuffixWithN)2885    TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));2886  if (!isa<DefinedOrUnknownSVal>(TotalSize))2887    return nullptr;2888 2889  // Compare the size argument to 0.2890  DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(2891      State, TotalSize.castAs<DefinedOrUnknownSVal>(),2892      svalBuilder.makeIntValWithWidth(2893          svalBuilder.getContext().getCanonicalSizeType(), 0));2894 2895  ProgramStateRef StatePtrIsNull, StatePtrNotNull;2896  std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);2897  ProgramStateRef StateSizeIsZero, StateSizeNotZero;2898  std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);2899  // We only assume exceptional states if they are definitely true; if the2900  // state is under-constrained, assume regular realloc behavior.2901  bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;2902  bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;2903 2904  // If the ptr is NULL and the size is not 0, the call is equivalent to2905  // malloc(size).2906  if (PrtIsNull && !SizeIsZero) {2907    ProgramStateRef stateMalloc = MallocMemAux(2908        C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);2909    return stateMalloc;2910  }2911 2912  // Proccess as allocation of 0 bytes.2913  if (PrtIsNull && SizeIsZero)2914    return State;2915 2916  assert(!PrtIsNull);2917 2918  bool IsKnownToBeAllocated = false;2919 2920  // If the size is 0, free the memory.2921  if (SizeIsZero)2922    // The semantics of the return value are:2923    // If size was equal to 0, either NULL or a pointer suitable to be passed2924    // to free() is returned. We just free the input pointer and do not add2925    // any constrains on the output pointer.2926    if (ProgramStateRef stateFree = FreeMemAux(2927            C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))2928      return stateFree;2929 2930  // Default behavior.2931  if (ProgramStateRef stateFree =2932          FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {2933 2934    ProgramStateRef stateRealloc =2935        MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);2936    if (!stateRealloc)2937      return nullptr;2938 2939    OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;2940    if (ShouldFreeOnFail)2941      Kind = OAR_FreeOnFailure;2942    else if (!IsKnownToBeAllocated)2943      Kind = OAR_DoNotTrackAfterFailure;2944 2945    // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).2946    SymbolRef FromPtr = arg0Val.getLocSymbolInBase();2947    SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());2948    SymbolRef ToPtr = RetVal.getAsSymbol();2949    assert(FromPtr && ToPtr &&2950           "By this point, FreeMemAux and MallocMemAux should have checked "2951           "whether the argument or the return value is symbolic!");2952 2953    // Record the info about the reallocated symbol so that we could properly2954    // process failed reallocation.2955    stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,2956                                                   ReallocPair(FromPtr, Kind));2957    // The reallocated symbol should stay alive for as long as the new symbol.2958    C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);2959    return stateRealloc;2960  }2961  return nullptr;2962}2963 2964ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,2965                                         const CallEvent &Call,2966                                         ProgramStateRef State) const {2967  if (!State)2968    return nullptr;2969 2970  if (Call.getNumArgs() < 2)2971    return nullptr;2972 2973  SValBuilder &svalBuilder = C.getSValBuilder();2974  SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);2975  SVal TotalSize =2976      evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));2977 2978  return MallocMemAux(C, Call, TotalSize, zeroVal, State,2979                      AllocationFamily(AF_Malloc));2980}2981 2982MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,2983                                                         SymbolRef Sym,2984                                                         CheckerContext &C) {2985  const LocationContext *LeakContext = N->getLocationContext();2986  // Walk the ExplodedGraph backwards and find the first node that referred to2987  // the tracked symbol.2988  const ExplodedNode *AllocNode = N;2989  const MemRegion *ReferenceRegion = nullptr;2990 2991  while (N) {2992    ProgramStateRef State = N->getState();2993    if (!State->get<RegionState>(Sym))2994      break;2995 2996    // Find the most recent expression bound to the symbol in the current2997    // context.2998    if (!ReferenceRegion) {2999      if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {3000        SVal Val = State->getSVal(MR);3001        if (Val.getAsLocSymbol() == Sym) {3002          const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();3003          // Do not show local variables belonging to a function other than3004          // where the error is reported.3005          if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))3006            ReferenceRegion = MR;3007        }3008      }3009    }3010 3011    // Allocation node, is the last node in the current or parent context in3012    // which the symbol was tracked.3013    const LocationContext *NContext = N->getLocationContext();3014    if (NContext == LeakContext ||3015        NContext->isParentOf(LeakContext))3016      AllocNode = N;3017    N = N->pred_empty() ? nullptr : *(N->pred_begin());3018  }3019 3020  return LeakInfo(AllocNode, ReferenceRegion);3021}3022 3023void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,3024                               CheckerContext &C) const {3025  assert(N && "HandleLeak is only called with a non-null node");3026 3027  const RefState *RS = C.getState()->get<RegionState>(Sym);3028  assert(RS && "cannot leak an untracked symbol");3029  AllocationFamily Family = RS->getAllocationFamily();3030 3031  if (Family.Kind == AF_Alloca)3032    return;3033 3034  const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);3035  // Note that for leaks we don't add a sink when the relevant frontend is3036  // disabled because the leak is reported with a non-fatal error node, while3037  // the sink would be the "silent" alternative of a (fatal) error node.3038  if (!Frontend || !Frontend->isEnabled())3039    return;3040 3041  // Most bug reports are cached at the location where they occurred.3042  // With leaks, we want to unique them by the location where they were3043  // allocated, and only report a single path.3044  PathDiagnosticLocation LocUsedForUniqueing;3045  const ExplodedNode *AllocNode = nullptr;3046  const MemRegion *Region = nullptr;3047  std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);3048 3049  const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();3050  if (AllocationStmt)3051    LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,3052                                              C.getSourceManager(),3053                                              AllocNode->getLocationContext());3054 3055  SmallString<200> buf;3056  llvm::raw_svector_ostream os(buf);3057  if (Region && Region->canPrintPretty()) {3058    os << "Potential leak of memory pointed to by ";3059    Region->printPretty(os);3060  } else {3061    os << "Potential memory leak";3062  }3063 3064  auto R = std::make_unique<PathSensitiveBugReport>(3065      Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,3066      AllocNode->getLocationContext()->getDecl());3067  R->markInteresting(Sym);3068  R->addVisitor<MallocBugVisitor>(Sym, true);3069  if (ShouldRegisterNoOwnershipChangeVisitor)3070    R->addVisitor<NoMemOwnershipChangeVisitor>(Sym, this);3071  C.emitReport(std::move(R));3072}3073 3074void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,3075                                     CheckerContext &C) const3076{3077  ProgramStateRef state = C.getState();3078  RegionStateTy OldRS = state->get<RegionState>();3079  RegionStateTy::Factory &F = state->get_context<RegionState>();3080 3081  RegionStateTy RS = OldRS;3082  SmallVector<SymbolRef, 2> Errors;3083  for (auto [Sym, State] : RS) {3084    if (SymReaper.isDead(Sym)) {3085      if (State.isAllocated() || State.isAllocatedOfSizeZero())3086        Errors.push_back(Sym);3087      // Remove the dead symbol from the map.3088      RS = F.remove(RS, Sym);3089    }3090  }3091 3092  if (RS == OldRS) {3093    // We shouldn't have touched other maps yet.3094    assert(state->get<ReallocPairs>() ==3095           C.getState()->get<ReallocPairs>());3096    assert(state->get<FreeReturnValue>() ==3097           C.getState()->get<FreeReturnValue>());3098    return;3099  }3100 3101  // Cleanup the Realloc Pairs Map.3102  ReallocPairsTy RP = state->get<ReallocPairs>();3103  for (auto [Sym, ReallocPair] : RP) {3104    if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {3105      state = state->remove<ReallocPairs>(Sym);3106    }3107  }3108 3109  // Cleanup the FreeReturnValue Map.3110  FreeReturnValueTy FR = state->get<FreeReturnValue>();3111  for (auto [Sym, RetSym] : FR) {3112    if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {3113      state = state->remove<FreeReturnValue>(Sym);3114    }3115  }3116 3117  // Generate leak node.3118  ExplodedNode *N = C.getPredecessor();3119  if (!Errors.empty()) {3120    N = C.generateNonFatalErrorNode(C.getState());3121    if (N) {3122      for (SymbolRef Sym : Errors) {3123        HandleLeak(Sym, N, C);3124      }3125    }3126  }3127 3128  C.addTransition(state->set<RegionState>(RS), N);3129}3130 3131// Allowlist of owning smart pointers we want to recognize.3132// Start with unique_ptr and shared_ptr; weak_ptr is excluded intentionally3133// because it does not own the pointee.3134static bool isSmartPtrName(StringRef Name) {3135  return Name == "unique_ptr" || Name == "shared_ptr";3136}3137 3138// Check if a type is a smart owning pointer type.3139static bool isSmartPtrType(QualType QT) {3140  QT = QT->getCanonicalTypeUnqualified();3141 3142  if (const auto *TST = QT->getAs<TemplateSpecializationType>()) {3143    const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();3144    if (!TD)3145      return false;3146 3147    const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl());3148    if (!ND)3149      return false;3150 3151    // For broader coverage we recognize all template classes with names that3152    // match the allowlist even if they are not declared in namespace 'std'.3153    return isSmartPtrName(ND->getName());3154  }3155 3156  return false;3157}3158 3159/// Helper struct for collecting smart owning pointer field regions.3160/// This allows both hasSmartPtrField and3161/// collectSmartPtrFieldRegions to share the same traversal logic,3162/// ensuring consistency.3163struct FieldConsumer {3164  const MemRegion *Reg;3165  CheckerContext *C;3166  llvm::SmallPtrSetImpl<const MemRegion *> *Out;3167 3168  FieldConsumer(const MemRegion *Reg, CheckerContext &C,3169                llvm::SmallPtrSetImpl<const MemRegion *> &Out)3170      : Reg(Reg), C(&C), Out(&Out) {}3171 3172  void consume(const FieldDecl *FD) {3173    SVal L = C->getState()->getLValue(FD, loc::MemRegionVal(Reg));3174    if (const MemRegion *FR = L.getAsRegion())3175      Out->insert(FR);3176  }3177 3178  std::optional<FieldConsumer> switchToBase(const CXXRecordDecl *BaseDecl,3179                                            bool IsVirtual) {3180    // Get the base class region3181    SVal BaseL =3182        C->getState()->getLValue(BaseDecl, Reg->getAs<SubRegion>(), IsVirtual);3183    if (const MemRegion *BaseObjRegion = BaseL.getAsRegion()) {3184      // Return a consumer for the base class3185      return FieldConsumer{BaseObjRegion, *C, *Out};3186    }3187    return std::nullopt;3188  }3189};3190 3191/// Check if a record type has smart owning pointer fields (directly or in base3192/// classes). When FC is provided, also collect the field regions.3193///3194/// This function has dual behavior:3195/// - When FC is nullopt: Returns true if smart pointer fields are found3196/// - When FC is provided: Always returns false, but collects field regions3197///   as a side effect through the FieldConsumer3198///3199/// Note: When FC is provided, the return value should be ignored since the3200/// function performs full traversal for collection and always returns false3201/// to avoid early termination.3202static bool hasSmartPtrField(const CXXRecordDecl *CRD,3203                             std::optional<FieldConsumer> FC = std::nullopt) {3204  // Check direct fields3205  for (const FieldDecl *FD : CRD->fields()) {3206    if (isSmartPtrType(FD->getType())) {3207      if (!FC)3208        return true;3209      FC->consume(FD);3210    }3211  }3212 3213  // Check fields from base classes3214  for (const CXXBaseSpecifier &BaseSpec : CRD->bases()) {3215    if (const CXXRecordDecl *BaseDecl =3216            BaseSpec.getType()->getAsCXXRecordDecl()) {3217      std::optional<FieldConsumer> NewFC;3218      if (FC) {3219        NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());3220        if (!NewFC)3221          continue;3222      }3223      bool Found = hasSmartPtrField(BaseDecl, NewFC);3224      if (Found && !FC)3225        return true;3226    }3227  }3228  return false;3229}3230 3231/// Check if an expression is an rvalue record type passed by value.3232static bool isRvalueByValueRecord(const Expr *AE) {3233  if (AE->isGLValue())3234    return false;3235 3236  QualType T = AE->getType();3237  if (!T->isRecordType() || T->isReferenceType())3238    return false;3239 3240  // Accept common temp/construct forms but don't overfit.3241  return isa<CXXTemporaryObjectExpr, MaterializeTemporaryExpr, CXXConstructExpr,3242             InitListExpr, ImplicitCastExpr, CXXBindTemporaryExpr>(AE);3243}3244 3245/// Check if an expression is an rvalue record with smart owning pointer fields3246/// passed by value.3247static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE) {3248  if (!isRvalueByValueRecord(AE))3249    return false;3250 3251  const auto *CRD = AE->getType()->getAsCXXRecordDecl();3252  return CRD && hasSmartPtrField(CRD);3253}3254 3255/// Check if a CXXRecordDecl has a name matching recognized smart pointer names.3256static bool isSmartPtrRecord(const CXXRecordDecl *RD) {3257  if (!RD)3258    return false;3259 3260  // Check the record name directly and accept both std and custom smart pointer3261  // implementations for broader coverage3262  return isSmartPtrName(RD->getName());3263}3264 3265/// Check if a call is a constructor of a smart owning pointer class that3266/// accepts pointer parameters.3267static bool isSmartPtrCall(const CallEvent &Call) {3268  // Only check for smart pointer constructor calls3269  const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Call.getDecl());3270  if (!CD)3271    return false;3272 3273  const auto *RD = CD->getParent();3274  if (!isSmartPtrRecord(RD))3275    return false;3276 3277  // Check if constructor takes a pointer parameter3278  for (const auto *Param : CD->parameters()) {3279    QualType ParamType = Param->getType();3280    if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&3281        !ParamType->isVoidPointerType()) {3282      return true;3283    }3284  }3285 3286  return false;3287}3288 3289/// Collect memory regions of smart owning pointer fields from a record type3290/// (including fields from base classes).3291static void3292collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT,3293                            CheckerContext &C,3294                            llvm::SmallPtrSetImpl<const MemRegion *> &Out) {3295  if (!Reg)3296    return;3297 3298  const auto *CRD = RecQT->getAsCXXRecordDecl();3299  if (!CRD)3300    return;3301 3302  FieldConsumer FC{Reg, C, Out};3303  hasSmartPtrField(CRD, FC);3304}3305 3306/// Handle smart pointer constructor calls by escaping allocated symbols3307/// that are passed as pointer arguments to the constructor.3308ProgramStateRef MallocChecker::handleSmartPointerConstructorArguments(3309    const CallEvent &Call, ProgramStateRef State) const {3310  const auto *CD = cast<CXXConstructorDecl>(Call.getDecl());3311  for (unsigned I = 0, E = std::min(Call.getNumArgs(), CD->getNumParams());3312       I != E; ++I) {3313    const Expr *ArgExpr = Call.getArgExpr(I);3314    if (!ArgExpr)3315      continue;3316 3317    QualType ParamType = CD->getParamDecl(I)->getType();3318    if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&3319        !ParamType->isVoidPointerType()) {3320      // This argument is a pointer being passed to smart pointer constructor3321      SVal ArgVal = Call.getArgSVal(I);3322      SymbolRef Sym = ArgVal.getAsSymbol();3323      if (Sym && State->contains<RegionState>(Sym)) {3324        const RefState *RS = State->get<RegionState>(Sym);3325        if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {3326          State = State->set<RegionState>(Sym, RefState::getEscaped(RS));3327        }3328      }3329    }3330  }3331  return State;3332}3333 3334/// Handle all smart pointer related processing in function calls.3335/// This includes both direct smart pointer constructor calls and by-value3336/// arguments containing smart pointer fields.3337ProgramStateRef MallocChecker::handleSmartPointerRelatedCalls(3338    const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {3339 3340  // Handle direct smart pointer constructor calls first3341  if (isSmartPtrCall(Call)) {3342    return handleSmartPointerConstructorArguments(Call, State);3343  }3344 3345  // Handle smart pointer fields in by-value record arguments3346  llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;3347  for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {3348    const Expr *AE = Call.getArgExpr(I);3349    if (!AE)3350      continue;3351    AE = AE->IgnoreParenImpCasts();3352 3353    if (!isRvalueByValueRecordWithSmartPtr(AE))3354      continue;3355 3356    // Find a region for the argument.3357    SVal ArgVal = Call.getArgSVal(I);3358    const MemRegion *ArgRegion = ArgVal.getAsRegion();3359    // Collect direct smart owning pointer field regions3360    collectSmartPtrFieldRegions(ArgRegion, AE->getType(), C,3361                                SmartPtrFieldRoots);3362  }3363 3364  // Escape symbols reachable from smart pointer fields3365  if (!SmartPtrFieldRoots.empty()) {3366    SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(3367        SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());3368    State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(3369        SmartPtrFieldRootsVec, State);3370  }3371 3372  return State;3373}3374 3375void MallocChecker::checkPostCall(const CallEvent &Call,3376                                  CheckerContext &C) const {3377  // Handle existing post-call handlers first3378  if (const auto *PostFN = PostFnMap.lookup(Call)) {3379    (*PostFN)(this, C.getState(), Call, C);3380    return; // Post-handler already called addTransition, we're done3381  }3382 3383  // Handle smart pointer related processing only if no post-handler was called3384  C.addTransition(handleSmartPointerRelatedCalls(Call, C, C.getState()));3385}3386 3387void MallocChecker::checkPreCall(const CallEvent &Call,3388                                 CheckerContext &C) const {3389 3390  if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {3391    const CXXDeleteExpr *DE = DC->getOriginExpr();3392 3393    // FIXME: I don't see a good reason for restricting the check against3394    // use-after-free violations to the case when NewDeleteChecker is disabled.3395    // (However, if NewDeleteChecker is enabled, perhaps it would be better to3396    // do this check a bit later?)3397    if (!NewDeleteChecker.isEnabled())3398      if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())3399        checkUseAfterFree(Sym, C, DE->getArgument());3400 3401    if (!isStandardNewDelete(DC->getDecl()))3402      return;3403 3404    ProgramStateRef State = C.getState();3405    bool IsKnownToBeAllocated;3406    State = FreeMemAux(3407        C, DE->getArgument(), Call, State,3408        /*Hold*/ false, IsKnownToBeAllocated,3409        AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));3410 3411    C.addTransition(State);3412    return;3413  }3414 3415  // If we see a `CXXDestructorCall` (that is, an _implicit_ destructor call)3416  // to a region that's symbolic and known to be already freed, then it must be3417  // implicitly triggered by a `delete` expression. In this situation we should3418  // emit a `DoubleFree` report _now_ (before entering the call to the3419  // destructor) because otherwise the destructor call can trigger a3420  // use-after-free bug (by accessing any member variable) and that would be3421  // (technically valid, but) less user-friendly report than the `DoubleFree`.3422  if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {3423    SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();3424    if (!Sym)3425      return;3426    if (isReleased(Sym, C)) {3427      HandleDoubleFree(C, SourceRange(), /*Released=*/true, Sym,3428                       /*PrevSym=*/nullptr);3429      return;3430    }3431  }3432 3433  // We need to handle getline pre-conditions here before the pointed region3434  // gets invalidated by StreamChecker3435  if (const auto *PreFN = PreFnMap.lookup(Call)) {3436    (*PreFN)(this, C.getState(), Call, C);3437    return;3438  }3439 3440  // We will check for double free in the `evalCall` callback.3441  // FIXME: It would be more logical to emit double free and use-after-free3442  // reports via the same pathway (because double free is essentially a specia3443  // case of use-after-free).3444  if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {3445    const FunctionDecl *FD = FC->getDecl();3446    if (!FD)3447      return;3448 3449    // FIXME: I suspect we should remove `MallocChecker.isEnabled() &&` because3450    // it's fishy that the enabled/disabled state of one frontend may influence3451    // reports produced by other frontends.3452    if (MallocChecker.isEnabled() && isFreeingCall(Call))3453      return;3454  }3455 3456  // Check if the callee of a method is deleted.3457  if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {3458    SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();3459    if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))3460      return;3461  }3462 3463  // Check arguments for being used after free.3464  for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {3465    SVal ArgSVal = Call.getArgSVal(I);3466    if (isa<Loc>(ArgSVal)) {3467      SymbolRef Sym = ArgSVal.getAsSymbol(/*IncludeBaseRegions=*/true);3468      if (!Sym)3469        continue;3470      if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))3471        return;3472    }3473  }3474}3475 3476void MallocChecker::checkPreStmt(const ReturnStmt *S,3477                                 CheckerContext &C) const {3478  checkEscapeOnReturn(S, C);3479}3480 3481// In the CFG, automatic destructors come after the return statement.3482// This callback checks for returning memory that is freed by automatic3483// destructors, as those cannot be reached in checkPreStmt().3484void MallocChecker::checkEndFunction(const ReturnStmt *S,3485                                     CheckerContext &C) const {3486  checkEscapeOnReturn(S, C);3487}3488 3489void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,3490                                        CheckerContext &C) const {3491  if (!S)3492    return;3493 3494  const Expr *E = S->getRetValue();3495  if (!E)3496    return;3497 3498  // Check if we are returning a symbol.3499  ProgramStateRef State = C.getState();3500  SVal RetVal = C.getSVal(E);3501  SymbolRef Sym = RetVal.getAsSymbol();3502  if (!Sym)3503    // If we are returning a field of the allocated struct or an array element,3504    // the callee could still free the memory.3505    if (const MemRegion *MR = RetVal.getAsRegion())3506      if (isa<FieldRegion, ElementRegion>(MR))3507        if (const SymbolicRegion *BMR =3508              dyn_cast<SymbolicRegion>(MR->getBaseRegion()))3509          Sym = BMR->getSymbol();3510 3511  // Check if we are returning freed memory.3512  if (Sym)3513    checkUseAfterFree(Sym, C, E);3514}3515 3516// TODO: Blocks should be either inlined or should call invalidate regions3517// upon invocation. After that's in place, special casing here will not be3518// needed.3519void MallocChecker::checkPostStmt(const BlockExpr *BE,3520                                  CheckerContext &C) const {3521 3522  // Scan the BlockDecRefExprs for any object the retain count checker3523  // may be tracking.3524  if (!BE->getBlockDecl()->hasCaptures())3525    return;3526 3527  ProgramStateRef state = C.getState();3528  const BlockDataRegion *R =3529    cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());3530 3531  auto ReferencedVars = R->referenced_vars();3532  if (ReferencedVars.empty())3533    return;3534 3535  SmallVector<const MemRegion*, 10> Regions;3536  const LocationContext *LC = C.getLocationContext();3537  MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();3538 3539  for (const auto &Var : ReferencedVars) {3540    const VarRegion *VR = Var.getCapturedRegion();3541    if (VR->getSuperRegion() == R) {3542      VR = MemMgr.getVarRegion(VR->getDecl(), LC);3543    }3544    Regions.push_back(VR);3545  }3546 3547  state =3548    state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();3549  C.addTransition(state);3550}3551 3552static bool isReleased(SymbolRef Sym, CheckerContext &C) {3553  assert(Sym);3554  const RefState *RS = C.getState()->get<RegionState>(Sym);3555  return (RS && RS->isReleased());3556}3557 3558bool MallocChecker::suppressDeallocationsInSuspiciousContexts(3559    const CallEvent &Call, CheckerContext &C) const {3560  if (Call.getNumArgs() == 0)3561    return false;3562 3563  StringRef FunctionStr = "";3564  if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))3565    if (const Stmt *Body = FD->getBody())3566      if (Body->getBeginLoc().isValid())3567        FunctionStr =3568            Lexer::getSourceText(CharSourceRange::getTokenRange(3569                                     {FD->getBeginLoc(), Body->getBeginLoc()}),3570                                 C.getSourceManager(), C.getLangOpts());3571 3572  // We do not model the Integer Set Library's retain-count based allocation.3573  if (!FunctionStr.contains("__isl_"))3574    return false;3575 3576  ProgramStateRef State = C.getState();3577 3578  for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments())3579    if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())3580      if (const RefState *RS = State->get<RegionState>(Sym))3581        State = State->set<RegionState>(Sym, RefState::getEscaped(RS));3582 3583  C.addTransition(State);3584  return true;3585}3586 3587bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,3588                                      const Stmt *S) const {3589 3590  if (isReleased(Sym, C)) {3591    HandleUseAfterFree(C, S->getSourceRange(), Sym);3592    return true;3593  }3594 3595  return false;3596}3597 3598void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,3599                                          const Stmt *S) const {3600  assert(Sym);3601 3602  if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {3603    if (RS->isAllocatedOfSizeZero())3604      HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);3605  }3606  else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {3607    HandleUseZeroAlloc(C, S->getSourceRange(), Sym);3608  }3609}3610 3611// Check if the location is a freed symbolic region.3612void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,3613                                  CheckerContext &C) const {3614  SymbolRef Sym = l.getLocSymbolInBase();3615  if (Sym) {3616    checkUseAfterFree(Sym, C, S);3617    checkUseZeroAllocated(Sym, C, S);3618  }3619}3620 3621// If a symbolic region is assumed to NULL (or another constant), stop tracking3622// it - assuming that allocation failed on this path.3623ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,3624                                              SVal Cond,3625                                              bool Assumption) const {3626  RegionStateTy RS = state->get<RegionState>();3627  for (SymbolRef Sym : llvm::make_first_range(RS)) {3628    // If the symbol is assumed to be NULL, remove it from consideration.3629    ConstraintManager &CMgr = state->getConstraintManager();3630    ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);3631    if (AllocFailed.isConstrainedTrue())3632      state = state->remove<RegionState>(Sym);3633  }3634 3635  // Realloc returns 0 when reallocation fails, which means that we should3636  // restore the state of the pointer being reallocated.3637  ReallocPairsTy RP = state->get<ReallocPairs>();3638  for (auto [Sym, ReallocPair] : RP) {3639    // If the symbol is assumed to be NULL, remove it from consideration.3640    ConstraintManager &CMgr = state->getConstraintManager();3641    ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);3642    if (!AllocFailed.isConstrainedTrue())3643      continue;3644 3645    SymbolRef ReallocSym = ReallocPair.ReallocatedSym;3646    if (const RefState *RS = state->get<RegionState>(ReallocSym)) {3647      if (RS->isReleased()) {3648        switch (ReallocPair.Kind) {3649        case OAR_ToBeFreedAfterFailure:3650          state = state->set<RegionState>(ReallocSym,3651              RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));3652          break;3653        case OAR_DoNotTrackAfterFailure:3654          state = state->remove<RegionState>(ReallocSym);3655          break;3656        default:3657          assert(ReallocPair.Kind == OAR_FreeOnFailure);3658        }3659      }3660    }3661    state = state->remove<ReallocPairs>(Sym);3662  }3663 3664  return state;3665}3666 3667bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(3668                                              const CallEvent *Call,3669                                              ProgramStateRef State,3670                                              SymbolRef &EscapingSymbol) const {3671  assert(Call);3672  EscapingSymbol = nullptr;3673 3674  // For now, assume that any C++ or block call can free memory.3675  // TODO: If we want to be more optimistic here, we'll need to make sure that3676  // regions escape to C++ containers. They seem to do that even now, but for3677  // mysterious reasons.3678  if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))3679    return true;3680 3681  // Check Objective-C messages by selector name.3682  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {3683    // If it's not a framework call, or if it takes a callback, assume it3684    // can free memory.3685    if (!Call->isInSystemHeader() || Call->argumentsMayEscape())3686      return true;3687 3688    // If it's a method we know about, handle it explicitly post-call.3689    // This should happen before the "freeWhenDone" check below.3690    if (isKnownDeallocObjCMethodName(*Msg))3691      return false;3692 3693    // If there's a "freeWhenDone" parameter, but the method isn't one we know3694    // about, we can't be sure that the object will use free() to deallocate the3695    // memory, so we can't model it explicitly. The best we can do is use it to3696    // decide whether the pointer escapes.3697    if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))3698      return *FreeWhenDone;3699 3700    // If the first selector piece ends with "NoCopy", and there is no3701    // "freeWhenDone" parameter set to zero, we know ownership is being3702    // transferred. Again, though, we can't be sure that the object will use3703    // free() to deallocate the memory, so we can't model it explicitly.3704    StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);3705    if (FirstSlot.ends_with("NoCopy"))3706      return true;3707 3708    // If the first selector starts with addPointer, insertPointer,3709    // or replacePointer, assume we are dealing with NSPointerArray or similar.3710    // This is similar to C++ containers (vector); we still might want to check3711    // that the pointers get freed by following the container itself.3712    if (FirstSlot.starts_with("addPointer") ||3713        FirstSlot.starts_with("insertPointer") ||3714        FirstSlot.starts_with("replacePointer") ||3715        FirstSlot == "valueWithPointer") {3716      return true;3717    }3718 3719    // We should escape receiver on call to 'init'. This is especially relevant3720    // to the receiver, as the corresponding symbol is usually not referenced3721    // after the call.3722    if (Msg->getMethodFamily() == OMF_init) {3723      EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();3724      return true;3725    }3726 3727    // Otherwise, assume that the method does not free memory.3728    // Most framework methods do not free memory.3729    return false;3730  }3731 3732  // At this point the only thing left to handle is straight function calls.3733  const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();3734  if (!FD)3735    return true;3736 3737  // If it's one of the allocation functions we can reason about, we model3738  // its behavior explicitly.3739  if (isMemCall(*Call))3740    return false;3741 3742  // If it's not a system call, assume it frees memory.3743  if (!Call->isInSystemHeader())3744    return true;3745 3746  // White list the system functions whose arguments escape.3747  const IdentifierInfo *II = FD->getIdentifier();3748  if (!II)3749    return true;3750  StringRef FName = II->getName();3751 3752  // White list the 'XXXNoCopy' CoreFoundation functions.3753  // We specifically check these before3754  if (FName.ends_with("NoCopy")) {3755    // Look for the deallocator argument. We know that the memory ownership3756    // is not transferred only if the deallocator argument is3757    // 'kCFAllocatorNull'.3758    for (unsigned i = 1; i < Call->getNumArgs(); ++i) {3759      const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();3760      if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {3761        StringRef DeallocatorName = DE->getFoundDecl()->getName();3762        if (DeallocatorName == "kCFAllocatorNull")3763          return false;3764      }3765    }3766    return true;3767  }3768 3769  // Associating streams with malloced buffers. The pointer can escape if3770  // 'closefn' is specified (and if that function does free memory),3771  // but it will not if closefn is not specified.3772  // Currently, we do not inspect the 'closefn' function (PR12101).3773  if (FName == "funopen")3774    if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))3775      return false;3776 3777  // Do not warn on pointers passed to 'setbuf' when used with std streams,3778  // these leaks might be intentional when setting the buffer for stdio.3779  // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer3780  if (FName == "setbuf" || FName =="setbuffer" ||3781      FName == "setlinebuf" || FName == "setvbuf") {3782    if (Call->getNumArgs() >= 1) {3783      const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();3784      if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))3785        if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))3786          if (D->getCanonicalDecl()->getName().contains("std"))3787            return true;3788    }3789  }3790 3791  // A bunch of other functions which either take ownership of a pointer or3792  // wrap the result up in a struct or object, meaning it can be freed later.3793  // (See RetainCountChecker.) Not all the parameters here are invalidated,3794  // but the Malloc checker cannot differentiate between them. The right way3795  // of doing this would be to implement a pointer escapes callback.3796  if (FName == "CGBitmapContextCreate" ||3797      FName == "CGBitmapContextCreateWithData" ||3798      FName == "CVPixelBufferCreateWithBytes" ||3799      FName == "CVPixelBufferCreateWithPlanarBytes" ||3800      FName == "OSAtomicEnqueue") {3801    return true;3802  }3803 3804  if (FName == "postEvent" &&3805      FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {3806    return true;3807  }3808 3809  if (FName == "connectImpl" &&3810      FD->getQualifiedNameAsString() == "QObject::connectImpl") {3811    return true;3812  }3813 3814  if (FName == "singleShotImpl" &&3815      FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") {3816    return true;3817  }3818 3819  // Protobuf function declared in `generated_message_util.h` that takes3820  // ownership of the second argument. As the first and third arguments are3821  // allocation arenas and won't be tracked by this checker, there is no reason3822  // to set `EscapingSymbol`. (Also, this is an implementation detail of3823  // Protobuf, so it's better to be a bit more permissive.)3824  if (FName == "GetOwnedMessageInternal") {3825    return true;3826  }3827 3828  // Handle cases where we know a buffer's /address/ can escape.3829  // Note that the above checks handle some special cases where we know that3830  // even though the address escapes, it's still our responsibility to free the3831  // buffer.3832  if (Call->argumentsMayEscape())3833    return true;3834 3835  // Otherwise, assume that the function does not free memory.3836  // Most system calls do not free the memory.3837  return false;3838}3839 3840ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,3841                                             const InvalidatedSymbols &Escaped,3842                                             const CallEvent *Call,3843                                             PointerEscapeKind Kind) const {3844  return checkPointerEscapeAux(State, Escaped, Call, Kind,3845                               /*IsConstPointerEscape*/ false);3846}3847 3848ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,3849                                              const InvalidatedSymbols &Escaped,3850                                              const CallEvent *Call,3851                                              PointerEscapeKind Kind) const {3852  // If a const pointer escapes, it may not be freed(), but it could be deleted.3853  return checkPointerEscapeAux(State, Escaped, Call, Kind,3854                               /*IsConstPointerEscape*/ true);3855}3856 3857static bool checkIfNewOrNewArrayFamily(const RefState *RS) {3858  return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||3859          RS->getAllocationFamily().Kind == AF_CXXNew);3860}3861 3862ProgramStateRef MallocChecker::checkPointerEscapeAux(3863    ProgramStateRef State, const InvalidatedSymbols &Escaped,3864    const CallEvent *Call, PointerEscapeKind Kind,3865    bool IsConstPointerEscape) const {3866  // If we know that the call does not free memory, or we want to process the3867  // call later, keep tracking the top level arguments.3868  SymbolRef EscapingSymbol = nullptr;3869  if (Kind == PSK_DirectEscapeOnCall &&3870      !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,3871                                                    EscapingSymbol) &&3872      !EscapingSymbol) {3873    return State;3874  }3875 3876  for (SymbolRef sym : Escaped) {3877    if (EscapingSymbol && EscapingSymbol != sym)3878      continue;3879 3880    if (const RefState *RS = State->get<RegionState>(sym))3881      if (RS->isAllocated() || RS->isAllocatedOfSizeZero())3882        if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))3883          State = State->set<RegionState>(sym, RefState::getEscaped(RS));3884  }3885  return State;3886}3887 3888bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,3889                                       SVal ArgVal) const {3890  if (!KernelZeroSizePtrValue)3891    KernelZeroSizePtrValue =3892        tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor());3893 3894  const llvm::APSInt *ArgValKnown =3895      C.getSValBuilder().getKnownValue(State, ArgVal);3896  return ArgValKnown && *KernelZeroSizePtrValue &&3897         ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;3898}3899 3900static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,3901                                         ProgramStateRef prevState) {3902  ReallocPairsTy currMap = currState->get<ReallocPairs>();3903  ReallocPairsTy prevMap = prevState->get<ReallocPairs>();3904 3905  for (const ReallocPairsTy::value_type &Pair : prevMap) {3906    SymbolRef sym = Pair.first;3907    if (!currMap.lookup(sym))3908      return sym;3909  }3910 3911  return nullptr;3912}3913 3914static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {3915  if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) {3916    StringRef N = II->getName();3917    if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {3918      if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||3919          N.contains_insensitive("intrusive") ||3920          N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {3921        return true;3922      }3923    }3924  }3925  return false;3926}3927 3928PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,3929                                                   BugReporterContext &BRC,3930                                                   PathSensitiveBugReport &BR) {3931  ProgramStateRef state = N->getState();3932  ProgramStateRef statePrev = N->getFirstPred()->getState();3933 3934  const RefState *RSCurr = state->get<RegionState>(Sym);3935  const RefState *RSPrev = statePrev->get<RegionState>(Sym);3936 3937  const Stmt *S = N->getStmtForDiagnostics();3938  // When dealing with containers, we sometimes want to give a note3939  // even if the statement is missing.3940  if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))3941    return nullptr;3942 3943  const LocationContext *CurrentLC = N->getLocationContext();3944 3945  // If we find an atomic fetch_add or fetch_sub within the function in which3946  // the pointer was released (before the release), this is likely a release3947  // point of reference-counted object (like shared pointer).3948  //3949  // Because we don't model atomics, and also because we don't know that the3950  // original reference count is positive, we should not report use-after-frees3951  // on objects deleted in such functions. This can probably be improved3952  // through better shared pointer modeling.3953  if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||3954                            ReleaseFunctionLC->isParentOf(CurrentLC))) {3955    if (const auto *AE = dyn_cast<AtomicExpr>(S)) {3956      // Check for manual use of atomic builtins.3957      AtomicExpr::AtomicOp Op = AE->getOp();3958      if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||3959          Op == AtomicExpr::AO__c11_atomic_fetch_sub) {3960        BR.markInvalid(getTag(), S);3961        // After report is considered invalid there is no need to proceed3962        // futher.3963        return nullptr;3964      }3965    } else if (const auto *CE = dyn_cast<CallExpr>(S)) {3966      // Check for `std::atomic` and such. This covers both regular method calls3967      // and operator calls.3968      if (const auto *MD =3969              dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) {3970        const CXXRecordDecl *RD = MD->getParent();3971        // A bit wobbly with ".contains()" because it may be like3972        // "__atomic_base" or something.3973        if (StringRef(RD->getNameAsString()).contains("atomic")) {3974          BR.markInvalid(getTag(), S);3975          // After report is considered invalid there is no need to proceed3976          // futher.3977          return nullptr;3978        }3979      }3980    }3981  }3982 3983  // FIXME: We will eventually need to handle non-statement-based events3984  // (__attribute__((cleanup))).3985 3986  // Find out if this is an interesting point and what is the kind.3987  StringRef Msg;3988  std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;3989  SmallString<256> Buf;3990  llvm::raw_svector_ostream OS(Buf);3991 3992  if (Mode == Normal) {3993    if (isAllocated(RSCurr, RSPrev, S)) {3994      Msg = "Memory is allocated";3995      StackHint = std::make_unique<StackHintGeneratorForSymbol>(3996          Sym, "Returned allocated memory");3997    } else if (isReleased(RSCurr, RSPrev, S)) {3998      const auto Family = RSCurr->getAllocationFamily();3999      switch (Family.Kind) {4000      case AF_Alloca:4001      case AF_Malloc:4002      case AF_Custom:4003      case AF_CXXNew:4004      case AF_CXXNewArray:4005      case AF_IfNameIndex:4006        Msg = "Memory is released";4007        StackHint = std::make_unique<StackHintGeneratorForSymbol>(4008            Sym, "Returning; memory was released");4009        break;4010      case AF_InnerBuffer: {4011        const MemRegion *ObjRegion =4012            allocation_state::getContainerObjRegion(statePrev, Sym);4013        const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);4014        QualType ObjTy = TypedRegion->getValueType();4015        OS << "Inner buffer of '" << ObjTy << "' ";4016 4017        if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {4018          OS << "deallocated by call to destructor";4019          StackHint = std::make_unique<StackHintGeneratorForSymbol>(4020              Sym, "Returning; inner buffer was deallocated");4021        } else {4022          OS << "reallocated by call to '";4023          const Stmt *S = RSCurr->getStmt();4024          if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {4025            OS << MemCallE->getMethodDecl()->getDeclName();4026          } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {4027            OS << OpCallE->getDirectCallee()->getDeclName();4028          } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {4029            auto &CEMgr = BRC.getStateManager().getCallEventManager();4030            CallEventRef<> Call =4031                CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});4032            if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))4033              OS << D->getDeclName();4034            else4035              OS << "unknown";4036          }4037          OS << "'";4038          StackHint = std::make_unique<StackHintGeneratorForSymbol>(4039              Sym, "Returning; inner buffer was reallocated");4040        }4041        Msg = OS.str();4042        break;4043        }4044        case AF_None:4045          assert(false && "Unhandled allocation family!");4046          return nullptr;4047        }4048 4049        // Record the stack frame that is _responsible_ for this memory release4050        // event. This will be used by the false positive suppression heuristics4051        // that recognize the release points of reference-counted objects.4052        //4053        // Usually (e.g. in C) we say that the _responsible_ stack frame is the4054        // current innermost stack frame:4055        ReleaseFunctionLC = CurrentLC->getStackFrame();4056        // ...but if the stack contains a destructor call, then we say that the4057        // outermost destructor stack frame is the _responsible_ one:4058        for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {4059          if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {4060            if (isReferenceCountingPointerDestructor(DD)) {4061              // This immediately looks like a reference-counting destructor.4062              // We're bad at guessing the original reference count of the4063              // object, so suppress the report for now.4064              BR.markInvalid(getTag(), DD);4065 4066              // After report is considered invalid there is no need to proceed4067              // futher.4068              return nullptr;4069            }4070 4071            // Switch suspection to outer destructor to catch patterns like:4072            // (note that class name is distorted to bypass4073            // isReferenceCountingPointerDestructor() logic)4074            //4075            // SmartPointr::~SmartPointr() {4076            //  if (refcount.fetch_sub(1) == 1)4077            //    release_resources();4078            // }4079            // void SmartPointr::release_resources() {4080            //   free(buffer);4081            // }4082            //4083            // This way ReleaseFunctionLC will point to outermost destructor and4084            // it would be possible to catch wider range of FP.4085            //4086            // NOTE: it would be great to support smth like that in C, since4087            // currently patterns like following won't be supressed:4088            //4089            // void doFree(struct Data *data) { free(data); }4090            // void putData(struct Data *data)4091            // {4092            //   if (refPut(data))4093            //     doFree(data);4094            // }4095            ReleaseFunctionLC = LC->getStackFrame();4096          }4097        }4098 4099    } else if (isRelinquished(RSCurr, RSPrev, S)) {4100      Msg = "Memory ownership is transferred";4101      StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");4102    } else if (hasReallocFailed(RSCurr, RSPrev, S)) {4103      Mode = ReallocationFailed;4104      Msg = "Reallocation failed";4105      StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(4106          Sym, "Reallocation failed");4107 4108      if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {4109        // Is it possible to fail two reallocs WITHOUT testing in between?4110        assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&4111          "We only support one failed realloc at a time.");4112        BR.markInteresting(sym);4113        FailedReallocSymbol = sym;4114      }4115    }4116 4117  // We are in a special mode if a reallocation failed later in the path.4118  } else if (Mode == ReallocationFailed) {4119    assert(FailedReallocSymbol && "No symbol to look for.");4120 4121    // Is this is the first appearance of the reallocated symbol?4122    if (!statePrev->get<RegionState>(FailedReallocSymbol)) {4123      // We're at the reallocation point.4124      Msg = "Attempt to reallocate memory";4125      StackHint = std::make_unique<StackHintGeneratorForSymbol>(4126          Sym, "Returned reallocated memory");4127      FailedReallocSymbol = nullptr;4128      Mode = Normal;4129    }4130  }4131 4132  if (Msg.empty()) {4133    assert(!StackHint);4134    return nullptr;4135  }4136 4137  assert(StackHint);4138 4139  // Generate the extra diagnostic.4140  PathDiagnosticLocation Pos;4141  if (!S) {4142    assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);4143    auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();4144    if (!PostImplCall)4145      return nullptr;4146    Pos = PathDiagnosticLocation(PostImplCall->getLocation(),4147                                 BRC.getSourceManager());4148  } else {4149    Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),4150                                 N->getLocationContext());4151  }4152 4153  auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);4154  BR.addCallStackHint(P, std::move(StackHint));4155  return P;4156}4157 4158void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,4159                               const char *NL, const char *Sep) const {4160 4161  RegionStateTy RS = State->get<RegionState>();4162 4163  if (!RS.isEmpty()) {4164    Out << Sep << "MallocChecker :" << NL;4165    for (auto [Sym, Data] : RS) {4166      const RefState *RefS = State->get<RegionState>(Sym);4167      AllocationFamily Family = RefS->getAllocationFamily();4168 4169      const CheckerFrontend *Frontend =4170          getRelevantFrontendAs<CheckerFrontend>(Family);4171 4172      Sym->dumpToStream(Out);4173      Out << " : ";4174      Data.dump(Out);4175      if (Frontend && Frontend->isEnabled())4176        Out << " (" << Frontend->getName() << ")";4177      Out << NL;4178    }4179  }4180}4181 4182namespace clang {4183namespace ento {4184namespace allocation_state {4185 4186ProgramStateRef4187markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {4188  AllocationFamily Family(AF_InnerBuffer);4189  return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));4190}4191 4192} // end namespace allocation_state4193} // end namespace ento4194} // end namespace clang4195 4196// Intended to be used in InnerPointerChecker to register the part of4197// MallocChecker connected to it.4198void ento::registerInnerPointerCheckerAux(CheckerManager &Mgr) {4199  Mgr.getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);4200}4201 4202void ento::registerDynamicMemoryModeling(CheckerManager &Mgr) {4203  auto *Chk = Mgr.getChecker<MallocChecker>();4204  // FIXME: This is a "hidden" undocumented frontend but there are public4205  // checker options which are attached to it.4206  CheckerNameRef DMMName = Mgr.getCurrentCheckerName();4207  Chk->ShouldIncludeOwnershipAnnotatedFunctions =4208      Mgr.getAnalyzerOptions().getCheckerBooleanOption(DMMName, "Optimistic");4209  Chk->ShouldRegisterNoOwnershipChangeVisitor =4210      Mgr.getAnalyzerOptions().getCheckerBooleanOption(4211          DMMName, "AddNoOwnershipChangeNotes");4212}4213 4214bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {4215  return true;4216}4217 4218#define REGISTER_CHECKER(NAME)                                                 \4219  void ento::register##NAME(CheckerManager &Mgr) {                             \4220    Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr);                         \4221  }                                                                            \4222                                                                               \4223  bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }4224 4225// TODO: NewDelete and NewDeleteLeaks shouldn't be registered when not in C++.4226REGISTER_CHECKER(MallocChecker)4227REGISTER_CHECKER(NewDeleteChecker)4228REGISTER_CHECKER(NewDeleteLeaksChecker)4229REGISTER_CHECKER(MismatchedDeallocatorChecker)4230REGISTER_CHECKER(TaintedAllocChecker)4231