xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
RefState(Kind k,const Stmt * s,AllocationFamily family)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:
isAllocated() const1650b57cec5SDimitry Andric   bool isAllocated() const { return K == Allocated; }
isAllocatedOfSizeZero() const1660b57cec5SDimitry Andric   bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
isReleased() const1670b57cec5SDimitry Andric   bool isReleased() const { return K == Released; }
isRelinquished() const1680b57cec5SDimitry Andric   bool isRelinquished() const { return K == Relinquished; }
isEscaped() const1690b57cec5SDimitry Andric   bool isEscaped() const { return K == Escaped; }
getAllocationFamily() const170a7dea167SDimitry Andric   AllocationFamily getAllocationFamily() const { return Family; }
getStmt() const1710b57cec5SDimitry Andric   const Stmt *getStmt() const { return S; }
1720b57cec5SDimitry Andric 
operator ==(const RefState & X) const1730b57cec5SDimitry Andric   bool operator==(const RefState &X) const {
1740b57cec5SDimitry Andric     return K == X.K && S == X.S && Family == X.Family;
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric 
getAllocated(AllocationFamily family,const Stmt * s)177a7dea167SDimitry Andric   static RefState getAllocated(AllocationFamily family, const Stmt *s) {
1780b57cec5SDimitry Andric     return RefState(Allocated, s, family);
1790b57cec5SDimitry Andric   }
getAllocatedOfSizeZero(const RefState * RS)1800b57cec5SDimitry Andric   static RefState getAllocatedOfSizeZero(const RefState *RS) {
1810b57cec5SDimitry Andric     return RefState(AllocatedOfSizeZero, RS->getStmt(),
1820b57cec5SDimitry Andric                     RS->getAllocationFamily());
1830b57cec5SDimitry Andric   }
getReleased(AllocationFamily family,const Stmt * s)184a7dea167SDimitry Andric   static RefState getReleased(AllocationFamily family, const Stmt *s) {
1850b57cec5SDimitry Andric     return RefState(Released, s, family);
1860b57cec5SDimitry Andric   }
getRelinquished(AllocationFamily family,const Stmt * s)187a7dea167SDimitry Andric   static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
1880b57cec5SDimitry Andric     return RefState(Relinquished, s, family);
1890b57cec5SDimitry Andric   }
getEscaped(const RefState * RS)1900b57cec5SDimitry Andric   static RefState getEscaped(const RefState *RS) {
1910b57cec5SDimitry Andric     return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const1940b57cec5SDimitry 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 
dump(raw_ostream & OS) const200a7dea167SDimitry 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 
dump() const2110b57cec5SDimitry 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 
ReallocPair__anon0957485b0311::ReallocPair268a7dea167SDimitry Andric   ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
269a7dea167SDimitry Andric       : ReallocatedSym(S), Kind(K) {}
Profile__anon0957485b0311::ReallocPair2700b57cec5SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
2710b57cec5SDimitry Andric     ID.AddInteger(Kind);
2720b57cec5SDimitry Andric     ID.AddPointer(ReallocatedSym);
2730b57cec5SDimitry Andric   }
operator ==__anon0957485b0311::ReallocPair2740b57cec5SDimitry 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);
isStandardNewDelete(const CallEvent & Call)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.
isFreeingCallAsWritten(const CallExpr & Call) const77681ad6265SDimitry 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 
hasResourceStateChanged(ProgramStateRef CallEnterState,ProgramStateRef CallExitEndState)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.
doesFnIntendToHandleOwnership(const Decl * Callee,ASTContext & ACtx)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 
emitNote(const ExplodedNode * N)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:
NoMemOwnershipChangeVisitor(SymbolRef Sym,const MallocChecker * Checker)831*0fca6ea1SDimitry Andric   NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
832*0fca6ea1SDimitry Andric       : NoOwnershipChangeVisitor(Sym, Checker) {}
833349cc55cSDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const834349cc55cSDimitry 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:
MallocBugVisitor(SymbolRef S,bool isLeak=false)8710b57cec5SDimitry Andric   MallocBugVisitor(SymbolRef S, bool isLeak = false)
8720b57cec5SDimitry Andric       : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
8730b57cec5SDimitry Andric         ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
8740b57cec5SDimitry Andric 
getTag()8750b57cec5SDimitry Andric   static void *getTag() {
8760b57cec5SDimitry Andric     static int Tag = 0;
8770b57cec5SDimitry Andric     return &Tag;
8780b57cec5SDimitry Andric   }
8790b57cec5SDimitry Andric 
Profile(llvm::FoldingSetNodeID & ID) const8800b57cec5SDimitry 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.
isAllocated(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)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.
isReleased(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)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.
isRelinquished(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)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.
hasReallocFailed(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)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 
getEndPath(BugReporterContext & BRC,const ExplodedNode * EndPathNode,PathSensitiveBugReport & BR)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:
StackHintGeneratorForReallocationFailed(SymbolRef S,StringRef M)9490b57cec5SDimitry Andric     StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
9500b57cec5SDimitry Andric         : StackHintGeneratorForSymbol(S, M) {}
9510b57cec5SDimitry Andric 
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)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 
getMessageForReturn(const CallExpr * CallExpr)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:
StopTrackingCallback(ProgramStateRef st)9810b57cec5SDimitry Andric   StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const9820b57cec5SDimitry Andric   ProgramStateRef getState() const { return state; }
9830b57cec5SDimitry Andric 
VisitSymbol(SymbolRef sym)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 
isStandardNewDelete(const FunctionDecl * FD)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 
isFreeingOwnershipAttrCall(const FunctionDecl * Func)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 
isFreeingCall(const CallEvent & Call) const102381ad6265SDimitry 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 
isMemCall(const CallEvent & Call) const10335ffd83dbSDimitry 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>
performKernelMalloc(const CallEvent & Call,CheckerContext & C,const ProgramStateRef & State) const10465ffd83dbSDimitry 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 
evalMulForBufferSize(CheckerContext & C,const Expr * Blocks,const Expr * BlockBytes)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 
checkBasicAlloc(const CallEvent & Call,CheckerContext & C) const11425ffd83dbSDimitry 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 
checkKernelMalloc(const CallEvent & Call,CheckerContext & C) const11515ffd83dbSDimitry 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 
isStandardRealloc(const CallEvent & Call)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 
isGRealloc(const CallEvent & Call)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 
checkRealloc(const CallEvent & Call,CheckerContext & C,bool ShouldFreeOnFail) const11865ffd83dbSDimitry 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 
checkCalloc(const CallEvent & Call,CheckerContext & C) const12025ffd83dbSDimitry 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 
checkFree(const CallEvent & Call,CheckerContext & C) const12115ffd83dbSDimitry 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 
checkAlloca(const CallEvent & Call,CheckerContext & C) const12215ffd83dbSDimitry 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 
checkStrdup(const CallEvent & Call,CheckerContext & C) const12305ffd83dbSDimitry 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 
checkIfNameIndex(const CallEvent & Call,CheckerContext & C) const12415ffd83dbSDimitry 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 
checkIfFreeNameIndex(const CallEvent & Call,CheckerContext & C) const12525ffd83dbSDimitry 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 
checkCXXNewOrCXXDelete(const CallEvent & Call,CheckerContext & C) const12615ffd83dbSDimitry 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 
checkGMalloc0(const CallEvent & Call,CheckerContext & C) const13025ffd83dbSDimitry 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 
checkGMemdup(const CallEvent & Call,CheckerContext & C) const13125ffd83dbSDimitry 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 
checkGMallocN(const CallEvent & Call,CheckerContext & C) const13215ffd83dbSDimitry 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 
checkGMallocN0(const CallEvent & Call,CheckerContext & C) const13325ffd83dbSDimitry 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 
isFromStdNamespace(const CallEvent & Call)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 
preGetdelim(const CallEvent & Call,CheckerContext & C) const1350*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 
checkGetdelim(const CallEvent & Call,CheckerContext & C) const1373*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 
checkReallocN(const CallEvent & Call,CheckerContext & C) const14005ffd83dbSDimitry 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 
checkOwnershipAttr(const CallEvent & Call,CheckerContext & C) const14105ffd83dbSDimitry 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 
checkPostCall(const CallEvent & Call,CheckerContext & C) const14395ffd83dbSDimitry 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.
ProcessZeroAllocCheck(const CallEvent & Call,const unsigned IndexOfSizeArg,ProgramStateRef State,std::optional<SVal> RetVal)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 
getDeepPointeeType(QualType T)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.
hasNonTrivialConstructorCall(const CXXNewExpr * NE)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
processNewAllocation(const CXXAllocatorCall & Call,CheckerContext & C,AllocationFamily Family) const15775ffd83dbSDimitry 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 
checkNewAllocator(const CXXAllocatorCall & Call,CheckerContext & C) const16095ffd83dbSDimitry 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 
isKnownDeallocObjCMethodName(const ObjCMethodCall & Call)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 
getFreeWhenDoneArg(const ObjCMethodCall & Call)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 
checkPostObjCMessage(const ObjCMethodCall & Call,CheckerContext & C) const16420b57cec5SDimitry 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
MallocMemReturnsAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const16675ffd83dbSDimitry 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 
MallocMemAux(CheckerContext & C,const CallEvent & Call,const Expr * SizeEx,SVal Init,ProgramStateRef State,AllocationFamily Family) const16840b57cec5SDimitry 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 
reportTaintBug(StringRef Msg,ProgramStateRef State,CheckerContext & C,llvm::ArrayRef<SymbolRef> TaintedSyms,AllocationFamily Family) const1696*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 
checkTaintedness(CheckerContext & C,const CallEvent & Call,const SVal SizeSVal,ProgramStateRef State,AllocationFamily Family) const1713*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 
MallocMemAux(CheckerContext & C,const CallEvent & Call,SVal Size,SVal Init,ProgramStateRef State,AllocationFamily Family) const17520b57cec5SDimitry 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 
MallocUpdateRefState(CheckerContext & C,const Expr * E,ProgramStateRef State,AllocationFamily Family,std::optional<SVal> RetVal)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 
FreeMemAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const18260b57cec5SDimitry 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 
FreeMemAux(CheckerContext & C,const CallEvent & Call,ProgramStateRef State,unsigned Num,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure) const18495ffd83dbSDimitry 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.
didPreviousFreeFail(ProgramStateRef State,SymbolRef Sym,SymbolRef & RetStatusSymbol)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 
printMemFnName(raw_ostream & os,CheckerContext & C,const Expr * E)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 
printExpectedAllocName(raw_ostream & os,AllocationFamily Family)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 
printExpectedDeallocName(raw_ostream & os,AllocationFamily Family)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
FreeMemAux(CheckerContext & C,const Expr * ArgExpr,const CallEvent & Call,ProgramStateRef State,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure,std::optional<SVal> ArgValOpt) const1945*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>
getCheckIfTracked(AllocationFamily Family,bool IsALeakCheck) const21200b57cec5SDimitry 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>
getCheckIfTracked(CheckerContext & C,SymbolRef Sym,bool IsALeakCheck) const21550b57cec5SDimitry 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 
SummarizeValue(raw_ostream & os,SVal V)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 
SummarizeRegion(raw_ostream & os,const MemRegion * MR)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 
HandleNonHeapDealloc(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family) const22545ffd83dbSDimitry 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 
HandleFreeAlloca(CheckerContext & C,SVal ArgVal,SourceRange Range) const23025ffd83dbSDimitry 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 
HandleMismatchedDealloc(CheckerContext & C,SourceRange Range,const Expr * DeallocExpr,const RefState * RS,SymbolRef Sym,bool OwnershipTransferred) const23305ffd83dbSDimitry 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 
HandleOffsetFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family,const Expr * AllocExpr) const23875ffd83dbSDimitry 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 
HandleUseAfterFree(CheckerContext & C,SourceRange Range,SymbolRef Sym) const24455ffd83dbSDimitry 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 
HandleDoubleFree(CheckerContext & C,SourceRange Range,bool Released,SymbolRef Sym,SymbolRef PrevSym) const24845ffd83dbSDimitry 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 
HandleDoubleDelete(CheckerContext & C,SymbolRef Sym) const25165ffd83dbSDimitry 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 
HandleUseZeroAlloc(CheckerContext & C,SourceRange Range,SymbolRef Sym) const25425ffd83dbSDimitry 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 
HandleFunctionPtrFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * FreeExpr,AllocationFamily Family) const25745ffd83dbSDimitry 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
ReallocMemAux(CheckerContext & C,const CallEvent & Call,bool ShouldFreeOnFail,ProgramStateRef State,AllocationFamily Family,bool SuffixWithN) const26145ffd83dbSDimitry 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 
CallocMem(CheckerContext & C,const CallEvent & Call,ProgramStateRef State) const27225ffd83dbSDimitry 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 
getAllocationSite(const ExplodedNode * N,SymbolRef Sym,CheckerContext & C)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 
HandleLeak(SymbolRef Sym,ExplodedNode * N,CheckerContext & C) const27805ffd83dbSDimitry 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 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const28450b57cec5SDimitry 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 
checkPreCall(const CallEvent & Call,CheckerContext & C) const29030b57cec5SDimitry 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 
checkPreStmt(const ReturnStmt * S,CheckerContext & C) const29690b57cec5SDimitry 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().
checkEndFunction(const ReturnStmt * S,CheckerContext & C) const29770b57cec5SDimitry Andric void MallocChecker::checkEndFunction(const ReturnStmt *S,
29780b57cec5SDimitry Andric                                      CheckerContext &C) const {
29790b57cec5SDimitry Andric   checkEscapeOnReturn(S, C);
29800b57cec5SDimitry Andric }
29810b57cec5SDimitry Andric 
checkEscapeOnReturn(const ReturnStmt * S,CheckerContext & C) const29820b57cec5SDimitry 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.
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const30130b57cec5SDimitry 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 
isReleased(SymbolRef Sym,CheckerContext & C)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 
suppressDeallocationsInSuspiciousContexts(const CallEvent & Call,CheckerContext & C) const30520b57cec5SDimitry 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 
checkUseAfterFree(SymbolRef Sym,CheckerContext & C,const Stmt * S) const30810b57cec5SDimitry 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 
checkUseZeroAllocated(SymbolRef Sym,CheckerContext & C,const Stmt * S) const30920b57cec5SDimitry 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 
checkDoubleDelete(SymbolRef Sym,CheckerContext & C) const31050b57cec5SDimitry 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.
checkLocation(SVal l,bool isLoad,const Stmt * S,CheckerContext & C) const31150b57cec5SDimitry 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.
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const31260b57cec5SDimitry 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 
mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent * Call,ProgramStateRef State,SymbolRef & EscapingSymbol) const31700b57cec5SDimitry 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 
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3334a7dea167SDimitry 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 
checkConstPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3342a7dea167SDimitry 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 
checkIfNewOrNewArrayFamily(const RefState * RS)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 
checkPointerEscapeAux(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,bool IsConstPointerEscape) const3356a7dea167SDimitry 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 
isArgZERO_SIZE_PTR(ProgramStateRef State,CheckerContext & C,SVal ArgVal) const33825ffd83dbSDimitry 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 
findFailedReallocSymbol(ProgramStateRef currState,ProgramStateRef prevState)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 
isReferenceCountingPointerDestructor(const CXXDestructorDecl * DD)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 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)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 
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const36220b57cec5SDimitry 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
markReleased(ProgramStateRef State,SymbolRef Sym,const Expr * Origin)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.
registerInnerPointerCheckerAux(CheckerManager & mgr)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 
registerDynamicMemoryModeling(CheckerManager & mgr)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 
shouldRegisterDynamicMemoryModeling(const CheckerManager & mgr)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