10b57cec5SDimitry Andric //=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 9a7dea167SDimitry Andric // This file defines a variety of memory management related checkers, such as 10a7dea167SDimitry Andric // leak, double free, and use-after-free. 11a7dea167SDimitry Andric // 12a7dea167SDimitry Andric // The following checkers are defined here: 13a7dea167SDimitry Andric // 14a7dea167SDimitry Andric // * MallocChecker 15a7dea167SDimitry Andric // Despite its name, it models all sorts of memory allocations and 16a7dea167SDimitry Andric // de- or reallocation, including but not limited to malloc, free, 17a7dea167SDimitry Andric // relloc, new, delete. It also reports on a variety of memory misuse 18a7dea167SDimitry Andric // errors. 19a7dea167SDimitry Andric // Many other checkers interact very closely with this checker, in fact, 20a7dea167SDimitry Andric // most are merely options to this one. Other checkers may register 21a7dea167SDimitry Andric // MallocChecker, but do not enable MallocChecker's reports (more details 22a7dea167SDimitry Andric // to follow around its field, ChecksEnabled). 23a7dea167SDimitry Andric // It also has a boolean "Optimistic" checker option, which if set to true 24a7dea167SDimitry Andric // will cause the checker to model user defined memory management related 25a7dea167SDimitry Andric // functions annotated via the attribute ownership_takes, ownership_holds 26a7dea167SDimitry Andric // and ownership_returns. 27a7dea167SDimitry Andric // 28a7dea167SDimitry Andric // * NewDeleteChecker 29a7dea167SDimitry Andric // Enables the modeling of new, new[], delete, delete[] in MallocChecker, 30a7dea167SDimitry Andric // and checks for related double-free and use-after-free errors. 31a7dea167SDimitry Andric // 32a7dea167SDimitry Andric // * NewDeleteLeaksChecker 33a7dea167SDimitry Andric // Checks for leaks related to new, new[], delete, delete[]. 34a7dea167SDimitry Andric // Depends on NewDeleteChecker. 35a7dea167SDimitry Andric // 36a7dea167SDimitry Andric // * MismatchedDeallocatorChecker 37a7dea167SDimitry Andric // Enables checking whether memory is deallocated with the correspending 38a7dea167SDimitry Andric // allocation function in MallocChecker, such as malloc() allocated 39a7dea167SDimitry Andric // regions are only freed by free(), new by delete, new[] by delete[]. 40a7dea167SDimitry Andric // 41a7dea167SDimitry Andric // InnerPointerChecker interacts very closely with MallocChecker, but unlike 42a7dea167SDimitry Andric // the above checkers, it has it's own file, hence the many InnerPointerChecker 43a7dea167SDimitry Andric // related headers and non-static functions. 440b57cec5SDimitry Andric // 450b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 460b57cec5SDimitry Andric 475ffd83dbSDimitry Andric #include "AllocationState.h" 480b57cec5SDimitry Andric #include "InterCheckerAPI.h" 49*0fca6ea1SDimitry Andric #include "NoOwnershipChangeVisitor.h" 500b57cec5SDimitry Andric #include "clang/AST/Attr.h" 515ffd83dbSDimitry Andric #include "clang/AST/DeclCXX.h" 52349cc55cSDimitry Andric #include "clang/AST/DeclTemplate.h" 535ffd83dbSDimitry Andric #include "clang/AST/Expr.h" 545ffd83dbSDimitry Andric #include "clang/AST/ExprCXX.h" 550b57cec5SDimitry Andric #include "clang/AST/ParentMap.h" 56349cc55cSDimitry Andric #include "clang/ASTMatchers/ASTMatchFinder.h" 57349cc55cSDimitry Andric #include "clang/ASTMatchers/ASTMatchers.h" 58349cc55cSDimitry Andric #include "clang/Analysis/ProgramPoint.h" 595ffd83dbSDimitry Andric #include "clang/Basic/LLVM.h" 600b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 610b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h" 620b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 635ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 64*0fca6ea1SDimitry Andric #include "clang/StaticAnalyzer/Checkers/Taint.h" 650b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 660b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" 670b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 680b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 69349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" 700b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 710b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 725ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" 73fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 74349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 750b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 760b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 775ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 785ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 79349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" 800b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 810b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 82349cc55cSDimitry Andric #include "llvm/ADT/SetOperations.h" 830b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 84349cc55cSDimitry Andric #include "llvm/Support/Casting.h" 855ffd83dbSDimitry Andric #include "llvm/Support/Compiler.h" 865ffd83dbSDimitry Andric #include "llvm/Support/ErrorHandling.h" 87349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h" 885ffd83dbSDimitry Andric #include <functional> 89bdd1243dSDimitry Andric #include <optional> 900b57cec5SDimitry Andric #include <utility> 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric using namespace clang; 930b57cec5SDimitry Andric using namespace ento; 945ffd83dbSDimitry Andric using namespace std::placeholders; 950b57cec5SDimitry Andric 96a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 975ffd83dbSDimitry Andric // The types of allocation we're modeling. This is used to check whether a 985ffd83dbSDimitry Andric // dynamically allocated object is deallocated with the correct function, like 995ffd83dbSDimitry Andric // not using operator delete on an object created by malloc(), or alloca regions 1005ffd83dbSDimitry Andric // aren't ever deallocated manually. 101a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 102a7dea167SDimitry Andric 1030b57cec5SDimitry Andric namespace { 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // Used to check correspondence between allocators and deallocators. 1060b57cec5SDimitry Andric enum AllocationFamily { 1070b57cec5SDimitry Andric AF_None, 1080b57cec5SDimitry Andric AF_Malloc, 1090b57cec5SDimitry Andric AF_CXXNew, 1100b57cec5SDimitry Andric AF_CXXNewArray, 1110b57cec5SDimitry Andric AF_IfNameIndex, 1120b57cec5SDimitry Andric AF_Alloca, 1130b57cec5SDimitry Andric AF_InnerBuffer 1140b57cec5SDimitry Andric }; 1150b57cec5SDimitry Andric 116a7dea167SDimitry Andric } // end of anonymous namespace 117a7dea167SDimitry Andric 118a7dea167SDimitry Andric /// Print names of allocators and deallocators. 119a7dea167SDimitry Andric /// 120a7dea167SDimitry Andric /// \returns true on success. 1215ffd83dbSDimitry Andric static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E); 122a7dea167SDimitry Andric 1235ffd83dbSDimitry Andric /// Print expected name of an allocator based on the deallocator's family 1245ffd83dbSDimitry Andric /// derived from the DeallocExpr. 1255ffd83dbSDimitry Andric static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family); 126a7dea167SDimitry Andric 127a7dea167SDimitry Andric /// Print expected name of a deallocator based on the allocator's 128a7dea167SDimitry Andric /// family. 129a7dea167SDimitry Andric static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family); 130a7dea167SDimitry Andric 131a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 132a7dea167SDimitry Andric // The state of a symbol, in terms of memory management. 133a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 134a7dea167SDimitry Andric 135a7dea167SDimitry Andric namespace { 136a7dea167SDimitry Andric 1370b57cec5SDimitry Andric class RefState { 138a7dea167SDimitry Andric enum Kind { 139a7dea167SDimitry Andric // Reference to allocated memory. 1400b57cec5SDimitry Andric Allocated, 1410b57cec5SDimitry Andric // Reference to zero-allocated memory. 1420b57cec5SDimitry Andric AllocatedOfSizeZero, 1430b57cec5SDimitry Andric // Reference to released/freed memory. 1440b57cec5SDimitry Andric Released, 1450b57cec5SDimitry Andric // The responsibility for freeing resources has transferred from 1460b57cec5SDimitry Andric // this reference. A relinquished symbol should not be freed. 1470b57cec5SDimitry Andric Relinquished, 1480b57cec5SDimitry Andric // We are no longer guaranteed to have observed all manipulations 1490b57cec5SDimitry Andric // of this pointer/memory. For example, it could have been 1500b57cec5SDimitry Andric // passed as a parameter to an opaque function. 1510b57cec5SDimitry Andric Escaped 1520b57cec5SDimitry Andric }; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric const Stmt *S; 1550b57cec5SDimitry Andric 156a7dea167SDimitry Andric Kind K; 157a7dea167SDimitry Andric AllocationFamily Family; 158a7dea167SDimitry Andric 159a7dea167SDimitry Andric RefState(Kind k, const Stmt *s, AllocationFamily family) 1600b57cec5SDimitry Andric : S(s), K(k), Family(family) { 1610b57cec5SDimitry Andric assert(family != AF_None); 1620b57cec5SDimitry Andric } 163a7dea167SDimitry Andric 1640b57cec5SDimitry Andric public: 1650b57cec5SDimitry Andric bool isAllocated() const { return K == Allocated; } 1660b57cec5SDimitry Andric bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; } 1670b57cec5SDimitry Andric bool isReleased() const { return K == Released; } 1680b57cec5SDimitry Andric bool isRelinquished() const { return K == Relinquished; } 1690b57cec5SDimitry Andric bool isEscaped() const { return K == Escaped; } 170a7dea167SDimitry Andric AllocationFamily getAllocationFamily() const { return Family; } 1710b57cec5SDimitry Andric const Stmt *getStmt() const { return S; } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric bool operator==(const RefState &X) const { 1740b57cec5SDimitry Andric return K == X.K && S == X.S && Family == X.Family; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 177a7dea167SDimitry Andric static RefState getAllocated(AllocationFamily family, const Stmt *s) { 1780b57cec5SDimitry Andric return RefState(Allocated, s, family); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric static RefState getAllocatedOfSizeZero(const RefState *RS) { 1810b57cec5SDimitry Andric return RefState(AllocatedOfSizeZero, RS->getStmt(), 1820b57cec5SDimitry Andric RS->getAllocationFamily()); 1830b57cec5SDimitry Andric } 184a7dea167SDimitry Andric static RefState getReleased(AllocationFamily family, const Stmt *s) { 1850b57cec5SDimitry Andric return RefState(Released, s, family); 1860b57cec5SDimitry Andric } 187a7dea167SDimitry Andric static RefState getRelinquished(AllocationFamily family, const Stmt *s) { 1880b57cec5SDimitry Andric return RefState(Relinquished, s, family); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric static RefState getEscaped(const RefState *RS) { 1910b57cec5SDimitry Andric return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily()); 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const { 1950b57cec5SDimitry Andric ID.AddInteger(K); 1960b57cec5SDimitry Andric ID.AddPointer(S); 1970b57cec5SDimitry Andric ID.AddInteger(Family); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 200a7dea167SDimitry Andric LLVM_DUMP_METHOD void dump(raw_ostream &OS) const { 201a7dea167SDimitry Andric switch (K) { 2020b57cec5SDimitry Andric #define CASE(ID) case ID: OS << #ID; break; 2030b57cec5SDimitry Andric CASE(Allocated) 2040b57cec5SDimitry Andric CASE(AllocatedOfSizeZero) 2050b57cec5SDimitry Andric CASE(Released) 2060b57cec5SDimitry Andric CASE(Relinquished) 2070b57cec5SDimitry Andric CASE(Escaped) 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } 2120b57cec5SDimitry Andric }; 2130b57cec5SDimitry Andric 214a7dea167SDimitry Andric } // end of anonymous namespace 215a7dea167SDimitry Andric 216a7dea167SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) 217a7dea167SDimitry Andric 218a7dea167SDimitry Andric /// Check if the memory associated with this symbol was released. 219a7dea167SDimitry Andric static bool isReleased(SymbolRef Sym, CheckerContext &C); 220a7dea167SDimitry Andric 221a7dea167SDimitry Andric /// Update the RefState to reflect the new memory allocation. 222a7dea167SDimitry Andric /// The optional \p RetVal parameter specifies the newly allocated pointer 223a7dea167SDimitry Andric /// value; if unspecified, the value of expression \p E is used. 224bdd1243dSDimitry Andric static ProgramStateRef 225bdd1243dSDimitry Andric MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, 2265ffd83dbSDimitry Andric AllocationFamily Family, 227bdd1243dSDimitry Andric std::optional<SVal> RetVal = std::nullopt); 228a7dea167SDimitry Andric 229a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 230a7dea167SDimitry Andric // The modeling of memory reallocation. 231a7dea167SDimitry Andric // 232a7dea167SDimitry Andric // The terminology 'toPtr' and 'fromPtr' will be used: 233a7dea167SDimitry Andric // toPtr = realloc(fromPtr, 20); 234a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 235a7dea167SDimitry Andric 236a7dea167SDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef) 237a7dea167SDimitry Andric 238a7dea167SDimitry Andric namespace { 239a7dea167SDimitry Andric 240a7dea167SDimitry Andric /// The state of 'fromPtr' after reallocation is known to have failed. 241a7dea167SDimitry Andric enum OwnershipAfterReallocKind { 242a7dea167SDimitry Andric // The symbol needs to be freed (e.g.: realloc) 243a7dea167SDimitry Andric OAR_ToBeFreedAfterFailure, 244a7dea167SDimitry Andric // The symbol has been freed (e.g.: reallocf) 245a7dea167SDimitry Andric OAR_FreeOnFailure, 246a7dea167SDimitry Andric // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where 247a7dea167SDimitry Andric // 'fromPtr' was allocated: 248a7dea167SDimitry Andric // void Haha(int *ptr) { 249a7dea167SDimitry Andric // ptr = realloc(ptr, 67); 250a7dea167SDimitry Andric // // ... 251a7dea167SDimitry Andric // } 252a7dea167SDimitry Andric // ). 253a7dea167SDimitry Andric OAR_DoNotTrackAfterFailure 2540b57cec5SDimitry Andric }; 2550b57cec5SDimitry Andric 256a7dea167SDimitry Andric /// Stores information about the 'fromPtr' symbol after reallocation. 257a7dea167SDimitry Andric /// 258a7dea167SDimitry Andric /// This is important because realloc may fail, and that needs special modeling. 259a7dea167SDimitry Andric /// Whether reallocation failed or not will not be known until later, so we'll 260a7dea167SDimitry Andric /// store whether upon failure 'fromPtr' will be freed, or needs to be freed 261a7dea167SDimitry Andric /// later, etc. 2620b57cec5SDimitry Andric struct ReallocPair { 2630b57cec5SDimitry Andric 264a7dea167SDimitry Andric // The 'fromPtr'. 265a7dea167SDimitry Andric SymbolRef ReallocatedSym; 266a7dea167SDimitry Andric OwnershipAfterReallocKind Kind; 267a7dea167SDimitry Andric 268a7dea167SDimitry Andric ReallocPair(SymbolRef S, OwnershipAfterReallocKind K) 269a7dea167SDimitry Andric : ReallocatedSym(S), Kind(K) {} 2700b57cec5SDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const { 2710b57cec5SDimitry Andric ID.AddInteger(Kind); 2720b57cec5SDimitry Andric ID.AddPointer(ReallocatedSym); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric bool operator==(const ReallocPair &X) const { 2750b57cec5SDimitry Andric return ReallocatedSym == X.ReallocatedSym && 2760b57cec5SDimitry Andric Kind == X.Kind; 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric }; 2790b57cec5SDimitry Andric 280a7dea167SDimitry Andric } // end of anonymous namespace 2810b57cec5SDimitry Andric 282a7dea167SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) 2830b57cec5SDimitry Andric 284a7dea167SDimitry Andric /// Tells if the callee is one of the builtin new/delete operators, including 285a7dea167SDimitry Andric /// placement operators and other standard overloads. 2865ffd83dbSDimitry Andric static bool isStandardNewDelete(const FunctionDecl *FD); 2875ffd83dbSDimitry Andric static bool isStandardNewDelete(const CallEvent &Call) { 2885ffd83dbSDimitry Andric if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl())) 2895ffd83dbSDimitry Andric return false; 2905ffd83dbSDimitry Andric return isStandardNewDelete(cast<FunctionDecl>(Call.getDecl())); 2915ffd83dbSDimitry Andric } 292a7dea167SDimitry Andric 293a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 294a7dea167SDimitry Andric // Definition of the MallocChecker class. 295a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 296a7dea167SDimitry Andric 297a7dea167SDimitry Andric namespace { 298a7dea167SDimitry Andric 299a7dea167SDimitry Andric class MallocChecker 300a7dea167SDimitry Andric : public Checker<check::DeadSymbols, check::PointerEscape, 301a7dea167SDimitry Andric check::ConstPointerEscape, check::PreStmt<ReturnStmt>, 3025ffd83dbSDimitry Andric check::EndFunction, check::PreCall, check::PostCall, 3035ffd83dbSDimitry Andric check::NewAllocator, check::PostStmt<BlockExpr>, 3045ffd83dbSDimitry Andric check::PostObjCMessage, check::Location, eval::Assume> { 305a7dea167SDimitry Andric public: 3065ffd83dbSDimitry Andric /// In pessimistic mode, the checker assumes that it does not know which 3075ffd83dbSDimitry Andric /// functions might free the memory. 3085ffd83dbSDimitry Andric /// In optimistic mode, the checker assumes that all user-defined functions 3095ffd83dbSDimitry Andric /// which might free a pointer are annotated. 31081ad6265SDimitry Andric bool ShouldIncludeOwnershipAnnotatedFunctions = false; 311a7dea167SDimitry Andric 31281ad6265SDimitry Andric bool ShouldRegisterNoOwnershipChangeVisitor = false; 313349cc55cSDimitry Andric 314a7dea167SDimitry Andric /// Many checkers are essentially built into this one, so enabling them will 315a7dea167SDimitry Andric /// make MallocChecker perform additional modeling and reporting. 3160b57cec5SDimitry Andric enum CheckKind { 317a7dea167SDimitry Andric /// When a subchecker is enabled but MallocChecker isn't, model memory 318a7dea167SDimitry Andric /// management but do not emit warnings emitted with MallocChecker only 319a7dea167SDimitry Andric /// enabled. 3200b57cec5SDimitry Andric CK_MallocChecker, 3210b57cec5SDimitry Andric CK_NewDeleteChecker, 3220b57cec5SDimitry Andric CK_NewDeleteLeaksChecker, 3230b57cec5SDimitry Andric CK_MismatchedDeallocatorChecker, 3240b57cec5SDimitry Andric CK_InnerPointerChecker, 325*0fca6ea1SDimitry Andric CK_TaintedAllocChecker, 3260b57cec5SDimitry Andric CK_NumCheckKinds 3270b57cec5SDimitry Andric }; 3280b57cec5SDimitry Andric 329a7dea167SDimitry Andric using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>; 3300b57cec5SDimitry Andric 33181ad6265SDimitry Andric bool ChecksEnabled[CK_NumCheckKinds] = {false}; 332a7dea167SDimitry Andric CheckerNameRef CheckNames[CK_NumCheckKinds]; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 3355ffd83dbSDimitry Andric void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 3365ffd83dbSDimitry Andric void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const; 3370b57cec5SDimitry Andric void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const; 3380b57cec5SDimitry Andric void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; 3390b57cec5SDimitry Andric void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 3400b57cec5SDimitry Andric void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 3410b57cec5SDimitry Andric void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const; 3420b57cec5SDimitry Andric ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, 3430b57cec5SDimitry Andric bool Assumption) const; 3440b57cec5SDimitry Andric void checkLocation(SVal l, bool isLoad, const Stmt *S, 3450b57cec5SDimitry Andric CheckerContext &C) const; 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric ProgramStateRef checkPointerEscape(ProgramStateRef State, 3480b57cec5SDimitry Andric const InvalidatedSymbols &Escaped, 3490b57cec5SDimitry Andric const CallEvent *Call, 3500b57cec5SDimitry Andric PointerEscapeKind Kind) const; 3510b57cec5SDimitry Andric ProgramStateRef checkConstPointerEscape(ProgramStateRef State, 3520b57cec5SDimitry Andric const InvalidatedSymbols &Escaped, 3530b57cec5SDimitry Andric const CallEvent *Call, 3540b57cec5SDimitry Andric PointerEscapeKind Kind) const; 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, 3570b57cec5SDimitry Andric const char *NL, const char *Sep) const override; 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric private: 3600b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds]; 3610b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_DoubleDelete; 3620b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds]; 3630b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds]; 3640b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds]; 3650b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds]; 3660b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_MismatchedDealloc; 3670b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds]; 3680b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds]; 369*0fca6ea1SDimitry Andric mutable std::unique_ptr<BugType> BT_TaintedAlloc; 370a7dea167SDimitry Andric 3715ffd83dbSDimitry Andric #define CHECK_FN(NAME) \ 3725ffd83dbSDimitry Andric void NAME(const CallEvent &Call, CheckerContext &C) const; 3735ffd83dbSDimitry Andric 3745ffd83dbSDimitry Andric CHECK_FN(checkFree) 3755ffd83dbSDimitry Andric CHECK_FN(checkIfNameIndex) 3765ffd83dbSDimitry Andric CHECK_FN(checkBasicAlloc) 3775ffd83dbSDimitry Andric CHECK_FN(checkKernelMalloc) 3785ffd83dbSDimitry Andric CHECK_FN(checkCalloc) 3795ffd83dbSDimitry Andric CHECK_FN(checkAlloca) 3805ffd83dbSDimitry Andric CHECK_FN(checkStrdup) 3815ffd83dbSDimitry Andric CHECK_FN(checkIfFreeNameIndex) 3825ffd83dbSDimitry Andric CHECK_FN(checkCXXNewOrCXXDelete) 3835ffd83dbSDimitry Andric CHECK_FN(checkGMalloc0) 3845ffd83dbSDimitry Andric CHECK_FN(checkGMemdup) 3855ffd83dbSDimitry Andric CHECK_FN(checkGMallocN) 3865ffd83dbSDimitry Andric CHECK_FN(checkGMallocN0) 387*0fca6ea1SDimitry Andric CHECK_FN(preGetdelim) 388*0fca6ea1SDimitry Andric CHECK_FN(checkGetdelim) 3895ffd83dbSDimitry Andric CHECK_FN(checkReallocN) 3905ffd83dbSDimitry Andric CHECK_FN(checkOwnershipAttr) 3915ffd83dbSDimitry Andric 3925ffd83dbSDimitry Andric void checkRealloc(const CallEvent &Call, CheckerContext &C, 3935ffd83dbSDimitry Andric bool ShouldFreeOnFail) const; 3945ffd83dbSDimitry Andric 3955ffd83dbSDimitry Andric using CheckFn = std::function<void(const MallocChecker *, 3965ffd83dbSDimitry Andric const CallEvent &Call, CheckerContext &C)>; 3975ffd83dbSDimitry Andric 398*0fca6ea1SDimitry Andric const CallDescriptionMap<CheckFn> PreFnMap{ 399*0fca6ea1SDimitry Andric // NOTE: the following CallDescription also matches the C++ standard 400*0fca6ea1SDimitry Andric // library function std::getline(); the callback will filter it out. 401*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetdelim}, 402*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetdelim}, 403*0fca6ea1SDimitry Andric }; 404*0fca6ea1SDimitry Andric 4055ffd83dbSDimitry Andric const CallDescriptionMap<CheckFn> FreeingMemFnMap{ 406*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree}, 407*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"if_freenameindex"}, 1}, 408*0fca6ea1SDimitry Andric &MallocChecker::checkIfFreeNameIndex}, 409*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree}, 410*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree}, 4115ffd83dbSDimitry Andric }; 4125ffd83dbSDimitry Andric 4135ffd83dbSDimitry Andric bool isFreeingCall(const CallEvent &Call) const; 41481ad6265SDimitry Andric static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func); 41581ad6265SDimitry Andric 416*0fca6ea1SDimitry Andric friend class NoMemOwnershipChangeVisitor; 4175ffd83dbSDimitry Andric 4185ffd83dbSDimitry Andric CallDescriptionMap<CheckFn> AllocatingMemFnMap{ 419*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca}, 420*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca}, 421*0fca6ea1SDimitry Andric // The line for "alloca" also covers "__builtin_alloca", but the 422*0fca6ea1SDimitry Andric // _with_align variant must be listed separately because it takes an 423*0fca6ea1SDimitry Andric // extra argument: 424*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2}, 425*0fca6ea1SDimitry Andric &MallocChecker::checkAlloca}, 426*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc}, 427*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc}, 428*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc}, 429*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc}, 430*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup}, 431*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup}, 432*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup}, 433*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc}, 434*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex}, 435*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup}, 436*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup}, 437*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc}, 438*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0}, 439*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc}, 440*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0}, 441*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup}, 442*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN}, 443*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0}, 444*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN}, 445*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0}, 4465ffd83dbSDimitry Andric }; 4475ffd83dbSDimitry Andric 4485ffd83dbSDimitry Andric CallDescriptionMap<CheckFn> ReallocatingMemFnMap{ 449*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"realloc"}, 2}, 4505ffd83dbSDimitry Andric std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)}, 451*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"reallocf"}, 2}, 4525ffd83dbSDimitry Andric std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)}, 453*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_realloc"}, 2}, 4545ffd83dbSDimitry Andric std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)}, 455*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_realloc"}, 2}, 4565ffd83dbSDimitry Andric std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)}, 457*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN}, 458*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN}, 459*0fca6ea1SDimitry Andric 460*0fca6ea1SDimitry Andric // NOTE: the following CallDescription also matches the C++ standard 461*0fca6ea1SDimitry Andric // library function std::getline(); the callback will filter it out. 462*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetdelim}, 463*0fca6ea1SDimitry Andric {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::checkGetdelim}, 4645ffd83dbSDimitry Andric }; 4655ffd83dbSDimitry Andric 4665ffd83dbSDimitry Andric bool isMemCall(const CallEvent &Call) const; 467*0fca6ea1SDimitry Andric void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C, 468*0fca6ea1SDimitry Andric llvm::ArrayRef<SymbolRef> TaintedSyms, 469*0fca6ea1SDimitry Andric AllocationFamily Family) const; 470*0fca6ea1SDimitry Andric 471*0fca6ea1SDimitry Andric void checkTaintedness(CheckerContext &C, const CallEvent &Call, 472*0fca6ea1SDimitry Andric const SVal SizeSVal, ProgramStateRef State, 473*0fca6ea1SDimitry Andric AllocationFamily Family) const; 4745ffd83dbSDimitry Andric 475a7dea167SDimitry Andric // TODO: Remove mutable by moving the initializtaion to the registry function. 476bdd1243dSDimitry Andric mutable std::optional<uint64_t> KernelZeroFlagVal; 4770b57cec5SDimitry Andric 478bdd1243dSDimitry Andric using KernelZeroSizePtrValueTy = std::optional<int>; 4795ffd83dbSDimitry Andric /// Store the value of macro called `ZERO_SIZE_PTR`. 4805ffd83dbSDimitry Andric /// The value is initialized at first use, before first use the outer 4815ffd83dbSDimitry Andric /// Optional is empty, afterwards it contains another Optional that indicates 4825ffd83dbSDimitry Andric /// if the macro value could be determined, and if yes the value itself. 483bdd1243dSDimitry Andric mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue; 4845ffd83dbSDimitry Andric 4850b57cec5SDimitry Andric /// Process C++ operator new()'s allocation, which is the part of C++ 4860b57cec5SDimitry Andric /// new-expression that goes before the constructor. 487bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 488bdd1243dSDimitry Andric processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C, 4895ffd83dbSDimitry Andric AllocationFamily Family) const; 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric /// Perform a zero-allocation check. 492a7dea167SDimitry Andric /// 4935ffd83dbSDimitry Andric /// \param [in] Call The expression that allocates memory. 494a7dea167SDimitry Andric /// \param [in] IndexOfSizeArg Index of the argument that specifies the size 495a7dea167SDimitry Andric /// of the memory that needs to be allocated. E.g. for malloc, this would be 496a7dea167SDimitry Andric /// 0. 497a7dea167SDimitry Andric /// \param [in] RetVal Specifies the newly allocated pointer value; 498a7dea167SDimitry Andric /// if unspecified, the value of expression \p E is used. 499bdd1243dSDimitry Andric [[nodiscard]] static ProgramStateRef 500bdd1243dSDimitry Andric ProcessZeroAllocCheck(const CallEvent &Call, const unsigned IndexOfSizeArg, 5010b57cec5SDimitry Andric ProgramStateRef State, 502bdd1243dSDimitry Andric std::optional<SVal> RetVal = std::nullopt); 5030b57cec5SDimitry Andric 504a7dea167SDimitry Andric /// Model functions with the ownership_returns attribute. 505a7dea167SDimitry Andric /// 506a7dea167SDimitry Andric /// User-defined function may have the ownership_returns attribute, which 507a7dea167SDimitry Andric /// annotates that the function returns with an object that was allocated on 508a7dea167SDimitry Andric /// the heap, and passes the ownertship to the callee. 509a7dea167SDimitry Andric /// 510a7dea167SDimitry Andric /// void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t); 511a7dea167SDimitry Andric /// 512a7dea167SDimitry Andric /// It has two parameters: 513a7dea167SDimitry Andric /// - first: name of the resource (e.g. 'malloc') 514a7dea167SDimitry Andric /// - (OPTIONAL) second: size of the allocated region 515a7dea167SDimitry Andric /// 5165ffd83dbSDimitry Andric /// \param [in] Call The expression that allocates memory. 517a7dea167SDimitry Andric /// \param [in] Att The ownership_returns attribute. 518a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 519a7dea167SDimitry Andric /// \returns The ProgramState right after allocation. 520bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 521bdd1243dSDimitry Andric MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call, 522bdd1243dSDimitry Andric const OwnershipAttr *Att, ProgramStateRef State) const; 523a7dea167SDimitry Andric 524a7dea167SDimitry Andric /// Models memory allocation. 525a7dea167SDimitry Andric /// 5265ffd83dbSDimitry Andric /// \param [in] Call The expression that allocates memory. 527a7dea167SDimitry Andric /// \param [in] SizeEx Size of the memory that needs to be allocated. 528a7dea167SDimitry Andric /// \param [in] Init The value the allocated memory needs to be initialized. 529a7dea167SDimitry Andric /// with. For example, \c calloc initializes the allocated memory to 0, 530a7dea167SDimitry Andric /// malloc leaves it undefined. 531a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 532a7dea167SDimitry Andric /// \returns The ProgramState right after allocation. 533*0fca6ea1SDimitry Andric [[nodiscard]] ProgramStateRef 534bdd1243dSDimitry Andric MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx, 535*0fca6ea1SDimitry Andric SVal Init, ProgramStateRef State, AllocationFamily Family) const; 536a7dea167SDimitry Andric 537a7dea167SDimitry Andric /// Models memory allocation. 538a7dea167SDimitry Andric /// 5395ffd83dbSDimitry Andric /// \param [in] Call The expression that allocates memory. 540a7dea167SDimitry Andric /// \param [in] Size Size of the memory that needs to be allocated. 541a7dea167SDimitry Andric /// \param [in] Init The value the allocated memory needs to be initialized. 542a7dea167SDimitry Andric /// with. For example, \c calloc initializes the allocated memory to 0, 543a7dea167SDimitry Andric /// malloc leaves it undefined. 544a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 545a7dea167SDimitry Andric /// \returns The ProgramState right after allocation. 546*0fca6ea1SDimitry Andric [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C, 547*0fca6ea1SDimitry Andric const CallEvent &Call, SVal Size, 548*0fca6ea1SDimitry Andric SVal Init, ProgramStateRef State, 549*0fca6ea1SDimitry Andric AllocationFamily Family) const; 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric // Check if this malloc() for special flags. At present that means M_ZERO or 5520b57cec5SDimitry Andric // __GFP_ZERO (in which case, treat it like calloc). 553bdd1243dSDimitry Andric [[nodiscard]] std::optional<ProgramStateRef> 5545ffd83dbSDimitry Andric performKernelMalloc(const CallEvent &Call, CheckerContext &C, 5550b57cec5SDimitry Andric const ProgramStateRef &State) const; 5560b57cec5SDimitry Andric 557a7dea167SDimitry Andric /// Model functions with the ownership_takes and ownership_holds attributes. 558a7dea167SDimitry Andric /// 559a7dea167SDimitry Andric /// User-defined function may have the ownership_takes and/or ownership_holds 560a7dea167SDimitry Andric /// attributes, which annotates that the function frees the memory passed as a 561a7dea167SDimitry Andric /// parameter. 562a7dea167SDimitry Andric /// 563a7dea167SDimitry Andric /// void __attribute((ownership_takes(malloc, 1))) my_free(void *); 564a7dea167SDimitry Andric /// void __attribute((ownership_holds(malloc, 1))) my_hold(void *); 565a7dea167SDimitry Andric /// 566a7dea167SDimitry Andric /// They have two parameters: 567a7dea167SDimitry Andric /// - first: name of the resource (e.g. 'malloc') 568a7dea167SDimitry Andric /// - second: index of the parameter the attribute applies to 569a7dea167SDimitry Andric /// 5705ffd83dbSDimitry Andric /// \param [in] Call The expression that frees memory. 571a7dea167SDimitry Andric /// \param [in] Att The ownership_takes or ownership_holds attribute. 572a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 573a7dea167SDimitry Andric /// \returns The ProgramState right after deallocation. 574bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C, 575bdd1243dSDimitry Andric const CallEvent &Call, 5760b57cec5SDimitry Andric const OwnershipAttr *Att, 5770b57cec5SDimitry Andric ProgramStateRef State) const; 578a7dea167SDimitry Andric 579a7dea167SDimitry Andric /// Models memory deallocation. 580a7dea167SDimitry Andric /// 5815ffd83dbSDimitry Andric /// \param [in] Call The expression that frees memory. 582a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 583a7dea167SDimitry Andric /// \param [in] Num Index of the argument that needs to be freed. This is 584a7dea167SDimitry Andric /// normally 0, but for custom free functions it may be different. 585a7dea167SDimitry Andric /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds 586a7dea167SDimitry Andric /// attribute. 587a7dea167SDimitry Andric /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known 588a7dea167SDimitry Andric /// to have been allocated, or in other words, the symbol to be freed was 589a7dea167SDimitry Andric /// registered as allocated by this checker. In the following case, \c ptr 590a7dea167SDimitry Andric /// isn't known to be allocated. 591a7dea167SDimitry Andric /// void Haha(int *ptr) { 592a7dea167SDimitry Andric /// ptr = realloc(ptr, 67); 593a7dea167SDimitry Andric /// // ... 594a7dea167SDimitry Andric /// } 595a7dea167SDimitry Andric /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function 596a7dea167SDimitry Andric /// we're modeling returns with Null on failure. 597a7dea167SDimitry Andric /// \returns The ProgramState right after deallocation. 598bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 599bdd1243dSDimitry Andric FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State, 600bdd1243dSDimitry Andric unsigned Num, bool Hold, bool &IsKnownToBeAllocated, 601bdd1243dSDimitry Andric AllocationFamily Family, bool ReturnsNullOnFailure = false) const; 6020b57cec5SDimitry Andric 603a7dea167SDimitry Andric /// Models memory deallocation. 604a7dea167SDimitry Andric /// 605a7dea167SDimitry Andric /// \param [in] ArgExpr The variable who's pointee needs to be freed. 6065ffd83dbSDimitry Andric /// \param [in] Call The expression that frees the memory. 607a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before allocation. 608a7dea167SDimitry Andric /// normally 0, but for custom free functions it may be different. 609a7dea167SDimitry Andric /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds 610a7dea167SDimitry Andric /// attribute. 611a7dea167SDimitry Andric /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known 612a7dea167SDimitry Andric /// to have been allocated, or in other words, the symbol to be freed was 613a7dea167SDimitry Andric /// registered as allocated by this checker. In the following case, \c ptr 614a7dea167SDimitry Andric /// isn't known to be allocated. 615a7dea167SDimitry Andric /// void Haha(int *ptr) { 616a7dea167SDimitry Andric /// ptr = realloc(ptr, 67); 617a7dea167SDimitry Andric /// // ... 618a7dea167SDimitry Andric /// } 619a7dea167SDimitry Andric /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function 620a7dea167SDimitry Andric /// we're modeling returns with Null on failure. 621*0fca6ea1SDimitry Andric /// \param [in] ArgValOpt Optional value to use for the argument instead of 622*0fca6ea1SDimitry Andric /// the one obtained from ArgExpr. 623a7dea167SDimitry Andric /// \returns The ProgramState right after deallocation. 624bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 625bdd1243dSDimitry Andric FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call, 626bdd1243dSDimitry Andric ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated, 627*0fca6ea1SDimitry Andric AllocationFamily Family, bool ReturnsNullOnFailure = false, 628*0fca6ea1SDimitry Andric std::optional<SVal> ArgValOpt = {}) const; 629a7dea167SDimitry Andric 630a7dea167SDimitry Andric // TODO: Needs some refactoring, as all other deallocation modeling 631a7dea167SDimitry Andric // functions are suffering from out parameters and messy code due to how 632a7dea167SDimitry Andric // realloc is handled. 633a7dea167SDimitry Andric // 634a7dea167SDimitry Andric /// Models memory reallocation. 635a7dea167SDimitry Andric /// 6365ffd83dbSDimitry Andric /// \param [in] Call The expression that reallocated memory 637a7dea167SDimitry Andric /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied 638a7dea167SDimitry Andric /// memory should be freed. 639a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before reallocation. 640a7dea167SDimitry Andric /// \param [in] SuffixWithN Whether the reallocation function we're modeling 641a7dea167SDimitry Andric /// has an '_n' suffix, such as g_realloc_n. 642a7dea167SDimitry Andric /// \returns The ProgramState right after reallocation. 643bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 644bdd1243dSDimitry Andric ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail, 645bdd1243dSDimitry Andric ProgramStateRef State, AllocationFamily Family, 6460b57cec5SDimitry Andric bool SuffixWithN = false) const; 647a7dea167SDimitry Andric 648a7dea167SDimitry Andric /// Evaluates the buffer size that needs to be allocated. 649a7dea167SDimitry Andric /// 650a7dea167SDimitry Andric /// \param [in] Blocks The amount of blocks that needs to be allocated. 651a7dea167SDimitry Andric /// \param [in] BlockBytes The size of a block. 652a7dea167SDimitry Andric /// \returns The symbolic value of \p Blocks * \p BlockBytes. 653bdd1243dSDimitry Andric [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C, 654bdd1243dSDimitry Andric const Expr *Blocks, 6550b57cec5SDimitry Andric const Expr *BlockBytes); 656a7dea167SDimitry Andric 657a7dea167SDimitry Andric /// Models zero initialized array allocation. 658a7dea167SDimitry Andric /// 6595ffd83dbSDimitry Andric /// \param [in] Call The expression that reallocated memory 660a7dea167SDimitry Andric /// \param [in] State The \c ProgramState right before reallocation. 661a7dea167SDimitry Andric /// \returns The ProgramState right after allocation. 662*0fca6ea1SDimitry Andric [[nodiscard]] ProgramStateRef CallocMem(CheckerContext &C, 663*0fca6ea1SDimitry Andric const CallEvent &Call, 664*0fca6ea1SDimitry Andric ProgramStateRef State) const; 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric /// See if deallocation happens in a suspicious context. If so, escape the 6670b57cec5SDimitry Andric /// pointers that otherwise would have been deallocated and return true. 6685ffd83dbSDimitry Andric bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call, 6690b57cec5SDimitry Andric CheckerContext &C) const; 6700b57cec5SDimitry Andric 671a7dea167SDimitry Andric /// If in \p S \p Sym is used, check whether \p Sym was already freed. 6720b57cec5SDimitry Andric bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; 6730b57cec5SDimitry Andric 674a7dea167SDimitry Andric /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero 675a7dea167SDimitry Andric /// sized memory region. 6760b57cec5SDimitry Andric void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, 6770b57cec5SDimitry Andric const Stmt *S) const; 6780b57cec5SDimitry Andric 679a7dea167SDimitry Andric /// If in \p S \p Sym is being freed, check whether \p Sym was already freed. 6800b57cec5SDimitry Andric bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const; 6810b57cec5SDimitry Andric 682a7dea167SDimitry Andric /// Check if the function is known to free memory, or if it is 6830b57cec5SDimitry Andric /// "interesting" and should be modeled explicitly. 6840b57cec5SDimitry Andric /// 6850b57cec5SDimitry Andric /// \param [out] EscapingSymbol A function might not free memory in general, 6860b57cec5SDimitry Andric /// but could be known to free a particular symbol. In this case, false is 6870b57cec5SDimitry Andric /// returned and the single escaping symbol is returned through the out 6880b57cec5SDimitry Andric /// parameter. 6890b57cec5SDimitry Andric /// 6900b57cec5SDimitry Andric /// We assume that pointers do not escape through calls to system functions 6910b57cec5SDimitry Andric /// not handled by this checker. 6920b57cec5SDimitry Andric bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call, 6930b57cec5SDimitry Andric ProgramStateRef State, 6940b57cec5SDimitry Andric SymbolRef &EscapingSymbol) const; 6950b57cec5SDimitry Andric 696a7dea167SDimitry Andric /// Implementation of the checkPointerEscape callbacks. 697bdd1243dSDimitry Andric [[nodiscard]] ProgramStateRef 698bdd1243dSDimitry Andric checkPointerEscapeAux(ProgramStateRef State, 6990b57cec5SDimitry Andric const InvalidatedSymbols &Escaped, 700bdd1243dSDimitry Andric const CallEvent *Call, PointerEscapeKind Kind, 701a7dea167SDimitry Andric bool IsConstPointerEscape) const; 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric // Implementation of the checkPreStmt and checkEndFunction callbacks. 7040b57cec5SDimitry Andric void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const; 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric ///@{ 7070b57cec5SDimitry Andric /// Tells if a given family/call/symbol is tracked by the current checker. 7080b57cec5SDimitry Andric /// Sets CheckKind to the kind of the checker responsible for this 7090b57cec5SDimitry Andric /// family/call/symbol. 710bdd1243dSDimitry Andric std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family, 7110b57cec5SDimitry Andric bool IsALeakCheck = false) const; 7125ffd83dbSDimitry Andric 713bdd1243dSDimitry Andric std::optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym, 7140b57cec5SDimitry Andric bool IsALeakCheck = false) const; 7150b57cec5SDimitry Andric ///@} 7160b57cec5SDimitry Andric static bool SummarizeValue(raw_ostream &os, SVal V); 7170b57cec5SDimitry Andric static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); 718a7dea167SDimitry Andric 7195ffd83dbSDimitry Andric void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range, 7205ffd83dbSDimitry Andric const Expr *DeallocExpr, 7215ffd83dbSDimitry Andric AllocationFamily Family) const; 7225ffd83dbSDimitry Andric 7235ffd83dbSDimitry Andric void HandleFreeAlloca(CheckerContext &C, SVal ArgVal, 7240b57cec5SDimitry Andric SourceRange Range) const; 7255ffd83dbSDimitry Andric 7265ffd83dbSDimitry Andric void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range, 7270b57cec5SDimitry Andric const Expr *DeallocExpr, const RefState *RS, 7280b57cec5SDimitry Andric SymbolRef Sym, bool OwnershipTransferred) const; 7295ffd83dbSDimitry Andric 7305ffd83dbSDimitry Andric void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, 7315ffd83dbSDimitry Andric const Expr *DeallocExpr, AllocationFamily Family, 7320b57cec5SDimitry Andric const Expr *AllocExpr = nullptr) const; 7335ffd83dbSDimitry Andric 7345ffd83dbSDimitry Andric void HandleUseAfterFree(CheckerContext &C, SourceRange Range, 7350b57cec5SDimitry Andric SymbolRef Sym) const; 7365ffd83dbSDimitry Andric 7375ffd83dbSDimitry Andric void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released, 7380b57cec5SDimitry Andric SymbolRef Sym, SymbolRef PrevSym) const; 7390b57cec5SDimitry Andric 7405ffd83dbSDimitry Andric void HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const; 7410b57cec5SDimitry Andric 7425ffd83dbSDimitry Andric void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range, 7430b57cec5SDimitry Andric SymbolRef Sym) const; 7440b57cec5SDimitry Andric 7455ffd83dbSDimitry Andric void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range, 7465ffd83dbSDimitry Andric const Expr *FreeExpr, 7475ffd83dbSDimitry Andric AllocationFamily Family) const; 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric /// Find the location of the allocation for Sym on the path leading to the 7500b57cec5SDimitry Andric /// exploded node N. 751a7dea167SDimitry Andric static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, 752a7dea167SDimitry Andric CheckerContext &C); 7530b57cec5SDimitry Andric 7545ffd83dbSDimitry Andric void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; 7555ffd83dbSDimitry Andric 7565ffd83dbSDimitry Andric /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`. 7575ffd83dbSDimitry Andric bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, 7585ffd83dbSDimitry Andric SVal ArgVal) const; 759a7dea167SDimitry Andric }; 760349cc55cSDimitry Andric } // end anonymous namespace 761349cc55cSDimitry Andric 762349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 763349cc55cSDimitry Andric // Definition of NoOwnershipChangeVisitor. 764349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 765349cc55cSDimitry Andric 766349cc55cSDimitry Andric namespace { 767*0fca6ea1SDimitry Andric class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor { 768349cc55cSDimitry Andric protected: 76981ad6265SDimitry Andric /// Syntactically checks whether the callee is a deallocating function. Since 77081ad6265SDimitry Andric /// we have no path-sensitive information on this call (we would need a 77181ad6265SDimitry Andric /// CallEvent instead of a CallExpr for that), its possible that a 77281ad6265SDimitry Andric /// deallocation function was called indirectly through a function pointer, 77381ad6265SDimitry Andric /// but we are not able to tell, so this is a best effort analysis. 77481ad6265SDimitry Andric /// See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in 77581ad6265SDimitry Andric /// clang/test/Analysis/NewDeleteLeaks.cpp. 77681ad6265SDimitry Andric bool isFreeingCallAsWritten(const CallExpr &Call) const { 777*0fca6ea1SDimitry Andric const auto *MallocChk = static_cast<const MallocChecker *>(&Checker); 778*0fca6ea1SDimitry Andric if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) || 779*0fca6ea1SDimitry Andric MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call)) 78081ad6265SDimitry Andric return true; 78181ad6265SDimitry Andric 78281ad6265SDimitry Andric if (const auto *Func = 78381ad6265SDimitry Andric llvm::dyn_cast_or_null<FunctionDecl>(Call.getCalleeDecl())) 78481ad6265SDimitry Andric return MallocChecker::isFreeingOwnershipAttrCall(Func); 78581ad6265SDimitry Andric 78681ad6265SDimitry Andric return false; 78781ad6265SDimitry Andric } 78881ad6265SDimitry Andric 789*0fca6ea1SDimitry Andric bool hasResourceStateChanged(ProgramStateRef CallEnterState, 790*0fca6ea1SDimitry Andric ProgramStateRef CallExitEndState) final { 791*0fca6ea1SDimitry Andric return CallEnterState->get<RegionState>(Sym) != 792*0fca6ea1SDimitry Andric CallExitEndState->get<RegionState>(Sym); 793*0fca6ea1SDimitry Andric } 794*0fca6ea1SDimitry Andric 79581ad6265SDimitry Andric /// Heuristically guess whether the callee intended to free memory. This is 79681ad6265SDimitry Andric /// done syntactically, because we are trying to argue about alternative 79781ad6265SDimitry Andric /// paths of execution, and as a consequence we don't have path-sensitive 79881ad6265SDimitry Andric /// information. 799*0fca6ea1SDimitry Andric bool doesFnIntendToHandleOwnership(const Decl *Callee, 800*0fca6ea1SDimitry Andric ASTContext &ACtx) final { 801349cc55cSDimitry Andric using namespace clang::ast_matchers; 802349cc55cSDimitry Andric const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee); 80381ad6265SDimitry Andric 80481ad6265SDimitry Andric auto Matches = match(findAll(stmt(anyOf(cxxDeleteExpr().bind("delete"), 80581ad6265SDimitry Andric callExpr().bind("call")))), 80681ad6265SDimitry Andric *FD->getBody(), ACtx); 80781ad6265SDimitry Andric for (BoundNodes Match : Matches) { 80881ad6265SDimitry Andric if (Match.getNodeAs<CXXDeleteExpr>("delete")) 80981ad6265SDimitry Andric return true; 81081ad6265SDimitry Andric 81181ad6265SDimitry Andric if (const auto *Call = Match.getNodeAs<CallExpr>("call")) 81281ad6265SDimitry Andric if (isFreeingCallAsWritten(*Call)) 81381ad6265SDimitry Andric return true; 81481ad6265SDimitry Andric } 81581ad6265SDimitry Andric // TODO: Ownership might change with an attempt to store the allocated 81681ad6265SDimitry Andric // memory, not only through deallocation. Check for attempted stores as 81781ad6265SDimitry Andric // well. 81881ad6265SDimitry Andric return false; 819349cc55cSDimitry Andric } 820349cc55cSDimitry Andric 821*0fca6ea1SDimitry Andric PathDiagnosticPieceRef emitNote(const ExplodedNode *N) final { 822349cc55cSDimitry Andric PathDiagnosticLocation L = PathDiagnosticLocation::create( 823349cc55cSDimitry Andric N->getLocation(), 824349cc55cSDimitry Andric N->getState()->getStateManager().getContext().getSourceManager()); 825349cc55cSDimitry Andric return std::make_shared<PathDiagnosticEventPiece>( 826349cc55cSDimitry Andric L, "Returning without deallocating memory or storing the pointer for " 827349cc55cSDimitry Andric "later deallocation"); 828349cc55cSDimitry Andric } 829349cc55cSDimitry Andric 830349cc55cSDimitry Andric public: 831*0fca6ea1SDimitry Andric NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker) 832*0fca6ea1SDimitry Andric : NoOwnershipChangeVisitor(Sym, Checker) {} 833349cc55cSDimitry Andric 834349cc55cSDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const override { 835349cc55cSDimitry Andric static int Tag = 0; 836349cc55cSDimitry Andric ID.AddPointer(&Tag); 837349cc55cSDimitry Andric ID.AddPointer(Sym); 838349cc55cSDimitry Andric } 839349cc55cSDimitry Andric }; 840349cc55cSDimitry Andric 841349cc55cSDimitry Andric } // end anonymous namespace 842a7dea167SDimitry Andric 843a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 844a7dea167SDimitry Andric // Definition of MallocBugVisitor. 845a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8460b57cec5SDimitry Andric 847349cc55cSDimitry Andric namespace { 8480b57cec5SDimitry Andric /// The bug visitor which allows us to print extra diagnostics along the 8490b57cec5SDimitry Andric /// BugReport path. For example, showing the allocation site of the leaked 8500b57cec5SDimitry Andric /// region. 8510b57cec5SDimitry Andric class MallocBugVisitor final : public BugReporterVisitor { 8520b57cec5SDimitry Andric protected: 853a7dea167SDimitry Andric enum NotificationMode { Normal, ReallocationFailed }; 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // The allocated region symbol tracked by the main analysis. 8560b57cec5SDimitry Andric SymbolRef Sym; 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric // The mode we are in, i.e. what kind of diagnostics will be emitted. 8590b57cec5SDimitry Andric NotificationMode Mode; 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric // A symbol from when the primary region should have been reallocated. 8620b57cec5SDimitry Andric SymbolRef FailedReallocSymbol; 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric // A C++ destructor stack frame in which memory was released. Used for 8650b57cec5SDimitry Andric // miscellaneous false positive suppression. 8660b57cec5SDimitry Andric const StackFrameContext *ReleaseDestructorLC; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric bool IsLeak; 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric public: 8710b57cec5SDimitry Andric MallocBugVisitor(SymbolRef S, bool isLeak = false) 8720b57cec5SDimitry Andric : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr), 8730b57cec5SDimitry Andric ReleaseDestructorLC(nullptr), IsLeak(isLeak) {} 8740b57cec5SDimitry Andric 8750b57cec5SDimitry Andric static void *getTag() { 8760b57cec5SDimitry Andric static int Tag = 0; 8770b57cec5SDimitry Andric return &Tag; 8780b57cec5SDimitry Andric } 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric void Profile(llvm::FoldingSetNodeID &ID) const override { 8810b57cec5SDimitry Andric ID.AddPointer(getTag()); 8820b57cec5SDimitry Andric ID.AddPointer(Sym); 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 885a7dea167SDimitry Andric /// Did not track -> allocated. Other state (released) -> allocated. 886a7dea167SDimitry Andric static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev, 8870b57cec5SDimitry Andric const Stmt *Stmt) { 888349cc55cSDimitry Andric return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) && 889a7dea167SDimitry Andric (RSCurr && 890a7dea167SDimitry Andric (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && 891a7dea167SDimitry Andric (!RSPrev || 892a7dea167SDimitry Andric !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero()))); 8930b57cec5SDimitry Andric } 8940b57cec5SDimitry Andric 895a7dea167SDimitry Andric /// Did not track -> released. Other state (allocated) -> released. 896a7dea167SDimitry Andric /// The statement associated with the release might be missing. 897a7dea167SDimitry Andric static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev, 8980b57cec5SDimitry Andric const Stmt *Stmt) { 899a7dea167SDimitry Andric bool IsReleased = 900a7dea167SDimitry Andric (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased()); 901349cc55cSDimitry Andric assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) || 902a7dea167SDimitry Andric (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer)); 9030b57cec5SDimitry Andric return IsReleased; 9040b57cec5SDimitry Andric } 9050b57cec5SDimitry Andric 906a7dea167SDimitry Andric /// Did not track -> relinquished. Other state (allocated) -> relinquished. 907a7dea167SDimitry Andric static inline bool isRelinquished(const RefState *RSCurr, 908a7dea167SDimitry Andric const RefState *RSPrev, const Stmt *Stmt) { 909349cc55cSDimitry Andric return ( 910349cc55cSDimitry Andric isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) && 911a7dea167SDimitry Andric (RSCurr && RSCurr->isRelinquished()) && 912a7dea167SDimitry Andric (!RSPrev || !RSPrev->isRelinquished())); 9130b57cec5SDimitry Andric } 9140b57cec5SDimitry Andric 915a7dea167SDimitry Andric /// If the expression is not a call, and the state change is 916a7dea167SDimitry Andric /// released -> allocated, it must be the realloc return value 917a7dea167SDimitry Andric /// check. If we have to handle more cases here, it might be cleaner just 918a7dea167SDimitry Andric /// to track this extra bit in the state itself. 919a7dea167SDimitry Andric static inline bool hasReallocFailed(const RefState *RSCurr, 920a7dea167SDimitry Andric const RefState *RSPrev, 9210b57cec5SDimitry Andric const Stmt *Stmt) { 922349cc55cSDimitry Andric return ((!isa_and_nonnull<CallExpr>(Stmt)) && 923a7dea167SDimitry Andric (RSCurr && 924a7dea167SDimitry Andric (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && 925a7dea167SDimitry Andric (RSPrev && 926a7dea167SDimitry Andric !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero()))); 9270b57cec5SDimitry Andric } 9280b57cec5SDimitry Andric 929a7dea167SDimitry Andric PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 9300b57cec5SDimitry Andric BugReporterContext &BRC, 931a7dea167SDimitry Andric PathSensitiveBugReport &BR) override; 9320b57cec5SDimitry Andric 933a7dea167SDimitry Andric PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 934a7dea167SDimitry Andric const ExplodedNode *EndPathNode, 935a7dea167SDimitry Andric PathSensitiveBugReport &BR) override { 9360b57cec5SDimitry Andric if (!IsLeak) 9370b57cec5SDimitry Andric return nullptr; 9380b57cec5SDimitry Andric 939a7dea167SDimitry Andric PathDiagnosticLocation L = BR.getLocation(); 9400b57cec5SDimitry Andric // Do not add the statement itself as a range in case of leak. 9410b57cec5SDimitry Andric return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(), 9420b57cec5SDimitry Andric false); 9430b57cec5SDimitry Andric } 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric private: 9460b57cec5SDimitry Andric class StackHintGeneratorForReallocationFailed 9470b57cec5SDimitry Andric : public StackHintGeneratorForSymbol { 9480b57cec5SDimitry Andric public: 9490b57cec5SDimitry Andric StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M) 9500b57cec5SDimitry Andric : StackHintGeneratorForSymbol(S, M) {} 9510b57cec5SDimitry Andric 952a7dea167SDimitry Andric std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override { 9530b57cec5SDimitry Andric // Printed parameters start at 1, not 0. 9540b57cec5SDimitry Andric ++ArgIndex; 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric SmallString<200> buf; 9570b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 9600b57cec5SDimitry Andric << " parameter failed"; 9610b57cec5SDimitry Andric 9625ffd83dbSDimitry Andric return std::string(os.str()); 9630b57cec5SDimitry Andric } 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric std::string getMessageForReturn(const CallExpr *CallExpr) override { 9660b57cec5SDimitry Andric return "Reallocation of returned value failed"; 9670b57cec5SDimitry Andric } 9680b57cec5SDimitry Andric }; 9690b57cec5SDimitry Andric }; 970a7dea167SDimitry Andric } // end anonymous namespace 9710b57cec5SDimitry Andric 9720b57cec5SDimitry Andric // A map from the freed symbol to the symbol representing the return value of 9730b57cec5SDimitry Andric // the free function. 9740b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef) 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric namespace { 9770b57cec5SDimitry Andric class StopTrackingCallback final : public SymbolVisitor { 9780b57cec5SDimitry Andric ProgramStateRef state; 9795ffd83dbSDimitry Andric 9800b57cec5SDimitry Andric public: 9810b57cec5SDimitry Andric StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {} 9820b57cec5SDimitry Andric ProgramStateRef getState() const { return state; } 9830b57cec5SDimitry Andric 9840b57cec5SDimitry Andric bool VisitSymbol(SymbolRef sym) override { 9850b57cec5SDimitry Andric state = state->remove<RegionState>(sym); 9860b57cec5SDimitry Andric return true; 9870b57cec5SDimitry Andric } 9880b57cec5SDimitry Andric }; 9890b57cec5SDimitry Andric } // end anonymous namespace 9900b57cec5SDimitry Andric 9915ffd83dbSDimitry Andric static bool isStandardNewDelete(const FunctionDecl *FD) { 9920b57cec5SDimitry Andric if (!FD) 9930b57cec5SDimitry Andric return false; 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric OverloadedOperatorKind Kind = FD->getOverloadedOperator(); 9965ffd83dbSDimitry Andric if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete && 9975ffd83dbSDimitry Andric Kind != OO_Array_Delete) 9980b57cec5SDimitry Andric return false; 9990b57cec5SDimitry Andric 10000b57cec5SDimitry Andric // This is standard if and only if it's not defined in a user file. 10010b57cec5SDimitry Andric SourceLocation L = FD->getLocation(); 10020b57cec5SDimitry Andric // If the header for operator delete is not included, it's still defined 10030b57cec5SDimitry Andric // in an invalid source location. Check to make sure we don't crash. 10045ffd83dbSDimitry Andric return !L.isValid() || 10055ffd83dbSDimitry Andric FD->getASTContext().getSourceManager().isInSystemHeader(L); 10060b57cec5SDimitry Andric } 10070b57cec5SDimitry Andric 1008a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1009a7dea167SDimitry Andric // Methods of MallocChecker and MallocBugVisitor. 1010a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1011a7dea167SDimitry Andric 101281ad6265SDimitry Andric bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) { 101381ad6265SDimitry Andric if (Func->hasAttrs()) { 10145ffd83dbSDimitry Andric for (const auto *I : Func->specific_attrs<OwnershipAttr>()) { 10155ffd83dbSDimitry Andric OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind(); 10165ffd83dbSDimitry Andric if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) 10175ffd83dbSDimitry Andric return true; 10185ffd83dbSDimitry Andric } 10195ffd83dbSDimitry Andric } 10205ffd83dbSDimitry Andric return false; 10215ffd83dbSDimitry Andric } 10225ffd83dbSDimitry Andric 102381ad6265SDimitry Andric bool MallocChecker::isFreeingCall(const CallEvent &Call) const { 102481ad6265SDimitry Andric if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call)) 102581ad6265SDimitry Andric return true; 102681ad6265SDimitry Andric 102781ad6265SDimitry Andric if (const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl())) 102881ad6265SDimitry Andric return isFreeingOwnershipAttrCall(Func); 102981ad6265SDimitry Andric 103081ad6265SDimitry Andric return false; 103181ad6265SDimitry Andric } 103281ad6265SDimitry Andric 10335ffd83dbSDimitry Andric bool MallocChecker::isMemCall(const CallEvent &Call) const { 10345ffd83dbSDimitry Andric if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) || 10355ffd83dbSDimitry Andric ReallocatingMemFnMap.lookup(Call)) 10365ffd83dbSDimitry Andric return true; 10375ffd83dbSDimitry Andric 10385ffd83dbSDimitry Andric if (!ShouldIncludeOwnershipAnnotatedFunctions) 10395ffd83dbSDimitry Andric return false; 10405ffd83dbSDimitry Andric 10415ffd83dbSDimitry Andric const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl()); 10425ffd83dbSDimitry Andric return Func && Func->hasAttr<OwnershipAttr>(); 10435ffd83dbSDimitry Andric } 10445ffd83dbSDimitry Andric 1045bdd1243dSDimitry Andric std::optional<ProgramStateRef> 10465ffd83dbSDimitry Andric MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C, 10475ffd83dbSDimitry Andric const ProgramStateRef &State) const { 10480b57cec5SDimitry Andric // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels: 10490b57cec5SDimitry Andric // 10500b57cec5SDimitry Andric // void *malloc(unsigned long size, struct malloc_type *mtp, int flags); 10510b57cec5SDimitry Andric // 10520b57cec5SDimitry Andric // One of the possible flags is M_ZERO, which means 'give me back an 10530b57cec5SDimitry Andric // allocation which is already zeroed', like calloc. 10540b57cec5SDimitry Andric 10550b57cec5SDimitry Andric // 2-argument kmalloc(), as used in the Linux kernel: 10560b57cec5SDimitry Andric // 10570b57cec5SDimitry Andric // void *kmalloc(size_t size, gfp_t flags); 10580b57cec5SDimitry Andric // 10590b57cec5SDimitry Andric // Has the similar flag value __GFP_ZERO. 10600b57cec5SDimitry Andric 10610b57cec5SDimitry Andric // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some 10620b57cec5SDimitry Andric // code could be shared. 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric ASTContext &Ctx = C.getASTContext(); 10650b57cec5SDimitry Andric llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS(); 10660b57cec5SDimitry Andric 106781ad6265SDimitry Andric if (!KernelZeroFlagVal) { 10685f757f3fSDimitry Andric switch (OS) { 10695f757f3fSDimitry Andric case llvm::Triple::FreeBSD: 10700b57cec5SDimitry Andric KernelZeroFlagVal = 0x0100; 10715f757f3fSDimitry Andric break; 10725f757f3fSDimitry Andric case llvm::Triple::NetBSD: 10730b57cec5SDimitry Andric KernelZeroFlagVal = 0x0002; 10745f757f3fSDimitry Andric break; 10755f757f3fSDimitry Andric case llvm::Triple::OpenBSD: 10760b57cec5SDimitry Andric KernelZeroFlagVal = 0x0008; 10775f757f3fSDimitry Andric break; 10785f757f3fSDimitry Andric case llvm::Triple::Linux: 10790b57cec5SDimitry Andric // __GFP_ZERO 10800b57cec5SDimitry Andric KernelZeroFlagVal = 0x8000; 10815f757f3fSDimitry Andric break; 10825f757f3fSDimitry Andric default: 10830b57cec5SDimitry Andric // FIXME: We need a more general way of getting the M_ZERO value. 10840b57cec5SDimitry Andric // See also: O_CREAT in UnixAPIChecker.cpp. 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric // Fall back to normal malloc behavior on platforms where we don't 10870b57cec5SDimitry Andric // know M_ZERO. 1088bdd1243dSDimitry Andric return std::nullopt; 10890b57cec5SDimitry Andric } 10905f757f3fSDimitry Andric } 10910b57cec5SDimitry Andric 10920b57cec5SDimitry Andric // We treat the last argument as the flags argument, and callers fall-back to 10930b57cec5SDimitry Andric // normal malloc on a None return. This works for the FreeBSD kernel malloc 10940b57cec5SDimitry Andric // as well as Linux kmalloc. 10955ffd83dbSDimitry Andric if (Call.getNumArgs() < 2) 1096bdd1243dSDimitry Andric return std::nullopt; 10970b57cec5SDimitry Andric 10985ffd83dbSDimitry Andric const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1); 10990b57cec5SDimitry Andric const SVal V = C.getSVal(FlagsEx); 110081ad6265SDimitry Andric if (!isa<NonLoc>(V)) { 11010b57cec5SDimitry Andric // The case where 'V' can be a location can only be due to a bad header, 11020b57cec5SDimitry Andric // so in this case bail out. 1103bdd1243dSDimitry Andric return std::nullopt; 11040b57cec5SDimitry Andric } 11050b57cec5SDimitry Andric 11060b57cec5SDimitry Andric NonLoc Flags = V.castAs<NonLoc>(); 1107bdd1243dSDimitry Andric NonLoc ZeroFlag = C.getSValBuilder() 1108bdd1243dSDimitry Andric .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType()) 11090b57cec5SDimitry Andric .castAs<NonLoc>(); 11100b57cec5SDimitry Andric SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And, 11110b57cec5SDimitry Andric Flags, ZeroFlag, 11120b57cec5SDimitry Andric FlagsEx->getType()); 11130b57cec5SDimitry Andric if (MaskedFlagsUC.isUnknownOrUndef()) 1114bdd1243dSDimitry Andric return std::nullopt; 11150b57cec5SDimitry Andric DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>(); 11160b57cec5SDimitry Andric 11170b57cec5SDimitry Andric // Check if maskedFlags is non-zero. 11180b57cec5SDimitry Andric ProgramStateRef TrueState, FalseState; 11190b57cec5SDimitry Andric std::tie(TrueState, FalseState) = State->assume(MaskedFlags); 11200b57cec5SDimitry Andric 11210b57cec5SDimitry Andric // If M_ZERO is set, treat this like calloc (initialized). 11220b57cec5SDimitry Andric if (TrueState && !FalseState) { 11230b57cec5SDimitry Andric SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy); 11245ffd83dbSDimitry Andric return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState, 11255ffd83dbSDimitry Andric AF_Malloc); 11260b57cec5SDimitry Andric } 11270b57cec5SDimitry Andric 1128bdd1243dSDimitry Andric return std::nullopt; 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks, 11320b57cec5SDimitry Andric const Expr *BlockBytes) { 11330b57cec5SDimitry Andric SValBuilder &SB = C.getSValBuilder(); 11340b57cec5SDimitry Andric SVal BlocksVal = C.getSVal(Blocks); 11350b57cec5SDimitry Andric SVal BlockBytesVal = C.getSVal(BlockBytes); 11360b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 11370b57cec5SDimitry Andric SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal, 11380b57cec5SDimitry Andric SB.getContext().getSizeType()); 11390b57cec5SDimitry Andric return TotalSize; 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric 11425ffd83dbSDimitry Andric void MallocChecker::checkBasicAlloc(const CallEvent &Call, 11435ffd83dbSDimitry Andric CheckerContext &C) const { 11445ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 11455ffd83dbSDimitry Andric State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State, 11465ffd83dbSDimitry Andric AF_Malloc); 11475ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 11485ffd83dbSDimitry Andric C.addTransition(State); 11495ffd83dbSDimitry Andric } 11500b57cec5SDimitry Andric 11515ffd83dbSDimitry Andric void MallocChecker::checkKernelMalloc(const CallEvent &Call, 11525ffd83dbSDimitry Andric CheckerContext &C) const { 11535ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1154bdd1243dSDimitry Andric std::optional<ProgramStateRef> MaybeState = 11555ffd83dbSDimitry Andric performKernelMalloc(Call, C, State); 115681ad6265SDimitry Andric if (MaybeState) 1157bdd1243dSDimitry Andric State = *MaybeState; 11585ffd83dbSDimitry Andric else 11595ffd83dbSDimitry Andric State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State, 11605ffd83dbSDimitry Andric AF_Malloc); 11615ffd83dbSDimitry Andric C.addTransition(State); 11625ffd83dbSDimitry Andric } 11630b57cec5SDimitry Andric 11645ffd83dbSDimitry Andric static bool isStandardRealloc(const CallEvent &Call) { 11655ffd83dbSDimitry Andric const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl()); 11665ffd83dbSDimitry Andric assert(FD); 11675ffd83dbSDimitry Andric ASTContext &AC = FD->getASTContext(); 11685ffd83dbSDimitry Andric 11695ffd83dbSDimitry Andric return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy && 11705ffd83dbSDimitry Andric FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy && 11715ffd83dbSDimitry Andric FD->getParamDecl(1)->getType().getDesugaredType(AC) == 11725ffd83dbSDimitry Andric AC.getSizeType(); 11735ffd83dbSDimitry Andric } 11745ffd83dbSDimitry Andric 11755ffd83dbSDimitry Andric static bool isGRealloc(const CallEvent &Call) { 11765ffd83dbSDimitry Andric const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl()); 11775ffd83dbSDimitry Andric assert(FD); 11785ffd83dbSDimitry Andric ASTContext &AC = FD->getASTContext(); 11795ffd83dbSDimitry Andric 11805ffd83dbSDimitry Andric return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy && 11815ffd83dbSDimitry Andric FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy && 11825ffd83dbSDimitry Andric FD->getParamDecl(1)->getType().getDesugaredType(AC) == 11835ffd83dbSDimitry Andric AC.UnsignedLongTy; 11845ffd83dbSDimitry Andric } 11855ffd83dbSDimitry Andric 11865ffd83dbSDimitry Andric void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C, 11875ffd83dbSDimitry Andric bool ShouldFreeOnFail) const { 1188*0fca6ea1SDimitry Andric // Ignore calls to functions whose type does not match the expected type of 1189*0fca6ea1SDimitry Andric // either the standard realloc or g_realloc from GLib. 1190*0fca6ea1SDimitry Andric // FIXME: Should we perform this kind of checking consistently for each 1191*0fca6ea1SDimitry Andric // function? If yes, then perhaps extend the `CallDescription` interface to 1192*0fca6ea1SDimitry Andric // handle this. 11935ffd83dbSDimitry Andric if (!isStandardRealloc(Call) && !isGRealloc(Call)) 11945ffd83dbSDimitry Andric return; 1195*0fca6ea1SDimitry Andric 11965ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 11975ffd83dbSDimitry Andric State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc); 11985ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 11995ffd83dbSDimitry Andric C.addTransition(State); 12005ffd83dbSDimitry Andric } 12015ffd83dbSDimitry Andric 12025ffd83dbSDimitry Andric void MallocChecker::checkCalloc(const CallEvent &Call, 12035ffd83dbSDimitry Andric CheckerContext &C) const { 12045ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12055ffd83dbSDimitry Andric State = CallocMem(C, Call, State); 12065ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 12075ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 12085ffd83dbSDimitry Andric C.addTransition(State); 12095ffd83dbSDimitry Andric } 12105ffd83dbSDimitry Andric 12115ffd83dbSDimitry Andric void MallocChecker::checkFree(const CallEvent &Call, CheckerContext &C) const { 12120b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 1213a7dea167SDimitry Andric bool IsKnownToBeAllocatedMemory = false; 12145ffd83dbSDimitry Andric if (suppressDeallocationsInSuspiciousContexts(Call, C)) 12150b57cec5SDimitry Andric return; 12165ffd83dbSDimitry Andric State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory, 12175ffd83dbSDimitry Andric AF_Malloc); 12185ffd83dbSDimitry Andric C.addTransition(State); 12190b57cec5SDimitry Andric } 12205ffd83dbSDimitry Andric 12215ffd83dbSDimitry Andric void MallocChecker::checkAlloca(const CallEvent &Call, 12225ffd83dbSDimitry Andric CheckerContext &C) const { 12235ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12245ffd83dbSDimitry Andric State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State, 12255ffd83dbSDimitry Andric AF_Alloca); 12265ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 12275ffd83dbSDimitry Andric C.addTransition(State); 12285ffd83dbSDimitry Andric } 12295ffd83dbSDimitry Andric 12305ffd83dbSDimitry Andric void MallocChecker::checkStrdup(const CallEvent &Call, 12315ffd83dbSDimitry Andric CheckerContext &C) const { 12325ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12335ffd83dbSDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 12345ffd83dbSDimitry Andric if (!CE) 12350b57cec5SDimitry Andric return; 12365ffd83dbSDimitry Andric State = MallocUpdateRefState(C, CE, State, AF_Malloc); 12375ffd83dbSDimitry Andric 12385ffd83dbSDimitry Andric C.addTransition(State); 12395ffd83dbSDimitry Andric } 12405ffd83dbSDimitry Andric 12415ffd83dbSDimitry Andric void MallocChecker::checkIfNameIndex(const CallEvent &Call, 12425ffd83dbSDimitry Andric CheckerContext &C) const { 12435ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12445ffd83dbSDimitry Andric // Should we model this differently? We can allocate a fixed number of 12455ffd83dbSDimitry Andric // elements with zeros in the last one. 12465ffd83dbSDimitry Andric State = 12475ffd83dbSDimitry Andric MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, AF_IfNameIndex); 12485ffd83dbSDimitry Andric 12495ffd83dbSDimitry Andric C.addTransition(State); 12505ffd83dbSDimitry Andric } 12515ffd83dbSDimitry Andric 12525ffd83dbSDimitry Andric void MallocChecker::checkIfFreeNameIndex(const CallEvent &Call, 12535ffd83dbSDimitry Andric CheckerContext &C) const { 12545ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12555ffd83dbSDimitry Andric bool IsKnownToBeAllocatedMemory = false; 12565ffd83dbSDimitry Andric State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory, 12575ffd83dbSDimitry Andric AF_IfNameIndex); 12585ffd83dbSDimitry Andric C.addTransition(State); 12595ffd83dbSDimitry Andric } 12605ffd83dbSDimitry Andric 12615ffd83dbSDimitry Andric void MallocChecker::checkCXXNewOrCXXDelete(const CallEvent &Call, 12625ffd83dbSDimitry Andric CheckerContext &C) const { 12635ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12645ffd83dbSDimitry Andric bool IsKnownToBeAllocatedMemory = false; 12655ffd83dbSDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 12665ffd83dbSDimitry Andric if (!CE) 12670b57cec5SDimitry Andric return; 12680b57cec5SDimitry Andric 12695ffd83dbSDimitry Andric assert(isStandardNewDelete(Call)); 12705ffd83dbSDimitry Andric 12710b57cec5SDimitry Andric // Process direct calls to operator new/new[]/delete/delete[] functions 12720b57cec5SDimitry Andric // as distinct from new/new[]/delete/delete[] expressions that are 12730b57cec5SDimitry Andric // processed by the checkPostStmt callbacks for CXXNewExpr and 12740b57cec5SDimitry Andric // CXXDeleteExpr. 12755ffd83dbSDimitry Andric const FunctionDecl *FD = C.getCalleeDecl(CE); 1276a7dea167SDimitry Andric switch (FD->getOverloadedOperator()) { 1277a7dea167SDimitry Andric case OO_New: 12785ffd83dbSDimitry Andric State = 12795ffd83dbSDimitry Andric MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State, AF_CXXNew); 12805ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 1281a7dea167SDimitry Andric break; 1282a7dea167SDimitry Andric case OO_Array_New: 12835ffd83dbSDimitry Andric State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State, 12840b57cec5SDimitry Andric AF_CXXNewArray); 12855ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 1286a7dea167SDimitry Andric break; 1287a7dea167SDimitry Andric case OO_Delete: 12885ffd83dbSDimitry Andric State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory, 12895ffd83dbSDimitry Andric AF_CXXNew); 12905ffd83dbSDimitry Andric break; 1291a7dea167SDimitry Andric case OO_Array_Delete: 12925ffd83dbSDimitry Andric State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory, 12935ffd83dbSDimitry Andric AF_CXXNewArray); 1294a7dea167SDimitry Andric break; 1295a7dea167SDimitry Andric default: 12960b57cec5SDimitry Andric llvm_unreachable("not a new/delete operator"); 1297a7dea167SDimitry Andric } 12985ffd83dbSDimitry Andric 12995ffd83dbSDimitry Andric C.addTransition(State); 13000b57cec5SDimitry Andric } 13010b57cec5SDimitry Andric 13025ffd83dbSDimitry Andric void MallocChecker::checkGMalloc0(const CallEvent &Call, 13035ffd83dbSDimitry Andric CheckerContext &C) const { 13045ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 13055ffd83dbSDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 13065ffd83dbSDimitry Andric SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); 13075ffd83dbSDimitry Andric State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State, AF_Malloc); 13085ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 13095ffd83dbSDimitry Andric C.addTransition(State); 13105ffd83dbSDimitry Andric } 13115ffd83dbSDimitry Andric 13125ffd83dbSDimitry Andric void MallocChecker::checkGMemdup(const CallEvent &Call, 13135ffd83dbSDimitry Andric CheckerContext &C) const { 13145ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 131581ad6265SDimitry Andric State = 131681ad6265SDimitry Andric MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State, AF_Malloc); 13175ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 13185ffd83dbSDimitry Andric C.addTransition(State); 13195ffd83dbSDimitry Andric } 13205ffd83dbSDimitry Andric 13215ffd83dbSDimitry Andric void MallocChecker::checkGMallocN(const CallEvent &Call, 13225ffd83dbSDimitry Andric CheckerContext &C) const { 13235ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 13245ffd83dbSDimitry Andric SVal Init = UndefinedVal(); 13255ffd83dbSDimitry Andric SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1)); 13265ffd83dbSDimitry Andric State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc); 13275ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 13285ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 13295ffd83dbSDimitry Andric C.addTransition(State); 13305ffd83dbSDimitry Andric } 13315ffd83dbSDimitry Andric 13325ffd83dbSDimitry Andric void MallocChecker::checkGMallocN0(const CallEvent &Call, 13335ffd83dbSDimitry Andric CheckerContext &C) const { 13345ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 13355ffd83dbSDimitry Andric SValBuilder &SB = C.getSValBuilder(); 13365ffd83dbSDimitry Andric SVal Init = SB.makeZeroVal(SB.getContext().CharTy); 13375ffd83dbSDimitry Andric SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1)); 13385ffd83dbSDimitry Andric State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc); 13395ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State); 13405ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 13415ffd83dbSDimitry Andric C.addTransition(State); 13425ffd83dbSDimitry Andric } 13435ffd83dbSDimitry Andric 1344*0fca6ea1SDimitry Andric static bool isFromStdNamespace(const CallEvent &Call) { 1345*0fca6ea1SDimitry Andric const Decl *FD = Call.getDecl(); 1346*0fca6ea1SDimitry Andric assert(FD && "a CallDescription cannot match a call without a Decl"); 1347*0fca6ea1SDimitry Andric return FD->isInStdNamespace(); 1348*0fca6ea1SDimitry Andric } 1349*0fca6ea1SDimitry Andric 1350*0fca6ea1SDimitry Andric void MallocChecker::preGetdelim(const CallEvent &Call, 1351*0fca6ea1SDimitry Andric CheckerContext &C) const { 1352*0fca6ea1SDimitry Andric // Discard calls to the C++ standard library function std::getline(), which 1353*0fca6ea1SDimitry Andric // is completely unrelated to the POSIX getline() that we're checking. 1354*0fca6ea1SDimitry Andric if (isFromStdNamespace(Call)) 1355*0fca6ea1SDimitry Andric return; 1356*0fca6ea1SDimitry Andric 1357*0fca6ea1SDimitry Andric ProgramStateRef State = C.getState(); 1358*0fca6ea1SDimitry Andric const auto LinePtr = getPointeeVal(Call.getArgSVal(0), State); 1359*0fca6ea1SDimitry Andric if (!LinePtr) 1360*0fca6ea1SDimitry Andric return; 1361*0fca6ea1SDimitry Andric 1362*0fca6ea1SDimitry Andric // FreeMemAux takes IsKnownToBeAllocated as an output parameter, and it will 1363*0fca6ea1SDimitry Andric // be true after the call if the symbol was registered by this checker. 1364*0fca6ea1SDimitry Andric // We do not need this value here, as FreeMemAux will take care 1365*0fca6ea1SDimitry Andric // of reporting any violation of the preconditions. 1366*0fca6ea1SDimitry Andric bool IsKnownToBeAllocated = false; 1367*0fca6ea1SDimitry Andric State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false, 1368*0fca6ea1SDimitry Andric IsKnownToBeAllocated, AF_Malloc, false, LinePtr); 1369*0fca6ea1SDimitry Andric if (State) 1370*0fca6ea1SDimitry Andric C.addTransition(State); 1371*0fca6ea1SDimitry Andric } 1372*0fca6ea1SDimitry Andric 1373*0fca6ea1SDimitry Andric void MallocChecker::checkGetdelim(const CallEvent &Call, 1374*0fca6ea1SDimitry Andric CheckerContext &C) const { 1375*0fca6ea1SDimitry Andric // Discard calls to the C++ standard library function std::getline(), which 1376*0fca6ea1SDimitry Andric // is completely unrelated to the POSIX getline() that we're checking. 1377*0fca6ea1SDimitry Andric if (isFromStdNamespace(Call)) 1378*0fca6ea1SDimitry Andric return; 1379*0fca6ea1SDimitry Andric 1380*0fca6ea1SDimitry Andric ProgramStateRef State = C.getState(); 1381*0fca6ea1SDimitry Andric // Handle the post-conditions of getline and getdelim: 1382*0fca6ea1SDimitry Andric // Register the new conjured value as an allocated buffer. 1383*0fca6ea1SDimitry Andric const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 1384*0fca6ea1SDimitry Andric if (!CE) 1385*0fca6ea1SDimitry Andric return; 1386*0fca6ea1SDimitry Andric 1387*0fca6ea1SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 1388*0fca6ea1SDimitry Andric 1389*0fca6ea1SDimitry Andric const auto LinePtr = 1390*0fca6ea1SDimitry Andric getPointeeVal(Call.getArgSVal(0), State)->getAs<DefinedSVal>(); 1391*0fca6ea1SDimitry Andric const auto Size = 1392*0fca6ea1SDimitry Andric getPointeeVal(Call.getArgSVal(1), State)->getAs<DefinedSVal>(); 1393*0fca6ea1SDimitry Andric if (!LinePtr || !Size || !LinePtr->getAsRegion()) 1394*0fca6ea1SDimitry Andric return; 1395*0fca6ea1SDimitry Andric 1396*0fca6ea1SDimitry Andric State = setDynamicExtent(State, LinePtr->getAsRegion(), *Size, SVB); 1397*0fca6ea1SDimitry Andric C.addTransition(MallocUpdateRefState(C, CE, State, AF_Malloc, *LinePtr)); 1398*0fca6ea1SDimitry Andric } 1399*0fca6ea1SDimitry Andric 14005ffd83dbSDimitry Andric void MallocChecker::checkReallocN(const CallEvent &Call, 14015ffd83dbSDimitry Andric CheckerContext &C) const { 14025ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 14035ffd83dbSDimitry Andric State = ReallocMemAux(C, Call, /*ShouldFreeOnFail=*/false, State, AF_Malloc, 14045ffd83dbSDimitry Andric /*SuffixWithN=*/true); 14055ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 1, State); 14065ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 2, State); 14075ffd83dbSDimitry Andric C.addTransition(State); 14085ffd83dbSDimitry Andric } 14095ffd83dbSDimitry Andric 14105ffd83dbSDimitry Andric void MallocChecker::checkOwnershipAttr(const CallEvent &Call, 14115ffd83dbSDimitry Andric CheckerContext &C) const { 14125ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 14135ffd83dbSDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 14145ffd83dbSDimitry Andric if (!CE) 14155ffd83dbSDimitry Andric return; 14165ffd83dbSDimitry Andric const FunctionDecl *FD = C.getCalleeDecl(CE); 14175ffd83dbSDimitry Andric if (!FD) 14185ffd83dbSDimitry Andric return; 14195ffd83dbSDimitry Andric if (ShouldIncludeOwnershipAnnotatedFunctions || 1420a7dea167SDimitry Andric ChecksEnabled[CK_MismatchedDeallocatorChecker]) { 14210b57cec5SDimitry Andric // Check all the attributes, if there are any. 14220b57cec5SDimitry Andric // There can be multiple of these attributes. 14230b57cec5SDimitry Andric if (FD->hasAttrs()) 14240b57cec5SDimitry Andric for (const auto *I : FD->specific_attrs<OwnershipAttr>()) { 14250b57cec5SDimitry Andric switch (I->getOwnKind()) { 14260b57cec5SDimitry Andric case OwnershipAttr::Returns: 14275ffd83dbSDimitry Andric State = MallocMemReturnsAttr(C, Call, I, State); 14280b57cec5SDimitry Andric break; 14290b57cec5SDimitry Andric case OwnershipAttr::Takes: 14300b57cec5SDimitry Andric case OwnershipAttr::Holds: 14315ffd83dbSDimitry Andric State = FreeMemAttr(C, Call, I, State); 14320b57cec5SDimitry Andric break; 14330b57cec5SDimitry Andric } 14340b57cec5SDimitry Andric } 14350b57cec5SDimitry Andric } 14360b57cec5SDimitry Andric C.addTransition(State); 14370b57cec5SDimitry Andric } 14380b57cec5SDimitry Andric 14395ffd83dbSDimitry Andric void MallocChecker::checkPostCall(const CallEvent &Call, 14405ffd83dbSDimitry Andric CheckerContext &C) const { 14415ffd83dbSDimitry Andric if (C.wasInlined) 14425ffd83dbSDimitry Andric return; 14435ffd83dbSDimitry Andric if (!Call.getOriginExpr()) 14445ffd83dbSDimitry Andric return; 14455ffd83dbSDimitry Andric 14465ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 14475ffd83dbSDimitry Andric 14485ffd83dbSDimitry Andric if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) { 14495ffd83dbSDimitry Andric (*Callback)(this, Call, C); 14505ffd83dbSDimitry Andric return; 14515ffd83dbSDimitry Andric } 14525ffd83dbSDimitry Andric 14535ffd83dbSDimitry Andric if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) { 14545ffd83dbSDimitry Andric (*Callback)(this, Call, C); 14555ffd83dbSDimitry Andric return; 14565ffd83dbSDimitry Andric } 14575ffd83dbSDimitry Andric 14585ffd83dbSDimitry Andric if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) { 14595ffd83dbSDimitry Andric (*Callback)(this, Call, C); 14605ffd83dbSDimitry Andric return; 14615ffd83dbSDimitry Andric } 14625ffd83dbSDimitry Andric 14635ffd83dbSDimitry Andric if (isStandardNewDelete(Call)) { 14645ffd83dbSDimitry Andric checkCXXNewOrCXXDelete(Call, C); 14655ffd83dbSDimitry Andric return; 14665ffd83dbSDimitry Andric } 14675ffd83dbSDimitry Andric 14685ffd83dbSDimitry Andric checkOwnershipAttr(Call, C); 14695ffd83dbSDimitry Andric } 14705ffd83dbSDimitry Andric 14710b57cec5SDimitry Andric // Performs a 0-sized allocations check. 1472a7dea167SDimitry Andric ProgramStateRef MallocChecker::ProcessZeroAllocCheck( 14735ffd83dbSDimitry Andric const CallEvent &Call, const unsigned IndexOfSizeArg, ProgramStateRef State, 1474bdd1243dSDimitry Andric std::optional<SVal> RetVal) { 14750b57cec5SDimitry Andric if (!State) 14760b57cec5SDimitry Andric return nullptr; 14770b57cec5SDimitry Andric 14780b57cec5SDimitry Andric if (!RetVal) 14795ffd83dbSDimitry Andric RetVal = Call.getReturnValue(); 14800b57cec5SDimitry Andric 14810b57cec5SDimitry Andric const Expr *Arg = nullptr; 14820b57cec5SDimitry Andric 14835ffd83dbSDimitry Andric if (const CallExpr *CE = dyn_cast<CallExpr>(Call.getOriginExpr())) { 1484a7dea167SDimitry Andric Arg = CE->getArg(IndexOfSizeArg); 14855ffd83dbSDimitry Andric } else if (const CXXNewExpr *NE = 14865ffd83dbSDimitry Andric dyn_cast<CXXNewExpr>(Call.getOriginExpr())) { 14875ffd83dbSDimitry Andric if (NE->isArray()) { 14880b57cec5SDimitry Andric Arg = *NE->getArraySize(); 14895ffd83dbSDimitry Andric } else { 14900b57cec5SDimitry Andric return State; 14910b57cec5SDimitry Andric } 14925ffd83dbSDimitry Andric } else 14930b57cec5SDimitry Andric llvm_unreachable("not a CallExpr or CXXNewExpr"); 14940b57cec5SDimitry Andric 14950b57cec5SDimitry Andric assert(Arg); 14960b57cec5SDimitry Andric 14975ffd83dbSDimitry Andric auto DefArgVal = 14985ffd83dbSDimitry Andric State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>(); 14990b57cec5SDimitry Andric 15000b57cec5SDimitry Andric if (!DefArgVal) 15010b57cec5SDimitry Andric return State; 15020b57cec5SDimitry Andric 15030b57cec5SDimitry Andric // Check if the allocation size is 0. 15040b57cec5SDimitry Andric ProgramStateRef TrueState, FalseState; 15055ffd83dbSDimitry Andric SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder(); 15060b57cec5SDimitry Andric DefinedSVal Zero = 15070b57cec5SDimitry Andric SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>(); 15080b57cec5SDimitry Andric 15090b57cec5SDimitry Andric std::tie(TrueState, FalseState) = 15100b57cec5SDimitry Andric State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero)); 15110b57cec5SDimitry Andric 15120b57cec5SDimitry Andric if (TrueState && !FalseState) { 15130b57cec5SDimitry Andric SymbolRef Sym = RetVal->getAsLocSymbol(); 15140b57cec5SDimitry Andric if (!Sym) 15150b57cec5SDimitry Andric return State; 15160b57cec5SDimitry Andric 15170b57cec5SDimitry Andric const RefState *RS = State->get<RegionState>(Sym); 15180b57cec5SDimitry Andric if (RS) { 15190b57cec5SDimitry Andric if (RS->isAllocated()) 15200b57cec5SDimitry Andric return TrueState->set<RegionState>(Sym, 15210b57cec5SDimitry Andric RefState::getAllocatedOfSizeZero(RS)); 15220b57cec5SDimitry Andric else 15230b57cec5SDimitry Andric return State; 15240b57cec5SDimitry Andric } else { 15250b57cec5SDimitry Andric // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as 15260b57cec5SDimitry Andric // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not 15270b57cec5SDimitry Andric // tracked. Add zero-reallocated Sym to the state to catch references 15280b57cec5SDimitry Andric // to zero-allocated memory. 15290b57cec5SDimitry Andric return TrueState->add<ReallocSizeZeroSymbols>(Sym); 15300b57cec5SDimitry Andric } 15310b57cec5SDimitry Andric } 15320b57cec5SDimitry Andric 15330b57cec5SDimitry Andric // Assume the value is non-zero going forward. 15340b57cec5SDimitry Andric assert(FalseState); 15350b57cec5SDimitry Andric return FalseState; 15360b57cec5SDimitry Andric } 15370b57cec5SDimitry Andric 15380b57cec5SDimitry Andric static QualType getDeepPointeeType(QualType T) { 15390b57cec5SDimitry Andric QualType Result = T, PointeeType = T->getPointeeType(); 15400b57cec5SDimitry Andric while (!PointeeType.isNull()) { 15410b57cec5SDimitry Andric Result = PointeeType; 15420b57cec5SDimitry Andric PointeeType = PointeeType->getPointeeType(); 15430b57cec5SDimitry Andric } 15440b57cec5SDimitry Andric return Result; 15450b57cec5SDimitry Andric } 15460b57cec5SDimitry Andric 1547a7dea167SDimitry Andric /// \returns true if the constructor invoked by \p NE has an argument of a 1548a7dea167SDimitry Andric /// pointer/reference to a record type. 1549a7dea167SDimitry Andric static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) { 15500b57cec5SDimitry Andric 15510b57cec5SDimitry Andric const CXXConstructExpr *ConstructE = NE->getConstructExpr(); 15520b57cec5SDimitry Andric if (!ConstructE) 15530b57cec5SDimitry Andric return false; 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric if (!NE->getAllocatedType()->getAsCXXRecordDecl()) 15560b57cec5SDimitry Andric return false; 15570b57cec5SDimitry Andric 15580b57cec5SDimitry Andric const CXXConstructorDecl *CtorD = ConstructE->getConstructor(); 15590b57cec5SDimitry Andric 15600b57cec5SDimitry Andric // Iterate over the constructor parameters. 15610b57cec5SDimitry Andric for (const auto *CtorParam : CtorD->parameters()) { 15620b57cec5SDimitry Andric 15630b57cec5SDimitry Andric QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType(); 15640b57cec5SDimitry Andric if (CtorParamPointeeT.isNull()) 15650b57cec5SDimitry Andric continue; 15660b57cec5SDimitry Andric 15670b57cec5SDimitry Andric CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT); 15680b57cec5SDimitry Andric 15690b57cec5SDimitry Andric if (CtorParamPointeeT->getAsCXXRecordDecl()) 15700b57cec5SDimitry Andric return true; 15710b57cec5SDimitry Andric } 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric return false; 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric 15765ffd83dbSDimitry Andric ProgramStateRef 15775ffd83dbSDimitry Andric MallocChecker::processNewAllocation(const CXXAllocatorCall &Call, 15780b57cec5SDimitry Andric CheckerContext &C, 15795ffd83dbSDimitry Andric AllocationFamily Family) const { 15805ffd83dbSDimitry Andric if (!isStandardNewDelete(Call)) 15815ffd83dbSDimitry Andric return nullptr; 15820b57cec5SDimitry Andric 15835ffd83dbSDimitry Andric const CXXNewExpr *NE = Call.getOriginExpr(); 1584a7dea167SDimitry Andric const ParentMap &PM = C.getLocationContext()->getParentMap(); 15855ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 1586a7dea167SDimitry Andric 1587a7dea167SDimitry Andric // Non-trivial constructors have a chance to escape 'this', but marking all 1588a7dea167SDimitry Andric // invocations of trivial constructors as escaped would cause too great of 1589a7dea167SDimitry Andric // reduction of true positives, so let's just do that for constructors that 1590a7dea167SDimitry Andric // have an argument of a pointer-to-record type. 1591a7dea167SDimitry Andric if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE)) 15925ffd83dbSDimitry Andric return State; 15930b57cec5SDimitry Andric 15940b57cec5SDimitry Andric // The return value from operator new is bound to a specified initialization 15950b57cec5SDimitry Andric // value (if any) and we don't want to loose this value. So we call 15960b57cec5SDimitry Andric // MallocUpdateRefState() instead of MallocMemAux() which breaks the 15970b57cec5SDimitry Andric // existing binding. 15985ffd83dbSDimitry Andric SVal Target = Call.getObjectUnderConstruction(); 1599*0fca6ea1SDimitry Andric if (Call.getOriginExpr()->isArray()) { 1600*0fca6ea1SDimitry Andric if (auto SizeEx = NE->getArraySize()) 1601*0fca6ea1SDimitry Andric checkTaintedness(C, Call, C.getSVal(*SizeEx), State, AF_CXXNewArray); 1602*0fca6ea1SDimitry Andric } 1603*0fca6ea1SDimitry Andric 16045ffd83dbSDimitry Andric State = MallocUpdateRefState(C, NE, State, Family, Target); 16055ffd83dbSDimitry Andric State = ProcessZeroAllocCheck(Call, 0, State, Target); 16065ffd83dbSDimitry Andric return State; 16075ffd83dbSDimitry Andric } 16085ffd83dbSDimitry Andric 16095ffd83dbSDimitry Andric void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call, 16105ffd83dbSDimitry Andric CheckerContext &C) const { 16115ffd83dbSDimitry Andric if (!C.wasInlined) { 16125ffd83dbSDimitry Andric ProgramStateRef State = processNewAllocation( 16135ffd83dbSDimitry Andric Call, C, 16145ffd83dbSDimitry Andric (Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew)); 16150b57cec5SDimitry Andric C.addTransition(State); 16160b57cec5SDimitry Andric } 16170b57cec5SDimitry Andric } 16180b57cec5SDimitry Andric 16190b57cec5SDimitry Andric static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) { 16200b57cec5SDimitry Andric // If the first selector piece is one of the names below, assume that the 16210b57cec5SDimitry Andric // object takes ownership of the memory, promising to eventually deallocate it 16220b57cec5SDimitry Andric // with free(). 16230b57cec5SDimitry Andric // Ex: [NSData dataWithBytesNoCopy:bytes length:10]; 16240b57cec5SDimitry Andric // (...unless a 'freeWhenDone' parameter is false, but that's checked later.) 16250b57cec5SDimitry Andric StringRef FirstSlot = Call.getSelector().getNameForSlot(0); 16260b57cec5SDimitry Andric return FirstSlot == "dataWithBytesNoCopy" || 16270b57cec5SDimitry Andric FirstSlot == "initWithBytesNoCopy" || 16280b57cec5SDimitry Andric FirstSlot == "initWithCharactersNoCopy"; 16290b57cec5SDimitry Andric } 16300b57cec5SDimitry Andric 1631bdd1243dSDimitry Andric static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) { 16320b57cec5SDimitry Andric Selector S = Call.getSelector(); 16330b57cec5SDimitry Andric 16340b57cec5SDimitry Andric // FIXME: We should not rely on fully-constrained symbols being folded. 16350b57cec5SDimitry Andric for (unsigned i = 1; i < S.getNumArgs(); ++i) 1636*0fca6ea1SDimitry Andric if (S.getNameForSlot(i) == "freeWhenDone") 16370b57cec5SDimitry Andric return !Call.getArgSVal(i).isZeroConstant(); 16380b57cec5SDimitry Andric 1639bdd1243dSDimitry Andric return std::nullopt; 16400b57cec5SDimitry Andric } 16410b57cec5SDimitry Andric 16420b57cec5SDimitry Andric void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, 16430b57cec5SDimitry Andric CheckerContext &C) const { 16440b57cec5SDimitry Andric if (C.wasInlined) 16450b57cec5SDimitry Andric return; 16460b57cec5SDimitry Andric 16470b57cec5SDimitry Andric if (!isKnownDeallocObjCMethodName(Call)) 16480b57cec5SDimitry Andric return; 16490b57cec5SDimitry Andric 1650bdd1243dSDimitry Andric if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call)) 16510b57cec5SDimitry Andric if (!*FreeWhenDone) 16520b57cec5SDimitry Andric return; 16530b57cec5SDimitry Andric 1654480093f4SDimitry Andric if (Call.hasNonZeroCallbackArg()) 1655480093f4SDimitry Andric return; 1656480093f4SDimitry Andric 1657a7dea167SDimitry Andric bool IsKnownToBeAllocatedMemory; 1658a7dea167SDimitry Andric ProgramStateRef State = 16595ffd83dbSDimitry Andric FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(), 16605ffd83dbSDimitry Andric /*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc, 166104eeddc0SDimitry Andric /*ReturnsNullOnFailure=*/true); 16620b57cec5SDimitry Andric 16630b57cec5SDimitry Andric C.addTransition(State); 16640b57cec5SDimitry Andric } 16650b57cec5SDimitry Andric 16660b57cec5SDimitry Andric ProgramStateRef 16675ffd83dbSDimitry Andric MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call, 16680b57cec5SDimitry Andric const OwnershipAttr *Att, 16690b57cec5SDimitry Andric ProgramStateRef State) const { 16700b57cec5SDimitry Andric if (!State) 16710b57cec5SDimitry Andric return nullptr; 16720b57cec5SDimitry Andric 16735ffd83dbSDimitry Andric if (Att->getModule()->getName() != "malloc") 16740b57cec5SDimitry Andric return nullptr; 16750b57cec5SDimitry Andric 167606c3fb27SDimitry Andric if (!Att->args().empty()) { 167706c3fb27SDimitry Andric return MallocMemAux(C, Call, 167806c3fb27SDimitry Andric Call.getArgExpr(Att->args_begin()->getASTIndex()), 16795ffd83dbSDimitry Andric UndefinedVal(), State, AF_Malloc); 16800b57cec5SDimitry Andric } 16815ffd83dbSDimitry Andric return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, AF_Malloc); 16820b57cec5SDimitry Andric } 16830b57cec5SDimitry Andric 16840b57cec5SDimitry Andric ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, 16855ffd83dbSDimitry Andric const CallEvent &Call, 16860b57cec5SDimitry Andric const Expr *SizeEx, SVal Init, 16870b57cec5SDimitry Andric ProgramStateRef State, 1688*0fca6ea1SDimitry Andric AllocationFamily Family) const { 16890b57cec5SDimitry Andric if (!State) 16900b57cec5SDimitry Andric return nullptr; 16910b57cec5SDimitry Andric 16925ffd83dbSDimitry Andric assert(SizeEx); 16935ffd83dbSDimitry Andric return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family); 16940b57cec5SDimitry Andric } 16950b57cec5SDimitry Andric 1696*0fca6ea1SDimitry Andric void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State, 1697*0fca6ea1SDimitry Andric CheckerContext &C, 1698*0fca6ea1SDimitry Andric llvm::ArrayRef<SymbolRef> TaintedSyms, 1699*0fca6ea1SDimitry Andric AllocationFamily Family) const { 1700*0fca6ea1SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) { 1701*0fca6ea1SDimitry Andric if (!BT_TaintedAlloc) 1702*0fca6ea1SDimitry Andric BT_TaintedAlloc.reset(new BugType(CheckNames[CK_TaintedAllocChecker], 1703*0fca6ea1SDimitry Andric "Tainted Memory Allocation", 1704*0fca6ea1SDimitry Andric categories::TaintedData)); 1705*0fca6ea1SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*BT_TaintedAlloc, Msg, N); 1706*0fca6ea1SDimitry Andric for (auto TaintedSym : TaintedSyms) { 1707*0fca6ea1SDimitry Andric R->markInteresting(TaintedSym); 1708*0fca6ea1SDimitry Andric } 1709*0fca6ea1SDimitry Andric C.emitReport(std::move(R)); 1710*0fca6ea1SDimitry Andric } 1711*0fca6ea1SDimitry Andric } 1712*0fca6ea1SDimitry Andric 1713*0fca6ea1SDimitry Andric void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call, 1714*0fca6ea1SDimitry Andric const SVal SizeSVal, ProgramStateRef State, 1715*0fca6ea1SDimitry Andric AllocationFamily Family) const { 1716*0fca6ea1SDimitry Andric if (!ChecksEnabled[CK_TaintedAllocChecker]) 1717*0fca6ea1SDimitry Andric return; 1718*0fca6ea1SDimitry Andric std::vector<SymbolRef> TaintedSyms = 1719*0fca6ea1SDimitry Andric taint::getTaintedSymbols(State, SizeSVal); 1720*0fca6ea1SDimitry Andric if (TaintedSyms.empty()) 1721*0fca6ea1SDimitry Andric return; 1722*0fca6ea1SDimitry Andric 1723*0fca6ea1SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 1724*0fca6ea1SDimitry Andric QualType SizeTy = SVB.getContext().getSizeType(); 1725*0fca6ea1SDimitry Andric QualType CmpTy = SVB.getConditionType(); 1726*0fca6ea1SDimitry Andric // In case the symbol is tainted, we give a warning if the 1727*0fca6ea1SDimitry Andric // size is larger than SIZE_MAX/4 1728*0fca6ea1SDimitry Andric BasicValueFactory &BVF = SVB.getBasicValueFactory(); 1729*0fca6ea1SDimitry Andric const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy); 1730*0fca6ea1SDimitry Andric NonLoc MaxLength = 1731*0fca6ea1SDimitry Andric SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4)); 1732*0fca6ea1SDimitry Andric std::optional<NonLoc> SizeNL = SizeSVal.getAs<NonLoc>(); 1733*0fca6ea1SDimitry Andric auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy) 1734*0fca6ea1SDimitry Andric .getAs<DefinedOrUnknownSVal>(); 1735*0fca6ea1SDimitry Andric if (!Cmp) 1736*0fca6ea1SDimitry Andric return; 1737*0fca6ea1SDimitry Andric auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp); 1738*0fca6ea1SDimitry Andric if (!StateTooLarge && StateNotTooLarge) { 1739*0fca6ea1SDimitry Andric // We can prove that size is not too large so there is no issue. 1740*0fca6ea1SDimitry Andric return; 1741*0fca6ea1SDimitry Andric } 1742*0fca6ea1SDimitry Andric 1743*0fca6ea1SDimitry Andric std::string Callee = "Memory allocation function"; 1744*0fca6ea1SDimitry Andric if (Call.getCalleeIdentifier()) 1745*0fca6ea1SDimitry Andric Callee = Call.getCalleeIdentifier()->getName().str(); 1746*0fca6ea1SDimitry Andric reportTaintBug( 1747*0fca6ea1SDimitry Andric Callee + " is called with a tainted (potentially attacker controlled) " 1748*0fca6ea1SDimitry Andric "value. Make sure the value is bound checked.", 1749*0fca6ea1SDimitry Andric State, C, TaintedSyms, Family); 1750*0fca6ea1SDimitry Andric } 1751*0fca6ea1SDimitry Andric 17520b57cec5SDimitry Andric ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, 17535ffd83dbSDimitry Andric const CallEvent &Call, SVal Size, 17545ffd83dbSDimitry Andric SVal Init, ProgramStateRef State, 1755*0fca6ea1SDimitry Andric AllocationFamily Family) const { 17560b57cec5SDimitry Andric if (!State) 17570b57cec5SDimitry Andric return nullptr; 17580b57cec5SDimitry Andric 17595ffd83dbSDimitry Andric const Expr *CE = Call.getOriginExpr(); 17605ffd83dbSDimitry Andric 17610b57cec5SDimitry Andric // We expect the malloc functions to return a pointer. 17620b57cec5SDimitry Andric if (!Loc::isLocType(CE->getType())) 17630b57cec5SDimitry Andric return nullptr; 17640b57cec5SDimitry Andric 17650b57cec5SDimitry Andric // Bind the return value to the symbolic value from the heap region. 17665f757f3fSDimitry Andric // TODO: move use of this functions to an EvalCall callback, becasue 17675f757f3fSDimitry Andric // BindExpr() should'nt be used elsewhere. 17680b57cec5SDimitry Andric unsigned Count = C.blockCount(); 17695f757f3fSDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 17700b57cec5SDimitry Andric const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 17715f757f3fSDimitry Andric DefinedSVal RetVal = 17725f757f3fSDimitry Andric ((Family == AF_Alloca) ? SVB.getAllocaRegionVal(CE, LCtx, Count) 17735f757f3fSDimitry Andric : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count) 17745f757f3fSDimitry Andric .castAs<DefinedSVal>()); 17750b57cec5SDimitry Andric State = State->BindExpr(CE, C.getLocationContext(), RetVal); 17760b57cec5SDimitry Andric 17770b57cec5SDimitry Andric // Fill the region with the initialization value. 17780b57cec5SDimitry Andric State = State->bindDefaultInitial(RetVal, Init, LCtx); 17790b57cec5SDimitry Andric 1780bdd1243dSDimitry Andric // If Size is somehow undefined at this point, this line prevents a crash. 1781bdd1243dSDimitry Andric if (Size.isUndef()) 1782bdd1243dSDimitry Andric Size = UnknownVal(); 1783bdd1243dSDimitry Andric 1784*0fca6ea1SDimitry Andric checkTaintedness(C, Call, Size, State, AF_Malloc); 1785*0fca6ea1SDimitry Andric 1786fe6060f1SDimitry Andric // Set the region's extent. 1787fe6060f1SDimitry Andric State = setDynamicExtent(State, RetVal.getAsRegion(), 17885f757f3fSDimitry Andric Size.castAs<DefinedOrUnknownSVal>(), SVB); 17890b57cec5SDimitry Andric 17900b57cec5SDimitry Andric return MallocUpdateRefState(C, CE, State, Family); 17910b57cec5SDimitry Andric } 17920b57cec5SDimitry Andric 1793a7dea167SDimitry Andric static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, 17940b57cec5SDimitry Andric ProgramStateRef State, 17950b57cec5SDimitry Andric AllocationFamily Family, 1796bdd1243dSDimitry Andric std::optional<SVal> RetVal) { 17970b57cec5SDimitry Andric if (!State) 17980b57cec5SDimitry Andric return nullptr; 17990b57cec5SDimitry Andric 18000b57cec5SDimitry Andric // Get the return value. 18010b57cec5SDimitry Andric if (!RetVal) 18020b57cec5SDimitry Andric RetVal = C.getSVal(E); 18030b57cec5SDimitry Andric 18040b57cec5SDimitry Andric // We expect the malloc functions to return a pointer. 18050b57cec5SDimitry Andric if (!RetVal->getAs<Loc>()) 18060b57cec5SDimitry Andric return nullptr; 18070b57cec5SDimitry Andric 18080b57cec5SDimitry Andric SymbolRef Sym = RetVal->getAsLocSymbol(); 1809*0fca6ea1SDimitry Andric 18100b57cec5SDimitry Andric // This is a return value of a function that was not inlined, such as malloc() 18110b57cec5SDimitry Andric // or new(). We've checked that in the caller. Therefore, it must be a symbol. 18120b57cec5SDimitry Andric assert(Sym); 1813*0fca6ea1SDimitry Andric // FIXME: In theory this assertion should fail for `alloca()` calls (because 1814*0fca6ea1SDimitry Andric // `AllocaRegion`s are not symbolic); but in practice this does not happen. 1815*0fca6ea1SDimitry Andric // As the current code appears to work correctly, I'm not touching this issue 1816*0fca6ea1SDimitry Andric // now, but it would be good to investigate and clarify this. 1817*0fca6ea1SDimitry Andric // Also note that perhaps the special `AllocaRegion` should be replaced by 1818*0fca6ea1SDimitry Andric // `SymbolicRegion` (or turned into a subclass of `SymbolicRegion`) to enable 1819*0fca6ea1SDimitry Andric // proper tracking of memory allocated by `alloca()` -- and after that change 1820*0fca6ea1SDimitry Andric // this assertion would become valid again. 18210b57cec5SDimitry Andric 18220b57cec5SDimitry Andric // Set the symbol's state to Allocated. 18230b57cec5SDimitry Andric return State->set<RegionState>(Sym, RefState::getAllocated(Family, E)); 18240b57cec5SDimitry Andric } 18250b57cec5SDimitry Andric 18260b57cec5SDimitry Andric ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, 18275ffd83dbSDimitry Andric const CallEvent &Call, 18280b57cec5SDimitry Andric const OwnershipAttr *Att, 18290b57cec5SDimitry Andric ProgramStateRef State) const { 18300b57cec5SDimitry Andric if (!State) 18310b57cec5SDimitry Andric return nullptr; 18320b57cec5SDimitry Andric 18335ffd83dbSDimitry Andric if (Att->getModule()->getName() != "malloc") 18340b57cec5SDimitry Andric return nullptr; 18350b57cec5SDimitry Andric 1836a7dea167SDimitry Andric bool IsKnownToBeAllocated = false; 18370b57cec5SDimitry Andric 18380b57cec5SDimitry Andric for (const auto &Arg : Att->args()) { 18395ffd83dbSDimitry Andric ProgramStateRef StateI = 18405ffd83dbSDimitry Andric FreeMemAux(C, Call, State, Arg.getASTIndex(), 18415ffd83dbSDimitry Andric Att->getOwnKind() == OwnershipAttr::Holds, 18425ffd83dbSDimitry Andric IsKnownToBeAllocated, AF_Malloc); 18430b57cec5SDimitry Andric if (StateI) 18440b57cec5SDimitry Andric State = StateI; 18450b57cec5SDimitry Andric } 18460b57cec5SDimitry Andric return State; 18470b57cec5SDimitry Andric } 18480b57cec5SDimitry Andric 18495ffd83dbSDimitry Andric ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, 18505ffd83dbSDimitry Andric const CallEvent &Call, 1851a7dea167SDimitry Andric ProgramStateRef State, unsigned Num, 1852a7dea167SDimitry Andric bool Hold, bool &IsKnownToBeAllocated, 18535ffd83dbSDimitry Andric AllocationFamily Family, 18540b57cec5SDimitry Andric bool ReturnsNullOnFailure) const { 18550b57cec5SDimitry Andric if (!State) 18560b57cec5SDimitry Andric return nullptr; 18570b57cec5SDimitry Andric 18585ffd83dbSDimitry Andric if (Call.getNumArgs() < (Num + 1)) 18590b57cec5SDimitry Andric return nullptr; 18600b57cec5SDimitry Andric 18615ffd83dbSDimitry Andric return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold, 18625ffd83dbSDimitry Andric IsKnownToBeAllocated, Family, ReturnsNullOnFailure); 18630b57cec5SDimitry Andric } 18640b57cec5SDimitry Andric 18650b57cec5SDimitry Andric /// Checks if the previous call to free on the given symbol failed - if free 18660b57cec5SDimitry Andric /// failed, returns true. Also, returns the corresponding return value symbol. 18670b57cec5SDimitry Andric static bool didPreviousFreeFail(ProgramStateRef State, 18680b57cec5SDimitry Andric SymbolRef Sym, SymbolRef &RetStatusSymbol) { 18690b57cec5SDimitry Andric const SymbolRef *Ret = State->get<FreeReturnValue>(Sym); 18700b57cec5SDimitry Andric if (Ret) { 18710b57cec5SDimitry Andric assert(*Ret && "We should not store the null return symbol"); 18720b57cec5SDimitry Andric ConstraintManager &CMgr = State->getConstraintManager(); 18730b57cec5SDimitry Andric ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret); 18740b57cec5SDimitry Andric RetStatusSymbol = *Ret; 18750b57cec5SDimitry Andric return FreeFailed.isConstrainedTrue(); 18760b57cec5SDimitry Andric } 18770b57cec5SDimitry Andric return false; 18780b57cec5SDimitry Andric } 18790b57cec5SDimitry Andric 18805ffd83dbSDimitry Andric static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) { 18810b57cec5SDimitry Andric if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { 18820b57cec5SDimitry Andric // FIXME: This doesn't handle indirect calls. 18830b57cec5SDimitry Andric const FunctionDecl *FD = CE->getDirectCallee(); 18840b57cec5SDimitry Andric if (!FD) 18850b57cec5SDimitry Andric return false; 18860b57cec5SDimitry Andric 18870b57cec5SDimitry Andric os << *FD; 18880b57cec5SDimitry Andric if (!FD->isOverloadedOperator()) 18890b57cec5SDimitry Andric os << "()"; 18900b57cec5SDimitry Andric return true; 18910b57cec5SDimitry Andric } 18920b57cec5SDimitry Andric 18930b57cec5SDimitry Andric if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) { 18940b57cec5SDimitry Andric if (Msg->isInstanceMessage()) 18950b57cec5SDimitry Andric os << "-"; 18960b57cec5SDimitry Andric else 18970b57cec5SDimitry Andric os << "+"; 18980b57cec5SDimitry Andric Msg->getSelector().print(os); 18990b57cec5SDimitry Andric return true; 19000b57cec5SDimitry Andric } 19010b57cec5SDimitry Andric 19020b57cec5SDimitry Andric if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) { 19030b57cec5SDimitry Andric os << "'" 19040b57cec5SDimitry Andric << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator()) 19050b57cec5SDimitry Andric << "'"; 19060b57cec5SDimitry Andric return true; 19070b57cec5SDimitry Andric } 19080b57cec5SDimitry Andric 19090b57cec5SDimitry Andric if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) { 19100b57cec5SDimitry Andric os << "'" 19110b57cec5SDimitry Andric << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator()) 19120b57cec5SDimitry Andric << "'"; 19130b57cec5SDimitry Andric return true; 19140b57cec5SDimitry Andric } 19150b57cec5SDimitry Andric 19160b57cec5SDimitry Andric return false; 19170b57cec5SDimitry Andric } 19180b57cec5SDimitry Andric 19195ffd83dbSDimitry Andric static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) { 19200b57cec5SDimitry Andric 19210b57cec5SDimitry Andric switch(Family) { 19220b57cec5SDimitry Andric case AF_Malloc: os << "malloc()"; return; 19230b57cec5SDimitry Andric case AF_CXXNew: os << "'new'"; return; 19240b57cec5SDimitry Andric case AF_CXXNewArray: os << "'new[]'"; return; 19250b57cec5SDimitry Andric case AF_IfNameIndex: os << "'if_nameindex()'"; return; 19260b57cec5SDimitry Andric case AF_InnerBuffer: os << "container-specific allocator"; return; 19270b57cec5SDimitry Andric case AF_Alloca: 19280b57cec5SDimitry Andric case AF_None: llvm_unreachable("not a deallocation expression"); 19290b57cec5SDimitry Andric } 19300b57cec5SDimitry Andric } 19310b57cec5SDimitry Andric 1932a7dea167SDimitry Andric static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) { 19330b57cec5SDimitry Andric switch(Family) { 19340b57cec5SDimitry Andric case AF_Malloc: os << "free()"; return; 19350b57cec5SDimitry Andric case AF_CXXNew: os << "'delete'"; return; 19360b57cec5SDimitry Andric case AF_CXXNewArray: os << "'delete[]'"; return; 19370b57cec5SDimitry Andric case AF_IfNameIndex: os << "'if_freenameindex()'"; return; 19380b57cec5SDimitry Andric case AF_InnerBuffer: os << "container-specific deallocator"; return; 19390b57cec5SDimitry Andric case AF_Alloca: 19400b57cec5SDimitry Andric case AF_None: llvm_unreachable("suspicious argument"); 19410b57cec5SDimitry Andric } 19420b57cec5SDimitry Andric } 19430b57cec5SDimitry Andric 1944*0fca6ea1SDimitry Andric ProgramStateRef 1945*0fca6ea1SDimitry Andric MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, 1946*0fca6ea1SDimitry Andric const CallEvent &Call, ProgramStateRef State, 1947*0fca6ea1SDimitry Andric bool Hold, bool &IsKnownToBeAllocated, 1948*0fca6ea1SDimitry Andric AllocationFamily Family, bool ReturnsNullOnFailure, 1949*0fca6ea1SDimitry Andric std::optional<SVal> ArgValOpt) const { 19500b57cec5SDimitry Andric 19510b57cec5SDimitry Andric if (!State) 19520b57cec5SDimitry Andric return nullptr; 19530b57cec5SDimitry Andric 1954*0fca6ea1SDimitry Andric SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr)); 195581ad6265SDimitry Andric if (!isa<DefinedOrUnknownSVal>(ArgVal)) 19560b57cec5SDimitry Andric return nullptr; 19570b57cec5SDimitry Andric DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>(); 19580b57cec5SDimitry Andric 19590b57cec5SDimitry Andric // Check for null dereferences. 196081ad6265SDimitry Andric if (!isa<Loc>(location)) 19610b57cec5SDimitry Andric return nullptr; 19620b57cec5SDimitry Andric 19630b57cec5SDimitry Andric // The explicit NULL case, no operation is performed. 19640b57cec5SDimitry Andric ProgramStateRef notNullState, nullState; 19650b57cec5SDimitry Andric std::tie(notNullState, nullState) = State->assume(location); 19660b57cec5SDimitry Andric if (nullState && !notNullState) 19670b57cec5SDimitry Andric return nullptr; 19680b57cec5SDimitry Andric 19690b57cec5SDimitry Andric // Unknown values could easily be okay 19700b57cec5SDimitry Andric // Undefined values are handled elsewhere 19710b57cec5SDimitry Andric if (ArgVal.isUnknownOrUndef()) 19720b57cec5SDimitry Andric return nullptr; 19730b57cec5SDimitry Andric 19740b57cec5SDimitry Andric const MemRegion *R = ArgVal.getAsRegion(); 19755ffd83dbSDimitry Andric const Expr *ParentExpr = Call.getOriginExpr(); 19765ffd83dbSDimitry Andric 19775ffd83dbSDimitry Andric // NOTE: We detected a bug, but the checker under whose name we would emit the 19785ffd83dbSDimitry Andric // error could be disabled. Generally speaking, the MallocChecker family is an 19795ffd83dbSDimitry Andric // integral part of the Static Analyzer, and disabling any part of it should 19805ffd83dbSDimitry Andric // only be done under exceptional circumstances, such as frequent false 19815ffd83dbSDimitry Andric // positives. If this is the case, we can reasonably believe that there are 19825ffd83dbSDimitry Andric // serious faults in our understanding of the source code, and even if we 19835ffd83dbSDimitry Andric // don't emit an warning, we should terminate further analysis with a sink 19845ffd83dbSDimitry Andric // node. 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric // Nonlocs can't be freed, of course. 19870b57cec5SDimitry Andric // Non-region locations (labels and fixed addresses) also shouldn't be freed. 19880b57cec5SDimitry Andric if (!R) { 19895ffd83dbSDimitry Andric // Exception: 19905ffd83dbSDimitry Andric // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source 19915ffd83dbSDimitry Andric // code. In that case, the ZERO_SIZE_PTR defines a special value used for a 19925ffd83dbSDimitry Andric // zero-sized memory block which is allowed to be freed, despite not being a 19935ffd83dbSDimitry Andric // null pointer. 19945ffd83dbSDimitry Andric if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal)) 19955ffd83dbSDimitry Andric HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 19965ffd83dbSDimitry Andric Family); 19970b57cec5SDimitry Andric return nullptr; 19980b57cec5SDimitry Andric } 19990b57cec5SDimitry Andric 20000b57cec5SDimitry Andric R = R->StripCasts(); 20010b57cec5SDimitry Andric 20020b57cec5SDimitry Andric // Blocks might show up as heap data, but should not be free()d 20030b57cec5SDimitry Andric if (isa<BlockDataRegion>(R)) { 20045ffd83dbSDimitry Andric HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 20055ffd83dbSDimitry Andric Family); 20060b57cec5SDimitry Andric return nullptr; 20070b57cec5SDimitry Andric } 20080b57cec5SDimitry Andric 20090b57cec5SDimitry Andric const MemSpaceRegion *MS = R->getMemorySpace(); 20100b57cec5SDimitry Andric 20110b57cec5SDimitry Andric // Parameters, locals, statics, globals, and memory returned by 20120b57cec5SDimitry Andric // __builtin_alloca() shouldn't be freed. 2013349cc55cSDimitry Andric if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) { 20145f757f3fSDimitry Andric // Regions returned by malloc() are represented by SymbolicRegion objects 20155f757f3fSDimitry Andric // within HeapSpaceRegion. Of course, free() can work on memory allocated 20165f757f3fSDimitry Andric // outside the current function, so UnknownSpaceRegion is also a 20175f757f3fSDimitry Andric // possibility here. 20180b57cec5SDimitry Andric 20190b57cec5SDimitry Andric if (isa<AllocaRegion>(R)) 20205ffd83dbSDimitry Andric HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); 20210b57cec5SDimitry Andric else 20225ffd83dbSDimitry Andric HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 20235ffd83dbSDimitry Andric Family); 20240b57cec5SDimitry Andric 20250b57cec5SDimitry Andric return nullptr; 20260b57cec5SDimitry Andric } 20270b57cec5SDimitry Andric 20280b57cec5SDimitry Andric const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion()); 20290b57cec5SDimitry Andric // Various cases could lead to non-symbol values here. 20300b57cec5SDimitry Andric // For now, ignore them. 20310b57cec5SDimitry Andric if (!SrBase) 20320b57cec5SDimitry Andric return nullptr; 20330b57cec5SDimitry Andric 20340b57cec5SDimitry Andric SymbolRef SymBase = SrBase->getSymbol(); 20350b57cec5SDimitry Andric const RefState *RsBase = State->get<RegionState>(SymBase); 20360b57cec5SDimitry Andric SymbolRef PreviousRetStatusSymbol = nullptr; 20370b57cec5SDimitry Andric 2038a7dea167SDimitry Andric IsKnownToBeAllocated = 2039a7dea167SDimitry Andric RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero()); 2040a7dea167SDimitry Andric 20410b57cec5SDimitry Andric if (RsBase) { 20420b57cec5SDimitry Andric 20430b57cec5SDimitry Andric // Memory returned by alloca() shouldn't be freed. 20440b57cec5SDimitry Andric if (RsBase->getAllocationFamily() == AF_Alloca) { 20455ffd83dbSDimitry Andric HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); 20460b57cec5SDimitry Andric return nullptr; 20470b57cec5SDimitry Andric } 20480b57cec5SDimitry Andric 20490b57cec5SDimitry Andric // Check for double free first. 20500b57cec5SDimitry Andric if ((RsBase->isReleased() || RsBase->isRelinquished()) && 20510b57cec5SDimitry Andric !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { 20525ffd83dbSDimitry Andric HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), 20530b57cec5SDimitry Andric SymBase, PreviousRetStatusSymbol); 20540b57cec5SDimitry Andric return nullptr; 20550b57cec5SDimitry Andric 20560b57cec5SDimitry Andric // If the pointer is allocated or escaped, but we are now trying to free it, 20570b57cec5SDimitry Andric // check that the call to free is proper. 20580b57cec5SDimitry Andric } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() || 20590b57cec5SDimitry Andric RsBase->isEscaped()) { 20600b57cec5SDimitry Andric 20610b57cec5SDimitry Andric // Check if an expected deallocation function matches the real one. 20625ffd83dbSDimitry Andric bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family; 20630b57cec5SDimitry Andric if (!DeallocMatchesAlloc) { 20645ffd83dbSDimitry Andric HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, 20655ffd83dbSDimitry Andric RsBase, SymBase, Hold); 20660b57cec5SDimitry Andric return nullptr; 20670b57cec5SDimitry Andric } 20680b57cec5SDimitry Andric 20690b57cec5SDimitry Andric // Check if the memory location being freed is the actual location 20700b57cec5SDimitry Andric // allocated, or an offset. 20710b57cec5SDimitry Andric RegionOffset Offset = R->getAsOffset(); 20720b57cec5SDimitry Andric if (Offset.isValid() && 20730b57cec5SDimitry Andric !Offset.hasSymbolicOffset() && 20740b57cec5SDimitry Andric Offset.getOffset() != 0) { 20750b57cec5SDimitry Andric const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); 20765ffd83dbSDimitry Andric HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 20775ffd83dbSDimitry Andric Family, AllocExpr); 20780b57cec5SDimitry Andric return nullptr; 20790b57cec5SDimitry Andric } 20800b57cec5SDimitry Andric } 20810b57cec5SDimitry Andric } 20820b57cec5SDimitry Andric 20830b57cec5SDimitry Andric if (SymBase->getType()->isFunctionPointerType()) { 20845ffd83dbSDimitry Andric HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, 20855ffd83dbSDimitry Andric Family); 20860b57cec5SDimitry Andric return nullptr; 20870b57cec5SDimitry Andric } 20880b57cec5SDimitry Andric 20890b57cec5SDimitry Andric // Clean out the info on previous call to free return info. 20900b57cec5SDimitry Andric State = State->remove<FreeReturnValue>(SymBase); 20910b57cec5SDimitry Andric 20920b57cec5SDimitry Andric // Keep track of the return value. If it is NULL, we will know that free 20930b57cec5SDimitry Andric // failed. 20940b57cec5SDimitry Andric if (ReturnsNullOnFailure) { 20950b57cec5SDimitry Andric SVal RetVal = C.getSVal(ParentExpr); 20960b57cec5SDimitry Andric SymbolRef RetStatusSymbol = RetVal.getAsSymbol(); 20970b57cec5SDimitry Andric if (RetStatusSymbol) { 20980b57cec5SDimitry Andric C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol); 20990b57cec5SDimitry Andric State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol); 21000b57cec5SDimitry Andric } 21010b57cec5SDimitry Andric } 21020b57cec5SDimitry Andric 21035ffd83dbSDimitry Andric // If we don't know anything about this symbol, a free on it may be totally 21045ffd83dbSDimitry Andric // valid. If this is the case, lets assume that the allocation family of the 21055ffd83dbSDimitry Andric // freeing function is the same as the symbols allocation family, and go with 21065ffd83dbSDimitry Andric // that. 21075ffd83dbSDimitry Andric assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family)); 21085ffd83dbSDimitry Andric 21090b57cec5SDimitry Andric // Normal free. 21100b57cec5SDimitry Andric if (Hold) 21110b57cec5SDimitry Andric return State->set<RegionState>(SymBase, 21120b57cec5SDimitry Andric RefState::getRelinquished(Family, 21130b57cec5SDimitry Andric ParentExpr)); 21140b57cec5SDimitry Andric 21150b57cec5SDimitry Andric return State->set<RegionState>(SymBase, 21160b57cec5SDimitry Andric RefState::getReleased(Family, ParentExpr)); 21170b57cec5SDimitry Andric } 21180b57cec5SDimitry Andric 2119bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> 21200b57cec5SDimitry Andric MallocChecker::getCheckIfTracked(AllocationFamily Family, 21210b57cec5SDimitry Andric bool IsALeakCheck) const { 21220b57cec5SDimitry Andric switch (Family) { 21230b57cec5SDimitry Andric case AF_Malloc: 21240b57cec5SDimitry Andric case AF_Alloca: 21250b57cec5SDimitry Andric case AF_IfNameIndex: { 21260b57cec5SDimitry Andric if (ChecksEnabled[CK_MallocChecker]) 21270b57cec5SDimitry Andric return CK_MallocChecker; 2128bdd1243dSDimitry Andric return std::nullopt; 21290b57cec5SDimitry Andric } 21300b57cec5SDimitry Andric case AF_CXXNew: 21310b57cec5SDimitry Andric case AF_CXXNewArray: { 21320b57cec5SDimitry Andric if (IsALeakCheck) { 21330b57cec5SDimitry Andric if (ChecksEnabled[CK_NewDeleteLeaksChecker]) 21340b57cec5SDimitry Andric return CK_NewDeleteLeaksChecker; 21350b57cec5SDimitry Andric } 21360b57cec5SDimitry Andric else { 21370b57cec5SDimitry Andric if (ChecksEnabled[CK_NewDeleteChecker]) 21380b57cec5SDimitry Andric return CK_NewDeleteChecker; 21390b57cec5SDimitry Andric } 2140bdd1243dSDimitry Andric return std::nullopt; 21410b57cec5SDimitry Andric } 21420b57cec5SDimitry Andric case AF_InnerBuffer: { 21430b57cec5SDimitry Andric if (ChecksEnabled[CK_InnerPointerChecker]) 21440b57cec5SDimitry Andric return CK_InnerPointerChecker; 2145bdd1243dSDimitry Andric return std::nullopt; 21460b57cec5SDimitry Andric } 21470b57cec5SDimitry Andric case AF_None: { 21480b57cec5SDimitry Andric llvm_unreachable("no family"); 21490b57cec5SDimitry Andric } 21500b57cec5SDimitry Andric } 21510b57cec5SDimitry Andric llvm_unreachable("unhandled family"); 21520b57cec5SDimitry Andric } 21530b57cec5SDimitry Andric 2154bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> 21550b57cec5SDimitry Andric MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym, 21560b57cec5SDimitry Andric bool IsALeakCheck) const { 21570b57cec5SDimitry Andric if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) 21580b57cec5SDimitry Andric return CK_MallocChecker; 21590b57cec5SDimitry Andric 21600b57cec5SDimitry Andric const RefState *RS = C.getState()->get<RegionState>(Sym); 21610b57cec5SDimitry Andric assert(RS); 21620b57cec5SDimitry Andric return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck); 21630b57cec5SDimitry Andric } 21640b57cec5SDimitry Andric 21650b57cec5SDimitry Andric bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { 2166bdd1243dSDimitry Andric if (std::optional<nonloc::ConcreteInt> IntVal = 2167bdd1243dSDimitry Andric V.getAs<nonloc::ConcreteInt>()) 21680b57cec5SDimitry Andric os << "an integer (" << IntVal->getValue() << ")"; 2169bdd1243dSDimitry Andric else if (std::optional<loc::ConcreteInt> ConstAddr = 2170bdd1243dSDimitry Andric V.getAs<loc::ConcreteInt>()) 21710b57cec5SDimitry Andric os << "a constant address (" << ConstAddr->getValue() << ")"; 2172bdd1243dSDimitry Andric else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>()) 21730b57cec5SDimitry Andric os << "the address of the label '" << Label->getLabel()->getName() << "'"; 21740b57cec5SDimitry Andric else 21750b57cec5SDimitry Andric return false; 21760b57cec5SDimitry Andric 21770b57cec5SDimitry Andric return true; 21780b57cec5SDimitry Andric } 21790b57cec5SDimitry Andric 21800b57cec5SDimitry Andric bool MallocChecker::SummarizeRegion(raw_ostream &os, 21810b57cec5SDimitry Andric const MemRegion *MR) { 21820b57cec5SDimitry Andric switch (MR->getKind()) { 21830b57cec5SDimitry Andric case MemRegion::FunctionCodeRegionKind: { 21840b57cec5SDimitry Andric const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl(); 21850b57cec5SDimitry Andric if (FD) 21860b57cec5SDimitry Andric os << "the address of the function '" << *FD << '\''; 21870b57cec5SDimitry Andric else 21880b57cec5SDimitry Andric os << "the address of a function"; 21890b57cec5SDimitry Andric return true; 21900b57cec5SDimitry Andric } 21910b57cec5SDimitry Andric case MemRegion::BlockCodeRegionKind: 21920b57cec5SDimitry Andric os << "block text"; 21930b57cec5SDimitry Andric return true; 21940b57cec5SDimitry Andric case MemRegion::BlockDataRegionKind: 21950b57cec5SDimitry Andric // FIXME: where the block came from? 21960b57cec5SDimitry Andric os << "a block"; 21970b57cec5SDimitry Andric return true; 21980b57cec5SDimitry Andric default: { 21990b57cec5SDimitry Andric const MemSpaceRegion *MS = MR->getMemorySpace(); 22000b57cec5SDimitry Andric 22010b57cec5SDimitry Andric if (isa<StackLocalsSpaceRegion>(MS)) { 22020b57cec5SDimitry Andric const VarRegion *VR = dyn_cast<VarRegion>(MR); 22030b57cec5SDimitry Andric const VarDecl *VD; 22040b57cec5SDimitry Andric if (VR) 22050b57cec5SDimitry Andric VD = VR->getDecl(); 22060b57cec5SDimitry Andric else 22070b57cec5SDimitry Andric VD = nullptr; 22080b57cec5SDimitry Andric 22090b57cec5SDimitry Andric if (VD) 22100b57cec5SDimitry Andric os << "the address of the local variable '" << VD->getName() << "'"; 22110b57cec5SDimitry Andric else 22120b57cec5SDimitry Andric os << "the address of a local stack variable"; 22130b57cec5SDimitry Andric return true; 22140b57cec5SDimitry Andric } 22150b57cec5SDimitry Andric 22160b57cec5SDimitry Andric if (isa<StackArgumentsSpaceRegion>(MS)) { 22170b57cec5SDimitry Andric const VarRegion *VR = dyn_cast<VarRegion>(MR); 22180b57cec5SDimitry Andric const VarDecl *VD; 22190b57cec5SDimitry Andric if (VR) 22200b57cec5SDimitry Andric VD = VR->getDecl(); 22210b57cec5SDimitry Andric else 22220b57cec5SDimitry Andric VD = nullptr; 22230b57cec5SDimitry Andric 22240b57cec5SDimitry Andric if (VD) 22250b57cec5SDimitry Andric os << "the address of the parameter '" << VD->getName() << "'"; 22260b57cec5SDimitry Andric else 22270b57cec5SDimitry Andric os << "the address of a parameter"; 22280b57cec5SDimitry Andric return true; 22290b57cec5SDimitry Andric } 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric if (isa<GlobalsSpaceRegion>(MS)) { 22320b57cec5SDimitry Andric const VarRegion *VR = dyn_cast<VarRegion>(MR); 22330b57cec5SDimitry Andric const VarDecl *VD; 22340b57cec5SDimitry Andric if (VR) 22350b57cec5SDimitry Andric VD = VR->getDecl(); 22360b57cec5SDimitry Andric else 22370b57cec5SDimitry Andric VD = nullptr; 22380b57cec5SDimitry Andric 22390b57cec5SDimitry Andric if (VD) { 22400b57cec5SDimitry Andric if (VD->isStaticLocal()) 22410b57cec5SDimitry Andric os << "the address of the static variable '" << VD->getName() << "'"; 22420b57cec5SDimitry Andric else 22430b57cec5SDimitry Andric os << "the address of the global variable '" << VD->getName() << "'"; 22440b57cec5SDimitry Andric } else 22450b57cec5SDimitry Andric os << "the address of a global variable"; 22460b57cec5SDimitry Andric return true; 22470b57cec5SDimitry Andric } 22480b57cec5SDimitry Andric 22490b57cec5SDimitry Andric return false; 22500b57cec5SDimitry Andric } 22510b57cec5SDimitry Andric } 22520b57cec5SDimitry Andric } 22530b57cec5SDimitry Andric 22545ffd83dbSDimitry Andric void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, 22550b57cec5SDimitry Andric SourceRange Range, 22565ffd83dbSDimitry Andric const Expr *DeallocExpr, 22575ffd83dbSDimitry Andric AllocationFamily Family) const { 22580b57cec5SDimitry Andric 22595ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { 22605ffd83dbSDimitry Andric C.addSink(); 22610b57cec5SDimitry Andric return; 22625ffd83dbSDimitry Andric } 22630b57cec5SDimitry Andric 2264bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family); 226581ad6265SDimitry Andric if (!CheckKind) 22660b57cec5SDimitry Andric return; 22670b57cec5SDimitry Andric 22680b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 22690b57cec5SDimitry Andric if (!BT_BadFree[*CheckKind]) 22700b57cec5SDimitry Andric BT_BadFree[*CheckKind].reset(new BugType( 22710b57cec5SDimitry Andric CheckNames[*CheckKind], "Bad free", categories::MemoryError)); 22720b57cec5SDimitry Andric 22730b57cec5SDimitry Andric SmallString<100> buf; 22740b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 22750b57cec5SDimitry Andric 22760b57cec5SDimitry Andric const MemRegion *MR = ArgVal.getAsRegion(); 22770b57cec5SDimitry Andric while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR)) 22780b57cec5SDimitry Andric MR = ER->getSuperRegion(); 22790b57cec5SDimitry Andric 22800b57cec5SDimitry Andric os << "Argument to "; 22815ffd83dbSDimitry Andric if (!printMemFnName(os, C, DeallocExpr)) 22820b57cec5SDimitry Andric os << "deallocator"; 22830b57cec5SDimitry Andric 22840b57cec5SDimitry Andric os << " is "; 22850b57cec5SDimitry Andric bool Summarized = MR ? SummarizeRegion(os, MR) 22860b57cec5SDimitry Andric : SummarizeValue(os, ArgVal); 22870b57cec5SDimitry Andric if (Summarized) 22880b57cec5SDimitry Andric os << ", which is not memory allocated by "; 22890b57cec5SDimitry Andric else 22900b57cec5SDimitry Andric os << "not memory allocated by "; 22910b57cec5SDimitry Andric 22925ffd83dbSDimitry Andric printExpectedAllocName(os, Family); 22930b57cec5SDimitry Andric 2294a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind], 2295a7dea167SDimitry Andric os.str(), N); 22960b57cec5SDimitry Andric R->markInteresting(MR); 22970b57cec5SDimitry Andric R->addRange(Range); 22980b57cec5SDimitry Andric C.emitReport(std::move(R)); 22990b57cec5SDimitry Andric } 23000b57cec5SDimitry Andric } 23010b57cec5SDimitry Andric 23025ffd83dbSDimitry Andric void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal, 23030b57cec5SDimitry Andric SourceRange Range) const { 23040b57cec5SDimitry Andric 2305bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind; 23060b57cec5SDimitry Andric 23070b57cec5SDimitry Andric if (ChecksEnabled[CK_MallocChecker]) 23080b57cec5SDimitry Andric CheckKind = CK_MallocChecker; 23090b57cec5SDimitry Andric else if (ChecksEnabled[CK_MismatchedDeallocatorChecker]) 23100b57cec5SDimitry Andric CheckKind = CK_MismatchedDeallocatorChecker; 23115ffd83dbSDimitry Andric else { 23125ffd83dbSDimitry Andric C.addSink(); 23130b57cec5SDimitry Andric return; 23145ffd83dbSDimitry Andric } 23150b57cec5SDimitry Andric 23160b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 23170b57cec5SDimitry Andric if (!BT_FreeAlloca[*CheckKind]) 23180b57cec5SDimitry Andric BT_FreeAlloca[*CheckKind].reset(new BugType( 23190b57cec5SDimitry Andric CheckNames[*CheckKind], "Free alloca()", categories::MemoryError)); 23200b57cec5SDimitry Andric 2321a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 23220b57cec5SDimitry Andric *BT_FreeAlloca[*CheckKind], 23230b57cec5SDimitry Andric "Memory allocated by alloca() should not be deallocated", N); 23240b57cec5SDimitry Andric R->markInteresting(ArgVal.getAsRegion()); 23250b57cec5SDimitry Andric R->addRange(Range); 23260b57cec5SDimitry Andric C.emitReport(std::move(R)); 23270b57cec5SDimitry Andric } 23280b57cec5SDimitry Andric } 23290b57cec5SDimitry Andric 23305ffd83dbSDimitry Andric void MallocChecker::HandleMismatchedDealloc(CheckerContext &C, 23310b57cec5SDimitry Andric SourceRange Range, 23320b57cec5SDimitry Andric const Expr *DeallocExpr, 23335ffd83dbSDimitry Andric const RefState *RS, SymbolRef Sym, 23340b57cec5SDimitry Andric bool OwnershipTransferred) const { 23350b57cec5SDimitry Andric 23365ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) { 23375ffd83dbSDimitry Andric C.addSink(); 23380b57cec5SDimitry Andric return; 23395ffd83dbSDimitry Andric } 23400b57cec5SDimitry Andric 23410b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 23420b57cec5SDimitry Andric if (!BT_MismatchedDealloc) 23430b57cec5SDimitry Andric BT_MismatchedDealloc.reset( 23440b57cec5SDimitry Andric new BugType(CheckNames[CK_MismatchedDeallocatorChecker], 23450b57cec5SDimitry Andric "Bad deallocator", categories::MemoryError)); 23460b57cec5SDimitry Andric 23470b57cec5SDimitry Andric SmallString<100> buf; 23480b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 23490b57cec5SDimitry Andric 23500b57cec5SDimitry Andric const Expr *AllocExpr = cast<Expr>(RS->getStmt()); 23510b57cec5SDimitry Andric SmallString<20> AllocBuf; 23520b57cec5SDimitry Andric llvm::raw_svector_ostream AllocOs(AllocBuf); 23530b57cec5SDimitry Andric SmallString<20> DeallocBuf; 23540b57cec5SDimitry Andric llvm::raw_svector_ostream DeallocOs(DeallocBuf); 23550b57cec5SDimitry Andric 23560b57cec5SDimitry Andric if (OwnershipTransferred) { 23575ffd83dbSDimitry Andric if (printMemFnName(DeallocOs, C, DeallocExpr)) 23580b57cec5SDimitry Andric os << DeallocOs.str() << " cannot"; 23590b57cec5SDimitry Andric else 23600b57cec5SDimitry Andric os << "Cannot"; 23610b57cec5SDimitry Andric 23620b57cec5SDimitry Andric os << " take ownership of memory"; 23630b57cec5SDimitry Andric 23645ffd83dbSDimitry Andric if (printMemFnName(AllocOs, C, AllocExpr)) 23650b57cec5SDimitry Andric os << " allocated by " << AllocOs.str(); 23660b57cec5SDimitry Andric } else { 23670b57cec5SDimitry Andric os << "Memory"; 23685ffd83dbSDimitry Andric if (printMemFnName(AllocOs, C, AllocExpr)) 23690b57cec5SDimitry Andric os << " allocated by " << AllocOs.str(); 23700b57cec5SDimitry Andric 23710b57cec5SDimitry Andric os << " should be deallocated by "; 23720b57cec5SDimitry Andric printExpectedDeallocName(os, RS->getAllocationFamily()); 23730b57cec5SDimitry Andric 23745ffd83dbSDimitry Andric if (printMemFnName(DeallocOs, C, DeallocExpr)) 23750b57cec5SDimitry Andric os << ", not " << DeallocOs.str(); 23760b57cec5SDimitry Andric } 23770b57cec5SDimitry Andric 2378a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc, 2379a7dea167SDimitry Andric os.str(), N); 23800b57cec5SDimitry Andric R->markInteresting(Sym); 23810b57cec5SDimitry Andric R->addRange(Range); 2382fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym); 23830b57cec5SDimitry Andric C.emitReport(std::move(R)); 23840b57cec5SDimitry Andric } 23850b57cec5SDimitry Andric } 23860b57cec5SDimitry Andric 23875ffd83dbSDimitry Andric void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal, 23880b57cec5SDimitry Andric SourceRange Range, const Expr *DeallocExpr, 23895ffd83dbSDimitry Andric AllocationFamily Family, 23900b57cec5SDimitry Andric const Expr *AllocExpr) const { 23910b57cec5SDimitry Andric 23925ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { 23935ffd83dbSDimitry Andric C.addSink(); 23940b57cec5SDimitry Andric return; 23955ffd83dbSDimitry Andric } 23960b57cec5SDimitry Andric 2397bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family); 239881ad6265SDimitry Andric if (!CheckKind) 23990b57cec5SDimitry Andric return; 24000b57cec5SDimitry Andric 24010b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(); 24020b57cec5SDimitry Andric if (!N) 24030b57cec5SDimitry Andric return; 24040b57cec5SDimitry Andric 24050b57cec5SDimitry Andric if (!BT_OffsetFree[*CheckKind]) 24060b57cec5SDimitry Andric BT_OffsetFree[*CheckKind].reset(new BugType( 24070b57cec5SDimitry Andric CheckNames[*CheckKind], "Offset free", categories::MemoryError)); 24080b57cec5SDimitry Andric 24090b57cec5SDimitry Andric SmallString<100> buf; 24100b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 24110b57cec5SDimitry Andric SmallString<20> AllocNameBuf; 24120b57cec5SDimitry Andric llvm::raw_svector_ostream AllocNameOs(AllocNameBuf); 24130b57cec5SDimitry Andric 24140b57cec5SDimitry Andric const MemRegion *MR = ArgVal.getAsRegion(); 24150b57cec5SDimitry Andric assert(MR && "Only MemRegion based symbols can have offset free errors"); 24160b57cec5SDimitry Andric 24170b57cec5SDimitry Andric RegionOffset Offset = MR->getAsOffset(); 24180b57cec5SDimitry Andric assert((Offset.isValid() && 24190b57cec5SDimitry Andric !Offset.hasSymbolicOffset() && 24200b57cec5SDimitry Andric Offset.getOffset() != 0) && 24210b57cec5SDimitry Andric "Only symbols with a valid offset can have offset free errors"); 24220b57cec5SDimitry Andric 24230b57cec5SDimitry Andric int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth(); 24240b57cec5SDimitry Andric 24250b57cec5SDimitry Andric os << "Argument to "; 24265ffd83dbSDimitry Andric if (!printMemFnName(os, C, DeallocExpr)) 24270b57cec5SDimitry Andric os << "deallocator"; 24280b57cec5SDimitry Andric os << " is offset by " 24290b57cec5SDimitry Andric << offsetBytes 24300b57cec5SDimitry Andric << " " 24310b57cec5SDimitry Andric << ((abs(offsetBytes) > 1) ? "bytes" : "byte") 24320b57cec5SDimitry Andric << " from the start of "; 24335ffd83dbSDimitry Andric if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr)) 24340b57cec5SDimitry Andric os << "memory allocated by " << AllocNameOs.str(); 24350b57cec5SDimitry Andric else 24360b57cec5SDimitry Andric os << "allocated memory"; 24370b57cec5SDimitry Andric 2438a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind], 2439a7dea167SDimitry Andric os.str(), N); 24400b57cec5SDimitry Andric R->markInteresting(MR->getBaseRegion()); 24410b57cec5SDimitry Andric R->addRange(Range); 24420b57cec5SDimitry Andric C.emitReport(std::move(R)); 24430b57cec5SDimitry Andric } 24440b57cec5SDimitry Andric 24455ffd83dbSDimitry Andric void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range, 24460b57cec5SDimitry Andric SymbolRef Sym) const { 24470b57cec5SDimitry Andric 24485ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] && 24495ffd83dbSDimitry Andric !ChecksEnabled[CK_InnerPointerChecker]) { 24505ffd83dbSDimitry Andric C.addSink(); 24510b57cec5SDimitry Andric return; 24525ffd83dbSDimitry Andric } 24530b57cec5SDimitry Andric 2454bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); 245581ad6265SDimitry Andric if (!CheckKind) 24560b57cec5SDimitry Andric return; 24570b57cec5SDimitry Andric 24580b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 24590b57cec5SDimitry Andric if (!BT_UseFree[*CheckKind]) 24600b57cec5SDimitry Andric BT_UseFree[*CheckKind].reset(new BugType( 24610b57cec5SDimitry Andric CheckNames[*CheckKind], "Use-after-free", categories::MemoryError)); 24620b57cec5SDimitry Andric 24630b57cec5SDimitry Andric AllocationFamily AF = 24640b57cec5SDimitry Andric C.getState()->get<RegionState>(Sym)->getAllocationFamily(); 24650b57cec5SDimitry Andric 2466a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 2467a7dea167SDimitry Andric *BT_UseFree[*CheckKind], 24680b57cec5SDimitry Andric AF == AF_InnerBuffer 24690b57cec5SDimitry Andric ? "Inner pointer of container used after re/deallocation" 24700b57cec5SDimitry Andric : "Use of memory after it is freed", 24710b57cec5SDimitry Andric N); 24720b57cec5SDimitry Andric 24730b57cec5SDimitry Andric R->markInteresting(Sym); 24740b57cec5SDimitry Andric R->addRange(Range); 2475fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym); 24760b57cec5SDimitry Andric 24770b57cec5SDimitry Andric if (AF == AF_InnerBuffer) 24780b57cec5SDimitry Andric R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym)); 24790b57cec5SDimitry Andric 24800b57cec5SDimitry Andric C.emitReport(std::move(R)); 24810b57cec5SDimitry Andric } 24820b57cec5SDimitry Andric } 24830b57cec5SDimitry Andric 24845ffd83dbSDimitry Andric void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range, 24850b57cec5SDimitry Andric bool Released, SymbolRef Sym, 24860b57cec5SDimitry Andric SymbolRef PrevSym) const { 24870b57cec5SDimitry Andric 24885ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { 24895ffd83dbSDimitry Andric C.addSink(); 24900b57cec5SDimitry Andric return; 24915ffd83dbSDimitry Andric } 24920b57cec5SDimitry Andric 2493bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); 249481ad6265SDimitry Andric if (!CheckKind) 24950b57cec5SDimitry Andric return; 24960b57cec5SDimitry Andric 24970b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 24980b57cec5SDimitry Andric if (!BT_DoubleFree[*CheckKind]) 24990b57cec5SDimitry Andric BT_DoubleFree[*CheckKind].reset(new BugType( 25000b57cec5SDimitry Andric CheckNames[*CheckKind], "Double free", categories::MemoryError)); 25010b57cec5SDimitry Andric 2502a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 25030b57cec5SDimitry Andric *BT_DoubleFree[*CheckKind], 25040b57cec5SDimitry Andric (Released ? "Attempt to free released memory" 25050b57cec5SDimitry Andric : "Attempt to free non-owned memory"), 25060b57cec5SDimitry Andric N); 25070b57cec5SDimitry Andric R->addRange(Range); 25080b57cec5SDimitry Andric R->markInteresting(Sym); 25090b57cec5SDimitry Andric if (PrevSym) 25100b57cec5SDimitry Andric R->markInteresting(PrevSym); 2511fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym); 25120b57cec5SDimitry Andric C.emitReport(std::move(R)); 25130b57cec5SDimitry Andric } 25140b57cec5SDimitry Andric } 25150b57cec5SDimitry Andric 25165ffd83dbSDimitry Andric void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const { 25170b57cec5SDimitry Andric 25185ffd83dbSDimitry Andric if (!ChecksEnabled[CK_NewDeleteChecker]) { 25195ffd83dbSDimitry Andric C.addSink(); 25200b57cec5SDimitry Andric return; 25215ffd83dbSDimitry Andric } 25220b57cec5SDimitry Andric 2523bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); 252481ad6265SDimitry Andric if (!CheckKind) 25250b57cec5SDimitry Andric return; 25260b57cec5SDimitry Andric 25270b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 25280b57cec5SDimitry Andric if (!BT_DoubleDelete) 25290b57cec5SDimitry Andric BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker], 25300b57cec5SDimitry Andric "Double delete", 25310b57cec5SDimitry Andric categories::MemoryError)); 25320b57cec5SDimitry Andric 2533a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 25340b57cec5SDimitry Andric *BT_DoubleDelete, "Attempt to delete released memory", N); 25350b57cec5SDimitry Andric 25360b57cec5SDimitry Andric R->markInteresting(Sym); 2537fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym); 25380b57cec5SDimitry Andric C.emitReport(std::move(R)); 25390b57cec5SDimitry Andric } 25400b57cec5SDimitry Andric } 25410b57cec5SDimitry Andric 25425ffd83dbSDimitry Andric void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range, 25430b57cec5SDimitry Andric SymbolRef Sym) const { 25440b57cec5SDimitry Andric 25455ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { 25465ffd83dbSDimitry Andric C.addSink(); 25470b57cec5SDimitry Andric return; 25485ffd83dbSDimitry Andric } 25490b57cec5SDimitry Andric 2550bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym); 25510b57cec5SDimitry Andric 255281ad6265SDimitry Andric if (!CheckKind) 25530b57cec5SDimitry Andric return; 25540b57cec5SDimitry Andric 25550b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 25560b57cec5SDimitry Andric if (!BT_UseZerroAllocated[*CheckKind]) 25570b57cec5SDimitry Andric BT_UseZerroAllocated[*CheckKind].reset( 25580b57cec5SDimitry Andric new BugType(CheckNames[*CheckKind], "Use of zero allocated", 25590b57cec5SDimitry Andric categories::MemoryError)); 25600b57cec5SDimitry Andric 2561a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 2562349cc55cSDimitry Andric *BT_UseZerroAllocated[*CheckKind], 2563349cc55cSDimitry Andric "Use of memory allocated with size zero", N); 25640b57cec5SDimitry Andric 25650b57cec5SDimitry Andric R->addRange(Range); 25660b57cec5SDimitry Andric if (Sym) { 25670b57cec5SDimitry Andric R->markInteresting(Sym); 2568fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym); 25690b57cec5SDimitry Andric } 25700b57cec5SDimitry Andric C.emitReport(std::move(R)); 25710b57cec5SDimitry Andric } 25720b57cec5SDimitry Andric } 25730b57cec5SDimitry Andric 25745ffd83dbSDimitry Andric void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, 25750b57cec5SDimitry Andric SourceRange Range, 25765ffd83dbSDimitry Andric const Expr *FreeExpr, 25775ffd83dbSDimitry Andric AllocationFamily Family) const { 25785ffd83dbSDimitry Andric if (!ChecksEnabled[CK_MallocChecker]) { 25795ffd83dbSDimitry Andric C.addSink(); 25800b57cec5SDimitry Andric return; 25815ffd83dbSDimitry Andric } 25820b57cec5SDimitry Andric 2583bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family); 258481ad6265SDimitry Andric if (!CheckKind) 25850b57cec5SDimitry Andric return; 25860b57cec5SDimitry Andric 25870b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode()) { 25880b57cec5SDimitry Andric if (!BT_BadFree[*CheckKind]) 25890b57cec5SDimitry Andric BT_BadFree[*CheckKind].reset(new BugType( 25900b57cec5SDimitry Andric CheckNames[*CheckKind], "Bad free", categories::MemoryError)); 25910b57cec5SDimitry Andric 25920b57cec5SDimitry Andric SmallString<100> Buf; 25930b57cec5SDimitry Andric llvm::raw_svector_ostream Os(Buf); 25940b57cec5SDimitry Andric 25950b57cec5SDimitry Andric const MemRegion *MR = ArgVal.getAsRegion(); 25960b57cec5SDimitry Andric while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR)) 25970b57cec5SDimitry Andric MR = ER->getSuperRegion(); 25980b57cec5SDimitry Andric 25990b57cec5SDimitry Andric Os << "Argument to "; 26005ffd83dbSDimitry Andric if (!printMemFnName(Os, C, FreeExpr)) 26010b57cec5SDimitry Andric Os << "deallocator"; 26020b57cec5SDimitry Andric 26030b57cec5SDimitry Andric Os << " is a function pointer"; 26040b57cec5SDimitry Andric 2605a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind], 2606a7dea167SDimitry Andric Os.str(), N); 26070b57cec5SDimitry Andric R->markInteresting(MR); 26080b57cec5SDimitry Andric R->addRange(Range); 26090b57cec5SDimitry Andric C.emitReport(std::move(R)); 26100b57cec5SDimitry Andric } 26110b57cec5SDimitry Andric } 26120b57cec5SDimitry Andric 26135ffd83dbSDimitry Andric ProgramStateRef 26145ffd83dbSDimitry Andric MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call, 26155ffd83dbSDimitry Andric bool ShouldFreeOnFail, ProgramStateRef State, 26165ffd83dbSDimitry Andric AllocationFamily Family, bool SuffixWithN) const { 26170b57cec5SDimitry Andric if (!State) 26180b57cec5SDimitry Andric return nullptr; 26190b57cec5SDimitry Andric 26205ffd83dbSDimitry Andric const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); 26215ffd83dbSDimitry Andric 26220b57cec5SDimitry Andric if (SuffixWithN && CE->getNumArgs() < 3) 26230b57cec5SDimitry Andric return nullptr; 26240b57cec5SDimitry Andric else if (CE->getNumArgs() < 2) 26250b57cec5SDimitry Andric return nullptr; 26260b57cec5SDimitry Andric 26270b57cec5SDimitry Andric const Expr *arg0Expr = CE->getArg(0); 26280b57cec5SDimitry Andric SVal Arg0Val = C.getSVal(arg0Expr); 262981ad6265SDimitry Andric if (!isa<DefinedOrUnknownSVal>(Arg0Val)) 26300b57cec5SDimitry Andric return nullptr; 26310b57cec5SDimitry Andric DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>(); 26320b57cec5SDimitry Andric 26330b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 26340b57cec5SDimitry Andric 263581ad6265SDimitry Andric DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ( 263681ad6265SDimitry Andric State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType())); 26370b57cec5SDimitry Andric 26380b57cec5SDimitry Andric // Get the size argument. 26390b57cec5SDimitry Andric const Expr *Arg1 = CE->getArg(1); 26400b57cec5SDimitry Andric 26410b57cec5SDimitry Andric // Get the value of the size argument. 26420b57cec5SDimitry Andric SVal TotalSize = C.getSVal(Arg1); 26430b57cec5SDimitry Andric if (SuffixWithN) 26440b57cec5SDimitry Andric TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2)); 264581ad6265SDimitry Andric if (!isa<DefinedOrUnknownSVal>(TotalSize)) 26460b57cec5SDimitry Andric return nullptr; 26470b57cec5SDimitry Andric 26480b57cec5SDimitry Andric // Compare the size argument to 0. 26490b57cec5SDimitry Andric DefinedOrUnknownSVal SizeZero = 26500b57cec5SDimitry Andric svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(), 265181ad6265SDimitry Andric svalBuilder.makeIntValWithWidth( 265281ad6265SDimitry Andric svalBuilder.getContext().getSizeType(), 0)); 26530b57cec5SDimitry Andric 26540b57cec5SDimitry Andric ProgramStateRef StatePtrIsNull, StatePtrNotNull; 26550b57cec5SDimitry Andric std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ); 26560b57cec5SDimitry Andric ProgramStateRef StateSizeIsZero, StateSizeNotZero; 26570b57cec5SDimitry Andric std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero); 26580b57cec5SDimitry Andric // We only assume exceptional states if they are definitely true; if the 26590b57cec5SDimitry Andric // state is under-constrained, assume regular realloc behavior. 26600b57cec5SDimitry Andric bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull; 26610b57cec5SDimitry Andric bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero; 26620b57cec5SDimitry Andric 26630b57cec5SDimitry Andric // If the ptr is NULL and the size is not 0, the call is equivalent to 26640b57cec5SDimitry Andric // malloc(size). 26650b57cec5SDimitry Andric if (PrtIsNull && !SizeIsZero) { 26665ffd83dbSDimitry Andric ProgramStateRef stateMalloc = MallocMemAux( 26675ffd83dbSDimitry Andric C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family); 26680b57cec5SDimitry Andric return stateMalloc; 26690b57cec5SDimitry Andric } 26700b57cec5SDimitry Andric 26710b57cec5SDimitry Andric if (PrtIsNull && SizeIsZero) 26720b57cec5SDimitry Andric return State; 26730b57cec5SDimitry Andric 26740b57cec5SDimitry Andric assert(!PrtIsNull); 26750b57cec5SDimitry Andric 2676a7dea167SDimitry Andric bool IsKnownToBeAllocated = false; 26770b57cec5SDimitry Andric 26780b57cec5SDimitry Andric // If the size is 0, free the memory. 26790b57cec5SDimitry Andric if (SizeIsZero) 26800b57cec5SDimitry Andric // The semantics of the return value are: 26810b57cec5SDimitry Andric // If size was equal to 0, either NULL or a pointer suitable to be passed 26820b57cec5SDimitry Andric // to free() is returned. We just free the input pointer and do not add 26830b57cec5SDimitry Andric // any constrains on the output pointer. 26845ffd83dbSDimitry Andric if (ProgramStateRef stateFree = FreeMemAux( 26855ffd83dbSDimitry Andric C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family)) 26860b57cec5SDimitry Andric return stateFree; 26870b57cec5SDimitry Andric 26880b57cec5SDimitry Andric // Default behavior. 26890b57cec5SDimitry Andric if (ProgramStateRef stateFree = 26905ffd83dbSDimitry Andric FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) { 26910b57cec5SDimitry Andric 26925ffd83dbSDimitry Andric ProgramStateRef stateRealloc = 26935ffd83dbSDimitry Andric MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family); 26940b57cec5SDimitry Andric if (!stateRealloc) 26950b57cec5SDimitry Andric return nullptr; 26960b57cec5SDimitry Andric 2697a7dea167SDimitry Andric OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure; 2698a7dea167SDimitry Andric if (ShouldFreeOnFail) 2699a7dea167SDimitry Andric Kind = OAR_FreeOnFailure; 2700a7dea167SDimitry Andric else if (!IsKnownToBeAllocated) 2701a7dea167SDimitry Andric Kind = OAR_DoNotTrackAfterFailure; 27020b57cec5SDimitry Andric 27035ffd83dbSDimitry Andric // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size). 27045ffd83dbSDimitry Andric SymbolRef FromPtr = arg0Val.getLocSymbolInBase(); 27055ffd83dbSDimitry Andric SVal RetVal = C.getSVal(CE); 27065ffd83dbSDimitry Andric SymbolRef ToPtr = RetVal.getAsSymbol(); 27075ffd83dbSDimitry Andric assert(FromPtr && ToPtr && 27085ffd83dbSDimitry Andric "By this point, FreeMemAux and MallocMemAux should have checked " 27095ffd83dbSDimitry Andric "whether the argument or the return value is symbolic!"); 27105ffd83dbSDimitry Andric 27110b57cec5SDimitry Andric // Record the info about the reallocated symbol so that we could properly 27120b57cec5SDimitry Andric // process failed reallocation. 27130b57cec5SDimitry Andric stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, 27140b57cec5SDimitry Andric ReallocPair(FromPtr, Kind)); 27150b57cec5SDimitry Andric // The reallocated symbol should stay alive for as long as the new symbol. 27160b57cec5SDimitry Andric C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr); 27170b57cec5SDimitry Andric return stateRealloc; 27180b57cec5SDimitry Andric } 27190b57cec5SDimitry Andric return nullptr; 27200b57cec5SDimitry Andric } 27210b57cec5SDimitry Andric 27225ffd83dbSDimitry Andric ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, 27235ffd83dbSDimitry Andric const CallEvent &Call, 2724*0fca6ea1SDimitry Andric ProgramStateRef State) const { 27250b57cec5SDimitry Andric if (!State) 27260b57cec5SDimitry Andric return nullptr; 27270b57cec5SDimitry Andric 27285ffd83dbSDimitry Andric if (Call.getNumArgs() < 2) 27290b57cec5SDimitry Andric return nullptr; 27300b57cec5SDimitry Andric 27310b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 27320b57cec5SDimitry Andric SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); 27335ffd83dbSDimitry Andric SVal TotalSize = 27345ffd83dbSDimitry Andric evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1)); 27350b57cec5SDimitry Andric 27365ffd83dbSDimitry Andric return MallocMemAux(C, Call, TotalSize, zeroVal, State, AF_Malloc); 27370b57cec5SDimitry Andric } 27380b57cec5SDimitry Andric 2739a7dea167SDimitry Andric MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N, 2740a7dea167SDimitry Andric SymbolRef Sym, 2741a7dea167SDimitry Andric CheckerContext &C) { 27420b57cec5SDimitry Andric const LocationContext *LeakContext = N->getLocationContext(); 27430b57cec5SDimitry Andric // Walk the ExplodedGraph backwards and find the first node that referred to 27440b57cec5SDimitry Andric // the tracked symbol. 27450b57cec5SDimitry Andric const ExplodedNode *AllocNode = N; 27460b57cec5SDimitry Andric const MemRegion *ReferenceRegion = nullptr; 27470b57cec5SDimitry Andric 27480b57cec5SDimitry Andric while (N) { 27490b57cec5SDimitry Andric ProgramStateRef State = N->getState(); 27500b57cec5SDimitry Andric if (!State->get<RegionState>(Sym)) 27510b57cec5SDimitry Andric break; 27520b57cec5SDimitry Andric 27530b57cec5SDimitry Andric // Find the most recent expression bound to the symbol in the current 27540b57cec5SDimitry Andric // context. 27550b57cec5SDimitry Andric if (!ReferenceRegion) { 27560b57cec5SDimitry Andric if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { 27570b57cec5SDimitry Andric SVal Val = State->getSVal(MR); 27580b57cec5SDimitry Andric if (Val.getAsLocSymbol() == Sym) { 27590b57cec5SDimitry Andric const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>(); 27600b57cec5SDimitry Andric // Do not show local variables belonging to a function other than 27610b57cec5SDimitry Andric // where the error is reported. 2762480093f4SDimitry Andric if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame())) 27630b57cec5SDimitry Andric ReferenceRegion = MR; 27640b57cec5SDimitry Andric } 27650b57cec5SDimitry Andric } 27660b57cec5SDimitry Andric } 27670b57cec5SDimitry Andric 27680b57cec5SDimitry Andric // Allocation node, is the last node in the current or parent context in 27690b57cec5SDimitry Andric // which the symbol was tracked. 27700b57cec5SDimitry Andric const LocationContext *NContext = N->getLocationContext(); 27710b57cec5SDimitry Andric if (NContext == LeakContext || 27720b57cec5SDimitry Andric NContext->isParentOf(LeakContext)) 27730b57cec5SDimitry Andric AllocNode = N; 27740b57cec5SDimitry Andric N = N->pred_empty() ? nullptr : *(N->pred_begin()); 27750b57cec5SDimitry Andric } 27760b57cec5SDimitry Andric 27770b57cec5SDimitry Andric return LeakInfo(AllocNode, ReferenceRegion); 27780b57cec5SDimitry Andric } 27790b57cec5SDimitry Andric 27805ffd83dbSDimitry Andric void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N, 27810b57cec5SDimitry Andric CheckerContext &C) const { 27820b57cec5SDimitry Andric 27830b57cec5SDimitry Andric if (!ChecksEnabled[CK_MallocChecker] && 27840b57cec5SDimitry Andric !ChecksEnabled[CK_NewDeleteLeaksChecker]) 27850b57cec5SDimitry Andric return; 27860b57cec5SDimitry Andric 27870b57cec5SDimitry Andric const RefState *RS = C.getState()->get<RegionState>(Sym); 27880b57cec5SDimitry Andric assert(RS && "cannot leak an untracked symbol"); 27890b57cec5SDimitry Andric AllocationFamily Family = RS->getAllocationFamily(); 27900b57cec5SDimitry Andric 27910b57cec5SDimitry Andric if (Family == AF_Alloca) 27920b57cec5SDimitry Andric return; 27930b57cec5SDimitry Andric 2794bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = 2795bdd1243dSDimitry Andric getCheckIfTracked(Family, true); 27960b57cec5SDimitry Andric 279781ad6265SDimitry Andric if (!CheckKind) 27980b57cec5SDimitry Andric return; 27990b57cec5SDimitry Andric 28000b57cec5SDimitry Andric assert(N); 28010b57cec5SDimitry Andric if (!BT_Leak[*CheckKind]) { 28020b57cec5SDimitry Andric // Leaks should not be reported if they are post-dominated by a sink: 28030b57cec5SDimitry Andric // (1) Sinks are higher importance bugs. 28040b57cec5SDimitry Andric // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending 28050b57cec5SDimitry Andric // with __noreturn functions such as assert() or exit(). We choose not 28060b57cec5SDimitry Andric // to report leaks on such paths. 28070b57cec5SDimitry Andric BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak", 28080b57cec5SDimitry Andric categories::MemoryError, 28090b57cec5SDimitry Andric /*SuppressOnSink=*/true)); 28100b57cec5SDimitry Andric } 28110b57cec5SDimitry Andric 28120b57cec5SDimitry Andric // Most bug reports are cached at the location where they occurred. 28130b57cec5SDimitry Andric // With leaks, we want to unique them by the location where they were 28140b57cec5SDimitry Andric // allocated, and only report a single path. 28150b57cec5SDimitry Andric PathDiagnosticLocation LocUsedForUniqueing; 28160b57cec5SDimitry Andric const ExplodedNode *AllocNode = nullptr; 28170b57cec5SDimitry Andric const MemRegion *Region = nullptr; 28180b57cec5SDimitry Andric std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); 28190b57cec5SDimitry Andric 2820a7dea167SDimitry Andric const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics(); 28210b57cec5SDimitry Andric if (AllocationStmt) 28220b57cec5SDimitry Andric LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt, 28230b57cec5SDimitry Andric C.getSourceManager(), 28240b57cec5SDimitry Andric AllocNode->getLocationContext()); 28250b57cec5SDimitry Andric 28260b57cec5SDimitry Andric SmallString<200> buf; 28270b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 28280b57cec5SDimitry Andric if (Region && Region->canPrintPretty()) { 28290b57cec5SDimitry Andric os << "Potential leak of memory pointed to by "; 28300b57cec5SDimitry Andric Region->printPretty(os); 28310b57cec5SDimitry Andric } else { 28320b57cec5SDimitry Andric os << "Potential memory leak"; 28330b57cec5SDimitry Andric } 28340b57cec5SDimitry Andric 2835a7dea167SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>( 28360b57cec5SDimitry Andric *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing, 28370b57cec5SDimitry Andric AllocNode->getLocationContext()->getDecl()); 28380b57cec5SDimitry Andric R->markInteresting(Sym); 2839fe6060f1SDimitry Andric R->addVisitor<MallocBugVisitor>(Sym, true); 2840349cc55cSDimitry Andric if (ShouldRegisterNoOwnershipChangeVisitor) 2841*0fca6ea1SDimitry Andric R->addVisitor<NoMemOwnershipChangeVisitor>(Sym, this); 28420b57cec5SDimitry Andric C.emitReport(std::move(R)); 28430b57cec5SDimitry Andric } 28440b57cec5SDimitry Andric 28450b57cec5SDimitry Andric void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, 28460b57cec5SDimitry Andric CheckerContext &C) const 28470b57cec5SDimitry Andric { 28480b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 28490b57cec5SDimitry Andric RegionStateTy OldRS = state->get<RegionState>(); 28500b57cec5SDimitry Andric RegionStateTy::Factory &F = state->get_context<RegionState>(); 28510b57cec5SDimitry Andric 28520b57cec5SDimitry Andric RegionStateTy RS = OldRS; 28530b57cec5SDimitry Andric SmallVector<SymbolRef, 2> Errors; 285406c3fb27SDimitry Andric for (auto [Sym, State] : RS) { 285506c3fb27SDimitry Andric if (SymReaper.isDead(Sym)) { 285606c3fb27SDimitry Andric if (State.isAllocated() || State.isAllocatedOfSizeZero()) 285706c3fb27SDimitry Andric Errors.push_back(Sym); 28580b57cec5SDimitry Andric // Remove the dead symbol from the map. 285906c3fb27SDimitry Andric RS = F.remove(RS, Sym); 28600b57cec5SDimitry Andric } 28610b57cec5SDimitry Andric } 28620b57cec5SDimitry Andric 28630b57cec5SDimitry Andric if (RS == OldRS) { 28640b57cec5SDimitry Andric // We shouldn't have touched other maps yet. 28650b57cec5SDimitry Andric assert(state->get<ReallocPairs>() == 28660b57cec5SDimitry Andric C.getState()->get<ReallocPairs>()); 28670b57cec5SDimitry Andric assert(state->get<FreeReturnValue>() == 28680b57cec5SDimitry Andric C.getState()->get<FreeReturnValue>()); 28690b57cec5SDimitry Andric return; 28700b57cec5SDimitry Andric } 28710b57cec5SDimitry Andric 28720b57cec5SDimitry Andric // Cleanup the Realloc Pairs Map. 28730b57cec5SDimitry Andric ReallocPairsTy RP = state->get<ReallocPairs>(); 287406c3fb27SDimitry Andric for (auto [Sym, ReallocPair] : RP) { 287506c3fb27SDimitry Andric if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) { 287606c3fb27SDimitry Andric state = state->remove<ReallocPairs>(Sym); 28770b57cec5SDimitry Andric } 28780b57cec5SDimitry Andric } 28790b57cec5SDimitry Andric 28800b57cec5SDimitry Andric // Cleanup the FreeReturnValue Map. 28810b57cec5SDimitry Andric FreeReturnValueTy FR = state->get<FreeReturnValue>(); 288206c3fb27SDimitry Andric for (auto [Sym, RetSym] : FR) { 288306c3fb27SDimitry Andric if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) { 288406c3fb27SDimitry Andric state = state->remove<FreeReturnValue>(Sym); 28850b57cec5SDimitry Andric } 28860b57cec5SDimitry Andric } 28870b57cec5SDimitry Andric 28880b57cec5SDimitry Andric // Generate leak node. 28890b57cec5SDimitry Andric ExplodedNode *N = C.getPredecessor(); 28900b57cec5SDimitry Andric if (!Errors.empty()) { 28910b57cec5SDimitry Andric static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak"); 28920b57cec5SDimitry Andric N = C.generateNonFatalErrorNode(C.getState(), &Tag); 28930b57cec5SDimitry Andric if (N) { 289406c3fb27SDimitry Andric for (SymbolRef Sym : Errors) { 289506c3fb27SDimitry Andric HandleLeak(Sym, N, C); 28960b57cec5SDimitry Andric } 28970b57cec5SDimitry Andric } 28980b57cec5SDimitry Andric } 28990b57cec5SDimitry Andric 29000b57cec5SDimitry Andric C.addTransition(state->set<RegionState>(RS), N); 29010b57cec5SDimitry Andric } 29020b57cec5SDimitry Andric 29030b57cec5SDimitry Andric void MallocChecker::checkPreCall(const CallEvent &Call, 29040b57cec5SDimitry Andric CheckerContext &C) const { 29050b57cec5SDimitry Andric 29065ffd83dbSDimitry Andric if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) { 29075ffd83dbSDimitry Andric const CXXDeleteExpr *DE = DC->getOriginExpr(); 29085ffd83dbSDimitry Andric 29095ffd83dbSDimitry Andric if (!ChecksEnabled[CK_NewDeleteChecker]) 29105ffd83dbSDimitry Andric if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol()) 29115ffd83dbSDimitry Andric checkUseAfterFree(Sym, C, DE->getArgument()); 29125ffd83dbSDimitry Andric 29135ffd83dbSDimitry Andric if (!isStandardNewDelete(DC->getDecl())) 29145ffd83dbSDimitry Andric return; 29155ffd83dbSDimitry Andric 29165ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 29175ffd83dbSDimitry Andric bool IsKnownToBeAllocated; 29185ffd83dbSDimitry Andric State = FreeMemAux(C, DE->getArgument(), Call, State, 29195ffd83dbSDimitry Andric /*Hold*/ false, IsKnownToBeAllocated, 29205ffd83dbSDimitry Andric (DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew)); 29215ffd83dbSDimitry Andric 29225ffd83dbSDimitry Andric C.addTransition(State); 29235ffd83dbSDimitry Andric return; 29245ffd83dbSDimitry Andric } 29255ffd83dbSDimitry Andric 29265ffd83dbSDimitry Andric if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) { 29270b57cec5SDimitry Andric SymbolRef Sym = DC->getCXXThisVal().getAsSymbol(); 29280b57cec5SDimitry Andric if (!Sym || checkDoubleDelete(Sym, C)) 29290b57cec5SDimitry Andric return; 29300b57cec5SDimitry Andric } 29310b57cec5SDimitry Andric 2932*0fca6ea1SDimitry Andric // We need to handle getline pre-conditions here before the pointed region 2933*0fca6ea1SDimitry Andric // gets invalidated by StreamChecker 2934*0fca6ea1SDimitry Andric if (const auto *PreFN = PreFnMap.lookup(Call)) { 2935*0fca6ea1SDimitry Andric (*PreFN)(this, Call, C); 2936*0fca6ea1SDimitry Andric return; 2937*0fca6ea1SDimitry Andric } 2938*0fca6ea1SDimitry Andric 29390b57cec5SDimitry Andric // We will check for double free in the post visit. 29400b57cec5SDimitry Andric if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) { 29410b57cec5SDimitry Andric const FunctionDecl *FD = FC->getDecl(); 29420b57cec5SDimitry Andric if (!FD) 29430b57cec5SDimitry Andric return; 29440b57cec5SDimitry Andric 29455ffd83dbSDimitry Andric if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call)) 29460b57cec5SDimitry Andric return; 29470b57cec5SDimitry Andric } 29480b57cec5SDimitry Andric 29490b57cec5SDimitry Andric // Check if the callee of a method is deleted. 29500b57cec5SDimitry Andric if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { 29510b57cec5SDimitry Andric SymbolRef Sym = CC->getCXXThisVal().getAsSymbol(); 29520b57cec5SDimitry Andric if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr())) 29530b57cec5SDimitry Andric return; 29540b57cec5SDimitry Andric } 29550b57cec5SDimitry Andric 29560b57cec5SDimitry Andric // Check arguments for being used after free. 29570b57cec5SDimitry Andric for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) { 29580b57cec5SDimitry Andric SVal ArgSVal = Call.getArgSVal(I); 295981ad6265SDimitry Andric if (isa<Loc>(ArgSVal)) { 29600b57cec5SDimitry Andric SymbolRef Sym = ArgSVal.getAsSymbol(); 29610b57cec5SDimitry Andric if (!Sym) 29620b57cec5SDimitry Andric continue; 29630b57cec5SDimitry Andric if (checkUseAfterFree(Sym, C, Call.getArgExpr(I))) 29640b57cec5SDimitry Andric return; 29650b57cec5SDimitry Andric } 29660b57cec5SDimitry Andric } 29670b57cec5SDimitry Andric } 29680b57cec5SDimitry Andric 29690b57cec5SDimitry Andric void MallocChecker::checkPreStmt(const ReturnStmt *S, 29700b57cec5SDimitry Andric CheckerContext &C) const { 29710b57cec5SDimitry Andric checkEscapeOnReturn(S, C); 29720b57cec5SDimitry Andric } 29730b57cec5SDimitry Andric 29740b57cec5SDimitry Andric // In the CFG, automatic destructors come after the return statement. 29750b57cec5SDimitry Andric // This callback checks for returning memory that is freed by automatic 29760b57cec5SDimitry Andric // destructors, as those cannot be reached in checkPreStmt(). 29770b57cec5SDimitry Andric void MallocChecker::checkEndFunction(const ReturnStmt *S, 29780b57cec5SDimitry Andric CheckerContext &C) const { 29790b57cec5SDimitry Andric checkEscapeOnReturn(S, C); 29800b57cec5SDimitry Andric } 29810b57cec5SDimitry Andric 29820b57cec5SDimitry Andric void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S, 29830b57cec5SDimitry Andric CheckerContext &C) const { 29840b57cec5SDimitry Andric if (!S) 29850b57cec5SDimitry Andric return; 29860b57cec5SDimitry Andric 29870b57cec5SDimitry Andric const Expr *E = S->getRetValue(); 29880b57cec5SDimitry Andric if (!E) 29890b57cec5SDimitry Andric return; 29900b57cec5SDimitry Andric 29910b57cec5SDimitry Andric // Check if we are returning a symbol. 29920b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 29930b57cec5SDimitry Andric SVal RetVal = C.getSVal(E); 29940b57cec5SDimitry Andric SymbolRef Sym = RetVal.getAsSymbol(); 29950b57cec5SDimitry Andric if (!Sym) 29960b57cec5SDimitry Andric // If we are returning a field of the allocated struct or an array element, 29970b57cec5SDimitry Andric // the callee could still free the memory. 29980b57cec5SDimitry Andric // TODO: This logic should be a part of generic symbol escape callback. 29990b57cec5SDimitry Andric if (const MemRegion *MR = RetVal.getAsRegion()) 3000349cc55cSDimitry Andric if (isa<FieldRegion, ElementRegion>(MR)) 30010b57cec5SDimitry Andric if (const SymbolicRegion *BMR = 30020b57cec5SDimitry Andric dyn_cast<SymbolicRegion>(MR->getBaseRegion())) 30030b57cec5SDimitry Andric Sym = BMR->getSymbol(); 30040b57cec5SDimitry Andric 30050b57cec5SDimitry Andric // Check if we are returning freed memory. 30060b57cec5SDimitry Andric if (Sym) 30070b57cec5SDimitry Andric checkUseAfterFree(Sym, C, E); 30080b57cec5SDimitry Andric } 30090b57cec5SDimitry Andric 30100b57cec5SDimitry Andric // TODO: Blocks should be either inlined or should call invalidate regions 30110b57cec5SDimitry Andric // upon invocation. After that's in place, special casing here will not be 30120b57cec5SDimitry Andric // needed. 30130b57cec5SDimitry Andric void MallocChecker::checkPostStmt(const BlockExpr *BE, 30140b57cec5SDimitry Andric CheckerContext &C) const { 30150b57cec5SDimitry Andric 30160b57cec5SDimitry Andric // Scan the BlockDecRefExprs for any object the retain count checker 30170b57cec5SDimitry Andric // may be tracking. 30180b57cec5SDimitry Andric if (!BE->getBlockDecl()->hasCaptures()) 30190b57cec5SDimitry Andric return; 30200b57cec5SDimitry Andric 30210b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 30220b57cec5SDimitry Andric const BlockDataRegion *R = 30230b57cec5SDimitry Andric cast<BlockDataRegion>(C.getSVal(BE).getAsRegion()); 30240b57cec5SDimitry Andric 302506c3fb27SDimitry Andric auto ReferencedVars = R->referenced_vars(); 302606c3fb27SDimitry Andric if (ReferencedVars.empty()) 30270b57cec5SDimitry Andric return; 30280b57cec5SDimitry Andric 30290b57cec5SDimitry Andric SmallVector<const MemRegion*, 10> Regions; 30300b57cec5SDimitry Andric const LocationContext *LC = C.getLocationContext(); 30310b57cec5SDimitry Andric MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); 30320b57cec5SDimitry Andric 303306c3fb27SDimitry Andric for (const auto &Var : ReferencedVars) { 303406c3fb27SDimitry Andric const VarRegion *VR = Var.getCapturedRegion(); 30350b57cec5SDimitry Andric if (VR->getSuperRegion() == R) { 30360b57cec5SDimitry Andric VR = MemMgr.getVarRegion(VR->getDecl(), LC); 30370b57cec5SDimitry Andric } 30380b57cec5SDimitry Andric Regions.push_back(VR); 30390b57cec5SDimitry Andric } 30400b57cec5SDimitry Andric 30410b57cec5SDimitry Andric state = 30420b57cec5SDimitry Andric state->scanReachableSymbols<StopTrackingCallback>(Regions).getState(); 30430b57cec5SDimitry Andric C.addTransition(state); 30440b57cec5SDimitry Andric } 30450b57cec5SDimitry Andric 3046a7dea167SDimitry Andric static bool isReleased(SymbolRef Sym, CheckerContext &C) { 30470b57cec5SDimitry Andric assert(Sym); 30480b57cec5SDimitry Andric const RefState *RS = C.getState()->get<RegionState>(Sym); 30490b57cec5SDimitry Andric return (RS && RS->isReleased()); 30500b57cec5SDimitry Andric } 30510b57cec5SDimitry Andric 30520b57cec5SDimitry Andric bool MallocChecker::suppressDeallocationsInSuspiciousContexts( 30535ffd83dbSDimitry Andric const CallEvent &Call, CheckerContext &C) const { 30545ffd83dbSDimitry Andric if (Call.getNumArgs() == 0) 30550b57cec5SDimitry Andric return false; 30560b57cec5SDimitry Andric 30570b57cec5SDimitry Andric StringRef FunctionStr = ""; 30580b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) 30590b57cec5SDimitry Andric if (const Stmt *Body = FD->getBody()) 30600b57cec5SDimitry Andric if (Body->getBeginLoc().isValid()) 30610b57cec5SDimitry Andric FunctionStr = 30620b57cec5SDimitry Andric Lexer::getSourceText(CharSourceRange::getTokenRange( 30630b57cec5SDimitry Andric {FD->getBeginLoc(), Body->getBeginLoc()}), 30640b57cec5SDimitry Andric C.getSourceManager(), C.getLangOpts()); 30650b57cec5SDimitry Andric 30660b57cec5SDimitry Andric // We do not model the Integer Set Library's retain-count based allocation. 30670b57cec5SDimitry Andric if (!FunctionStr.contains("__isl_")) 30680b57cec5SDimitry Andric return false; 30690b57cec5SDimitry Andric 30700b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 30710b57cec5SDimitry Andric 30725ffd83dbSDimitry Andric for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments()) 30730b57cec5SDimitry Andric if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol()) 30740b57cec5SDimitry Andric if (const RefState *RS = State->get<RegionState>(Sym)) 30750b57cec5SDimitry Andric State = State->set<RegionState>(Sym, RefState::getEscaped(RS)); 30760b57cec5SDimitry Andric 30770b57cec5SDimitry Andric C.addTransition(State); 30780b57cec5SDimitry Andric return true; 30790b57cec5SDimitry Andric } 30800b57cec5SDimitry Andric 30810b57cec5SDimitry Andric bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, 30820b57cec5SDimitry Andric const Stmt *S) const { 30830b57cec5SDimitry Andric 30840b57cec5SDimitry Andric if (isReleased(Sym, C)) { 30855ffd83dbSDimitry Andric HandleUseAfterFree(C, S->getSourceRange(), Sym); 30860b57cec5SDimitry Andric return true; 30870b57cec5SDimitry Andric } 30880b57cec5SDimitry Andric 30890b57cec5SDimitry Andric return false; 30900b57cec5SDimitry Andric } 30910b57cec5SDimitry Andric 30920b57cec5SDimitry Andric void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, 30930b57cec5SDimitry Andric const Stmt *S) const { 30940b57cec5SDimitry Andric assert(Sym); 30950b57cec5SDimitry Andric 30960b57cec5SDimitry Andric if (const RefState *RS = C.getState()->get<RegionState>(Sym)) { 30970b57cec5SDimitry Andric if (RS->isAllocatedOfSizeZero()) 30985ffd83dbSDimitry Andric HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym); 30990b57cec5SDimitry Andric } 31000b57cec5SDimitry Andric else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) { 31015ffd83dbSDimitry Andric HandleUseZeroAlloc(C, S->getSourceRange(), Sym); 31020b57cec5SDimitry Andric } 31030b57cec5SDimitry Andric } 31040b57cec5SDimitry Andric 31050b57cec5SDimitry Andric bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { 31060b57cec5SDimitry Andric 31070b57cec5SDimitry Andric if (isReleased(Sym, C)) { 31085ffd83dbSDimitry Andric HandleDoubleDelete(C, Sym); 31090b57cec5SDimitry Andric return true; 31100b57cec5SDimitry Andric } 31110b57cec5SDimitry Andric return false; 31120b57cec5SDimitry Andric } 31130b57cec5SDimitry Andric 31140b57cec5SDimitry Andric // Check if the location is a freed symbolic region. 31150b57cec5SDimitry Andric void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, 31160b57cec5SDimitry Andric CheckerContext &C) const { 31170b57cec5SDimitry Andric SymbolRef Sym = l.getLocSymbolInBase(); 31180b57cec5SDimitry Andric if (Sym) { 31190b57cec5SDimitry Andric checkUseAfterFree(Sym, C, S); 31200b57cec5SDimitry Andric checkUseZeroAllocated(Sym, C, S); 31210b57cec5SDimitry Andric } 31220b57cec5SDimitry Andric } 31230b57cec5SDimitry Andric 31240b57cec5SDimitry Andric // If a symbolic region is assumed to NULL (or another constant), stop tracking 31250b57cec5SDimitry Andric // it - assuming that allocation failed on this path. 31260b57cec5SDimitry Andric ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, 31270b57cec5SDimitry Andric SVal Cond, 31280b57cec5SDimitry Andric bool Assumption) const { 31290b57cec5SDimitry Andric RegionStateTy RS = state->get<RegionState>(); 313006c3fb27SDimitry Andric for (SymbolRef Sym : llvm::make_first_range(RS)) { 31310b57cec5SDimitry Andric // If the symbol is assumed to be NULL, remove it from consideration. 31320b57cec5SDimitry Andric ConstraintManager &CMgr = state->getConstraintManager(); 313306c3fb27SDimitry Andric ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym); 31340b57cec5SDimitry Andric if (AllocFailed.isConstrainedTrue()) 313506c3fb27SDimitry Andric state = state->remove<RegionState>(Sym); 31360b57cec5SDimitry Andric } 31370b57cec5SDimitry Andric 31380b57cec5SDimitry Andric // Realloc returns 0 when reallocation fails, which means that we should 31390b57cec5SDimitry Andric // restore the state of the pointer being reallocated. 31400b57cec5SDimitry Andric ReallocPairsTy RP = state->get<ReallocPairs>(); 314106c3fb27SDimitry Andric for (auto [Sym, ReallocPair] : RP) { 31420b57cec5SDimitry Andric // If the symbol is assumed to be NULL, remove it from consideration. 31430b57cec5SDimitry Andric ConstraintManager &CMgr = state->getConstraintManager(); 314406c3fb27SDimitry Andric ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym); 31450b57cec5SDimitry Andric if (!AllocFailed.isConstrainedTrue()) 31460b57cec5SDimitry Andric continue; 31470b57cec5SDimitry Andric 314806c3fb27SDimitry Andric SymbolRef ReallocSym = ReallocPair.ReallocatedSym; 31490b57cec5SDimitry Andric if (const RefState *RS = state->get<RegionState>(ReallocSym)) { 31500b57cec5SDimitry Andric if (RS->isReleased()) { 315106c3fb27SDimitry Andric switch (ReallocPair.Kind) { 3152a7dea167SDimitry Andric case OAR_ToBeFreedAfterFailure: 31530b57cec5SDimitry Andric state = state->set<RegionState>(ReallocSym, 31540b57cec5SDimitry Andric RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt())); 3155a7dea167SDimitry Andric break; 3156a7dea167SDimitry Andric case OAR_DoNotTrackAfterFailure: 31570b57cec5SDimitry Andric state = state->remove<RegionState>(ReallocSym); 3158a7dea167SDimitry Andric break; 3159a7dea167SDimitry Andric default: 316006c3fb27SDimitry Andric assert(ReallocPair.Kind == OAR_FreeOnFailure); 3161a7dea167SDimitry Andric } 31620b57cec5SDimitry Andric } 31630b57cec5SDimitry Andric } 316406c3fb27SDimitry Andric state = state->remove<ReallocPairs>(Sym); 31650b57cec5SDimitry Andric } 31660b57cec5SDimitry Andric 31670b57cec5SDimitry Andric return state; 31680b57cec5SDimitry Andric } 31690b57cec5SDimitry Andric 31700b57cec5SDimitry Andric bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( 31710b57cec5SDimitry Andric const CallEvent *Call, 31720b57cec5SDimitry Andric ProgramStateRef State, 31730b57cec5SDimitry Andric SymbolRef &EscapingSymbol) const { 31740b57cec5SDimitry Andric assert(Call); 31750b57cec5SDimitry Andric EscapingSymbol = nullptr; 31760b57cec5SDimitry Andric 31770b57cec5SDimitry Andric // For now, assume that any C++ or block call can free memory. 31780b57cec5SDimitry Andric // TODO: If we want to be more optimistic here, we'll need to make sure that 31790b57cec5SDimitry Andric // regions escape to C++ containers. They seem to do that even now, but for 31800b57cec5SDimitry Andric // mysterious reasons. 3181349cc55cSDimitry Andric if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call)) 31820b57cec5SDimitry Andric return true; 31830b57cec5SDimitry Andric 31840b57cec5SDimitry Andric // Check Objective-C messages by selector name. 31850b57cec5SDimitry Andric if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { 31860b57cec5SDimitry Andric // If it's not a framework call, or if it takes a callback, assume it 31870b57cec5SDimitry Andric // can free memory. 31880b57cec5SDimitry Andric if (!Call->isInSystemHeader() || Call->argumentsMayEscape()) 31890b57cec5SDimitry Andric return true; 31900b57cec5SDimitry Andric 31910b57cec5SDimitry Andric // If it's a method we know about, handle it explicitly post-call. 31920b57cec5SDimitry Andric // This should happen before the "freeWhenDone" check below. 31930b57cec5SDimitry Andric if (isKnownDeallocObjCMethodName(*Msg)) 31940b57cec5SDimitry Andric return false; 31950b57cec5SDimitry Andric 31960b57cec5SDimitry Andric // If there's a "freeWhenDone" parameter, but the method isn't one we know 31970b57cec5SDimitry Andric // about, we can't be sure that the object will use free() to deallocate the 31980b57cec5SDimitry Andric // memory, so we can't model it explicitly. The best we can do is use it to 31990b57cec5SDimitry Andric // decide whether the pointer escapes. 3200bdd1243dSDimitry Andric if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg)) 32010b57cec5SDimitry Andric return *FreeWhenDone; 32020b57cec5SDimitry Andric 32030b57cec5SDimitry Andric // If the first selector piece ends with "NoCopy", and there is no 32040b57cec5SDimitry Andric // "freeWhenDone" parameter set to zero, we know ownership is being 32050b57cec5SDimitry Andric // transferred. Again, though, we can't be sure that the object will use 32060b57cec5SDimitry Andric // free() to deallocate the memory, so we can't model it explicitly. 32070b57cec5SDimitry Andric StringRef FirstSlot = Msg->getSelector().getNameForSlot(0); 32085f757f3fSDimitry Andric if (FirstSlot.ends_with("NoCopy")) 32090b57cec5SDimitry Andric return true; 32100b57cec5SDimitry Andric 32110b57cec5SDimitry Andric // If the first selector starts with addPointer, insertPointer, 32120b57cec5SDimitry Andric // or replacePointer, assume we are dealing with NSPointerArray or similar. 32130b57cec5SDimitry Andric // This is similar to C++ containers (vector); we still might want to check 32140b57cec5SDimitry Andric // that the pointers get freed by following the container itself. 32155f757f3fSDimitry Andric if (FirstSlot.starts_with("addPointer") || 32165f757f3fSDimitry Andric FirstSlot.starts_with("insertPointer") || 32175f757f3fSDimitry Andric FirstSlot.starts_with("replacePointer") || 3218*0fca6ea1SDimitry Andric FirstSlot == "valueWithPointer") { 32190b57cec5SDimitry Andric return true; 32200b57cec5SDimitry Andric } 32210b57cec5SDimitry Andric 32220b57cec5SDimitry Andric // We should escape receiver on call to 'init'. This is especially relevant 32230b57cec5SDimitry Andric // to the receiver, as the corresponding symbol is usually not referenced 32240b57cec5SDimitry Andric // after the call. 32250b57cec5SDimitry Andric if (Msg->getMethodFamily() == OMF_init) { 32260b57cec5SDimitry Andric EscapingSymbol = Msg->getReceiverSVal().getAsSymbol(); 32270b57cec5SDimitry Andric return true; 32280b57cec5SDimitry Andric } 32290b57cec5SDimitry Andric 32300b57cec5SDimitry Andric // Otherwise, assume that the method does not free memory. 32310b57cec5SDimitry Andric // Most framework methods do not free memory. 32320b57cec5SDimitry Andric return false; 32330b57cec5SDimitry Andric } 32340b57cec5SDimitry Andric 32350b57cec5SDimitry Andric // At this point the only thing left to handle is straight function calls. 32360b57cec5SDimitry Andric const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl(); 32370b57cec5SDimitry Andric if (!FD) 32380b57cec5SDimitry Andric return true; 32390b57cec5SDimitry Andric 32400b57cec5SDimitry Andric // If it's one of the allocation functions we can reason about, we model 32410b57cec5SDimitry Andric // its behavior explicitly. 32425ffd83dbSDimitry Andric if (isMemCall(*Call)) 32430b57cec5SDimitry Andric return false; 32440b57cec5SDimitry Andric 32450b57cec5SDimitry Andric // If it's not a system call, assume it frees memory. 32460b57cec5SDimitry Andric if (!Call->isInSystemHeader()) 32470b57cec5SDimitry Andric return true; 32480b57cec5SDimitry Andric 32490b57cec5SDimitry Andric // White list the system functions whose arguments escape. 32500b57cec5SDimitry Andric const IdentifierInfo *II = FD->getIdentifier(); 32510b57cec5SDimitry Andric if (!II) 32520b57cec5SDimitry Andric return true; 32530b57cec5SDimitry Andric StringRef FName = II->getName(); 32540b57cec5SDimitry Andric 32550b57cec5SDimitry Andric // White list the 'XXXNoCopy' CoreFoundation functions. 32560b57cec5SDimitry Andric // We specifically check these before 32575f757f3fSDimitry Andric if (FName.ends_with("NoCopy")) { 32580b57cec5SDimitry Andric // Look for the deallocator argument. We know that the memory ownership 32590b57cec5SDimitry Andric // is not transferred only if the deallocator argument is 32600b57cec5SDimitry Andric // 'kCFAllocatorNull'. 32610b57cec5SDimitry Andric for (unsigned i = 1; i < Call->getNumArgs(); ++i) { 32620b57cec5SDimitry Andric const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts(); 32630b57cec5SDimitry Andric if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) { 32640b57cec5SDimitry Andric StringRef DeallocatorName = DE->getFoundDecl()->getName(); 32650b57cec5SDimitry Andric if (DeallocatorName == "kCFAllocatorNull") 32660b57cec5SDimitry Andric return false; 32670b57cec5SDimitry Andric } 32680b57cec5SDimitry Andric } 32690b57cec5SDimitry Andric return true; 32700b57cec5SDimitry Andric } 32710b57cec5SDimitry Andric 32720b57cec5SDimitry Andric // Associating streams with malloced buffers. The pointer can escape if 32730b57cec5SDimitry Andric // 'closefn' is specified (and if that function does free memory), 32740b57cec5SDimitry Andric // but it will not if closefn is not specified. 32750b57cec5SDimitry Andric // Currently, we do not inspect the 'closefn' function (PR12101). 32760b57cec5SDimitry Andric if (FName == "funopen") 32770b57cec5SDimitry Andric if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0)) 32780b57cec5SDimitry Andric return false; 32790b57cec5SDimitry Andric 32800b57cec5SDimitry Andric // Do not warn on pointers passed to 'setbuf' when used with std streams, 32810b57cec5SDimitry Andric // these leaks might be intentional when setting the buffer for stdio. 32820b57cec5SDimitry Andric // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer 32830b57cec5SDimitry Andric if (FName == "setbuf" || FName =="setbuffer" || 32840b57cec5SDimitry Andric FName == "setlinebuf" || FName == "setvbuf") { 32850b57cec5SDimitry Andric if (Call->getNumArgs() >= 1) { 32860b57cec5SDimitry Andric const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts(); 32870b57cec5SDimitry Andric if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE)) 32880b57cec5SDimitry Andric if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl())) 3289349cc55cSDimitry Andric if (D->getCanonicalDecl()->getName().contains("std")) 32900b57cec5SDimitry Andric return true; 32910b57cec5SDimitry Andric } 32920b57cec5SDimitry Andric } 32930b57cec5SDimitry Andric 32940b57cec5SDimitry Andric // A bunch of other functions which either take ownership of a pointer or 32950b57cec5SDimitry Andric // wrap the result up in a struct or object, meaning it can be freed later. 32960b57cec5SDimitry Andric // (See RetainCountChecker.) Not all the parameters here are invalidated, 32970b57cec5SDimitry Andric // but the Malloc checker cannot differentiate between them. The right way 32980b57cec5SDimitry Andric // of doing this would be to implement a pointer escapes callback. 32990b57cec5SDimitry Andric if (FName == "CGBitmapContextCreate" || 33000b57cec5SDimitry Andric FName == "CGBitmapContextCreateWithData" || 33010b57cec5SDimitry Andric FName == "CVPixelBufferCreateWithBytes" || 33020b57cec5SDimitry Andric FName == "CVPixelBufferCreateWithPlanarBytes" || 33030b57cec5SDimitry Andric FName == "OSAtomicEnqueue") { 33040b57cec5SDimitry Andric return true; 33050b57cec5SDimitry Andric } 33060b57cec5SDimitry Andric 33070b57cec5SDimitry Andric if (FName == "postEvent" && 33080b57cec5SDimitry Andric FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") { 33090b57cec5SDimitry Andric return true; 33100b57cec5SDimitry Andric } 33110b57cec5SDimitry Andric 33120b57cec5SDimitry Andric if (FName == "connectImpl" && 33130b57cec5SDimitry Andric FD->getQualifiedNameAsString() == "QObject::connectImpl") { 33140b57cec5SDimitry Andric return true; 33150b57cec5SDimitry Andric } 33160b57cec5SDimitry Andric 331706c3fb27SDimitry Andric if (FName == "singleShotImpl" && 331806c3fb27SDimitry Andric FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") { 331906c3fb27SDimitry Andric return true; 332006c3fb27SDimitry Andric } 332106c3fb27SDimitry Andric 33220b57cec5SDimitry Andric // Handle cases where we know a buffer's /address/ can escape. 33230b57cec5SDimitry Andric // Note that the above checks handle some special cases where we know that 33240b57cec5SDimitry Andric // even though the address escapes, it's still our responsibility to free the 33250b57cec5SDimitry Andric // buffer. 33260b57cec5SDimitry Andric if (Call->argumentsMayEscape()) 33270b57cec5SDimitry Andric return true; 33280b57cec5SDimitry Andric 33290b57cec5SDimitry Andric // Otherwise, assume that the function does not free memory. 33300b57cec5SDimitry Andric // Most system calls do not free the memory. 33310b57cec5SDimitry Andric return false; 33320b57cec5SDimitry Andric } 33330b57cec5SDimitry Andric 3334a7dea167SDimitry Andric ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, 3335a7dea167SDimitry Andric const InvalidatedSymbols &Escaped, 3336a7dea167SDimitry Andric const CallEvent *Call, 3337a7dea167SDimitry Andric PointerEscapeKind Kind) const { 3338a7dea167SDimitry Andric return checkPointerEscapeAux(State, Escaped, Call, Kind, 3339a7dea167SDimitry Andric /*IsConstPointerEscape*/ false); 3340a7dea167SDimitry Andric } 3341a7dea167SDimitry Andric 3342a7dea167SDimitry Andric ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State, 3343a7dea167SDimitry Andric const InvalidatedSymbols &Escaped, 3344a7dea167SDimitry Andric const CallEvent *Call, 3345a7dea167SDimitry Andric PointerEscapeKind Kind) const { 3346a7dea167SDimitry Andric // If a const pointer escapes, it may not be freed(), but it could be deleted. 3347a7dea167SDimitry Andric return checkPointerEscapeAux(State, Escaped, Call, Kind, 3348a7dea167SDimitry Andric /*IsConstPointerEscape*/ true); 33490b57cec5SDimitry Andric } 33500b57cec5SDimitry Andric 33510b57cec5SDimitry Andric static bool checkIfNewOrNewArrayFamily(const RefState *RS) { 33520b57cec5SDimitry Andric return (RS->getAllocationFamily() == AF_CXXNewArray || 33530b57cec5SDimitry Andric RS->getAllocationFamily() == AF_CXXNew); 33540b57cec5SDimitry Andric } 33550b57cec5SDimitry Andric 3356a7dea167SDimitry Andric ProgramStateRef MallocChecker::checkPointerEscapeAux( 3357a7dea167SDimitry Andric ProgramStateRef State, const InvalidatedSymbols &Escaped, 3358a7dea167SDimitry Andric const CallEvent *Call, PointerEscapeKind Kind, 3359a7dea167SDimitry Andric bool IsConstPointerEscape) const { 33600b57cec5SDimitry Andric // If we know that the call does not free memory, or we want to process the 33610b57cec5SDimitry Andric // call later, keep tracking the top level arguments. 33620b57cec5SDimitry Andric SymbolRef EscapingSymbol = nullptr; 33630b57cec5SDimitry Andric if (Kind == PSK_DirectEscapeOnCall && 33640b57cec5SDimitry Andric !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State, 33650b57cec5SDimitry Andric EscapingSymbol) && 33660b57cec5SDimitry Andric !EscapingSymbol) { 33670b57cec5SDimitry Andric return State; 33680b57cec5SDimitry Andric } 33690b57cec5SDimitry Andric 337006c3fb27SDimitry Andric for (SymbolRef sym : Escaped) { 33710b57cec5SDimitry Andric if (EscapingSymbol && EscapingSymbol != sym) 33720b57cec5SDimitry Andric continue; 33730b57cec5SDimitry Andric 3374a7dea167SDimitry Andric if (const RefState *RS = State->get<RegionState>(sym)) 3375a7dea167SDimitry Andric if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) 3376a7dea167SDimitry Andric if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS)) 33770b57cec5SDimitry Andric State = State->set<RegionState>(sym, RefState::getEscaped(RS)); 33780b57cec5SDimitry Andric } 33790b57cec5SDimitry Andric return State; 33800b57cec5SDimitry Andric } 33810b57cec5SDimitry Andric 33825ffd83dbSDimitry Andric bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, 33835ffd83dbSDimitry Andric SVal ArgVal) const { 33845ffd83dbSDimitry Andric if (!KernelZeroSizePtrValue) 33855ffd83dbSDimitry Andric KernelZeroSizePtrValue = 33865ffd83dbSDimitry Andric tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor()); 33875ffd83dbSDimitry Andric 33885ffd83dbSDimitry Andric const llvm::APSInt *ArgValKnown = 33895ffd83dbSDimitry Andric C.getSValBuilder().getKnownValue(State, ArgVal); 33905ffd83dbSDimitry Andric return ArgValKnown && *KernelZeroSizePtrValue && 33915ffd83dbSDimitry Andric ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue; 33925ffd83dbSDimitry Andric } 33935ffd83dbSDimitry Andric 33940b57cec5SDimitry Andric static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, 33950b57cec5SDimitry Andric ProgramStateRef prevState) { 33960b57cec5SDimitry Andric ReallocPairsTy currMap = currState->get<ReallocPairs>(); 33970b57cec5SDimitry Andric ReallocPairsTy prevMap = prevState->get<ReallocPairs>(); 33980b57cec5SDimitry Andric 3399a7dea167SDimitry Andric for (const ReallocPairsTy::value_type &Pair : prevMap) { 3400a7dea167SDimitry Andric SymbolRef sym = Pair.first; 34010b57cec5SDimitry Andric if (!currMap.lookup(sym)) 34020b57cec5SDimitry Andric return sym; 34030b57cec5SDimitry Andric } 34040b57cec5SDimitry Andric 34050b57cec5SDimitry Andric return nullptr; 34060b57cec5SDimitry Andric } 34070b57cec5SDimitry Andric 34080b57cec5SDimitry Andric static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) { 34090b57cec5SDimitry Andric if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) { 34100b57cec5SDimitry Andric StringRef N = II->getName(); 3411fe6060f1SDimitry Andric if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) { 3412fe6060f1SDimitry Andric if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") || 3413fe6060f1SDimitry Andric N.contains_insensitive("intrusive") || 3414*0fca6ea1SDimitry Andric N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) { 34150b57cec5SDimitry Andric return true; 34160b57cec5SDimitry Andric } 34170b57cec5SDimitry Andric } 34180b57cec5SDimitry Andric } 34190b57cec5SDimitry Andric return false; 34200b57cec5SDimitry Andric } 34210b57cec5SDimitry Andric 3422a7dea167SDimitry Andric PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, 3423a7dea167SDimitry Andric BugReporterContext &BRC, 3424a7dea167SDimitry Andric PathSensitiveBugReport &BR) { 34250b57cec5SDimitry Andric ProgramStateRef state = N->getState(); 34260b57cec5SDimitry Andric ProgramStateRef statePrev = N->getFirstPred()->getState(); 34270b57cec5SDimitry Andric 3428a7dea167SDimitry Andric const RefState *RSCurr = state->get<RegionState>(Sym); 34290b57cec5SDimitry Andric const RefState *RSPrev = statePrev->get<RegionState>(Sym); 34300b57cec5SDimitry Andric 3431a7dea167SDimitry Andric const Stmt *S = N->getStmtForDiagnostics(); 34320b57cec5SDimitry Andric // When dealing with containers, we sometimes want to give a note 34330b57cec5SDimitry Andric // even if the statement is missing. 3434a7dea167SDimitry Andric if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer)) 34350b57cec5SDimitry Andric return nullptr; 34360b57cec5SDimitry Andric 34370b57cec5SDimitry Andric const LocationContext *CurrentLC = N->getLocationContext(); 34380b57cec5SDimitry Andric 34390b57cec5SDimitry Andric // If we find an atomic fetch_add or fetch_sub within the destructor in which 34400b57cec5SDimitry Andric // the pointer was released (before the release), this is likely a destructor 34410b57cec5SDimitry Andric // of a shared pointer. 34420b57cec5SDimitry Andric // Because we don't model atomics, and also because we don't know that the 34430b57cec5SDimitry Andric // original reference count is positive, we should not report use-after-frees 34440b57cec5SDimitry Andric // on objects deleted in such destructors. This can probably be improved 34450b57cec5SDimitry Andric // through better shared pointer modeling. 3446*0fca6ea1SDimitry Andric if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC || 3447*0fca6ea1SDimitry Andric ReleaseDestructorLC->isParentOf(CurrentLC))) { 34480b57cec5SDimitry Andric if (const auto *AE = dyn_cast<AtomicExpr>(S)) { 3449*0fca6ea1SDimitry Andric // Check for manual use of atomic builtins. 34500b57cec5SDimitry Andric AtomicExpr::AtomicOp Op = AE->getOp(); 34510b57cec5SDimitry Andric if (Op == AtomicExpr::AO__c11_atomic_fetch_add || 34520b57cec5SDimitry Andric Op == AtomicExpr::AO__c11_atomic_fetch_sub) { 3453*0fca6ea1SDimitry Andric BR.markInvalid(getTag(), S); 3454*0fca6ea1SDimitry Andric } 3455*0fca6ea1SDimitry Andric } else if (const auto *CE = dyn_cast<CallExpr>(S)) { 3456*0fca6ea1SDimitry Andric // Check for `std::atomic` and such. This covers both regular method calls 3457*0fca6ea1SDimitry Andric // and operator calls. 3458*0fca6ea1SDimitry Andric if (const auto *MD = 3459*0fca6ea1SDimitry Andric dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) { 3460*0fca6ea1SDimitry Andric const CXXRecordDecl *RD = MD->getParent(); 3461*0fca6ea1SDimitry Andric // A bit wobbly with ".contains()" because it may be like 3462*0fca6ea1SDimitry Andric // "__atomic_base" or something. 3463*0fca6ea1SDimitry Andric if (StringRef(RD->getNameAsString()).contains("atomic")) { 34640b57cec5SDimitry Andric BR.markInvalid(getTag(), S); 34650b57cec5SDimitry Andric } 34660b57cec5SDimitry Andric } 34670b57cec5SDimitry Andric } 34680b57cec5SDimitry Andric } 34690b57cec5SDimitry Andric 34700b57cec5SDimitry Andric // FIXME: We will eventually need to handle non-statement-based events 34710b57cec5SDimitry Andric // (__attribute__((cleanup))). 34720b57cec5SDimitry Andric 34730b57cec5SDimitry Andric // Find out if this is an interesting point and what is the kind. 34740b57cec5SDimitry Andric StringRef Msg; 3475a7dea167SDimitry Andric std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr; 34760b57cec5SDimitry Andric SmallString<256> Buf; 34770b57cec5SDimitry Andric llvm::raw_svector_ostream OS(Buf); 34780b57cec5SDimitry Andric 34790b57cec5SDimitry Andric if (Mode == Normal) { 3480a7dea167SDimitry Andric if (isAllocated(RSCurr, RSPrev, S)) { 34810b57cec5SDimitry Andric Msg = "Memory is allocated"; 3482a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>( 3483a7dea167SDimitry Andric Sym, "Returned allocated memory"); 3484a7dea167SDimitry Andric } else if (isReleased(RSCurr, RSPrev, S)) { 3485a7dea167SDimitry Andric const auto Family = RSCurr->getAllocationFamily(); 34860b57cec5SDimitry Andric switch (Family) { 34870b57cec5SDimitry Andric case AF_Alloca: 34880b57cec5SDimitry Andric case AF_Malloc: 34890b57cec5SDimitry Andric case AF_CXXNew: 34900b57cec5SDimitry Andric case AF_CXXNewArray: 34910b57cec5SDimitry Andric case AF_IfNameIndex: 34920b57cec5SDimitry Andric Msg = "Memory is released"; 3493a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>( 3494a7dea167SDimitry Andric Sym, "Returning; memory was released"); 34950b57cec5SDimitry Andric break; 34960b57cec5SDimitry Andric case AF_InnerBuffer: { 34970b57cec5SDimitry Andric const MemRegion *ObjRegion = 34980b57cec5SDimitry Andric allocation_state::getContainerObjRegion(statePrev, Sym); 34990b57cec5SDimitry Andric const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion); 35000b57cec5SDimitry Andric QualType ObjTy = TypedRegion->getValueType(); 350181ad6265SDimitry Andric OS << "Inner buffer of '" << ObjTy << "' "; 35020b57cec5SDimitry Andric 35030b57cec5SDimitry Andric if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) { 35040b57cec5SDimitry Andric OS << "deallocated by call to destructor"; 3505a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>( 3506a7dea167SDimitry Andric Sym, "Returning; inner buffer was deallocated"); 35070b57cec5SDimitry Andric } else { 35080b57cec5SDimitry Andric OS << "reallocated by call to '"; 3509a7dea167SDimitry Andric const Stmt *S = RSCurr->getStmt(); 35100b57cec5SDimitry Andric if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) { 3511e8d8bef9SDimitry Andric OS << MemCallE->getMethodDecl()->getDeclName(); 35120b57cec5SDimitry Andric } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) { 3513e8d8bef9SDimitry Andric OS << OpCallE->getDirectCallee()->getDeclName(); 35140b57cec5SDimitry Andric } else if (const auto *CallE = dyn_cast<CallExpr>(S)) { 35150b57cec5SDimitry Andric auto &CEMgr = BRC.getStateManager().getCallEventManager(); 351606c3fb27SDimitry Andric CallEventRef<> Call = 351706c3fb27SDimitry Andric CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0}); 3518e8d8bef9SDimitry Andric if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl())) 3519e8d8bef9SDimitry Andric OS << D->getDeclName(); 3520e8d8bef9SDimitry Andric else 3521e8d8bef9SDimitry Andric OS << "unknown"; 35220b57cec5SDimitry Andric } 35230b57cec5SDimitry Andric OS << "'"; 3524a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>( 3525a7dea167SDimitry Andric Sym, "Returning; inner buffer was reallocated"); 35260b57cec5SDimitry Andric } 35270b57cec5SDimitry Andric Msg = OS.str(); 35280b57cec5SDimitry Andric break; 35290b57cec5SDimitry Andric } 35300b57cec5SDimitry Andric case AF_None: 35310b57cec5SDimitry Andric llvm_unreachable("Unhandled allocation family!"); 35320b57cec5SDimitry Andric } 35330b57cec5SDimitry Andric 35340b57cec5SDimitry Andric // See if we're releasing memory while inlining a destructor 35350b57cec5SDimitry Andric // (or one of its callees). This turns on various common 35360b57cec5SDimitry Andric // false positive suppressions. 35370b57cec5SDimitry Andric bool FoundAnyDestructor = false; 35380b57cec5SDimitry Andric for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) { 35390b57cec5SDimitry Andric if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) { 35400b57cec5SDimitry Andric if (isReferenceCountingPointerDestructor(DD)) { 35410b57cec5SDimitry Andric // This immediately looks like a reference-counting destructor. 35420b57cec5SDimitry Andric // We're bad at guessing the original reference count of the object, 35430b57cec5SDimitry Andric // so suppress the report for now. 35440b57cec5SDimitry Andric BR.markInvalid(getTag(), DD); 35450b57cec5SDimitry Andric } else if (!FoundAnyDestructor) { 35460b57cec5SDimitry Andric assert(!ReleaseDestructorLC && 35470b57cec5SDimitry Andric "There can be only one release point!"); 35480b57cec5SDimitry Andric // Suspect that it's a reference counting pointer destructor. 35490b57cec5SDimitry Andric // On one of the next nodes might find out that it has atomic 35500b57cec5SDimitry Andric // reference counting operations within it (see the code above), 35510b57cec5SDimitry Andric // and if so, we'd conclude that it likely is a reference counting 35520b57cec5SDimitry Andric // pointer destructor. 35530b57cec5SDimitry Andric ReleaseDestructorLC = LC->getStackFrame(); 35540b57cec5SDimitry Andric // It is unlikely that releasing memory is delegated to a destructor 35550b57cec5SDimitry Andric // inside a destructor of a shared pointer, because it's fairly hard 35560b57cec5SDimitry Andric // to pass the information that the pointer indeed needs to be 35570b57cec5SDimitry Andric // released into it. So we're only interested in the innermost 35580b57cec5SDimitry Andric // destructor. 35590b57cec5SDimitry Andric FoundAnyDestructor = true; 35600b57cec5SDimitry Andric } 35610b57cec5SDimitry Andric } 35620b57cec5SDimitry Andric } 3563a7dea167SDimitry Andric } else if (isRelinquished(RSCurr, RSPrev, S)) { 35640b57cec5SDimitry Andric Msg = "Memory ownership is transferred"; 3565a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, ""); 3566a7dea167SDimitry Andric } else if (hasReallocFailed(RSCurr, RSPrev, S)) { 35670b57cec5SDimitry Andric Mode = ReallocationFailed; 35680b57cec5SDimitry Andric Msg = "Reallocation failed"; 3569a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>( 3570a7dea167SDimitry Andric Sym, "Reallocation failed"); 35710b57cec5SDimitry Andric 35720b57cec5SDimitry Andric if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) { 35730b57cec5SDimitry Andric // Is it possible to fail two reallocs WITHOUT testing in between? 35740b57cec5SDimitry Andric assert((!FailedReallocSymbol || FailedReallocSymbol == sym) && 35750b57cec5SDimitry Andric "We only support one failed realloc at a time."); 35760b57cec5SDimitry Andric BR.markInteresting(sym); 35770b57cec5SDimitry Andric FailedReallocSymbol = sym; 35780b57cec5SDimitry Andric } 35790b57cec5SDimitry Andric } 35800b57cec5SDimitry Andric 35810b57cec5SDimitry Andric // We are in a special mode if a reallocation failed later in the path. 35820b57cec5SDimitry Andric } else if (Mode == ReallocationFailed) { 35830b57cec5SDimitry Andric assert(FailedReallocSymbol && "No symbol to look for."); 35840b57cec5SDimitry Andric 35850b57cec5SDimitry Andric // Is this is the first appearance of the reallocated symbol? 35860b57cec5SDimitry Andric if (!statePrev->get<RegionState>(FailedReallocSymbol)) { 35870b57cec5SDimitry Andric // We're at the reallocation point. 35880b57cec5SDimitry Andric Msg = "Attempt to reallocate memory"; 3589a7dea167SDimitry Andric StackHint = std::make_unique<StackHintGeneratorForSymbol>( 3590a7dea167SDimitry Andric Sym, "Returned reallocated memory"); 35910b57cec5SDimitry Andric FailedReallocSymbol = nullptr; 35920b57cec5SDimitry Andric Mode = Normal; 35930b57cec5SDimitry Andric } 35940b57cec5SDimitry Andric } 35950b57cec5SDimitry Andric 3596a7dea167SDimitry Andric if (Msg.empty()) { 3597a7dea167SDimitry Andric assert(!StackHint); 35980b57cec5SDimitry Andric return nullptr; 3599a7dea167SDimitry Andric } 3600a7dea167SDimitry Andric 36010b57cec5SDimitry Andric assert(StackHint); 36020b57cec5SDimitry Andric 36030b57cec5SDimitry Andric // Generate the extra diagnostic. 36040b57cec5SDimitry Andric PathDiagnosticLocation Pos; 36050b57cec5SDimitry Andric if (!S) { 3606a7dea167SDimitry Andric assert(RSCurr->getAllocationFamily() == AF_InnerBuffer); 36070b57cec5SDimitry Andric auto PostImplCall = N->getLocation().getAs<PostImplicitCall>(); 36080b57cec5SDimitry Andric if (!PostImplCall) 36090b57cec5SDimitry Andric return nullptr; 36100b57cec5SDimitry Andric Pos = PathDiagnosticLocation(PostImplCall->getLocation(), 36110b57cec5SDimitry Andric BRC.getSourceManager()); 36120b57cec5SDimitry Andric } else { 36130b57cec5SDimitry Andric Pos = PathDiagnosticLocation(S, BRC.getSourceManager(), 36140b57cec5SDimitry Andric N->getLocationContext()); 36150b57cec5SDimitry Andric } 36160b57cec5SDimitry Andric 3617a7dea167SDimitry Andric auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true); 3618a7dea167SDimitry Andric BR.addCallStackHint(P, std::move(StackHint)); 3619a7dea167SDimitry Andric return P; 36200b57cec5SDimitry Andric } 36210b57cec5SDimitry Andric 36220b57cec5SDimitry Andric void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, 36230b57cec5SDimitry Andric const char *NL, const char *Sep) const { 36240b57cec5SDimitry Andric 36250b57cec5SDimitry Andric RegionStateTy RS = State->get<RegionState>(); 36260b57cec5SDimitry Andric 36270b57cec5SDimitry Andric if (!RS.isEmpty()) { 36280b57cec5SDimitry Andric Out << Sep << "MallocChecker :" << NL; 362906c3fb27SDimitry Andric for (auto [Sym, Data] : RS) { 363006c3fb27SDimitry Andric const RefState *RefS = State->get<RegionState>(Sym); 36310b57cec5SDimitry Andric AllocationFamily Family = RefS->getAllocationFamily(); 3632bdd1243dSDimitry Andric std::optional<MallocChecker::CheckKind> CheckKind = 3633bdd1243dSDimitry Andric getCheckIfTracked(Family); 363481ad6265SDimitry Andric if (!CheckKind) 36350b57cec5SDimitry Andric CheckKind = getCheckIfTracked(Family, true); 36360b57cec5SDimitry Andric 363706c3fb27SDimitry Andric Sym->dumpToStream(Out); 36380b57cec5SDimitry Andric Out << " : "; 363906c3fb27SDimitry Andric Data.dump(Out); 364081ad6265SDimitry Andric if (CheckKind) 36410b57cec5SDimitry Andric Out << " (" << CheckNames[*CheckKind].getName() << ")"; 36420b57cec5SDimitry Andric Out << NL; 36430b57cec5SDimitry Andric } 36440b57cec5SDimitry Andric } 36450b57cec5SDimitry Andric } 36460b57cec5SDimitry Andric 36470b57cec5SDimitry Andric namespace clang { 36480b57cec5SDimitry Andric namespace ento { 36490b57cec5SDimitry Andric namespace allocation_state { 36500b57cec5SDimitry Andric 36510b57cec5SDimitry Andric ProgramStateRef 36520b57cec5SDimitry Andric markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) { 36530b57cec5SDimitry Andric AllocationFamily Family = AF_InnerBuffer; 36540b57cec5SDimitry Andric return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin)); 36550b57cec5SDimitry Andric } 36560b57cec5SDimitry Andric 36570b57cec5SDimitry Andric } // end namespace allocation_state 36580b57cec5SDimitry Andric } // end namespace ento 36590b57cec5SDimitry Andric } // end namespace clang 36600b57cec5SDimitry Andric 36610b57cec5SDimitry Andric // Intended to be used in InnerPointerChecker to register the part of 36620b57cec5SDimitry Andric // MallocChecker connected to it. 36630b57cec5SDimitry Andric void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) { 36640b57cec5SDimitry Andric MallocChecker *checker = mgr.getChecker<MallocChecker>(); 36650b57cec5SDimitry Andric checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true; 36660b57cec5SDimitry Andric checker->CheckNames[MallocChecker::CK_InnerPointerChecker] = 3667a7dea167SDimitry Andric mgr.getCurrentCheckerName(); 36680b57cec5SDimitry Andric } 36690b57cec5SDimitry Andric 36700b57cec5SDimitry Andric void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { 36710b57cec5SDimitry Andric auto *checker = mgr.registerChecker<MallocChecker>(); 36725ffd83dbSDimitry Andric checker->ShouldIncludeOwnershipAnnotatedFunctions = 3673a7dea167SDimitry Andric mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic"); 3674349cc55cSDimitry Andric checker->ShouldRegisterNoOwnershipChangeVisitor = 3675349cc55cSDimitry Andric mgr.getAnalyzerOptions().getCheckerBooleanOption( 3676349cc55cSDimitry Andric checker, "AddNoOwnershipChangeNotes"); 36770b57cec5SDimitry Andric } 36780b57cec5SDimitry Andric 36795ffd83dbSDimitry Andric bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) { 36800b57cec5SDimitry Andric return true; 36810b57cec5SDimitry Andric } 36820b57cec5SDimitry Andric 36830b57cec5SDimitry Andric #define REGISTER_CHECKER(name) \ 36840b57cec5SDimitry Andric void ento::register##name(CheckerManager &mgr) { \ 36850b57cec5SDimitry Andric MallocChecker *checker = mgr.getChecker<MallocChecker>(); \ 36860b57cec5SDimitry Andric checker->ChecksEnabled[MallocChecker::CK_##name] = true; \ 3687a7dea167SDimitry Andric checker->CheckNames[MallocChecker::CK_##name] = \ 3688a7dea167SDimitry Andric mgr.getCurrentCheckerName(); \ 36890b57cec5SDimitry Andric } \ 36900b57cec5SDimitry Andric \ 36915ffd83dbSDimitry Andric bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 36920b57cec5SDimitry Andric 36930b57cec5SDimitry Andric REGISTER_CHECKER(MallocChecker) 36940b57cec5SDimitry Andric REGISTER_CHECKER(NewDeleteChecker) 36950b57cec5SDimitry Andric REGISTER_CHECKER(NewDeleteLeaksChecker) 36960b57cec5SDimitry Andric REGISTER_CHECKER(MismatchedDeallocatorChecker) 3697*0fca6ea1SDimitry Andric REGISTER_CHECKER(TaintedAllocChecker) 3698