xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file defines a variety of memory management related checkers, such as
10e5dd7070Spatrick // leak, double free, and use-after-free.
11e5dd7070Spatrick //
12e5dd7070Spatrick // The following checkers are defined here:
13e5dd7070Spatrick //
14e5dd7070Spatrick //   * MallocChecker
15e5dd7070Spatrick //       Despite its name, it models all sorts of memory allocations and
16e5dd7070Spatrick //       de- or reallocation, including but not limited to malloc, free,
17e5dd7070Spatrick //       relloc, new, delete. It also reports on a variety of memory misuse
18e5dd7070Spatrick //       errors.
19e5dd7070Spatrick //       Many other checkers interact very closely with this checker, in fact,
20e5dd7070Spatrick //       most are merely options to this one. Other checkers may register
21e5dd7070Spatrick //       MallocChecker, but do not enable MallocChecker's reports (more details
22e5dd7070Spatrick //       to follow around its field, ChecksEnabled).
23e5dd7070Spatrick //       It also has a boolean "Optimistic" checker option, which if set to true
24e5dd7070Spatrick //       will cause the checker to model user defined memory management related
25e5dd7070Spatrick //       functions annotated via the attribute ownership_takes, ownership_holds
26e5dd7070Spatrick //       and ownership_returns.
27e5dd7070Spatrick //
28e5dd7070Spatrick //   * NewDeleteChecker
29e5dd7070Spatrick //       Enables the modeling of new, new[], delete, delete[] in MallocChecker,
30e5dd7070Spatrick //       and checks for related double-free and use-after-free errors.
31e5dd7070Spatrick //
32e5dd7070Spatrick //   * NewDeleteLeaksChecker
33e5dd7070Spatrick //       Checks for leaks related to new, new[], delete, delete[].
34e5dd7070Spatrick //       Depends on NewDeleteChecker.
35e5dd7070Spatrick //
36e5dd7070Spatrick //   * MismatchedDeallocatorChecker
37e5dd7070Spatrick //       Enables checking whether memory is deallocated with the correspending
38e5dd7070Spatrick //       allocation function in MallocChecker, such as malloc() allocated
39e5dd7070Spatrick //       regions are only freed by free(), new by delete, new[] by delete[].
40e5dd7070Spatrick //
41e5dd7070Spatrick //  InnerPointerChecker interacts very closely with MallocChecker, but unlike
42e5dd7070Spatrick //  the above checkers, it has it's own file, hence the many InnerPointerChecker
43e5dd7070Spatrick //  related headers and non-static functions.
44e5dd7070Spatrick //
45e5dd7070Spatrick //===----------------------------------------------------------------------===//
46e5dd7070Spatrick 
47ec727ea7Spatrick #include "AllocationState.h"
48e5dd7070Spatrick #include "InterCheckerAPI.h"
49e5dd7070Spatrick #include "clang/AST/Attr.h"
50ec727ea7Spatrick #include "clang/AST/DeclCXX.h"
51*12c85518Srobert #include "clang/AST/DeclTemplate.h"
52ec727ea7Spatrick #include "clang/AST/Expr.h"
53ec727ea7Spatrick #include "clang/AST/ExprCXX.h"
54e5dd7070Spatrick #include "clang/AST/ParentMap.h"
55*12c85518Srobert #include "clang/ASTMatchers/ASTMatchFinder.h"
56*12c85518Srobert #include "clang/ASTMatchers/ASTMatchers.h"
57*12c85518Srobert #include "clang/Analysis/ProgramPoint.h"
58ec727ea7Spatrick #include "clang/Basic/LLVM.h"
59e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
60e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
61e5dd7070Spatrick #include "clang/Lex/Lexer.h"
62ec727ea7Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
63e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
64e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
65e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
66e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
67*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
68e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
69e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
70ec727ea7Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
71a9ac8606Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
72*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
73e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
74e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
75ec727ea7Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
76ec727ea7Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
77*12c85518Srobert #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
78e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
79e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
80*12c85518Srobert #include "llvm/ADT/SetOperations.h"
81e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
82e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
83*12c85518Srobert #include "llvm/Support/Casting.h"
84ec727ea7Spatrick #include "llvm/Support/Compiler.h"
85ec727ea7Spatrick #include "llvm/Support/ErrorHandling.h"
86*12c85518Srobert #include "llvm/Support/raw_ostream.h"
87e5dd7070Spatrick #include <climits>
88ec727ea7Spatrick #include <functional>
89*12c85518Srobert #include <optional>
90e5dd7070Spatrick #include <utility>
91e5dd7070Spatrick 
92e5dd7070Spatrick using namespace clang;
93e5dd7070Spatrick using namespace ento;
94ec727ea7Spatrick using namespace std::placeholders;
95e5dd7070Spatrick 
96e5dd7070Spatrick //===----------------------------------------------------------------------===//
97ec727ea7Spatrick // The types of allocation we're modeling. This is used to check whether a
98ec727ea7Spatrick // dynamically allocated object is deallocated with the correct function, like
99ec727ea7Spatrick // not using operator delete on an object created by malloc(), or alloca regions
100ec727ea7Spatrick // aren't ever deallocated manually.
101e5dd7070Spatrick //===----------------------------------------------------------------------===//
102e5dd7070Spatrick 
103e5dd7070Spatrick namespace {
104e5dd7070Spatrick 
105e5dd7070Spatrick // Used to check correspondence between allocators and deallocators.
106e5dd7070Spatrick enum AllocationFamily {
107e5dd7070Spatrick   AF_None,
108e5dd7070Spatrick   AF_Malloc,
109e5dd7070Spatrick   AF_CXXNew,
110e5dd7070Spatrick   AF_CXXNewArray,
111e5dd7070Spatrick   AF_IfNameIndex,
112e5dd7070Spatrick   AF_Alloca,
113e5dd7070Spatrick   AF_InnerBuffer
114e5dd7070Spatrick };
115e5dd7070Spatrick 
116e5dd7070Spatrick } // end of anonymous namespace
117e5dd7070Spatrick 
118e5dd7070Spatrick /// Print names of allocators and deallocators.
119e5dd7070Spatrick ///
120e5dd7070Spatrick /// \returns true on success.
121ec727ea7Spatrick static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);
122e5dd7070Spatrick 
123ec727ea7Spatrick /// Print expected name of an allocator based on the deallocator's family
124ec727ea7Spatrick /// derived from the DeallocExpr.
125ec727ea7Spatrick static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);
126e5dd7070Spatrick 
127e5dd7070Spatrick /// Print expected name of a deallocator based on the allocator's
128e5dd7070Spatrick /// family.
129e5dd7070Spatrick static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
130e5dd7070Spatrick 
131e5dd7070Spatrick //===----------------------------------------------------------------------===//
132e5dd7070Spatrick // The state of a symbol, in terms of memory management.
133e5dd7070Spatrick //===----------------------------------------------------------------------===//
134e5dd7070Spatrick 
135e5dd7070Spatrick namespace {
136e5dd7070Spatrick 
137e5dd7070Spatrick class RefState {
138e5dd7070Spatrick   enum Kind {
139e5dd7070Spatrick     // Reference to allocated memory.
140e5dd7070Spatrick     Allocated,
141e5dd7070Spatrick     // Reference to zero-allocated memory.
142e5dd7070Spatrick     AllocatedOfSizeZero,
143e5dd7070Spatrick     // Reference to released/freed memory.
144e5dd7070Spatrick     Released,
145e5dd7070Spatrick     // The responsibility for freeing resources has transferred from
146e5dd7070Spatrick     // this reference. A relinquished symbol should not be freed.
147e5dd7070Spatrick     Relinquished,
148e5dd7070Spatrick     // We are no longer guaranteed to have observed all manipulations
149e5dd7070Spatrick     // of this pointer/memory. For example, it could have been
150e5dd7070Spatrick     // passed as a parameter to an opaque function.
151e5dd7070Spatrick     Escaped
152e5dd7070Spatrick   };
153e5dd7070Spatrick 
154e5dd7070Spatrick   const Stmt *S;
155e5dd7070Spatrick 
156e5dd7070Spatrick   Kind K;
157e5dd7070Spatrick   AllocationFamily Family;
158e5dd7070Spatrick 
RefState(Kind k,const Stmt * s,AllocationFamily family)159e5dd7070Spatrick   RefState(Kind k, const Stmt *s, AllocationFamily family)
160e5dd7070Spatrick       : S(s), K(k), Family(family) {
161e5dd7070Spatrick     assert(family != AF_None);
162e5dd7070Spatrick   }
163e5dd7070Spatrick 
164e5dd7070Spatrick public:
isAllocated() const165e5dd7070Spatrick   bool isAllocated() const { return K == Allocated; }
isAllocatedOfSizeZero() const166e5dd7070Spatrick   bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
isReleased() const167e5dd7070Spatrick   bool isReleased() const { return K == Released; }
isRelinquished() const168e5dd7070Spatrick   bool isRelinquished() const { return K == Relinquished; }
isEscaped() const169e5dd7070Spatrick   bool isEscaped() const { return K == Escaped; }
getAllocationFamily() const170e5dd7070Spatrick   AllocationFamily getAllocationFamily() const { return Family; }
getStmt() const171e5dd7070Spatrick   const Stmt *getStmt() const { return S; }
172e5dd7070Spatrick 
operator ==(const RefState & X) const173e5dd7070Spatrick   bool operator==(const RefState &X) const {
174e5dd7070Spatrick     return K == X.K && S == X.S && Family == X.Family;
175e5dd7070Spatrick   }
176e5dd7070Spatrick 
getAllocated(AllocationFamily family,const Stmt * s)177e5dd7070Spatrick   static RefState getAllocated(AllocationFamily family, const Stmt *s) {
178e5dd7070Spatrick     return RefState(Allocated, s, family);
179e5dd7070Spatrick   }
getAllocatedOfSizeZero(const RefState * RS)180e5dd7070Spatrick   static RefState getAllocatedOfSizeZero(const RefState *RS) {
181e5dd7070Spatrick     return RefState(AllocatedOfSizeZero, RS->getStmt(),
182e5dd7070Spatrick                     RS->getAllocationFamily());
183e5dd7070Spatrick   }
getReleased(AllocationFamily family,const Stmt * s)184e5dd7070Spatrick   static RefState getReleased(AllocationFamily family, const Stmt *s) {
185e5dd7070Spatrick     return RefState(Released, s, family);
186e5dd7070Spatrick   }
getRelinquished(AllocationFamily family,const Stmt * s)187e5dd7070Spatrick   static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
188e5dd7070Spatrick     return RefState(Relinquished, s, family);
189e5dd7070Spatrick   }
getEscaped(const RefState * RS)190e5dd7070Spatrick   static RefState getEscaped(const RefState *RS) {
191e5dd7070Spatrick     return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
192e5dd7070Spatrick   }
193e5dd7070Spatrick 
Profile(llvm::FoldingSetNodeID & ID) const194e5dd7070Spatrick   void Profile(llvm::FoldingSetNodeID &ID) const {
195e5dd7070Spatrick     ID.AddInteger(K);
196e5dd7070Spatrick     ID.AddPointer(S);
197e5dd7070Spatrick     ID.AddInteger(Family);
198e5dd7070Spatrick   }
199e5dd7070Spatrick 
dump(raw_ostream & OS) const200e5dd7070Spatrick   LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
201e5dd7070Spatrick     switch (K) {
202e5dd7070Spatrick #define CASE(ID) case ID: OS << #ID; break;
203e5dd7070Spatrick     CASE(Allocated)
204e5dd7070Spatrick     CASE(AllocatedOfSizeZero)
205e5dd7070Spatrick     CASE(Released)
206e5dd7070Spatrick     CASE(Relinquished)
207e5dd7070Spatrick     CASE(Escaped)
208e5dd7070Spatrick     }
209e5dd7070Spatrick   }
210e5dd7070Spatrick 
dump() const211e5dd7070Spatrick   LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
212e5dd7070Spatrick };
213e5dd7070Spatrick 
214e5dd7070Spatrick } // end of anonymous namespace
215e5dd7070Spatrick 
216e5dd7070Spatrick REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
217e5dd7070Spatrick 
218e5dd7070Spatrick /// Check if the memory associated with this symbol was released.
219e5dd7070Spatrick static bool isReleased(SymbolRef Sym, CheckerContext &C);
220e5dd7070Spatrick 
221e5dd7070Spatrick /// Update the RefState to reflect the new memory allocation.
222e5dd7070Spatrick /// The optional \p RetVal parameter specifies the newly allocated pointer
223e5dd7070Spatrick /// value; if unspecified, the value of expression \p E is used.
224*12c85518Srobert static ProgramStateRef
225*12c85518Srobert MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
226ec727ea7Spatrick                      AllocationFamily Family,
227*12c85518Srobert                      std::optional<SVal> RetVal = std::nullopt);
228e5dd7070Spatrick 
229e5dd7070Spatrick //===----------------------------------------------------------------------===//
230e5dd7070Spatrick // The modeling of memory reallocation.
231e5dd7070Spatrick //
232e5dd7070Spatrick // The terminology 'toPtr' and 'fromPtr' will be used:
233e5dd7070Spatrick //   toPtr = realloc(fromPtr, 20);
234e5dd7070Spatrick //===----------------------------------------------------------------------===//
235e5dd7070Spatrick 
236e5dd7070Spatrick REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
237e5dd7070Spatrick 
238e5dd7070Spatrick namespace {
239e5dd7070Spatrick 
240e5dd7070Spatrick /// The state of 'fromPtr' after reallocation is known to have failed.
241e5dd7070Spatrick enum OwnershipAfterReallocKind {
242e5dd7070Spatrick   // The symbol needs to be freed (e.g.: realloc)
243e5dd7070Spatrick   OAR_ToBeFreedAfterFailure,
244e5dd7070Spatrick   // The symbol has been freed (e.g.: reallocf)
245e5dd7070Spatrick   OAR_FreeOnFailure,
246e5dd7070Spatrick   // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where
247e5dd7070Spatrick   // 'fromPtr' was allocated:
248e5dd7070Spatrick   //    void Haha(int *ptr) {
249e5dd7070Spatrick   //      ptr = realloc(ptr, 67);
250e5dd7070Spatrick   //      // ...
251e5dd7070Spatrick   //    }
252e5dd7070Spatrick   // ).
253e5dd7070Spatrick   OAR_DoNotTrackAfterFailure
254e5dd7070Spatrick };
255e5dd7070Spatrick 
256e5dd7070Spatrick /// Stores information about the 'fromPtr' symbol after reallocation.
257e5dd7070Spatrick ///
258e5dd7070Spatrick /// This is important because realloc may fail, and that needs special modeling.
259e5dd7070Spatrick /// Whether reallocation failed or not will not be known until later, so we'll
260e5dd7070Spatrick /// store whether upon failure 'fromPtr' will be freed, or needs to be freed
261e5dd7070Spatrick /// later, etc.
262e5dd7070Spatrick struct ReallocPair {
263e5dd7070Spatrick 
264e5dd7070Spatrick   // The 'fromPtr'.
265e5dd7070Spatrick   SymbolRef ReallocatedSym;
266e5dd7070Spatrick   OwnershipAfterReallocKind Kind;
267e5dd7070Spatrick 
ReallocPair__anon4d168ab20311::ReallocPair268e5dd7070Spatrick   ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
269e5dd7070Spatrick       : ReallocatedSym(S), Kind(K) {}
Profile__anon4d168ab20311::ReallocPair270e5dd7070Spatrick   void Profile(llvm::FoldingSetNodeID &ID) const {
271e5dd7070Spatrick     ID.AddInteger(Kind);
272e5dd7070Spatrick     ID.AddPointer(ReallocatedSym);
273e5dd7070Spatrick   }
operator ==__anon4d168ab20311::ReallocPair274e5dd7070Spatrick   bool operator==(const ReallocPair &X) const {
275e5dd7070Spatrick     return ReallocatedSym == X.ReallocatedSym &&
276e5dd7070Spatrick            Kind == X.Kind;
277e5dd7070Spatrick   }
278e5dd7070Spatrick };
279e5dd7070Spatrick 
280e5dd7070Spatrick } // end of anonymous namespace
281e5dd7070Spatrick 
282e5dd7070Spatrick REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
283e5dd7070Spatrick 
284e5dd7070Spatrick /// Tells if the callee is one of the builtin new/delete operators, including
285e5dd7070Spatrick /// placement operators and other standard overloads.
286ec727ea7Spatrick static bool isStandardNewDelete(const FunctionDecl *FD);
isStandardNewDelete(const CallEvent & Call)287ec727ea7Spatrick static bool isStandardNewDelete(const CallEvent &Call) {
288ec727ea7Spatrick   if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))
289ec727ea7Spatrick     return false;
290ec727ea7Spatrick   return isStandardNewDelete(cast<FunctionDecl>(Call.getDecl()));
291ec727ea7Spatrick }
292e5dd7070Spatrick 
293e5dd7070Spatrick //===----------------------------------------------------------------------===//
294e5dd7070Spatrick // Definition of the MallocChecker class.
295e5dd7070Spatrick //===----------------------------------------------------------------------===//
296e5dd7070Spatrick 
297e5dd7070Spatrick namespace {
298e5dd7070Spatrick 
299e5dd7070Spatrick class MallocChecker
300e5dd7070Spatrick     : public Checker<check::DeadSymbols, check::PointerEscape,
301e5dd7070Spatrick                      check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
302ec727ea7Spatrick                      check::EndFunction, check::PreCall, check::PostCall,
303ec727ea7Spatrick                      check::NewAllocator, check::PostStmt<BlockExpr>,
304ec727ea7Spatrick                      check::PostObjCMessage, check::Location, eval::Assume> {
305e5dd7070Spatrick public:
306ec727ea7Spatrick   /// In pessimistic mode, the checker assumes that it does not know which
307ec727ea7Spatrick   /// functions might free the memory.
308ec727ea7Spatrick   /// In optimistic mode, the checker assumes that all user-defined functions
309ec727ea7Spatrick   /// which might free a pointer are annotated.
310*12c85518Srobert   bool ShouldIncludeOwnershipAnnotatedFunctions = false;
311*12c85518Srobert 
312*12c85518Srobert   bool ShouldRegisterNoOwnershipChangeVisitor = false;
313e5dd7070Spatrick 
314e5dd7070Spatrick   /// Many checkers are essentially built into this one, so enabling them will
315e5dd7070Spatrick   /// make MallocChecker perform additional modeling and reporting.
316e5dd7070Spatrick   enum CheckKind {
317e5dd7070Spatrick     /// When a subchecker is enabled but MallocChecker isn't, model memory
318e5dd7070Spatrick     /// management but do not emit warnings emitted with MallocChecker only
319e5dd7070Spatrick     /// enabled.
320e5dd7070Spatrick     CK_MallocChecker,
321e5dd7070Spatrick     CK_NewDeleteChecker,
322e5dd7070Spatrick     CK_NewDeleteLeaksChecker,
323e5dd7070Spatrick     CK_MismatchedDeallocatorChecker,
324e5dd7070Spatrick     CK_InnerPointerChecker,
325e5dd7070Spatrick     CK_NumCheckKinds
326e5dd7070Spatrick   };
327e5dd7070Spatrick 
328e5dd7070Spatrick   using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
329e5dd7070Spatrick 
330*12c85518Srobert   bool ChecksEnabled[CK_NumCheckKinds] = {false};
331e5dd7070Spatrick   CheckerNameRef CheckNames[CK_NumCheckKinds];
332e5dd7070Spatrick 
333e5dd7070Spatrick   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
334ec727ea7Spatrick   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
335ec727ea7Spatrick   void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
336e5dd7070Spatrick   void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
337e5dd7070Spatrick   void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
338e5dd7070Spatrick   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
339e5dd7070Spatrick   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
340e5dd7070Spatrick   void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;
341e5dd7070Spatrick   ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
342e5dd7070Spatrick                             bool Assumption) const;
343e5dd7070Spatrick   void checkLocation(SVal l, bool isLoad, const Stmt *S,
344e5dd7070Spatrick                      CheckerContext &C) const;
345e5dd7070Spatrick 
346e5dd7070Spatrick   ProgramStateRef checkPointerEscape(ProgramStateRef State,
347e5dd7070Spatrick                                     const InvalidatedSymbols &Escaped,
348e5dd7070Spatrick                                     const CallEvent *Call,
349e5dd7070Spatrick                                     PointerEscapeKind Kind) const;
350e5dd7070Spatrick   ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
351e5dd7070Spatrick                                           const InvalidatedSymbols &Escaped,
352e5dd7070Spatrick                                           const CallEvent *Call,
353e5dd7070Spatrick                                           PointerEscapeKind Kind) const;
354e5dd7070Spatrick 
355e5dd7070Spatrick   void printState(raw_ostream &Out, ProgramStateRef State,
356e5dd7070Spatrick                   const char *NL, const char *Sep) const override;
357e5dd7070Spatrick 
358e5dd7070Spatrick private:
359e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
360e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_DoubleDelete;
361e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
362e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
363e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
364e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
365e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
366e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
367e5dd7070Spatrick   mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
368e5dd7070Spatrick 
369ec727ea7Spatrick #define CHECK_FN(NAME)                                                         \
370ec727ea7Spatrick   void NAME(const CallEvent &Call, CheckerContext &C) const;
371ec727ea7Spatrick 
372ec727ea7Spatrick   CHECK_FN(checkFree)
373ec727ea7Spatrick   CHECK_FN(checkIfNameIndex)
374ec727ea7Spatrick   CHECK_FN(checkBasicAlloc)
375ec727ea7Spatrick   CHECK_FN(checkKernelMalloc)
376ec727ea7Spatrick   CHECK_FN(checkCalloc)
377ec727ea7Spatrick   CHECK_FN(checkAlloca)
378ec727ea7Spatrick   CHECK_FN(checkStrdup)
379ec727ea7Spatrick   CHECK_FN(checkIfFreeNameIndex)
380ec727ea7Spatrick   CHECK_FN(checkCXXNewOrCXXDelete)
381ec727ea7Spatrick   CHECK_FN(checkGMalloc0)
382ec727ea7Spatrick   CHECK_FN(checkGMemdup)
383ec727ea7Spatrick   CHECK_FN(checkGMallocN)
384ec727ea7Spatrick   CHECK_FN(checkGMallocN0)
385ec727ea7Spatrick   CHECK_FN(checkReallocN)
386ec727ea7Spatrick   CHECK_FN(checkOwnershipAttr)
387ec727ea7Spatrick 
388ec727ea7Spatrick   void checkRealloc(const CallEvent &Call, CheckerContext &C,
389ec727ea7Spatrick                     bool ShouldFreeOnFail) const;
390ec727ea7Spatrick 
391ec727ea7Spatrick   using CheckFn = std::function<void(const MallocChecker *,
392ec727ea7Spatrick                                      const CallEvent &Call, CheckerContext &C)>;
393ec727ea7Spatrick 
394ec727ea7Spatrick   const CallDescriptionMap<CheckFn> FreeingMemFnMap{
395*12c85518Srobert       {{{"free"}, 1}, &MallocChecker::checkFree},
396*12c85518Srobert       {{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
397*12c85518Srobert       {{{"kfree"}, 1}, &MallocChecker::checkFree},
398*12c85518Srobert       {{{"g_free"}, 1}, &MallocChecker::checkFree},
399ec727ea7Spatrick   };
400ec727ea7Spatrick 
401ec727ea7Spatrick   bool isFreeingCall(const CallEvent &Call) const;
402*12c85518Srobert   static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);
403*12c85518Srobert 
404*12c85518Srobert   friend class NoOwnershipChangeVisitor;
405ec727ea7Spatrick 
406ec727ea7Spatrick   CallDescriptionMap<CheckFn> AllocatingMemFnMap{
407*12c85518Srobert       {{{"alloca"}, 1}, &MallocChecker::checkAlloca},
408*12c85518Srobert       {{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
409*12c85518Srobert       {{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
410*12c85518Srobert       {{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
411*12c85518Srobert       {{{"calloc"}, 2}, &MallocChecker::checkCalloc},
412*12c85518Srobert       {{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
413*12c85518Srobert       {{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
414*12c85518Srobert       {{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
415*12c85518Srobert       {{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
416*12c85518Srobert       {{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
417*12c85518Srobert       {{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
418*12c85518Srobert       {{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
419*12c85518Srobert       {{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
420*12c85518Srobert       {{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
421*12c85518Srobert       {{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
422*12c85518Srobert       {{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
423*12c85518Srobert       {{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
424*12c85518Srobert       {{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
425*12c85518Srobert       {{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
426*12c85518Srobert       {{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
427*12c85518Srobert       {{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
428*12c85518Srobert       {{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
429ec727ea7Spatrick   };
430ec727ea7Spatrick 
431ec727ea7Spatrick   CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
432*12c85518Srobert       {{{"realloc"}, 2},
433ec727ea7Spatrick        std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
434*12c85518Srobert       {{{"reallocf"}, 2},
435ec727ea7Spatrick        std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
436*12c85518Srobert       {{{"g_realloc"}, 2},
437ec727ea7Spatrick        std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
438*12c85518Srobert       {{{"g_try_realloc"}, 2},
439ec727ea7Spatrick        std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
440*12c85518Srobert       {{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
441*12c85518Srobert       {{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
442ec727ea7Spatrick   };
443ec727ea7Spatrick 
444ec727ea7Spatrick   bool isMemCall(const CallEvent &Call) const;
445ec727ea7Spatrick 
446e5dd7070Spatrick   // TODO: Remove mutable by moving the initializtaion to the registry function.
447*12c85518Srobert   mutable std::optional<uint64_t> KernelZeroFlagVal;
448e5dd7070Spatrick 
449*12c85518Srobert   using KernelZeroSizePtrValueTy = std::optional<int>;
450ec727ea7Spatrick   /// Store the value of macro called `ZERO_SIZE_PTR`.
451ec727ea7Spatrick   /// The value is initialized at first use, before first use the outer
452ec727ea7Spatrick   /// Optional is empty, afterwards it contains another Optional that indicates
453ec727ea7Spatrick   /// if the macro value could be determined, and if yes the value itself.
454*12c85518Srobert   mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
455ec727ea7Spatrick 
456e5dd7070Spatrick   /// Process C++ operator new()'s allocation, which is the part of C++
457e5dd7070Spatrick   /// new-expression that goes before the constructor.
458*12c85518Srobert   [[nodiscard]] ProgramStateRef
459*12c85518Srobert   processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
460ec727ea7Spatrick                        AllocationFamily Family) const;
461e5dd7070Spatrick 
462e5dd7070Spatrick   /// Perform a zero-allocation check.
463e5dd7070Spatrick   ///
464ec727ea7Spatrick   /// \param [in] Call The expression that allocates memory.
465e5dd7070Spatrick   /// \param [in] IndexOfSizeArg Index of the argument that specifies the size
466e5dd7070Spatrick   ///   of the memory that needs to be allocated. E.g. for malloc, this would be
467e5dd7070Spatrick   ///   0.
468e5dd7070Spatrick   /// \param [in] RetVal Specifies the newly allocated pointer value;
469e5dd7070Spatrick   ///   if unspecified, the value of expression \p E is used.
470*12c85518Srobert   [[nodiscard]] static ProgramStateRef
471*12c85518Srobert   ProcessZeroAllocCheck(const CallEvent &Call, const unsigned IndexOfSizeArg,
472e5dd7070Spatrick                         ProgramStateRef State,
473*12c85518Srobert                         std::optional<SVal> RetVal = std::nullopt);
474e5dd7070Spatrick 
475e5dd7070Spatrick   /// Model functions with the ownership_returns attribute.
476e5dd7070Spatrick   ///
477e5dd7070Spatrick   /// User-defined function may have the ownership_returns attribute, which
478e5dd7070Spatrick   /// annotates that the function returns with an object that was allocated on
479e5dd7070Spatrick   /// the heap, and passes the ownertship to the callee.
480e5dd7070Spatrick   ///
481e5dd7070Spatrick   ///   void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);
482e5dd7070Spatrick   ///
483e5dd7070Spatrick   /// It has two parameters:
484e5dd7070Spatrick   ///   - first: name of the resource (e.g. 'malloc')
485e5dd7070Spatrick   ///   - (OPTIONAL) second: size of the allocated region
486e5dd7070Spatrick   ///
487ec727ea7Spatrick   /// \param [in] Call The expression that allocates memory.
488e5dd7070Spatrick   /// \param [in] Att The ownership_returns attribute.
489e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
490e5dd7070Spatrick   /// \returns The ProgramState right after allocation.
491*12c85518Srobert   [[nodiscard]] ProgramStateRef
492*12c85518Srobert   MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
493*12c85518Srobert                        const OwnershipAttr *Att, ProgramStateRef State) const;
494e5dd7070Spatrick 
495e5dd7070Spatrick   /// Models memory allocation.
496e5dd7070Spatrick   ///
497ec727ea7Spatrick   /// \param [in] Call The expression that allocates memory.
498e5dd7070Spatrick   /// \param [in] SizeEx Size of the memory that needs to be allocated.
499e5dd7070Spatrick   /// \param [in] Init The value the allocated memory needs to be initialized.
500e5dd7070Spatrick   /// with. For example, \c calloc initializes the allocated memory to 0,
501e5dd7070Spatrick   /// malloc leaves it undefined.
502e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
503e5dd7070Spatrick   /// \returns The ProgramState right after allocation.
504*12c85518Srobert   [[nodiscard]] static ProgramStateRef
505*12c85518Srobert   MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
506*12c85518Srobert                SVal Init, ProgramStateRef State, AllocationFamily Family);
507e5dd7070Spatrick 
508e5dd7070Spatrick   /// Models memory allocation.
509e5dd7070Spatrick   ///
510ec727ea7Spatrick   /// \param [in] Call The expression that allocates memory.
511e5dd7070Spatrick   /// \param [in] Size Size of the memory that needs to be allocated.
512e5dd7070Spatrick   /// \param [in] Init The value the allocated memory needs to be initialized.
513e5dd7070Spatrick   /// with. For example, \c calloc initializes the allocated memory to 0,
514e5dd7070Spatrick   /// malloc leaves it undefined.
515e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
516e5dd7070Spatrick   /// \returns The ProgramState right after allocation.
517*12c85518Srobert   [[nodiscard]] static ProgramStateRef
518*12c85518Srobert   MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init,
519*12c85518Srobert                ProgramStateRef State, AllocationFamily Family);
520e5dd7070Spatrick 
521e5dd7070Spatrick   // Check if this malloc() for special flags. At present that means M_ZERO or
522e5dd7070Spatrick   // __GFP_ZERO (in which case, treat it like calloc).
523*12c85518Srobert   [[nodiscard]] std::optional<ProgramStateRef>
524ec727ea7Spatrick   performKernelMalloc(const CallEvent &Call, CheckerContext &C,
525e5dd7070Spatrick                       const ProgramStateRef &State) const;
526e5dd7070Spatrick 
527e5dd7070Spatrick   /// Model functions with the ownership_takes and ownership_holds attributes.
528e5dd7070Spatrick   ///
529e5dd7070Spatrick   /// User-defined function may have the ownership_takes and/or ownership_holds
530e5dd7070Spatrick   /// attributes, which annotates that the function frees the memory passed as a
531e5dd7070Spatrick   /// parameter.
532e5dd7070Spatrick   ///
533e5dd7070Spatrick   ///   void __attribute((ownership_takes(malloc, 1))) my_free(void *);
534e5dd7070Spatrick   ///   void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
535e5dd7070Spatrick   ///
536e5dd7070Spatrick   /// They have two parameters:
537e5dd7070Spatrick   ///   - first: name of the resource (e.g. 'malloc')
538e5dd7070Spatrick   ///   - second: index of the parameter the attribute applies to
539e5dd7070Spatrick   ///
540ec727ea7Spatrick   /// \param [in] Call The expression that frees memory.
541e5dd7070Spatrick   /// \param [in] Att The ownership_takes or ownership_holds attribute.
542e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
543e5dd7070Spatrick   /// \returns The ProgramState right after deallocation.
544*12c85518Srobert   [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,
545*12c85518Srobert                                             const CallEvent &Call,
546e5dd7070Spatrick                                             const OwnershipAttr *Att,
547e5dd7070Spatrick                                             ProgramStateRef State) const;
548e5dd7070Spatrick 
549e5dd7070Spatrick   /// Models memory deallocation.
550e5dd7070Spatrick   ///
551ec727ea7Spatrick   /// \param [in] Call The expression that frees memory.
552e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
553e5dd7070Spatrick   /// \param [in] Num Index of the argument that needs to be freed. This is
554e5dd7070Spatrick   ///   normally 0, but for custom free functions it may be different.
555e5dd7070Spatrick   /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
556e5dd7070Spatrick   ///   attribute.
557e5dd7070Spatrick   /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
558e5dd7070Spatrick   ///   to have been allocated, or in other words, the symbol to be freed was
559e5dd7070Spatrick   ///   registered as allocated by this checker. In the following case, \c ptr
560e5dd7070Spatrick   ///   isn't known to be allocated.
561e5dd7070Spatrick   ///      void Haha(int *ptr) {
562e5dd7070Spatrick   ///        ptr = realloc(ptr, 67);
563e5dd7070Spatrick   ///        // ...
564e5dd7070Spatrick   ///      }
565e5dd7070Spatrick   /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
566e5dd7070Spatrick   ///   we're modeling returns with Null on failure.
567e5dd7070Spatrick   /// \returns The ProgramState right after deallocation.
568*12c85518Srobert   [[nodiscard]] ProgramStateRef
569*12c85518Srobert   FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,
570*12c85518Srobert              unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
571*12c85518Srobert              AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
572e5dd7070Spatrick 
573e5dd7070Spatrick   /// Models memory deallocation.
574e5dd7070Spatrick   ///
575e5dd7070Spatrick   /// \param [in] ArgExpr The variable who's pointee needs to be freed.
576ec727ea7Spatrick   /// \param [in] Call The expression that frees the memory.
577e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before allocation.
578e5dd7070Spatrick   ///   normally 0, but for custom free functions it may be different.
579e5dd7070Spatrick   /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
580e5dd7070Spatrick   ///   attribute.
581e5dd7070Spatrick   /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
582e5dd7070Spatrick   ///   to have been allocated, or in other words, the symbol to be freed was
583e5dd7070Spatrick   ///   registered as allocated by this checker. In the following case, \c ptr
584e5dd7070Spatrick   ///   isn't known to be allocated.
585e5dd7070Spatrick   ///      void Haha(int *ptr) {
586e5dd7070Spatrick   ///        ptr = realloc(ptr, 67);
587e5dd7070Spatrick   ///        // ...
588e5dd7070Spatrick   ///      }
589e5dd7070Spatrick   /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
590e5dd7070Spatrick   ///   we're modeling returns with Null on failure.
591e5dd7070Spatrick   /// \returns The ProgramState right after deallocation.
592*12c85518Srobert   [[nodiscard]] ProgramStateRef
593*12c85518Srobert   FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
594*12c85518Srobert              ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
595*12c85518Srobert              AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
596e5dd7070Spatrick 
597e5dd7070Spatrick   // TODO: Needs some refactoring, as all other deallocation modeling
598e5dd7070Spatrick   // functions are suffering from out parameters and messy code due to how
599e5dd7070Spatrick   // realloc is handled.
600e5dd7070Spatrick   //
601e5dd7070Spatrick   /// Models memory reallocation.
602e5dd7070Spatrick   ///
603ec727ea7Spatrick   /// \param [in] Call The expression that reallocated memory
604e5dd7070Spatrick   /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied
605e5dd7070Spatrick   ///   memory should be freed.
606e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before reallocation.
607e5dd7070Spatrick   /// \param [in] SuffixWithN Whether the reallocation function we're modeling
608e5dd7070Spatrick   ///   has an '_n' suffix, such as g_realloc_n.
609e5dd7070Spatrick   /// \returns The ProgramState right after reallocation.
610*12c85518Srobert   [[nodiscard]] ProgramStateRef
611*12c85518Srobert   ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
612*12c85518Srobert                 ProgramStateRef State, AllocationFamily Family,
613e5dd7070Spatrick                 bool SuffixWithN = false) const;
614e5dd7070Spatrick 
615e5dd7070Spatrick   /// Evaluates the buffer size that needs to be allocated.
616e5dd7070Spatrick   ///
617e5dd7070Spatrick   /// \param [in] Blocks The amount of blocks that needs to be allocated.
618e5dd7070Spatrick   /// \param [in] BlockBytes The size of a block.
619e5dd7070Spatrick   /// \returns The symbolic value of \p Blocks * \p BlockBytes.
620*12c85518Srobert   [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
621*12c85518Srobert                                                  const Expr *Blocks,
622e5dd7070Spatrick                                                  const Expr *BlockBytes);
623e5dd7070Spatrick 
624e5dd7070Spatrick   /// Models zero initialized array allocation.
625e5dd7070Spatrick   ///
626ec727ea7Spatrick   /// \param [in] Call The expression that reallocated memory
627e5dd7070Spatrick   /// \param [in] State The \c ProgramState right before reallocation.
628e5dd7070Spatrick   /// \returns The ProgramState right after allocation.
629*12c85518Srobert   [[nodiscard]] static ProgramStateRef
630*12c85518Srobert   CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State);
631e5dd7070Spatrick 
632e5dd7070Spatrick   /// See if deallocation happens in a suspicious context. If so, escape the
633e5dd7070Spatrick   /// pointers that otherwise would have been deallocated and return true.
634ec727ea7Spatrick   bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,
635e5dd7070Spatrick                                                  CheckerContext &C) const;
636e5dd7070Spatrick 
637e5dd7070Spatrick   /// If in \p S  \p Sym is used, check whether \p Sym was already freed.
638e5dd7070Spatrick   bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
639e5dd7070Spatrick 
640e5dd7070Spatrick   /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero
641e5dd7070Spatrick   /// sized memory region.
642e5dd7070Spatrick   void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
643e5dd7070Spatrick                              const Stmt *S) const;
644e5dd7070Spatrick 
645e5dd7070Spatrick   /// If in \p S \p Sym is being freed, check whether \p Sym was already freed.
646e5dd7070Spatrick   bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
647e5dd7070Spatrick 
648e5dd7070Spatrick   /// Check if the function is known to free memory, or if it is
649e5dd7070Spatrick   /// "interesting" and should be modeled explicitly.
650e5dd7070Spatrick   ///
651e5dd7070Spatrick   /// \param [out] EscapingSymbol A function might not free memory in general,
652e5dd7070Spatrick   ///   but could be known to free a particular symbol. In this case, false is
653e5dd7070Spatrick   ///   returned and the single escaping symbol is returned through the out
654e5dd7070Spatrick   ///   parameter.
655e5dd7070Spatrick   ///
656e5dd7070Spatrick   /// We assume that pointers do not escape through calls to system functions
657e5dd7070Spatrick   /// not handled by this checker.
658e5dd7070Spatrick   bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
659e5dd7070Spatrick                                    ProgramStateRef State,
660e5dd7070Spatrick                                    SymbolRef &EscapingSymbol) const;
661e5dd7070Spatrick 
662e5dd7070Spatrick   /// Implementation of the checkPointerEscape callbacks.
663*12c85518Srobert   [[nodiscard]] ProgramStateRef
664*12c85518Srobert   checkPointerEscapeAux(ProgramStateRef State,
665e5dd7070Spatrick                         const InvalidatedSymbols &Escaped,
666*12c85518Srobert                         const CallEvent *Call, PointerEscapeKind Kind,
667e5dd7070Spatrick                         bool IsConstPointerEscape) const;
668e5dd7070Spatrick 
669e5dd7070Spatrick   // Implementation of the checkPreStmt and checkEndFunction callbacks.
670e5dd7070Spatrick   void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
671e5dd7070Spatrick 
672e5dd7070Spatrick   ///@{
673e5dd7070Spatrick   /// Tells if a given family/call/symbol is tracked by the current checker.
674e5dd7070Spatrick   /// Sets CheckKind to the kind of the checker responsible for this
675e5dd7070Spatrick   /// family/call/symbol.
676*12c85518Srobert   std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
677e5dd7070Spatrick                                              bool IsALeakCheck = false) const;
678ec727ea7Spatrick 
679*12c85518Srobert   std::optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
680e5dd7070Spatrick                                              bool IsALeakCheck = false) const;
681e5dd7070Spatrick   ///@}
682e5dd7070Spatrick   static bool SummarizeValue(raw_ostream &os, SVal V);
683e5dd7070Spatrick   static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
684e5dd7070Spatrick 
685ec727ea7Spatrick   void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
686ec727ea7Spatrick                             const Expr *DeallocExpr,
687ec727ea7Spatrick                             AllocationFamily Family) const;
688ec727ea7Spatrick 
689ec727ea7Spatrick   void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
690e5dd7070Spatrick                         SourceRange Range) const;
691ec727ea7Spatrick 
692ec727ea7Spatrick   void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,
693e5dd7070Spatrick                                const Expr *DeallocExpr, const RefState *RS,
694e5dd7070Spatrick                                SymbolRef Sym, bool OwnershipTransferred) const;
695ec727ea7Spatrick 
696ec727ea7Spatrick   void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
697ec727ea7Spatrick                         const Expr *DeallocExpr, AllocationFamily Family,
698e5dd7070Spatrick                         const Expr *AllocExpr = nullptr) const;
699ec727ea7Spatrick 
700ec727ea7Spatrick   void HandleUseAfterFree(CheckerContext &C, SourceRange Range,
701e5dd7070Spatrick                           SymbolRef Sym) const;
702ec727ea7Spatrick 
703ec727ea7Spatrick   void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
704e5dd7070Spatrick                         SymbolRef Sym, SymbolRef PrevSym) const;
705e5dd7070Spatrick 
706ec727ea7Spatrick   void HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const;
707e5dd7070Spatrick 
708ec727ea7Spatrick   void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
709e5dd7070Spatrick                           SymbolRef Sym) const;
710e5dd7070Spatrick 
711ec727ea7Spatrick   void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
712ec727ea7Spatrick                              const Expr *FreeExpr,
713ec727ea7Spatrick                              AllocationFamily Family) const;
714e5dd7070Spatrick 
715e5dd7070Spatrick   /// Find the location of the allocation for Sym on the path leading to the
716e5dd7070Spatrick   /// exploded node N.
717e5dd7070Spatrick   static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
718e5dd7070Spatrick                                     CheckerContext &C);
719e5dd7070Spatrick 
720ec727ea7Spatrick   void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
721ec727ea7Spatrick 
722ec727ea7Spatrick   /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`.
723ec727ea7Spatrick   bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
724ec727ea7Spatrick                           SVal ArgVal) const;
725e5dd7070Spatrick };
726*12c85518Srobert } // end anonymous namespace
727*12c85518Srobert 
728*12c85518Srobert //===----------------------------------------------------------------------===//
729*12c85518Srobert // Definition of NoOwnershipChangeVisitor.
730*12c85518Srobert //===----------------------------------------------------------------------===//
731*12c85518Srobert 
732*12c85518Srobert namespace {
733*12c85518Srobert class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
734*12c85518Srobert   // The symbol whose (lack of) ownership change we are interested in.
735*12c85518Srobert   SymbolRef Sym;
736*12c85518Srobert   const MallocChecker &Checker;
737*12c85518Srobert   using OwnerSet = llvm::SmallPtrSet<const MemRegion *, 8>;
738*12c85518Srobert 
739*12c85518Srobert   // Collect which entities point to the allocated memory, and could be
740*12c85518Srobert   // responsible for deallocating it.
741*12c85518Srobert   class OwnershipBindingsHandler : public StoreManager::BindingsHandler {
742*12c85518Srobert     SymbolRef Sym;
743*12c85518Srobert     OwnerSet &Owners;
744*12c85518Srobert 
745*12c85518Srobert   public:
OwnershipBindingsHandler(SymbolRef Sym,OwnerSet & Owners)746*12c85518Srobert     OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners)
747*12c85518Srobert         : Sym(Sym), Owners(Owners) {}
748*12c85518Srobert 
HandleBinding(StoreManager & SMgr,Store Store,const MemRegion * Region,SVal Val)749*12c85518Srobert     bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region,
750*12c85518Srobert                        SVal Val) override {
751*12c85518Srobert       if (Val.getAsSymbol() == Sym)
752*12c85518Srobert         Owners.insert(Region);
753*12c85518Srobert       return true;
754*12c85518Srobert     }
755*12c85518Srobert 
dump() const756*12c85518Srobert     LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
dumpToStream(llvm::raw_ostream & out) const757*12c85518Srobert     LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const {
758*12c85518Srobert       out << "Owners: {\n";
759*12c85518Srobert       for (const MemRegion *Owner : Owners) {
760*12c85518Srobert         out << "  ";
761*12c85518Srobert         Owner->dumpToStream(out);
762*12c85518Srobert         out << ",\n";
763*12c85518Srobert       }
764*12c85518Srobert       out << "}\n";
765*12c85518Srobert     }
766*12c85518Srobert   };
767*12c85518Srobert 
768*12c85518Srobert protected:
getOwnersAtNode(const ExplodedNode * N)769*12c85518Srobert   OwnerSet getOwnersAtNode(const ExplodedNode *N) {
770*12c85518Srobert     OwnerSet Ret;
771*12c85518Srobert 
772*12c85518Srobert     ProgramStateRef State = N->getState();
773*12c85518Srobert     OwnershipBindingsHandler Handler{Sym, Ret};
774*12c85518Srobert     State->getStateManager().getStoreManager().iterBindings(State->getStore(),
775*12c85518Srobert                                                             Handler);
776*12c85518Srobert     return Ret;
777*12c85518Srobert   }
778*12c85518Srobert 
779*12c85518Srobert   LLVM_DUMP_METHOD static std::string
getFunctionName(const ExplodedNode * CallEnterN)780*12c85518Srobert   getFunctionName(const ExplodedNode *CallEnterN) {
781*12c85518Srobert     if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
782*12c85518Srobert             CallEnterN->getLocationAs<CallEnter>()->getCallExpr()))
783*12c85518Srobert       if (const FunctionDecl *FD = CE->getDirectCallee())
784*12c85518Srobert         return FD->getQualifiedNameAsString();
785*12c85518Srobert     return "";
786*12c85518Srobert   }
787*12c85518Srobert 
788*12c85518Srobert   /// Syntactically checks whether the callee is a deallocating function. Since
789*12c85518Srobert   /// we have no path-sensitive information on this call (we would need a
790*12c85518Srobert   /// CallEvent instead of a CallExpr for that), its possible that a
791*12c85518Srobert   /// deallocation function was called indirectly through a function pointer,
792*12c85518Srobert   /// but we are not able to tell, so this is a best effort analysis.
793*12c85518Srobert   /// See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in
794*12c85518Srobert   /// clang/test/Analysis/NewDeleteLeaks.cpp.
isFreeingCallAsWritten(const CallExpr & Call) const795*12c85518Srobert   bool isFreeingCallAsWritten(const CallExpr &Call) const {
796*12c85518Srobert     if (Checker.FreeingMemFnMap.lookupAsWritten(Call) ||
797*12c85518Srobert         Checker.ReallocatingMemFnMap.lookupAsWritten(Call))
798*12c85518Srobert       return true;
799*12c85518Srobert 
800*12c85518Srobert     if (const auto *Func =
801*12c85518Srobert             llvm::dyn_cast_or_null<FunctionDecl>(Call.getCalleeDecl()))
802*12c85518Srobert       return MallocChecker::isFreeingOwnershipAttrCall(Func);
803*12c85518Srobert 
804*12c85518Srobert     return false;
805*12c85518Srobert   }
806*12c85518Srobert 
807*12c85518Srobert   /// Heuristically guess whether the callee intended to free memory. This is
808*12c85518Srobert   /// done syntactically, because we are trying to argue about alternative
809*12c85518Srobert   /// paths of execution, and as a consequence we don't have path-sensitive
810*12c85518Srobert   /// information.
doesFnIntendToHandleOwnership(const Decl * Callee,ASTContext & ACtx)811*12c85518Srobert   bool doesFnIntendToHandleOwnership(const Decl *Callee, ASTContext &ACtx) {
812*12c85518Srobert     using namespace clang::ast_matchers;
813*12c85518Srobert     const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
814*12c85518Srobert 
815*12c85518Srobert     // Given that the stack frame was entered, the body should always be
816*12c85518Srobert     // theoretically obtainable. In case of body farms, the synthesized body
817*12c85518Srobert     // is not attached to declaration, thus triggering the '!FD->hasBody()'
818*12c85518Srobert     // branch. That said, would a synthesized body ever intend to handle
819*12c85518Srobert     // ownership? As of today they don't. And if they did, how would we
820*12c85518Srobert     // put notes inside it, given that it doesn't match any source locations?
821*12c85518Srobert     if (!FD || !FD->hasBody())
822*12c85518Srobert       return false;
823*12c85518Srobert 
824*12c85518Srobert     auto Matches = match(findAll(stmt(anyOf(cxxDeleteExpr().bind("delete"),
825*12c85518Srobert                                             callExpr().bind("call")))),
826*12c85518Srobert                          *FD->getBody(), ACtx);
827*12c85518Srobert     for (BoundNodes Match : Matches) {
828*12c85518Srobert       if (Match.getNodeAs<CXXDeleteExpr>("delete"))
829*12c85518Srobert         return true;
830*12c85518Srobert 
831*12c85518Srobert       if (const auto *Call = Match.getNodeAs<CallExpr>("call"))
832*12c85518Srobert         if (isFreeingCallAsWritten(*Call))
833*12c85518Srobert           return true;
834*12c85518Srobert     }
835*12c85518Srobert     // TODO: Ownership might change with an attempt to store the allocated
836*12c85518Srobert     // memory, not only through deallocation. Check for attempted stores as
837*12c85518Srobert     // well.
838*12c85518Srobert     return false;
839*12c85518Srobert   }
840*12c85518Srobert 
wasModifiedInFunction(const ExplodedNode * CallEnterN,const ExplodedNode * CallExitEndN)841*12c85518Srobert   bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
842*12c85518Srobert                              const ExplodedNode *CallExitEndN) override {
843*12c85518Srobert     if (!doesFnIntendToHandleOwnership(
844*12c85518Srobert             CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
845*12c85518Srobert             CallExitEndN->getState()->getAnalysisManager().getASTContext()))
846*12c85518Srobert       return true;
847*12c85518Srobert 
848*12c85518Srobert     if (CallEnterN->getState()->get<RegionState>(Sym) !=
849*12c85518Srobert         CallExitEndN->getState()->get<RegionState>(Sym))
850*12c85518Srobert       return true;
851*12c85518Srobert 
852*12c85518Srobert     OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
853*12c85518Srobert     OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
854*12c85518Srobert 
855*12c85518Srobert     // Owners in the current set may be purged from the analyzer later on.
856*12c85518Srobert     // If a variable is dead (is not referenced directly or indirectly after
857*12c85518Srobert     // some point), it will be removed from the Store before the end of its
858*12c85518Srobert     // actual lifetime.
859*12c85518Srobert     // This means that if the ownership status didn't change, CurrOwners
860*12c85518Srobert     // must be a superset of, but not necessarily equal to ExitOwners.
861*12c85518Srobert     return !llvm::set_is_subset(ExitOwners, CurrOwners);
862*12c85518Srobert   }
863*12c85518Srobert 
emitNote(const ExplodedNode * N)864*12c85518Srobert   static PathDiagnosticPieceRef emitNote(const ExplodedNode *N) {
865*12c85518Srobert     PathDiagnosticLocation L = PathDiagnosticLocation::create(
866*12c85518Srobert         N->getLocation(),
867*12c85518Srobert         N->getState()->getStateManager().getContext().getSourceManager());
868*12c85518Srobert     return std::make_shared<PathDiagnosticEventPiece>(
869*12c85518Srobert         L, "Returning without deallocating memory or storing the pointer for "
870*12c85518Srobert            "later deallocation");
871*12c85518Srobert   }
872*12c85518Srobert 
873*12c85518Srobert   PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport & R,const ObjCMethodCall & Call,const ExplodedNode * N)874*12c85518Srobert   maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
875*12c85518Srobert                            const ObjCMethodCall &Call,
876*12c85518Srobert                            const ExplodedNode *N) override {
877*12c85518Srobert     // TODO: Implement.
878*12c85518Srobert     return nullptr;
879*12c85518Srobert   }
880*12c85518Srobert 
881*12c85518Srobert   PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport & R,const CXXConstructorCall & Call,const ExplodedNode * N)882*12c85518Srobert   maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
883*12c85518Srobert                           const CXXConstructorCall &Call,
884*12c85518Srobert                           const ExplodedNode *N) override {
885*12c85518Srobert     // TODO: Implement.
886*12c85518Srobert     return nullptr;
887*12c85518Srobert   }
888*12c85518Srobert 
889*12c85518Srobert   PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N)890*12c85518Srobert   maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
891*12c85518Srobert                              const ExplodedNode *N) override {
892*12c85518Srobert     // TODO: Factor the logic of "what constitutes as an entity being passed
893*12c85518Srobert     // into a function call" out by reusing the code in
894*12c85518Srobert     // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating
895*12c85518Srobert     // the printing technology in UninitializedObject's FieldChainInfo.
896*12c85518Srobert     ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
897*12c85518Srobert     for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
898*12c85518Srobert       SVal V = Call.getArgSVal(I);
899*12c85518Srobert       if (V.getAsSymbol() == Sym)
900*12c85518Srobert         return emitNote(N);
901*12c85518Srobert     }
902*12c85518Srobert     return nullptr;
903*12c85518Srobert   }
904*12c85518Srobert 
905*12c85518Srobert public:
NoOwnershipChangeVisitor(SymbolRef Sym,const MallocChecker * Checker)906*12c85518Srobert   NoOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
907*12c85518Srobert       : NoStateChangeFuncVisitor(bugreporter::TrackingKind::Thorough), Sym(Sym),
908*12c85518Srobert         Checker(*Checker) {}
909*12c85518Srobert 
Profile(llvm::FoldingSetNodeID & ID) const910*12c85518Srobert   void Profile(llvm::FoldingSetNodeID &ID) const override {
911*12c85518Srobert     static int Tag = 0;
912*12c85518Srobert     ID.AddPointer(&Tag);
913*12c85518Srobert     ID.AddPointer(Sym);
914*12c85518Srobert   }
915*12c85518Srobert };
916*12c85518Srobert 
917*12c85518Srobert } // end anonymous namespace
918e5dd7070Spatrick 
919e5dd7070Spatrick //===----------------------------------------------------------------------===//
920e5dd7070Spatrick // Definition of MallocBugVisitor.
921e5dd7070Spatrick //===----------------------------------------------------------------------===//
922e5dd7070Spatrick 
923*12c85518Srobert namespace {
924e5dd7070Spatrick /// The bug visitor which allows us to print extra diagnostics along the
925e5dd7070Spatrick /// BugReport path. For example, showing the allocation site of the leaked
926e5dd7070Spatrick /// region.
927e5dd7070Spatrick class MallocBugVisitor final : public BugReporterVisitor {
928e5dd7070Spatrick protected:
929e5dd7070Spatrick   enum NotificationMode { Normal, ReallocationFailed };
930e5dd7070Spatrick 
931e5dd7070Spatrick   // The allocated region symbol tracked by the main analysis.
932e5dd7070Spatrick   SymbolRef Sym;
933e5dd7070Spatrick 
934e5dd7070Spatrick   // The mode we are in, i.e. what kind of diagnostics will be emitted.
935e5dd7070Spatrick   NotificationMode Mode;
936e5dd7070Spatrick 
937e5dd7070Spatrick   // A symbol from when the primary region should have been reallocated.
938e5dd7070Spatrick   SymbolRef FailedReallocSymbol;
939e5dd7070Spatrick 
940e5dd7070Spatrick   // A C++ destructor stack frame in which memory was released. Used for
941e5dd7070Spatrick   // miscellaneous false positive suppression.
942e5dd7070Spatrick   const StackFrameContext *ReleaseDestructorLC;
943e5dd7070Spatrick 
944e5dd7070Spatrick   bool IsLeak;
945e5dd7070Spatrick 
946e5dd7070Spatrick public:
MallocBugVisitor(SymbolRef S,bool isLeak=false)947e5dd7070Spatrick   MallocBugVisitor(SymbolRef S, bool isLeak = false)
948e5dd7070Spatrick       : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
949e5dd7070Spatrick         ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
950e5dd7070Spatrick 
getTag()951e5dd7070Spatrick   static void *getTag() {
952e5dd7070Spatrick     static int Tag = 0;
953e5dd7070Spatrick     return &Tag;
954e5dd7070Spatrick   }
955e5dd7070Spatrick 
Profile(llvm::FoldingSetNodeID & ID) const956e5dd7070Spatrick   void Profile(llvm::FoldingSetNodeID &ID) const override {
957e5dd7070Spatrick     ID.AddPointer(getTag());
958e5dd7070Spatrick     ID.AddPointer(Sym);
959e5dd7070Spatrick   }
960e5dd7070Spatrick 
961e5dd7070Spatrick   /// Did not track -> allocated. Other state (released) -> allocated.
isAllocated(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)962e5dd7070Spatrick   static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
963e5dd7070Spatrick                                  const Stmt *Stmt) {
964*12c85518Srobert     return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
965e5dd7070Spatrick             (RSCurr &&
966e5dd7070Spatrick              (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
967e5dd7070Spatrick             (!RSPrev ||
968e5dd7070Spatrick              !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
969e5dd7070Spatrick   }
970e5dd7070Spatrick 
971e5dd7070Spatrick   /// Did not track -> released. Other state (allocated) -> released.
972e5dd7070Spatrick   /// The statement associated with the release might be missing.
isReleased(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)973e5dd7070Spatrick   static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
974e5dd7070Spatrick                                 const Stmt *Stmt) {
975e5dd7070Spatrick     bool IsReleased =
976e5dd7070Spatrick         (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
977*12c85518Srobert     assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
978e5dd7070Spatrick            (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
979e5dd7070Spatrick     return IsReleased;
980e5dd7070Spatrick   }
981e5dd7070Spatrick 
982e5dd7070Spatrick   /// Did not track -> relinquished. Other state (allocated) -> relinquished.
isRelinquished(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)983e5dd7070Spatrick   static inline bool isRelinquished(const RefState *RSCurr,
984e5dd7070Spatrick                                     const RefState *RSPrev, const Stmt *Stmt) {
985*12c85518Srobert     return (
986*12c85518Srobert         isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
987e5dd7070Spatrick         (RSCurr && RSCurr->isRelinquished()) &&
988e5dd7070Spatrick         (!RSPrev || !RSPrev->isRelinquished()));
989e5dd7070Spatrick   }
990e5dd7070Spatrick 
991e5dd7070Spatrick   /// If the expression is not a call, and the state change is
992e5dd7070Spatrick   /// released -> allocated, it must be the realloc return value
993e5dd7070Spatrick   /// check. If we have to handle more cases here, it might be cleaner just
994e5dd7070Spatrick   /// to track this extra bit in the state itself.
hasReallocFailed(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)995e5dd7070Spatrick   static inline bool hasReallocFailed(const RefState *RSCurr,
996e5dd7070Spatrick                                       const RefState *RSPrev,
997e5dd7070Spatrick                                       const Stmt *Stmt) {
998*12c85518Srobert     return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
999e5dd7070Spatrick             (RSCurr &&
1000e5dd7070Spatrick              (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1001e5dd7070Spatrick             (RSPrev &&
1002e5dd7070Spatrick              !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1003e5dd7070Spatrick   }
1004e5dd7070Spatrick 
1005e5dd7070Spatrick   PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1006e5dd7070Spatrick                                    BugReporterContext &BRC,
1007e5dd7070Spatrick                                    PathSensitiveBugReport &BR) override;
1008e5dd7070Spatrick 
getEndPath(BugReporterContext & BRC,const ExplodedNode * EndPathNode,PathSensitiveBugReport & BR)1009e5dd7070Spatrick   PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
1010e5dd7070Spatrick                                     const ExplodedNode *EndPathNode,
1011e5dd7070Spatrick                                     PathSensitiveBugReport &BR) override {
1012e5dd7070Spatrick     if (!IsLeak)
1013e5dd7070Spatrick       return nullptr;
1014e5dd7070Spatrick 
1015e5dd7070Spatrick     PathDiagnosticLocation L = BR.getLocation();
1016e5dd7070Spatrick     // Do not add the statement itself as a range in case of leak.
1017e5dd7070Spatrick     return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
1018e5dd7070Spatrick                                                       false);
1019e5dd7070Spatrick   }
1020e5dd7070Spatrick 
1021e5dd7070Spatrick private:
1022e5dd7070Spatrick   class StackHintGeneratorForReallocationFailed
1023e5dd7070Spatrick       : public StackHintGeneratorForSymbol {
1024e5dd7070Spatrick   public:
StackHintGeneratorForReallocationFailed(SymbolRef S,StringRef M)1025e5dd7070Spatrick     StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
1026e5dd7070Spatrick         : StackHintGeneratorForSymbol(S, M) {}
1027e5dd7070Spatrick 
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)1028e5dd7070Spatrick     std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
1029e5dd7070Spatrick       // Printed parameters start at 1, not 0.
1030e5dd7070Spatrick       ++ArgIndex;
1031e5dd7070Spatrick 
1032e5dd7070Spatrick       SmallString<200> buf;
1033e5dd7070Spatrick       llvm::raw_svector_ostream os(buf);
1034e5dd7070Spatrick 
1035e5dd7070Spatrick       os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1036e5dd7070Spatrick          << " parameter failed";
1037e5dd7070Spatrick 
1038ec727ea7Spatrick       return std::string(os.str());
1039e5dd7070Spatrick     }
1040e5dd7070Spatrick 
getMessageForReturn(const CallExpr * CallExpr)1041e5dd7070Spatrick     std::string getMessageForReturn(const CallExpr *CallExpr) override {
1042e5dd7070Spatrick       return "Reallocation of returned value failed";
1043e5dd7070Spatrick     }
1044e5dd7070Spatrick   };
1045e5dd7070Spatrick };
1046e5dd7070Spatrick } // end anonymous namespace
1047e5dd7070Spatrick 
1048e5dd7070Spatrick // A map from the freed symbol to the symbol representing the return value of
1049e5dd7070Spatrick // the free function.
1050e5dd7070Spatrick REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
1051e5dd7070Spatrick 
1052e5dd7070Spatrick namespace {
1053e5dd7070Spatrick class StopTrackingCallback final : public SymbolVisitor {
1054e5dd7070Spatrick   ProgramStateRef state;
1055ec727ea7Spatrick 
1056e5dd7070Spatrick public:
StopTrackingCallback(ProgramStateRef st)1057e5dd7070Spatrick   StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const1058e5dd7070Spatrick   ProgramStateRef getState() const { return state; }
1059e5dd7070Spatrick 
VisitSymbol(SymbolRef sym)1060e5dd7070Spatrick   bool VisitSymbol(SymbolRef sym) override {
1061e5dd7070Spatrick     state = state->remove<RegionState>(sym);
1062e5dd7070Spatrick     return true;
1063e5dd7070Spatrick   }
1064e5dd7070Spatrick };
1065e5dd7070Spatrick } // end anonymous namespace
1066e5dd7070Spatrick 
isStandardNewDelete(const FunctionDecl * FD)1067ec727ea7Spatrick static bool isStandardNewDelete(const FunctionDecl *FD) {
1068e5dd7070Spatrick   if (!FD)
1069e5dd7070Spatrick     return false;
1070e5dd7070Spatrick 
1071e5dd7070Spatrick   OverloadedOperatorKind Kind = FD->getOverloadedOperator();
1072ec727ea7Spatrick   if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1073ec727ea7Spatrick       Kind != OO_Array_Delete)
1074e5dd7070Spatrick     return false;
1075e5dd7070Spatrick 
1076e5dd7070Spatrick   // This is standard if and only if it's not defined in a user file.
1077e5dd7070Spatrick   SourceLocation L = FD->getLocation();
1078e5dd7070Spatrick   // If the header for operator delete is not included, it's still defined
1079e5dd7070Spatrick   // in an invalid source location. Check to make sure we don't crash.
1080ec727ea7Spatrick   return !L.isValid() ||
1081ec727ea7Spatrick          FD->getASTContext().getSourceManager().isInSystemHeader(L);
1082e5dd7070Spatrick }
1083e5dd7070Spatrick 
1084e5dd7070Spatrick //===----------------------------------------------------------------------===//
1085e5dd7070Spatrick // Methods of MallocChecker and MallocBugVisitor.
1086e5dd7070Spatrick //===----------------------------------------------------------------------===//
1087e5dd7070Spatrick 
isFreeingOwnershipAttrCall(const FunctionDecl * Func)1088*12c85518Srobert bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {
1089*12c85518Srobert   if (Func->hasAttrs()) {
1090ec727ea7Spatrick     for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
1091ec727ea7Spatrick       OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1092ec727ea7Spatrick       if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1093ec727ea7Spatrick         return true;
1094ec727ea7Spatrick     }
1095ec727ea7Spatrick   }
1096ec727ea7Spatrick   return false;
1097ec727ea7Spatrick }
1098ec727ea7Spatrick 
isFreeingCall(const CallEvent & Call) const1099*12c85518Srobert bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
1100*12c85518Srobert   if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1101*12c85518Srobert     return true;
1102*12c85518Srobert 
1103*12c85518Srobert   if (const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
1104*12c85518Srobert     return isFreeingOwnershipAttrCall(Func);
1105*12c85518Srobert 
1106*12c85518Srobert   return false;
1107*12c85518Srobert }
1108*12c85518Srobert 
isMemCall(const CallEvent & Call) const1109ec727ea7Spatrick bool MallocChecker::isMemCall(const CallEvent &Call) const {
1110ec727ea7Spatrick   if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1111ec727ea7Spatrick       ReallocatingMemFnMap.lookup(Call))
1112ec727ea7Spatrick     return true;
1113ec727ea7Spatrick 
1114ec727ea7Spatrick   if (!ShouldIncludeOwnershipAnnotatedFunctions)
1115ec727ea7Spatrick     return false;
1116ec727ea7Spatrick 
1117ec727ea7Spatrick   const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());
1118ec727ea7Spatrick   return Func && Func->hasAttr<OwnershipAttr>();
1119ec727ea7Spatrick }
1120ec727ea7Spatrick 
1121*12c85518Srobert std::optional<ProgramStateRef>
performKernelMalloc(const CallEvent & Call,CheckerContext & C,const ProgramStateRef & State) const1122ec727ea7Spatrick MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
1123ec727ea7Spatrick                                    const ProgramStateRef &State) const {
1124e5dd7070Spatrick   // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
1125e5dd7070Spatrick   //
1126e5dd7070Spatrick   // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);
1127e5dd7070Spatrick   //
1128e5dd7070Spatrick   // One of the possible flags is M_ZERO, which means 'give me back an
1129e5dd7070Spatrick   // allocation which is already zeroed', like calloc.
1130e5dd7070Spatrick 
1131e5dd7070Spatrick   // 2-argument kmalloc(), as used in the Linux kernel:
1132e5dd7070Spatrick   //
1133e5dd7070Spatrick   // void *kmalloc(size_t size, gfp_t flags);
1134e5dd7070Spatrick   //
1135e5dd7070Spatrick   // Has the similar flag value __GFP_ZERO.
1136e5dd7070Spatrick 
1137e5dd7070Spatrick   // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some
1138e5dd7070Spatrick   // code could be shared.
1139e5dd7070Spatrick 
1140e5dd7070Spatrick   ASTContext &Ctx = C.getASTContext();
1141e5dd7070Spatrick   llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();
1142e5dd7070Spatrick 
1143*12c85518Srobert   if (!KernelZeroFlagVal) {
1144e5dd7070Spatrick     if (OS == llvm::Triple::FreeBSD)
1145e5dd7070Spatrick       KernelZeroFlagVal = 0x0100;
1146e5dd7070Spatrick     else if (OS == llvm::Triple::NetBSD)
1147e5dd7070Spatrick       KernelZeroFlagVal = 0x0002;
1148e5dd7070Spatrick     else if (OS == llvm::Triple::OpenBSD)
1149e5dd7070Spatrick       KernelZeroFlagVal = 0x0008;
1150e5dd7070Spatrick     else if (OS == llvm::Triple::Linux)
1151e5dd7070Spatrick       // __GFP_ZERO
1152e5dd7070Spatrick       KernelZeroFlagVal = 0x8000;
1153e5dd7070Spatrick     else
1154e5dd7070Spatrick       // FIXME: We need a more general way of getting the M_ZERO value.
1155e5dd7070Spatrick       // See also: O_CREAT in UnixAPIChecker.cpp.
1156e5dd7070Spatrick 
1157e5dd7070Spatrick       // Fall back to normal malloc behavior on platforms where we don't
1158e5dd7070Spatrick       // know M_ZERO.
1159*12c85518Srobert       return std::nullopt;
1160e5dd7070Spatrick   }
1161e5dd7070Spatrick 
1162e5dd7070Spatrick   // We treat the last argument as the flags argument, and callers fall-back to
1163e5dd7070Spatrick   // normal malloc on a None return. This works for the FreeBSD kernel malloc
1164e5dd7070Spatrick   // as well as Linux kmalloc.
1165ec727ea7Spatrick   if (Call.getNumArgs() < 2)
1166*12c85518Srobert     return std::nullopt;
1167e5dd7070Spatrick 
1168ec727ea7Spatrick   const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
1169e5dd7070Spatrick   const SVal V = C.getSVal(FlagsEx);
1170*12c85518Srobert   if (!isa<NonLoc>(V)) {
1171e5dd7070Spatrick     // The case where 'V' can be a location can only be due to a bad header,
1172e5dd7070Spatrick     // so in this case bail out.
1173*12c85518Srobert     return std::nullopt;
1174e5dd7070Spatrick   }
1175e5dd7070Spatrick 
1176e5dd7070Spatrick   NonLoc Flags = V.castAs<NonLoc>();
1177e5dd7070Spatrick   NonLoc ZeroFlag = C.getSValBuilder()
1178*12c85518Srobert                         .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
1179e5dd7070Spatrick                         .castAs<NonLoc>();
1180e5dd7070Spatrick   SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
1181e5dd7070Spatrick                                                       Flags, ZeroFlag,
1182e5dd7070Spatrick                                                       FlagsEx->getType());
1183e5dd7070Spatrick   if (MaskedFlagsUC.isUnknownOrUndef())
1184*12c85518Srobert     return std::nullopt;
1185e5dd7070Spatrick   DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1186e5dd7070Spatrick 
1187e5dd7070Spatrick   // Check if maskedFlags is non-zero.
1188e5dd7070Spatrick   ProgramStateRef TrueState, FalseState;
1189e5dd7070Spatrick   std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1190e5dd7070Spatrick 
1191e5dd7070Spatrick   // If M_ZERO is set, treat this like calloc (initialized).
1192e5dd7070Spatrick   if (TrueState && !FalseState) {
1193e5dd7070Spatrick     SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
1194ec727ea7Spatrick     return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,
1195ec727ea7Spatrick                         AF_Malloc);
1196e5dd7070Spatrick   }
1197e5dd7070Spatrick 
1198*12c85518Srobert   return std::nullopt;
1199e5dd7070Spatrick }
1200e5dd7070Spatrick 
evalMulForBufferSize(CheckerContext & C,const Expr * Blocks,const Expr * BlockBytes)1201e5dd7070Spatrick SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
1202e5dd7070Spatrick                                          const Expr *BlockBytes) {
1203e5dd7070Spatrick   SValBuilder &SB = C.getSValBuilder();
1204e5dd7070Spatrick   SVal BlocksVal = C.getSVal(Blocks);
1205e5dd7070Spatrick   SVal BlockBytesVal = C.getSVal(BlockBytes);
1206e5dd7070Spatrick   ProgramStateRef State = C.getState();
1207e5dd7070Spatrick   SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1208e5dd7070Spatrick                                 SB.getContext().getSizeType());
1209e5dd7070Spatrick   return TotalSize;
1210e5dd7070Spatrick }
1211e5dd7070Spatrick 
checkBasicAlloc(const CallEvent & Call,CheckerContext & C) const1212ec727ea7Spatrick void MallocChecker::checkBasicAlloc(const CallEvent &Call,
1213ec727ea7Spatrick                                     CheckerContext &C) const {
1214ec727ea7Spatrick   ProgramStateRef State = C.getState();
1215ec727ea7Spatrick   State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1216ec727ea7Spatrick                        AF_Malloc);
1217ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1218ec727ea7Spatrick   C.addTransition(State);
1219ec727ea7Spatrick }
1220e5dd7070Spatrick 
checkKernelMalloc(const CallEvent & Call,CheckerContext & C) const1221ec727ea7Spatrick void MallocChecker::checkKernelMalloc(const CallEvent &Call,
1222ec727ea7Spatrick                                       CheckerContext &C) const {
1223ec727ea7Spatrick   ProgramStateRef State = C.getState();
1224*12c85518Srobert   std::optional<ProgramStateRef> MaybeState =
1225ec727ea7Spatrick       performKernelMalloc(Call, C, State);
1226*12c85518Srobert   if (MaybeState)
1227*12c85518Srobert     State = *MaybeState;
1228ec727ea7Spatrick   else
1229ec727ea7Spatrick     State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1230ec727ea7Spatrick                          AF_Malloc);
1231ec727ea7Spatrick   C.addTransition(State);
1232ec727ea7Spatrick }
1233e5dd7070Spatrick 
isStandardRealloc(const CallEvent & Call)1234ec727ea7Spatrick static bool isStandardRealloc(const CallEvent &Call) {
1235ec727ea7Spatrick   const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1236ec727ea7Spatrick   assert(FD);
1237ec727ea7Spatrick   ASTContext &AC = FD->getASTContext();
1238ec727ea7Spatrick 
1239ec727ea7Spatrick   if (isa<CXXMethodDecl>(FD))
1240ec727ea7Spatrick     return false;
1241ec727ea7Spatrick 
1242ec727ea7Spatrick   return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
1243ec727ea7Spatrick          FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
1244ec727ea7Spatrick          FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
1245ec727ea7Spatrick              AC.getSizeType();
1246ec727ea7Spatrick }
1247ec727ea7Spatrick 
isGRealloc(const CallEvent & Call)1248ec727ea7Spatrick static bool isGRealloc(const CallEvent &Call) {
1249ec727ea7Spatrick   const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1250ec727ea7Spatrick   assert(FD);
1251ec727ea7Spatrick   ASTContext &AC = FD->getASTContext();
1252ec727ea7Spatrick 
1253ec727ea7Spatrick   if (isa<CXXMethodDecl>(FD))
1254ec727ea7Spatrick     return false;
1255ec727ea7Spatrick 
1256ec727ea7Spatrick   return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
1257ec727ea7Spatrick          FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
1258ec727ea7Spatrick          FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
1259ec727ea7Spatrick              AC.UnsignedLongTy;
1260ec727ea7Spatrick }
1261ec727ea7Spatrick 
checkRealloc(const CallEvent & Call,CheckerContext & C,bool ShouldFreeOnFail) const1262ec727ea7Spatrick void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C,
1263ec727ea7Spatrick                                  bool ShouldFreeOnFail) const {
1264ec727ea7Spatrick   // HACK: CallDescription currently recognizes non-standard realloc functions
1265ec727ea7Spatrick   // as standard because it doesn't check the type, or wether its a non-method
1266ec727ea7Spatrick   // function. This should be solved by making CallDescription smarter.
1267ec727ea7Spatrick   // Mind that this came from a bug report, and all other functions suffer from
1268ec727ea7Spatrick   // this.
1269ec727ea7Spatrick   // https://bugs.llvm.org/show_bug.cgi?id=46253
1270ec727ea7Spatrick   if (!isStandardRealloc(Call) && !isGRealloc(Call))
1271ec727ea7Spatrick     return;
1272ec727ea7Spatrick   ProgramStateRef State = C.getState();
1273ec727ea7Spatrick   State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc);
1274ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1275ec727ea7Spatrick   C.addTransition(State);
1276ec727ea7Spatrick }
1277ec727ea7Spatrick 
checkCalloc(const CallEvent & Call,CheckerContext & C) const1278ec727ea7Spatrick void MallocChecker::checkCalloc(const CallEvent &Call,
1279ec727ea7Spatrick                                 CheckerContext &C) const {
1280ec727ea7Spatrick   ProgramStateRef State = C.getState();
1281ec727ea7Spatrick   State = CallocMem(C, Call, State);
1282ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1283ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1284ec727ea7Spatrick   C.addTransition(State);
1285ec727ea7Spatrick }
1286ec727ea7Spatrick 
checkFree(const CallEvent & Call,CheckerContext & C) const1287ec727ea7Spatrick void MallocChecker::checkFree(const CallEvent &Call, CheckerContext &C) const {
1288e5dd7070Spatrick   ProgramStateRef State = C.getState();
1289e5dd7070Spatrick   bool IsKnownToBeAllocatedMemory = false;
1290ec727ea7Spatrick   if (suppressDeallocationsInSuspiciousContexts(Call, C))
1291e5dd7070Spatrick     return;
1292ec727ea7Spatrick   State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1293ec727ea7Spatrick                      AF_Malloc);
1294ec727ea7Spatrick   C.addTransition(State);
1295e5dd7070Spatrick }
1296ec727ea7Spatrick 
checkAlloca(const CallEvent & Call,CheckerContext & C) const1297ec727ea7Spatrick void MallocChecker::checkAlloca(const CallEvent &Call,
1298ec727ea7Spatrick                                 CheckerContext &C) const {
1299ec727ea7Spatrick   ProgramStateRef State = C.getState();
1300ec727ea7Spatrick   State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1301ec727ea7Spatrick                        AF_Alloca);
1302ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1303ec727ea7Spatrick   C.addTransition(State);
1304ec727ea7Spatrick }
1305ec727ea7Spatrick 
checkStrdup(const CallEvent & Call,CheckerContext & C) const1306ec727ea7Spatrick void MallocChecker::checkStrdup(const CallEvent &Call,
1307ec727ea7Spatrick                                 CheckerContext &C) const {
1308ec727ea7Spatrick   ProgramStateRef State = C.getState();
1309ec727ea7Spatrick   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1310ec727ea7Spatrick   if (!CE)
1311e5dd7070Spatrick     return;
1312ec727ea7Spatrick   State = MallocUpdateRefState(C, CE, State, AF_Malloc);
1313ec727ea7Spatrick 
1314ec727ea7Spatrick   C.addTransition(State);
1315ec727ea7Spatrick }
1316ec727ea7Spatrick 
checkIfNameIndex(const CallEvent & Call,CheckerContext & C) const1317ec727ea7Spatrick void MallocChecker::checkIfNameIndex(const CallEvent &Call,
1318ec727ea7Spatrick                                      CheckerContext &C) const {
1319ec727ea7Spatrick   ProgramStateRef State = C.getState();
1320ec727ea7Spatrick   // Should we model this differently? We can allocate a fixed number of
1321ec727ea7Spatrick   // elements with zeros in the last one.
1322ec727ea7Spatrick   State =
1323ec727ea7Spatrick       MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, AF_IfNameIndex);
1324ec727ea7Spatrick 
1325ec727ea7Spatrick   C.addTransition(State);
1326ec727ea7Spatrick }
1327ec727ea7Spatrick 
checkIfFreeNameIndex(const CallEvent & Call,CheckerContext & C) const1328ec727ea7Spatrick void MallocChecker::checkIfFreeNameIndex(const CallEvent &Call,
1329ec727ea7Spatrick                                          CheckerContext &C) const {
1330ec727ea7Spatrick   ProgramStateRef State = C.getState();
1331ec727ea7Spatrick   bool IsKnownToBeAllocatedMemory = false;
1332ec727ea7Spatrick   State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1333ec727ea7Spatrick                      AF_IfNameIndex);
1334ec727ea7Spatrick   C.addTransition(State);
1335ec727ea7Spatrick }
1336ec727ea7Spatrick 
checkCXXNewOrCXXDelete(const CallEvent & Call,CheckerContext & C) const1337ec727ea7Spatrick void MallocChecker::checkCXXNewOrCXXDelete(const CallEvent &Call,
1338ec727ea7Spatrick                                            CheckerContext &C) const {
1339ec727ea7Spatrick   ProgramStateRef State = C.getState();
1340ec727ea7Spatrick   bool IsKnownToBeAllocatedMemory = false;
1341ec727ea7Spatrick   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1342ec727ea7Spatrick   if (!CE)
1343e5dd7070Spatrick     return;
1344e5dd7070Spatrick 
1345ec727ea7Spatrick   assert(isStandardNewDelete(Call));
1346ec727ea7Spatrick 
1347e5dd7070Spatrick   // Process direct calls to operator new/new[]/delete/delete[] functions
1348e5dd7070Spatrick   // as distinct from new/new[]/delete/delete[] expressions that are
1349e5dd7070Spatrick   // processed by the checkPostStmt callbacks for CXXNewExpr and
1350e5dd7070Spatrick   // CXXDeleteExpr.
1351ec727ea7Spatrick   const FunctionDecl *FD = C.getCalleeDecl(CE);
1352e5dd7070Spatrick   switch (FD->getOverloadedOperator()) {
1353e5dd7070Spatrick   case OO_New:
1354ec727ea7Spatrick     State =
1355ec727ea7Spatrick         MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State, AF_CXXNew);
1356ec727ea7Spatrick     State = ProcessZeroAllocCheck(Call, 0, State);
1357e5dd7070Spatrick     break;
1358e5dd7070Spatrick   case OO_Array_New:
1359ec727ea7Spatrick     State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1360e5dd7070Spatrick                          AF_CXXNewArray);
1361ec727ea7Spatrick     State = ProcessZeroAllocCheck(Call, 0, State);
1362e5dd7070Spatrick     break;
1363e5dd7070Spatrick   case OO_Delete:
1364ec727ea7Spatrick     State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1365ec727ea7Spatrick                        AF_CXXNew);
1366ec727ea7Spatrick     break;
1367e5dd7070Spatrick   case OO_Array_Delete:
1368ec727ea7Spatrick     State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1369ec727ea7Spatrick                        AF_CXXNewArray);
1370e5dd7070Spatrick     break;
1371e5dd7070Spatrick   default:
1372e5dd7070Spatrick     llvm_unreachable("not a new/delete operator");
1373e5dd7070Spatrick   }
1374ec727ea7Spatrick 
1375ec727ea7Spatrick   C.addTransition(State);
1376e5dd7070Spatrick }
1377e5dd7070Spatrick 
checkGMalloc0(const CallEvent & Call,CheckerContext & C) const1378ec727ea7Spatrick void MallocChecker::checkGMalloc0(const CallEvent &Call,
1379ec727ea7Spatrick                                   CheckerContext &C) const {
1380ec727ea7Spatrick   ProgramStateRef State = C.getState();
1381ec727ea7Spatrick   SValBuilder &svalBuilder = C.getSValBuilder();
1382ec727ea7Spatrick   SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
1383ec727ea7Spatrick   State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State, AF_Malloc);
1384ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1385ec727ea7Spatrick   C.addTransition(State);
1386ec727ea7Spatrick }
1387ec727ea7Spatrick 
checkGMemdup(const CallEvent & Call,CheckerContext & C) const1388ec727ea7Spatrick void MallocChecker::checkGMemdup(const CallEvent &Call,
1389ec727ea7Spatrick                                  CheckerContext &C) const {
1390ec727ea7Spatrick   ProgramStateRef State = C.getState();
1391*12c85518Srobert   State =
1392*12c85518Srobert       MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State, AF_Malloc);
1393ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1394ec727ea7Spatrick   C.addTransition(State);
1395ec727ea7Spatrick }
1396ec727ea7Spatrick 
checkGMallocN(const CallEvent & Call,CheckerContext & C) const1397ec727ea7Spatrick void MallocChecker::checkGMallocN(const CallEvent &Call,
1398ec727ea7Spatrick                                   CheckerContext &C) const {
1399ec727ea7Spatrick   ProgramStateRef State = C.getState();
1400ec727ea7Spatrick   SVal Init = UndefinedVal();
1401ec727ea7Spatrick   SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1402ec727ea7Spatrick   State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc);
1403ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1404ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1405ec727ea7Spatrick   C.addTransition(State);
1406ec727ea7Spatrick }
1407ec727ea7Spatrick 
checkGMallocN0(const CallEvent & Call,CheckerContext & C) const1408ec727ea7Spatrick void MallocChecker::checkGMallocN0(const CallEvent &Call,
1409ec727ea7Spatrick                                    CheckerContext &C) const {
1410ec727ea7Spatrick   ProgramStateRef State = C.getState();
1411ec727ea7Spatrick   SValBuilder &SB = C.getSValBuilder();
1412ec727ea7Spatrick   SVal Init = SB.makeZeroVal(SB.getContext().CharTy);
1413ec727ea7Spatrick   SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1414ec727ea7Spatrick   State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc);
1415ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State);
1416ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1417ec727ea7Spatrick   C.addTransition(State);
1418ec727ea7Spatrick }
1419ec727ea7Spatrick 
checkReallocN(const CallEvent & Call,CheckerContext & C) const1420ec727ea7Spatrick void MallocChecker::checkReallocN(const CallEvent &Call,
1421ec727ea7Spatrick                                   CheckerContext &C) const {
1422ec727ea7Spatrick   ProgramStateRef State = C.getState();
1423ec727ea7Spatrick   State = ReallocMemAux(C, Call, /*ShouldFreeOnFail=*/false, State, AF_Malloc,
1424ec727ea7Spatrick                         /*SuffixWithN=*/true);
1425ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 1, State);
1426ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 2, State);
1427ec727ea7Spatrick   C.addTransition(State);
1428ec727ea7Spatrick }
1429ec727ea7Spatrick 
checkOwnershipAttr(const CallEvent & Call,CheckerContext & C) const1430ec727ea7Spatrick void MallocChecker::checkOwnershipAttr(const CallEvent &Call,
1431ec727ea7Spatrick                                        CheckerContext &C) const {
1432ec727ea7Spatrick   ProgramStateRef State = C.getState();
1433ec727ea7Spatrick   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1434ec727ea7Spatrick   if (!CE)
1435ec727ea7Spatrick     return;
1436ec727ea7Spatrick   const FunctionDecl *FD = C.getCalleeDecl(CE);
1437ec727ea7Spatrick   if (!FD)
1438ec727ea7Spatrick     return;
1439ec727ea7Spatrick   if (ShouldIncludeOwnershipAnnotatedFunctions ||
1440e5dd7070Spatrick       ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1441e5dd7070Spatrick     // Check all the attributes, if there are any.
1442e5dd7070Spatrick     // There can be multiple of these attributes.
1443e5dd7070Spatrick     if (FD->hasAttrs())
1444e5dd7070Spatrick       for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
1445e5dd7070Spatrick         switch (I->getOwnKind()) {
1446e5dd7070Spatrick         case OwnershipAttr::Returns:
1447ec727ea7Spatrick           State = MallocMemReturnsAttr(C, Call, I, State);
1448e5dd7070Spatrick           break;
1449e5dd7070Spatrick         case OwnershipAttr::Takes:
1450e5dd7070Spatrick         case OwnershipAttr::Holds:
1451ec727ea7Spatrick           State = FreeMemAttr(C, Call, I, State);
1452e5dd7070Spatrick           break;
1453e5dd7070Spatrick         }
1454e5dd7070Spatrick       }
1455e5dd7070Spatrick   }
1456e5dd7070Spatrick   C.addTransition(State);
1457e5dd7070Spatrick }
1458e5dd7070Spatrick 
checkPostCall(const CallEvent & Call,CheckerContext & C) const1459ec727ea7Spatrick void MallocChecker::checkPostCall(const CallEvent &Call,
1460ec727ea7Spatrick                                   CheckerContext &C) const {
1461ec727ea7Spatrick   if (C.wasInlined)
1462ec727ea7Spatrick     return;
1463ec727ea7Spatrick   if (!Call.getOriginExpr())
1464ec727ea7Spatrick     return;
1465ec727ea7Spatrick 
1466ec727ea7Spatrick   ProgramStateRef State = C.getState();
1467ec727ea7Spatrick 
1468ec727ea7Spatrick   if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1469ec727ea7Spatrick     (*Callback)(this, Call, C);
1470ec727ea7Spatrick     return;
1471ec727ea7Spatrick   }
1472ec727ea7Spatrick 
1473ec727ea7Spatrick   if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1474ec727ea7Spatrick     (*Callback)(this, Call, C);
1475ec727ea7Spatrick     return;
1476ec727ea7Spatrick   }
1477ec727ea7Spatrick 
1478ec727ea7Spatrick   if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1479ec727ea7Spatrick     (*Callback)(this, Call, C);
1480ec727ea7Spatrick     return;
1481ec727ea7Spatrick   }
1482ec727ea7Spatrick 
1483ec727ea7Spatrick   if (isStandardNewDelete(Call)) {
1484ec727ea7Spatrick     checkCXXNewOrCXXDelete(Call, C);
1485ec727ea7Spatrick     return;
1486ec727ea7Spatrick   }
1487ec727ea7Spatrick 
1488ec727ea7Spatrick   checkOwnershipAttr(Call, C);
1489ec727ea7Spatrick }
1490ec727ea7Spatrick 
1491e5dd7070Spatrick // Performs a 0-sized allocations check.
ProcessZeroAllocCheck(const CallEvent & Call,const unsigned IndexOfSizeArg,ProgramStateRef State,std::optional<SVal> RetVal)1492e5dd7070Spatrick ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
1493ec727ea7Spatrick     const CallEvent &Call, const unsigned IndexOfSizeArg, ProgramStateRef State,
1494*12c85518Srobert     std::optional<SVal> RetVal) {
1495e5dd7070Spatrick   if (!State)
1496e5dd7070Spatrick     return nullptr;
1497e5dd7070Spatrick 
1498e5dd7070Spatrick   if (!RetVal)
1499ec727ea7Spatrick     RetVal = Call.getReturnValue();
1500e5dd7070Spatrick 
1501e5dd7070Spatrick   const Expr *Arg = nullptr;
1502e5dd7070Spatrick 
1503ec727ea7Spatrick   if (const CallExpr *CE = dyn_cast<CallExpr>(Call.getOriginExpr())) {
1504e5dd7070Spatrick     Arg = CE->getArg(IndexOfSizeArg);
1505ec727ea7Spatrick   } else if (const CXXNewExpr *NE =
1506ec727ea7Spatrick                  dyn_cast<CXXNewExpr>(Call.getOriginExpr())) {
1507ec727ea7Spatrick     if (NE->isArray()) {
1508e5dd7070Spatrick       Arg = *NE->getArraySize();
1509ec727ea7Spatrick     } else {
1510e5dd7070Spatrick       return State;
1511e5dd7070Spatrick     }
1512ec727ea7Spatrick   } else
1513e5dd7070Spatrick     llvm_unreachable("not a CallExpr or CXXNewExpr");
1514e5dd7070Spatrick 
1515e5dd7070Spatrick   assert(Arg);
1516e5dd7070Spatrick 
1517ec727ea7Spatrick   auto DefArgVal =
1518ec727ea7Spatrick       State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
1519e5dd7070Spatrick 
1520e5dd7070Spatrick   if (!DefArgVal)
1521e5dd7070Spatrick     return State;
1522e5dd7070Spatrick 
1523e5dd7070Spatrick   // Check if the allocation size is 0.
1524e5dd7070Spatrick   ProgramStateRef TrueState, FalseState;
1525ec727ea7Spatrick   SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1526e5dd7070Spatrick   DefinedSVal Zero =
1527e5dd7070Spatrick       SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
1528e5dd7070Spatrick 
1529e5dd7070Spatrick   std::tie(TrueState, FalseState) =
1530e5dd7070Spatrick       State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
1531e5dd7070Spatrick 
1532e5dd7070Spatrick   if (TrueState && !FalseState) {
1533e5dd7070Spatrick     SymbolRef Sym = RetVal->getAsLocSymbol();
1534e5dd7070Spatrick     if (!Sym)
1535e5dd7070Spatrick       return State;
1536e5dd7070Spatrick 
1537e5dd7070Spatrick     const RefState *RS = State->get<RegionState>(Sym);
1538e5dd7070Spatrick     if (RS) {
1539e5dd7070Spatrick       if (RS->isAllocated())
1540e5dd7070Spatrick         return TrueState->set<RegionState>(Sym,
1541e5dd7070Spatrick                                           RefState::getAllocatedOfSizeZero(RS));
1542e5dd7070Spatrick       else
1543e5dd7070Spatrick         return State;
1544e5dd7070Spatrick     } else {
1545e5dd7070Spatrick       // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as
1546e5dd7070Spatrick       // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not
1547e5dd7070Spatrick       // tracked. Add zero-reallocated Sym to the state to catch references
1548e5dd7070Spatrick       // to zero-allocated memory.
1549e5dd7070Spatrick       return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1550e5dd7070Spatrick     }
1551e5dd7070Spatrick   }
1552e5dd7070Spatrick 
1553e5dd7070Spatrick   // Assume the value is non-zero going forward.
1554e5dd7070Spatrick   assert(FalseState);
1555e5dd7070Spatrick   return FalseState;
1556e5dd7070Spatrick }
1557e5dd7070Spatrick 
getDeepPointeeType(QualType T)1558e5dd7070Spatrick static QualType getDeepPointeeType(QualType T) {
1559e5dd7070Spatrick   QualType Result = T, PointeeType = T->getPointeeType();
1560e5dd7070Spatrick   while (!PointeeType.isNull()) {
1561e5dd7070Spatrick     Result = PointeeType;
1562e5dd7070Spatrick     PointeeType = PointeeType->getPointeeType();
1563e5dd7070Spatrick   }
1564e5dd7070Spatrick   return Result;
1565e5dd7070Spatrick }
1566e5dd7070Spatrick 
1567e5dd7070Spatrick /// \returns true if the constructor invoked by \p NE has an argument of a
1568e5dd7070Spatrick /// pointer/reference to a record type.
hasNonTrivialConstructorCall(const CXXNewExpr * NE)1569e5dd7070Spatrick static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) {
1570e5dd7070Spatrick 
1571e5dd7070Spatrick   const CXXConstructExpr *ConstructE = NE->getConstructExpr();
1572e5dd7070Spatrick   if (!ConstructE)
1573e5dd7070Spatrick     return false;
1574e5dd7070Spatrick 
1575e5dd7070Spatrick   if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1576e5dd7070Spatrick     return false;
1577e5dd7070Spatrick 
1578e5dd7070Spatrick   const CXXConstructorDecl *CtorD = ConstructE->getConstructor();
1579e5dd7070Spatrick 
1580e5dd7070Spatrick   // Iterate over the constructor parameters.
1581e5dd7070Spatrick   for (const auto *CtorParam : CtorD->parameters()) {
1582e5dd7070Spatrick 
1583e5dd7070Spatrick     QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType();
1584e5dd7070Spatrick     if (CtorParamPointeeT.isNull())
1585e5dd7070Spatrick       continue;
1586e5dd7070Spatrick 
1587e5dd7070Spatrick     CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT);
1588e5dd7070Spatrick 
1589e5dd7070Spatrick     if (CtorParamPointeeT->getAsCXXRecordDecl())
1590e5dd7070Spatrick       return true;
1591e5dd7070Spatrick   }
1592e5dd7070Spatrick 
1593e5dd7070Spatrick   return false;
1594e5dd7070Spatrick }
1595e5dd7070Spatrick 
1596ec727ea7Spatrick ProgramStateRef
processNewAllocation(const CXXAllocatorCall & Call,CheckerContext & C,AllocationFamily Family) const1597ec727ea7Spatrick MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
1598e5dd7070Spatrick                                     CheckerContext &C,
1599ec727ea7Spatrick                                     AllocationFamily Family) const {
1600ec727ea7Spatrick   if (!isStandardNewDelete(Call))
1601ec727ea7Spatrick     return nullptr;
1602e5dd7070Spatrick 
1603ec727ea7Spatrick   const CXXNewExpr *NE = Call.getOriginExpr();
1604e5dd7070Spatrick   const ParentMap &PM = C.getLocationContext()->getParentMap();
1605ec727ea7Spatrick   ProgramStateRef State = C.getState();
1606e5dd7070Spatrick 
1607e5dd7070Spatrick   // Non-trivial constructors have a chance to escape 'this', but marking all
1608e5dd7070Spatrick   // invocations of trivial constructors as escaped would cause too great of
1609e5dd7070Spatrick   // reduction of true positives, so let's just do that for constructors that
1610e5dd7070Spatrick   // have an argument of a pointer-to-record type.
1611e5dd7070Spatrick   if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE))
1612ec727ea7Spatrick     return State;
1613e5dd7070Spatrick 
1614e5dd7070Spatrick   // The return value from operator new is bound to a specified initialization
1615e5dd7070Spatrick   // value (if any) and we don't want to loose this value. So we call
1616e5dd7070Spatrick   // MallocUpdateRefState() instead of MallocMemAux() which breaks the
1617e5dd7070Spatrick   // existing binding.
1618ec727ea7Spatrick   SVal Target = Call.getObjectUnderConstruction();
1619ec727ea7Spatrick   State = MallocUpdateRefState(C, NE, State, Family, Target);
1620ec727ea7Spatrick   State = ProcessZeroAllocCheck(Call, 0, State, Target);
1621ec727ea7Spatrick   return State;
1622ec727ea7Spatrick }
1623ec727ea7Spatrick 
checkNewAllocator(const CXXAllocatorCall & Call,CheckerContext & C) const1624ec727ea7Spatrick void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
1625ec727ea7Spatrick                                       CheckerContext &C) const {
1626ec727ea7Spatrick   if (!C.wasInlined) {
1627ec727ea7Spatrick     ProgramStateRef State = processNewAllocation(
1628ec727ea7Spatrick         Call, C,
1629ec727ea7Spatrick         (Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
1630e5dd7070Spatrick     C.addTransition(State);
1631e5dd7070Spatrick   }
1632e5dd7070Spatrick }
1633e5dd7070Spatrick 
isKnownDeallocObjCMethodName(const ObjCMethodCall & Call)1634e5dd7070Spatrick static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
1635e5dd7070Spatrick   // If the first selector piece is one of the names below, assume that the
1636e5dd7070Spatrick   // object takes ownership of the memory, promising to eventually deallocate it
1637e5dd7070Spatrick   // with free().
1638e5dd7070Spatrick   // Ex:  [NSData dataWithBytesNoCopy:bytes length:10];
1639e5dd7070Spatrick   // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
1640e5dd7070Spatrick   StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1641e5dd7070Spatrick   return FirstSlot == "dataWithBytesNoCopy" ||
1642e5dd7070Spatrick          FirstSlot == "initWithBytesNoCopy" ||
1643e5dd7070Spatrick          FirstSlot == "initWithCharactersNoCopy";
1644e5dd7070Spatrick }
1645e5dd7070Spatrick 
getFreeWhenDoneArg(const ObjCMethodCall & Call)1646*12c85518Srobert static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
1647e5dd7070Spatrick   Selector S = Call.getSelector();
1648e5dd7070Spatrick 
1649e5dd7070Spatrick   // FIXME: We should not rely on fully-constrained symbols being folded.
1650e5dd7070Spatrick   for (unsigned i = 1; i < S.getNumArgs(); ++i)
1651e5dd7070Spatrick     if (S.getNameForSlot(i).equals("freeWhenDone"))
1652e5dd7070Spatrick       return !Call.getArgSVal(i).isZeroConstant();
1653e5dd7070Spatrick 
1654*12c85518Srobert   return std::nullopt;
1655e5dd7070Spatrick }
1656e5dd7070Spatrick 
checkPostObjCMessage(const ObjCMethodCall & Call,CheckerContext & C) const1657e5dd7070Spatrick void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
1658e5dd7070Spatrick                                          CheckerContext &C) const {
1659e5dd7070Spatrick   if (C.wasInlined)
1660e5dd7070Spatrick     return;
1661e5dd7070Spatrick 
1662e5dd7070Spatrick   if (!isKnownDeallocObjCMethodName(Call))
1663e5dd7070Spatrick     return;
1664e5dd7070Spatrick 
1665*12c85518Srobert   if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
1666e5dd7070Spatrick     if (!*FreeWhenDone)
1667e5dd7070Spatrick       return;
1668e5dd7070Spatrick 
1669e5dd7070Spatrick   if (Call.hasNonZeroCallbackArg())
1670e5dd7070Spatrick     return;
1671e5dd7070Spatrick 
1672e5dd7070Spatrick   bool IsKnownToBeAllocatedMemory;
1673e5dd7070Spatrick   ProgramStateRef State =
1674ec727ea7Spatrick       FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(),
1675ec727ea7Spatrick                  /*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc,
1676*12c85518Srobert                  /*ReturnsNullOnFailure=*/true);
1677e5dd7070Spatrick 
1678e5dd7070Spatrick   C.addTransition(State);
1679e5dd7070Spatrick }
1680e5dd7070Spatrick 
1681e5dd7070Spatrick ProgramStateRef
MallocMemReturnsAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const1682ec727ea7Spatrick MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
1683e5dd7070Spatrick                                     const OwnershipAttr *Att,
1684e5dd7070Spatrick                                     ProgramStateRef State) const {
1685e5dd7070Spatrick   if (!State)
1686e5dd7070Spatrick     return nullptr;
1687e5dd7070Spatrick 
1688ec727ea7Spatrick   if (Att->getModule()->getName() != "malloc")
1689e5dd7070Spatrick     return nullptr;
1690e5dd7070Spatrick 
1691e5dd7070Spatrick   OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
1692e5dd7070Spatrick   if (I != E) {
1693ec727ea7Spatrick     return MallocMemAux(C, Call, Call.getArgExpr(I->getASTIndex()),
1694ec727ea7Spatrick                         UndefinedVal(), State, AF_Malloc);
1695e5dd7070Spatrick   }
1696ec727ea7Spatrick   return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, AF_Malloc);
1697e5dd7070Spatrick }
1698e5dd7070Spatrick 
MallocMemAux(CheckerContext & C,const CallEvent & Call,const Expr * SizeEx,SVal Init,ProgramStateRef State,AllocationFamily Family)1699e5dd7070Spatrick ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1700ec727ea7Spatrick                                             const CallEvent &Call,
1701e5dd7070Spatrick                                             const Expr *SizeEx, SVal Init,
1702e5dd7070Spatrick                                             ProgramStateRef State,
1703e5dd7070Spatrick                                             AllocationFamily Family) {
1704e5dd7070Spatrick   if (!State)
1705e5dd7070Spatrick     return nullptr;
1706e5dd7070Spatrick 
1707ec727ea7Spatrick   assert(SizeEx);
1708ec727ea7Spatrick   return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
1709e5dd7070Spatrick }
1710e5dd7070Spatrick 
MallocMemAux(CheckerContext & C,const CallEvent & Call,SVal Size,SVal Init,ProgramStateRef State,AllocationFamily Family)1711e5dd7070Spatrick ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1712ec727ea7Spatrick                                             const CallEvent &Call, SVal Size,
1713ec727ea7Spatrick                                             SVal Init, ProgramStateRef State,
1714e5dd7070Spatrick                                             AllocationFamily Family) {
1715e5dd7070Spatrick   if (!State)
1716e5dd7070Spatrick     return nullptr;
1717e5dd7070Spatrick 
1718ec727ea7Spatrick   const Expr *CE = Call.getOriginExpr();
1719ec727ea7Spatrick 
1720e5dd7070Spatrick   // We expect the malloc functions to return a pointer.
1721e5dd7070Spatrick   if (!Loc::isLocType(CE->getType()))
1722e5dd7070Spatrick     return nullptr;
1723e5dd7070Spatrick 
1724e5dd7070Spatrick   // Bind the return value to the symbolic value from the heap region.
1725e5dd7070Spatrick   // TODO: We could rewrite post visit to eval call; 'malloc' does not have
1726e5dd7070Spatrick   // side effects other than what we model here.
1727e5dd7070Spatrick   unsigned Count = C.blockCount();
1728e5dd7070Spatrick   SValBuilder &svalBuilder = C.getSValBuilder();
1729e5dd7070Spatrick   const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1730e5dd7070Spatrick   DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
1731e5dd7070Spatrick       .castAs<DefinedSVal>();
1732e5dd7070Spatrick   State = State->BindExpr(CE, C.getLocationContext(), RetVal);
1733e5dd7070Spatrick 
1734e5dd7070Spatrick   // Fill the region with the initialization value.
1735e5dd7070Spatrick   State = State->bindDefaultInitial(RetVal, Init, LCtx);
1736e5dd7070Spatrick 
1737*12c85518Srobert   // If Size is somehow undefined at this point, this line prevents a crash.
1738*12c85518Srobert   if (Size.isUndef())
1739*12c85518Srobert     Size = UnknownVal();
1740*12c85518Srobert 
1741a9ac8606Spatrick   // Set the region's extent.
1742a9ac8606Spatrick   State = setDynamicExtent(State, RetVal.getAsRegion(),
1743a9ac8606Spatrick                            Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
1744e5dd7070Spatrick 
1745e5dd7070Spatrick   return MallocUpdateRefState(C, CE, State, Family);
1746e5dd7070Spatrick }
1747e5dd7070Spatrick 
MallocUpdateRefState(CheckerContext & C,const Expr * E,ProgramStateRef State,AllocationFamily Family,std::optional<SVal> RetVal)1748e5dd7070Spatrick static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
1749e5dd7070Spatrick                                             ProgramStateRef State,
1750e5dd7070Spatrick                                             AllocationFamily Family,
1751*12c85518Srobert                                             std::optional<SVal> RetVal) {
1752e5dd7070Spatrick   if (!State)
1753e5dd7070Spatrick     return nullptr;
1754e5dd7070Spatrick 
1755e5dd7070Spatrick   // Get the return value.
1756e5dd7070Spatrick   if (!RetVal)
1757e5dd7070Spatrick     RetVal = C.getSVal(E);
1758e5dd7070Spatrick 
1759e5dd7070Spatrick   // We expect the malloc functions to return a pointer.
1760e5dd7070Spatrick   if (!RetVal->getAs<Loc>())
1761e5dd7070Spatrick     return nullptr;
1762e5dd7070Spatrick 
1763e5dd7070Spatrick   SymbolRef Sym = RetVal->getAsLocSymbol();
1764e5dd7070Spatrick   // This is a return value of a function that was not inlined, such as malloc()
1765e5dd7070Spatrick   // or new(). We've checked that in the caller. Therefore, it must be a symbol.
1766e5dd7070Spatrick   assert(Sym);
1767e5dd7070Spatrick 
1768e5dd7070Spatrick   // Set the symbol's state to Allocated.
1769e5dd7070Spatrick   return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1770e5dd7070Spatrick }
1771e5dd7070Spatrick 
FreeMemAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const1772e5dd7070Spatrick ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
1773ec727ea7Spatrick                                            const CallEvent &Call,
1774e5dd7070Spatrick                                            const OwnershipAttr *Att,
1775e5dd7070Spatrick                                            ProgramStateRef State) const {
1776e5dd7070Spatrick   if (!State)
1777e5dd7070Spatrick     return nullptr;
1778e5dd7070Spatrick 
1779ec727ea7Spatrick   if (Att->getModule()->getName() != "malloc")
1780e5dd7070Spatrick     return nullptr;
1781e5dd7070Spatrick 
1782e5dd7070Spatrick   bool IsKnownToBeAllocated = false;
1783e5dd7070Spatrick 
1784e5dd7070Spatrick   for (const auto &Arg : Att->args()) {
1785ec727ea7Spatrick     ProgramStateRef StateI =
1786ec727ea7Spatrick         FreeMemAux(C, Call, State, Arg.getASTIndex(),
1787ec727ea7Spatrick                    Att->getOwnKind() == OwnershipAttr::Holds,
1788ec727ea7Spatrick                    IsKnownToBeAllocated, AF_Malloc);
1789e5dd7070Spatrick     if (StateI)
1790e5dd7070Spatrick       State = StateI;
1791e5dd7070Spatrick   }
1792e5dd7070Spatrick   return State;
1793e5dd7070Spatrick }
1794e5dd7070Spatrick 
FreeMemAux(CheckerContext & C,const CallEvent & Call,ProgramStateRef State,unsigned Num,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure) const1795ec727ea7Spatrick ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
1796ec727ea7Spatrick                                           const CallEvent &Call,
1797e5dd7070Spatrick                                           ProgramStateRef State, unsigned Num,
1798e5dd7070Spatrick                                           bool Hold, bool &IsKnownToBeAllocated,
1799ec727ea7Spatrick                                           AllocationFamily Family,
1800e5dd7070Spatrick                                           bool ReturnsNullOnFailure) const {
1801e5dd7070Spatrick   if (!State)
1802e5dd7070Spatrick     return nullptr;
1803e5dd7070Spatrick 
1804ec727ea7Spatrick   if (Call.getNumArgs() < (Num + 1))
1805e5dd7070Spatrick     return nullptr;
1806e5dd7070Spatrick 
1807ec727ea7Spatrick   return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,
1808ec727ea7Spatrick                     IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1809e5dd7070Spatrick }
1810e5dd7070Spatrick 
1811e5dd7070Spatrick /// Checks if the previous call to free on the given symbol failed - if free
1812e5dd7070Spatrick /// failed, returns true. Also, returns the corresponding return value symbol.
didPreviousFreeFail(ProgramStateRef State,SymbolRef Sym,SymbolRef & RetStatusSymbol)1813e5dd7070Spatrick static bool didPreviousFreeFail(ProgramStateRef State,
1814e5dd7070Spatrick                                 SymbolRef Sym, SymbolRef &RetStatusSymbol) {
1815e5dd7070Spatrick   const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1816e5dd7070Spatrick   if (Ret) {
1817e5dd7070Spatrick     assert(*Ret && "We should not store the null return symbol");
1818e5dd7070Spatrick     ConstraintManager &CMgr = State->getConstraintManager();
1819e5dd7070Spatrick     ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);
1820e5dd7070Spatrick     RetStatusSymbol = *Ret;
1821e5dd7070Spatrick     return FreeFailed.isConstrainedTrue();
1822e5dd7070Spatrick   }
1823e5dd7070Spatrick   return false;
1824e5dd7070Spatrick }
1825e5dd7070Spatrick 
printMemFnName(raw_ostream & os,CheckerContext & C,const Expr * E)1826ec727ea7Spatrick static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
1827e5dd7070Spatrick   if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1828e5dd7070Spatrick     // FIXME: This doesn't handle indirect calls.
1829e5dd7070Spatrick     const FunctionDecl *FD = CE->getDirectCallee();
1830e5dd7070Spatrick     if (!FD)
1831e5dd7070Spatrick       return false;
1832e5dd7070Spatrick 
1833e5dd7070Spatrick     os << *FD;
1834e5dd7070Spatrick     if (!FD->isOverloadedOperator())
1835e5dd7070Spatrick       os << "()";
1836e5dd7070Spatrick     return true;
1837e5dd7070Spatrick   }
1838e5dd7070Spatrick 
1839e5dd7070Spatrick   if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
1840e5dd7070Spatrick     if (Msg->isInstanceMessage())
1841e5dd7070Spatrick       os << "-";
1842e5dd7070Spatrick     else
1843e5dd7070Spatrick       os << "+";
1844e5dd7070Spatrick     Msg->getSelector().print(os);
1845e5dd7070Spatrick     return true;
1846e5dd7070Spatrick   }
1847e5dd7070Spatrick 
1848e5dd7070Spatrick   if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1849e5dd7070Spatrick     os << "'"
1850e5dd7070Spatrick        << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
1851e5dd7070Spatrick        << "'";
1852e5dd7070Spatrick     return true;
1853e5dd7070Spatrick   }
1854e5dd7070Spatrick 
1855e5dd7070Spatrick   if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
1856e5dd7070Spatrick     os << "'"
1857e5dd7070Spatrick        << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
1858e5dd7070Spatrick        << "'";
1859e5dd7070Spatrick     return true;
1860e5dd7070Spatrick   }
1861e5dd7070Spatrick 
1862e5dd7070Spatrick   return false;
1863e5dd7070Spatrick }
1864e5dd7070Spatrick 
printExpectedAllocName(raw_ostream & os,AllocationFamily Family)1865ec727ea7Spatrick static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
1866e5dd7070Spatrick 
1867e5dd7070Spatrick   switch(Family) {
1868e5dd7070Spatrick     case AF_Malloc: os << "malloc()"; return;
1869e5dd7070Spatrick     case AF_CXXNew: os << "'new'"; return;
1870e5dd7070Spatrick     case AF_CXXNewArray: os << "'new[]'"; return;
1871e5dd7070Spatrick     case AF_IfNameIndex: os << "'if_nameindex()'"; return;
1872e5dd7070Spatrick     case AF_InnerBuffer: os << "container-specific allocator"; return;
1873e5dd7070Spatrick     case AF_Alloca:
1874e5dd7070Spatrick     case AF_None: llvm_unreachable("not a deallocation expression");
1875e5dd7070Spatrick   }
1876e5dd7070Spatrick }
1877e5dd7070Spatrick 
printExpectedDeallocName(raw_ostream & os,AllocationFamily Family)1878e5dd7070Spatrick static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
1879e5dd7070Spatrick   switch(Family) {
1880e5dd7070Spatrick     case AF_Malloc: os << "free()"; return;
1881e5dd7070Spatrick     case AF_CXXNew: os << "'delete'"; return;
1882e5dd7070Spatrick     case AF_CXXNewArray: os << "'delete[]'"; return;
1883e5dd7070Spatrick     case AF_IfNameIndex: os << "'if_freenameindex()'"; return;
1884e5dd7070Spatrick     case AF_InnerBuffer: os << "container-specific deallocator"; return;
1885e5dd7070Spatrick     case AF_Alloca:
1886e5dd7070Spatrick     case AF_None: llvm_unreachable("suspicious argument");
1887e5dd7070Spatrick   }
1888e5dd7070Spatrick }
1889e5dd7070Spatrick 
FreeMemAux(CheckerContext & C,const Expr * ArgExpr,const CallEvent & Call,ProgramStateRef State,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure) const1890ec727ea7Spatrick ProgramStateRef MallocChecker::FreeMemAux(
1891ec727ea7Spatrick     CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
1892ec727ea7Spatrick     ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
1893ec727ea7Spatrick     AllocationFamily Family, bool ReturnsNullOnFailure) const {
1894e5dd7070Spatrick 
1895e5dd7070Spatrick   if (!State)
1896e5dd7070Spatrick     return nullptr;
1897e5dd7070Spatrick 
1898e5dd7070Spatrick   SVal ArgVal = C.getSVal(ArgExpr);
1899*12c85518Srobert   if (!isa<DefinedOrUnknownSVal>(ArgVal))
1900e5dd7070Spatrick     return nullptr;
1901e5dd7070Spatrick   DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
1902e5dd7070Spatrick 
1903e5dd7070Spatrick   // Check for null dereferences.
1904*12c85518Srobert   if (!isa<Loc>(location))
1905e5dd7070Spatrick     return nullptr;
1906e5dd7070Spatrick 
1907e5dd7070Spatrick   // The explicit NULL case, no operation is performed.
1908e5dd7070Spatrick   ProgramStateRef notNullState, nullState;
1909e5dd7070Spatrick   std::tie(notNullState, nullState) = State->assume(location);
1910e5dd7070Spatrick   if (nullState && !notNullState)
1911e5dd7070Spatrick     return nullptr;
1912e5dd7070Spatrick 
1913e5dd7070Spatrick   // Unknown values could easily be okay
1914e5dd7070Spatrick   // Undefined values are handled elsewhere
1915e5dd7070Spatrick   if (ArgVal.isUnknownOrUndef())
1916e5dd7070Spatrick     return nullptr;
1917e5dd7070Spatrick 
1918e5dd7070Spatrick   const MemRegion *R = ArgVal.getAsRegion();
1919ec727ea7Spatrick   const Expr *ParentExpr = Call.getOriginExpr();
1920ec727ea7Spatrick 
1921ec727ea7Spatrick   // NOTE: We detected a bug, but the checker under whose name we would emit the
1922ec727ea7Spatrick   // error could be disabled. Generally speaking, the MallocChecker family is an
1923ec727ea7Spatrick   // integral part of the Static Analyzer, and disabling any part of it should
1924ec727ea7Spatrick   // only be done under exceptional circumstances, such as frequent false
1925ec727ea7Spatrick   // positives. If this is the case, we can reasonably believe that there are
1926ec727ea7Spatrick   // serious faults in our understanding of the source code, and even if we
1927ec727ea7Spatrick   // don't emit an warning, we should terminate further analysis with a sink
1928ec727ea7Spatrick   // node.
1929e5dd7070Spatrick 
1930e5dd7070Spatrick   // Nonlocs can't be freed, of course.
1931e5dd7070Spatrick   // Non-region locations (labels and fixed addresses) also shouldn't be freed.
1932e5dd7070Spatrick   if (!R) {
1933ec727ea7Spatrick     // Exception:
1934ec727ea7Spatrick     // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source
1935ec727ea7Spatrick     // code. In that case, the ZERO_SIZE_PTR defines a special value used for a
1936ec727ea7Spatrick     // zero-sized memory block which is allowed to be freed, despite not being a
1937ec727ea7Spatrick     // null pointer.
1938ec727ea7Spatrick     if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))
1939ec727ea7Spatrick       HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1940ec727ea7Spatrick                            Family);
1941e5dd7070Spatrick     return nullptr;
1942e5dd7070Spatrick   }
1943e5dd7070Spatrick 
1944e5dd7070Spatrick   R = R->StripCasts();
1945e5dd7070Spatrick 
1946e5dd7070Spatrick   // Blocks might show up as heap data, but should not be free()d
1947e5dd7070Spatrick   if (isa<BlockDataRegion>(R)) {
1948ec727ea7Spatrick     HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1949ec727ea7Spatrick                          Family);
1950e5dd7070Spatrick     return nullptr;
1951e5dd7070Spatrick   }
1952e5dd7070Spatrick 
1953e5dd7070Spatrick   const MemSpaceRegion *MS = R->getMemorySpace();
1954e5dd7070Spatrick 
1955e5dd7070Spatrick   // Parameters, locals, statics, globals, and memory returned by
1956e5dd7070Spatrick   // __builtin_alloca() shouldn't be freed.
1957*12c85518Srobert   if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
1958e5dd7070Spatrick     // FIXME: at the time this code was written, malloc() regions were
1959e5dd7070Spatrick     // represented by conjured symbols, which are all in UnknownSpaceRegion.
1960e5dd7070Spatrick     // This means that there isn't actually anything from HeapSpaceRegion
1961e5dd7070Spatrick     // that should be freed, even though we allow it here.
1962e5dd7070Spatrick     // Of course, free() can work on memory allocated outside the current
1963e5dd7070Spatrick     // function, so UnknownSpaceRegion is always a possibility.
1964e5dd7070Spatrick     // False negatives are better than false positives.
1965e5dd7070Spatrick 
1966e5dd7070Spatrick     if (isa<AllocaRegion>(R))
1967ec727ea7Spatrick       HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
1968e5dd7070Spatrick     else
1969ec727ea7Spatrick       HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1970ec727ea7Spatrick                            Family);
1971e5dd7070Spatrick 
1972e5dd7070Spatrick     return nullptr;
1973e5dd7070Spatrick   }
1974e5dd7070Spatrick 
1975e5dd7070Spatrick   const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
1976e5dd7070Spatrick   // Various cases could lead to non-symbol values here.
1977e5dd7070Spatrick   // For now, ignore them.
1978e5dd7070Spatrick   if (!SrBase)
1979e5dd7070Spatrick     return nullptr;
1980e5dd7070Spatrick 
1981e5dd7070Spatrick   SymbolRef SymBase = SrBase->getSymbol();
1982e5dd7070Spatrick   const RefState *RsBase = State->get<RegionState>(SymBase);
1983e5dd7070Spatrick   SymbolRef PreviousRetStatusSymbol = nullptr;
1984e5dd7070Spatrick 
1985e5dd7070Spatrick   IsKnownToBeAllocated =
1986e5dd7070Spatrick       RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
1987e5dd7070Spatrick 
1988e5dd7070Spatrick   if (RsBase) {
1989e5dd7070Spatrick 
1990e5dd7070Spatrick     // Memory returned by alloca() shouldn't be freed.
1991e5dd7070Spatrick     if (RsBase->getAllocationFamily() == AF_Alloca) {
1992ec727ea7Spatrick       HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
1993e5dd7070Spatrick       return nullptr;
1994e5dd7070Spatrick     }
1995e5dd7070Spatrick 
1996e5dd7070Spatrick     // Check for double free first.
1997e5dd7070Spatrick     if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
1998e5dd7070Spatrick         !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
1999ec727ea7Spatrick       HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2000e5dd7070Spatrick                        SymBase, PreviousRetStatusSymbol);
2001e5dd7070Spatrick       return nullptr;
2002e5dd7070Spatrick 
2003e5dd7070Spatrick     // If the pointer is allocated or escaped, but we are now trying to free it,
2004e5dd7070Spatrick     // check that the call to free is proper.
2005e5dd7070Spatrick     } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2006e5dd7070Spatrick                RsBase->isEscaped()) {
2007e5dd7070Spatrick 
2008e5dd7070Spatrick       // Check if an expected deallocation function matches the real one.
2009ec727ea7Spatrick       bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2010e5dd7070Spatrick       if (!DeallocMatchesAlloc) {
2011ec727ea7Spatrick         HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,
2012ec727ea7Spatrick                                 RsBase, SymBase, Hold);
2013e5dd7070Spatrick         return nullptr;
2014e5dd7070Spatrick       }
2015e5dd7070Spatrick 
2016e5dd7070Spatrick       // Check if the memory location being freed is the actual location
2017e5dd7070Spatrick       // allocated, or an offset.
2018e5dd7070Spatrick       RegionOffset Offset = R->getAsOffset();
2019e5dd7070Spatrick       if (Offset.isValid() &&
2020e5dd7070Spatrick           !Offset.hasSymbolicOffset() &&
2021e5dd7070Spatrick           Offset.getOffset() != 0) {
2022e5dd7070Spatrick         const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2023ec727ea7Spatrick         HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2024ec727ea7Spatrick                          Family, AllocExpr);
2025e5dd7070Spatrick         return nullptr;
2026e5dd7070Spatrick       }
2027e5dd7070Spatrick     }
2028e5dd7070Spatrick   }
2029e5dd7070Spatrick 
2030e5dd7070Spatrick   if (SymBase->getType()->isFunctionPointerType()) {
2031ec727ea7Spatrick     HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2032ec727ea7Spatrick                           Family);
2033e5dd7070Spatrick     return nullptr;
2034e5dd7070Spatrick   }
2035e5dd7070Spatrick 
2036e5dd7070Spatrick   // Clean out the info on previous call to free return info.
2037e5dd7070Spatrick   State = State->remove<FreeReturnValue>(SymBase);
2038e5dd7070Spatrick 
2039e5dd7070Spatrick   // Keep track of the return value. If it is NULL, we will know that free
2040e5dd7070Spatrick   // failed.
2041e5dd7070Spatrick   if (ReturnsNullOnFailure) {
2042e5dd7070Spatrick     SVal RetVal = C.getSVal(ParentExpr);
2043e5dd7070Spatrick     SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
2044e5dd7070Spatrick     if (RetStatusSymbol) {
2045e5dd7070Spatrick       C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2046e5dd7070Spatrick       State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2047e5dd7070Spatrick     }
2048e5dd7070Spatrick   }
2049e5dd7070Spatrick 
2050ec727ea7Spatrick   // If we don't know anything about this symbol, a free on it may be totally
2051ec727ea7Spatrick   // valid. If this is the case, lets assume that the allocation family of the
2052ec727ea7Spatrick   // freeing function is the same as the symbols allocation family, and go with
2053ec727ea7Spatrick   // that.
2054ec727ea7Spatrick   assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2055ec727ea7Spatrick 
2056e5dd7070Spatrick   // Normal free.
2057e5dd7070Spatrick   if (Hold)
2058e5dd7070Spatrick     return State->set<RegionState>(SymBase,
2059e5dd7070Spatrick                                    RefState::getRelinquished(Family,
2060e5dd7070Spatrick                                                              ParentExpr));
2061e5dd7070Spatrick 
2062e5dd7070Spatrick   return State->set<RegionState>(SymBase,
2063e5dd7070Spatrick                                  RefState::getReleased(Family, ParentExpr));
2064e5dd7070Spatrick }
2065e5dd7070Spatrick 
2066*12c85518Srobert std::optional<MallocChecker::CheckKind>
getCheckIfTracked(AllocationFamily Family,bool IsALeakCheck) const2067e5dd7070Spatrick MallocChecker::getCheckIfTracked(AllocationFamily Family,
2068e5dd7070Spatrick                                  bool IsALeakCheck) const {
2069e5dd7070Spatrick   switch (Family) {
2070e5dd7070Spatrick   case AF_Malloc:
2071e5dd7070Spatrick   case AF_Alloca:
2072e5dd7070Spatrick   case AF_IfNameIndex: {
2073e5dd7070Spatrick     if (ChecksEnabled[CK_MallocChecker])
2074e5dd7070Spatrick       return CK_MallocChecker;
2075*12c85518Srobert     return std::nullopt;
2076e5dd7070Spatrick   }
2077e5dd7070Spatrick   case AF_CXXNew:
2078e5dd7070Spatrick   case AF_CXXNewArray: {
2079e5dd7070Spatrick     if (IsALeakCheck) {
2080e5dd7070Spatrick       if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2081e5dd7070Spatrick         return CK_NewDeleteLeaksChecker;
2082e5dd7070Spatrick     }
2083e5dd7070Spatrick     else {
2084e5dd7070Spatrick       if (ChecksEnabled[CK_NewDeleteChecker])
2085e5dd7070Spatrick         return CK_NewDeleteChecker;
2086e5dd7070Spatrick     }
2087*12c85518Srobert     return std::nullopt;
2088e5dd7070Spatrick   }
2089e5dd7070Spatrick   case AF_InnerBuffer: {
2090e5dd7070Spatrick     if (ChecksEnabled[CK_InnerPointerChecker])
2091e5dd7070Spatrick       return CK_InnerPointerChecker;
2092*12c85518Srobert     return std::nullopt;
2093e5dd7070Spatrick   }
2094e5dd7070Spatrick   case AF_None: {
2095e5dd7070Spatrick     llvm_unreachable("no family");
2096e5dd7070Spatrick   }
2097e5dd7070Spatrick   }
2098e5dd7070Spatrick   llvm_unreachable("unhandled family");
2099e5dd7070Spatrick }
2100e5dd7070Spatrick 
2101*12c85518Srobert std::optional<MallocChecker::CheckKind>
getCheckIfTracked(CheckerContext & C,SymbolRef Sym,bool IsALeakCheck) const2102e5dd7070Spatrick MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
2103e5dd7070Spatrick                                  bool IsALeakCheck) const {
2104e5dd7070Spatrick   if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2105e5dd7070Spatrick     return CK_MallocChecker;
2106e5dd7070Spatrick 
2107e5dd7070Spatrick   const RefState *RS = C.getState()->get<RegionState>(Sym);
2108e5dd7070Spatrick   assert(RS);
2109e5dd7070Spatrick   return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2110e5dd7070Spatrick }
2111e5dd7070Spatrick 
SummarizeValue(raw_ostream & os,SVal V)2112e5dd7070Spatrick bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
2113*12c85518Srobert   if (std::optional<nonloc::ConcreteInt> IntVal =
2114*12c85518Srobert           V.getAs<nonloc::ConcreteInt>())
2115e5dd7070Spatrick     os << "an integer (" << IntVal->getValue() << ")";
2116*12c85518Srobert   else if (std::optional<loc::ConcreteInt> ConstAddr =
2117*12c85518Srobert                V.getAs<loc::ConcreteInt>())
2118e5dd7070Spatrick     os << "a constant address (" << ConstAddr->getValue() << ")";
2119*12c85518Srobert   else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
2120e5dd7070Spatrick     os << "the address of the label '" << Label->getLabel()->getName() << "'";
2121e5dd7070Spatrick   else
2122e5dd7070Spatrick     return false;
2123e5dd7070Spatrick 
2124e5dd7070Spatrick   return true;
2125e5dd7070Spatrick }
2126e5dd7070Spatrick 
SummarizeRegion(raw_ostream & os,const MemRegion * MR)2127e5dd7070Spatrick bool MallocChecker::SummarizeRegion(raw_ostream &os,
2128e5dd7070Spatrick                                     const MemRegion *MR) {
2129e5dd7070Spatrick   switch (MR->getKind()) {
2130e5dd7070Spatrick   case MemRegion::FunctionCodeRegionKind: {
2131e5dd7070Spatrick     const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2132e5dd7070Spatrick     if (FD)
2133e5dd7070Spatrick       os << "the address of the function '" << *FD << '\'';
2134e5dd7070Spatrick     else
2135e5dd7070Spatrick       os << "the address of a function";
2136e5dd7070Spatrick     return true;
2137e5dd7070Spatrick   }
2138e5dd7070Spatrick   case MemRegion::BlockCodeRegionKind:
2139e5dd7070Spatrick     os << "block text";
2140e5dd7070Spatrick     return true;
2141e5dd7070Spatrick   case MemRegion::BlockDataRegionKind:
2142e5dd7070Spatrick     // FIXME: where the block came from?
2143e5dd7070Spatrick     os << "a block";
2144e5dd7070Spatrick     return true;
2145e5dd7070Spatrick   default: {
2146e5dd7070Spatrick     const MemSpaceRegion *MS = MR->getMemorySpace();
2147e5dd7070Spatrick 
2148e5dd7070Spatrick     if (isa<StackLocalsSpaceRegion>(MS)) {
2149e5dd7070Spatrick       const VarRegion *VR = dyn_cast<VarRegion>(MR);
2150e5dd7070Spatrick       const VarDecl *VD;
2151e5dd7070Spatrick       if (VR)
2152e5dd7070Spatrick         VD = VR->getDecl();
2153e5dd7070Spatrick       else
2154e5dd7070Spatrick         VD = nullptr;
2155e5dd7070Spatrick 
2156e5dd7070Spatrick       if (VD)
2157e5dd7070Spatrick         os << "the address of the local variable '" << VD->getName() << "'";
2158e5dd7070Spatrick       else
2159e5dd7070Spatrick         os << "the address of a local stack variable";
2160e5dd7070Spatrick       return true;
2161e5dd7070Spatrick     }
2162e5dd7070Spatrick 
2163e5dd7070Spatrick     if (isa<StackArgumentsSpaceRegion>(MS)) {
2164e5dd7070Spatrick       const VarRegion *VR = dyn_cast<VarRegion>(MR);
2165e5dd7070Spatrick       const VarDecl *VD;
2166e5dd7070Spatrick       if (VR)
2167e5dd7070Spatrick         VD = VR->getDecl();
2168e5dd7070Spatrick       else
2169e5dd7070Spatrick         VD = nullptr;
2170e5dd7070Spatrick 
2171e5dd7070Spatrick       if (VD)
2172e5dd7070Spatrick         os << "the address of the parameter '" << VD->getName() << "'";
2173e5dd7070Spatrick       else
2174e5dd7070Spatrick         os << "the address of a parameter";
2175e5dd7070Spatrick       return true;
2176e5dd7070Spatrick     }
2177e5dd7070Spatrick 
2178e5dd7070Spatrick     if (isa<GlobalsSpaceRegion>(MS)) {
2179e5dd7070Spatrick       const VarRegion *VR = dyn_cast<VarRegion>(MR);
2180e5dd7070Spatrick       const VarDecl *VD;
2181e5dd7070Spatrick       if (VR)
2182e5dd7070Spatrick         VD = VR->getDecl();
2183e5dd7070Spatrick       else
2184e5dd7070Spatrick         VD = nullptr;
2185e5dd7070Spatrick 
2186e5dd7070Spatrick       if (VD) {
2187e5dd7070Spatrick         if (VD->isStaticLocal())
2188e5dd7070Spatrick           os << "the address of the static variable '" << VD->getName() << "'";
2189e5dd7070Spatrick         else
2190e5dd7070Spatrick           os << "the address of the global variable '" << VD->getName() << "'";
2191e5dd7070Spatrick       } else
2192e5dd7070Spatrick         os << "the address of a global variable";
2193e5dd7070Spatrick       return true;
2194e5dd7070Spatrick     }
2195e5dd7070Spatrick 
2196e5dd7070Spatrick     return false;
2197e5dd7070Spatrick   }
2198e5dd7070Spatrick   }
2199e5dd7070Spatrick }
2200e5dd7070Spatrick 
HandleNonHeapDealloc(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family) const2201ec727ea7Spatrick void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
2202e5dd7070Spatrick                                          SourceRange Range,
2203ec727ea7Spatrick                                          const Expr *DeallocExpr,
2204ec727ea7Spatrick                                          AllocationFamily Family) const {
2205e5dd7070Spatrick 
2206ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2207ec727ea7Spatrick     C.addSink();
2208e5dd7070Spatrick     return;
2209ec727ea7Spatrick   }
2210e5dd7070Spatrick 
2211*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2212*12c85518Srobert   if (!CheckKind)
2213e5dd7070Spatrick     return;
2214e5dd7070Spatrick 
2215e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2216e5dd7070Spatrick     if (!BT_BadFree[*CheckKind])
2217e5dd7070Spatrick       BT_BadFree[*CheckKind].reset(new BugType(
2218e5dd7070Spatrick           CheckNames[*CheckKind], "Bad free", categories::MemoryError));
2219e5dd7070Spatrick 
2220e5dd7070Spatrick     SmallString<100> buf;
2221e5dd7070Spatrick     llvm::raw_svector_ostream os(buf);
2222e5dd7070Spatrick 
2223e5dd7070Spatrick     const MemRegion *MR = ArgVal.getAsRegion();
2224e5dd7070Spatrick     while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2225e5dd7070Spatrick       MR = ER->getSuperRegion();
2226e5dd7070Spatrick 
2227e5dd7070Spatrick     os << "Argument to ";
2228ec727ea7Spatrick     if (!printMemFnName(os, C, DeallocExpr))
2229e5dd7070Spatrick       os << "deallocator";
2230e5dd7070Spatrick 
2231e5dd7070Spatrick     os << " is ";
2232e5dd7070Spatrick     bool Summarized = MR ? SummarizeRegion(os, MR)
2233e5dd7070Spatrick                          : SummarizeValue(os, ArgVal);
2234e5dd7070Spatrick     if (Summarized)
2235e5dd7070Spatrick       os << ", which is not memory allocated by ";
2236e5dd7070Spatrick     else
2237e5dd7070Spatrick       os << "not memory allocated by ";
2238e5dd7070Spatrick 
2239ec727ea7Spatrick     printExpectedAllocName(os, Family);
2240e5dd7070Spatrick 
2241e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2242e5dd7070Spatrick                                                       os.str(), N);
2243e5dd7070Spatrick     R->markInteresting(MR);
2244e5dd7070Spatrick     R->addRange(Range);
2245e5dd7070Spatrick     C.emitReport(std::move(R));
2246e5dd7070Spatrick   }
2247e5dd7070Spatrick }
2248e5dd7070Spatrick 
HandleFreeAlloca(CheckerContext & C,SVal ArgVal,SourceRange Range) const2249ec727ea7Spatrick void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
2250e5dd7070Spatrick                                      SourceRange Range) const {
2251e5dd7070Spatrick 
2252*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind;
2253e5dd7070Spatrick 
2254e5dd7070Spatrick   if (ChecksEnabled[CK_MallocChecker])
2255e5dd7070Spatrick     CheckKind = CK_MallocChecker;
2256e5dd7070Spatrick   else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2257e5dd7070Spatrick     CheckKind = CK_MismatchedDeallocatorChecker;
2258ec727ea7Spatrick   else {
2259ec727ea7Spatrick     C.addSink();
2260e5dd7070Spatrick     return;
2261ec727ea7Spatrick   }
2262e5dd7070Spatrick 
2263e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2264e5dd7070Spatrick     if (!BT_FreeAlloca[*CheckKind])
2265e5dd7070Spatrick       BT_FreeAlloca[*CheckKind].reset(new BugType(
2266e5dd7070Spatrick           CheckNames[*CheckKind], "Free alloca()", categories::MemoryError));
2267e5dd7070Spatrick 
2268e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(
2269e5dd7070Spatrick         *BT_FreeAlloca[*CheckKind],
2270e5dd7070Spatrick         "Memory allocated by alloca() should not be deallocated", N);
2271e5dd7070Spatrick     R->markInteresting(ArgVal.getAsRegion());
2272e5dd7070Spatrick     R->addRange(Range);
2273e5dd7070Spatrick     C.emitReport(std::move(R));
2274e5dd7070Spatrick   }
2275e5dd7070Spatrick }
2276e5dd7070Spatrick 
HandleMismatchedDealloc(CheckerContext & C,SourceRange Range,const Expr * DeallocExpr,const RefState * RS,SymbolRef Sym,bool OwnershipTransferred) const2277ec727ea7Spatrick void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2278e5dd7070Spatrick                                             SourceRange Range,
2279e5dd7070Spatrick                                             const Expr *DeallocExpr,
2280ec727ea7Spatrick                                             const RefState *RS, SymbolRef Sym,
2281e5dd7070Spatrick                                             bool OwnershipTransferred) const {
2282e5dd7070Spatrick 
2283ec727ea7Spatrick   if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2284ec727ea7Spatrick     C.addSink();
2285e5dd7070Spatrick     return;
2286ec727ea7Spatrick   }
2287e5dd7070Spatrick 
2288e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2289e5dd7070Spatrick     if (!BT_MismatchedDealloc)
2290e5dd7070Spatrick       BT_MismatchedDealloc.reset(
2291e5dd7070Spatrick           new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2292e5dd7070Spatrick                       "Bad deallocator", categories::MemoryError));
2293e5dd7070Spatrick 
2294e5dd7070Spatrick     SmallString<100> buf;
2295e5dd7070Spatrick     llvm::raw_svector_ostream os(buf);
2296e5dd7070Spatrick 
2297e5dd7070Spatrick     const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2298e5dd7070Spatrick     SmallString<20> AllocBuf;
2299e5dd7070Spatrick     llvm::raw_svector_ostream AllocOs(AllocBuf);
2300e5dd7070Spatrick     SmallString<20> DeallocBuf;
2301e5dd7070Spatrick     llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2302e5dd7070Spatrick 
2303e5dd7070Spatrick     if (OwnershipTransferred) {
2304ec727ea7Spatrick       if (printMemFnName(DeallocOs, C, DeallocExpr))
2305e5dd7070Spatrick         os << DeallocOs.str() << " cannot";
2306e5dd7070Spatrick       else
2307e5dd7070Spatrick         os << "Cannot";
2308e5dd7070Spatrick 
2309e5dd7070Spatrick       os << " take ownership of memory";
2310e5dd7070Spatrick 
2311ec727ea7Spatrick       if (printMemFnName(AllocOs, C, AllocExpr))
2312e5dd7070Spatrick         os << " allocated by " << AllocOs.str();
2313e5dd7070Spatrick     } else {
2314e5dd7070Spatrick       os << "Memory";
2315ec727ea7Spatrick       if (printMemFnName(AllocOs, C, AllocExpr))
2316e5dd7070Spatrick         os << " allocated by " << AllocOs.str();
2317e5dd7070Spatrick 
2318e5dd7070Spatrick       os << " should be deallocated by ";
2319e5dd7070Spatrick         printExpectedDeallocName(os, RS->getAllocationFamily());
2320e5dd7070Spatrick 
2321ec727ea7Spatrick         if (printMemFnName(DeallocOs, C, DeallocExpr))
2322e5dd7070Spatrick           os << ", not " << DeallocOs.str();
2323e5dd7070Spatrick     }
2324e5dd7070Spatrick 
2325e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2326e5dd7070Spatrick                                                       os.str(), N);
2327e5dd7070Spatrick     R->markInteresting(Sym);
2328e5dd7070Spatrick     R->addRange(Range);
2329a9ac8606Spatrick     R->addVisitor<MallocBugVisitor>(Sym);
2330e5dd7070Spatrick     C.emitReport(std::move(R));
2331e5dd7070Spatrick   }
2332e5dd7070Spatrick }
2333e5dd7070Spatrick 
HandleOffsetFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family,const Expr * AllocExpr) const2334ec727ea7Spatrick void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
2335e5dd7070Spatrick                                      SourceRange Range, const Expr *DeallocExpr,
2336ec727ea7Spatrick                                      AllocationFamily Family,
2337e5dd7070Spatrick                                      const Expr *AllocExpr) const {
2338e5dd7070Spatrick 
2339ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2340ec727ea7Spatrick     C.addSink();
2341e5dd7070Spatrick     return;
2342ec727ea7Spatrick   }
2343e5dd7070Spatrick 
2344*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2345*12c85518Srobert   if (!CheckKind)
2346e5dd7070Spatrick     return;
2347e5dd7070Spatrick 
2348e5dd7070Spatrick   ExplodedNode *N = C.generateErrorNode();
2349e5dd7070Spatrick   if (!N)
2350e5dd7070Spatrick     return;
2351e5dd7070Spatrick 
2352e5dd7070Spatrick   if (!BT_OffsetFree[*CheckKind])
2353e5dd7070Spatrick     BT_OffsetFree[*CheckKind].reset(new BugType(
2354e5dd7070Spatrick         CheckNames[*CheckKind], "Offset free", categories::MemoryError));
2355e5dd7070Spatrick 
2356e5dd7070Spatrick   SmallString<100> buf;
2357e5dd7070Spatrick   llvm::raw_svector_ostream os(buf);
2358e5dd7070Spatrick   SmallString<20> AllocNameBuf;
2359e5dd7070Spatrick   llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2360e5dd7070Spatrick 
2361e5dd7070Spatrick   const MemRegion *MR = ArgVal.getAsRegion();
2362e5dd7070Spatrick   assert(MR && "Only MemRegion based symbols can have offset free errors");
2363e5dd7070Spatrick 
2364e5dd7070Spatrick   RegionOffset Offset = MR->getAsOffset();
2365e5dd7070Spatrick   assert((Offset.isValid() &&
2366e5dd7070Spatrick           !Offset.hasSymbolicOffset() &&
2367e5dd7070Spatrick           Offset.getOffset() != 0) &&
2368e5dd7070Spatrick          "Only symbols with a valid offset can have offset free errors");
2369e5dd7070Spatrick 
2370e5dd7070Spatrick   int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
2371e5dd7070Spatrick 
2372e5dd7070Spatrick   os << "Argument to ";
2373ec727ea7Spatrick   if (!printMemFnName(os, C, DeallocExpr))
2374e5dd7070Spatrick     os << "deallocator";
2375e5dd7070Spatrick   os << " is offset by "
2376e5dd7070Spatrick      << offsetBytes
2377e5dd7070Spatrick      << " "
2378e5dd7070Spatrick      << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2379e5dd7070Spatrick      << " from the start of ";
2380ec727ea7Spatrick   if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2381e5dd7070Spatrick     os << "memory allocated by " << AllocNameOs.str();
2382e5dd7070Spatrick   else
2383e5dd7070Spatrick     os << "allocated memory";
2384e5dd7070Spatrick 
2385e5dd7070Spatrick   auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2386e5dd7070Spatrick                                                     os.str(), N);
2387e5dd7070Spatrick   R->markInteresting(MR->getBaseRegion());
2388e5dd7070Spatrick   R->addRange(Range);
2389e5dd7070Spatrick   C.emitReport(std::move(R));
2390e5dd7070Spatrick }
2391e5dd7070Spatrick 
HandleUseAfterFree(CheckerContext & C,SourceRange Range,SymbolRef Sym) const2392ec727ea7Spatrick void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
2393e5dd7070Spatrick                                        SymbolRef Sym) const {
2394e5dd7070Spatrick 
2395ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2396ec727ea7Spatrick       !ChecksEnabled[CK_InnerPointerChecker]) {
2397ec727ea7Spatrick     C.addSink();
2398e5dd7070Spatrick     return;
2399ec727ea7Spatrick   }
2400e5dd7070Spatrick 
2401*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2402*12c85518Srobert   if (!CheckKind)
2403e5dd7070Spatrick     return;
2404e5dd7070Spatrick 
2405e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2406e5dd7070Spatrick     if (!BT_UseFree[*CheckKind])
2407e5dd7070Spatrick       BT_UseFree[*CheckKind].reset(new BugType(
2408e5dd7070Spatrick           CheckNames[*CheckKind], "Use-after-free", categories::MemoryError));
2409e5dd7070Spatrick 
2410e5dd7070Spatrick     AllocationFamily AF =
2411e5dd7070Spatrick         C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2412e5dd7070Spatrick 
2413e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(
2414e5dd7070Spatrick         *BT_UseFree[*CheckKind],
2415e5dd7070Spatrick         AF == AF_InnerBuffer
2416e5dd7070Spatrick             ? "Inner pointer of container used after re/deallocation"
2417e5dd7070Spatrick             : "Use of memory after it is freed",
2418e5dd7070Spatrick         N);
2419e5dd7070Spatrick 
2420e5dd7070Spatrick     R->markInteresting(Sym);
2421e5dd7070Spatrick     R->addRange(Range);
2422a9ac8606Spatrick     R->addVisitor<MallocBugVisitor>(Sym);
2423e5dd7070Spatrick 
2424e5dd7070Spatrick     if (AF == AF_InnerBuffer)
2425e5dd7070Spatrick       R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
2426e5dd7070Spatrick 
2427e5dd7070Spatrick     C.emitReport(std::move(R));
2428e5dd7070Spatrick   }
2429e5dd7070Spatrick }
2430e5dd7070Spatrick 
HandleDoubleFree(CheckerContext & C,SourceRange Range,bool Released,SymbolRef Sym,SymbolRef PrevSym) const2431ec727ea7Spatrick void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2432e5dd7070Spatrick                                      bool Released, SymbolRef Sym,
2433e5dd7070Spatrick                                      SymbolRef PrevSym) const {
2434e5dd7070Spatrick 
2435ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2436ec727ea7Spatrick     C.addSink();
2437e5dd7070Spatrick     return;
2438ec727ea7Spatrick   }
2439e5dd7070Spatrick 
2440*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2441*12c85518Srobert   if (!CheckKind)
2442e5dd7070Spatrick     return;
2443e5dd7070Spatrick 
2444e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2445e5dd7070Spatrick     if (!BT_DoubleFree[*CheckKind])
2446e5dd7070Spatrick       BT_DoubleFree[*CheckKind].reset(new BugType(
2447e5dd7070Spatrick           CheckNames[*CheckKind], "Double free", categories::MemoryError));
2448e5dd7070Spatrick 
2449e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(
2450e5dd7070Spatrick         *BT_DoubleFree[*CheckKind],
2451e5dd7070Spatrick         (Released ? "Attempt to free released memory"
2452e5dd7070Spatrick                   : "Attempt to free non-owned memory"),
2453e5dd7070Spatrick         N);
2454e5dd7070Spatrick     R->addRange(Range);
2455e5dd7070Spatrick     R->markInteresting(Sym);
2456e5dd7070Spatrick     if (PrevSym)
2457e5dd7070Spatrick       R->markInteresting(PrevSym);
2458a9ac8606Spatrick     R->addVisitor<MallocBugVisitor>(Sym);
2459e5dd7070Spatrick     C.emitReport(std::move(R));
2460e5dd7070Spatrick   }
2461e5dd7070Spatrick }
2462e5dd7070Spatrick 
HandleDoubleDelete(CheckerContext & C,SymbolRef Sym) const2463ec727ea7Spatrick void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
2464e5dd7070Spatrick 
2465ec727ea7Spatrick   if (!ChecksEnabled[CK_NewDeleteChecker]) {
2466ec727ea7Spatrick     C.addSink();
2467e5dd7070Spatrick     return;
2468ec727ea7Spatrick   }
2469e5dd7070Spatrick 
2470*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2471*12c85518Srobert   if (!CheckKind)
2472e5dd7070Spatrick     return;
2473e5dd7070Spatrick 
2474e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2475e5dd7070Spatrick     if (!BT_DoubleDelete)
2476e5dd7070Spatrick       BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
2477e5dd7070Spatrick                                         "Double delete",
2478e5dd7070Spatrick                                         categories::MemoryError));
2479e5dd7070Spatrick 
2480e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(
2481e5dd7070Spatrick         *BT_DoubleDelete, "Attempt to delete released memory", N);
2482e5dd7070Spatrick 
2483e5dd7070Spatrick     R->markInteresting(Sym);
2484a9ac8606Spatrick     R->addVisitor<MallocBugVisitor>(Sym);
2485e5dd7070Spatrick     C.emitReport(std::move(R));
2486e5dd7070Spatrick   }
2487e5dd7070Spatrick }
2488e5dd7070Spatrick 
HandleUseZeroAlloc(CheckerContext & C,SourceRange Range,SymbolRef Sym) const2489ec727ea7Spatrick void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
2490e5dd7070Spatrick                                        SymbolRef Sym) const {
2491e5dd7070Spatrick 
2492ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2493ec727ea7Spatrick     C.addSink();
2494e5dd7070Spatrick     return;
2495ec727ea7Spatrick   }
2496e5dd7070Spatrick 
2497*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2498e5dd7070Spatrick 
2499*12c85518Srobert   if (!CheckKind)
2500e5dd7070Spatrick     return;
2501e5dd7070Spatrick 
2502e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2503e5dd7070Spatrick     if (!BT_UseZerroAllocated[*CheckKind])
2504e5dd7070Spatrick       BT_UseZerroAllocated[*CheckKind].reset(
2505e5dd7070Spatrick           new BugType(CheckNames[*CheckKind], "Use of zero allocated",
2506e5dd7070Spatrick                       categories::MemoryError));
2507e5dd7070Spatrick 
2508e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(
2509*12c85518Srobert         *BT_UseZerroAllocated[*CheckKind],
2510*12c85518Srobert         "Use of memory allocated with size zero", N);
2511e5dd7070Spatrick 
2512e5dd7070Spatrick     R->addRange(Range);
2513e5dd7070Spatrick     if (Sym) {
2514e5dd7070Spatrick       R->markInteresting(Sym);
2515a9ac8606Spatrick       R->addVisitor<MallocBugVisitor>(Sym);
2516e5dd7070Spatrick     }
2517e5dd7070Spatrick     C.emitReport(std::move(R));
2518e5dd7070Spatrick   }
2519e5dd7070Spatrick }
2520e5dd7070Spatrick 
HandleFunctionPtrFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * FreeExpr,AllocationFamily Family) const2521ec727ea7Spatrick void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
2522e5dd7070Spatrick                                           SourceRange Range,
2523ec727ea7Spatrick                                           const Expr *FreeExpr,
2524ec727ea7Spatrick                                           AllocationFamily Family) const {
2525ec727ea7Spatrick   if (!ChecksEnabled[CK_MallocChecker]) {
2526ec727ea7Spatrick     C.addSink();
2527e5dd7070Spatrick     return;
2528ec727ea7Spatrick   }
2529e5dd7070Spatrick 
2530*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2531*12c85518Srobert   if (!CheckKind)
2532e5dd7070Spatrick     return;
2533e5dd7070Spatrick 
2534e5dd7070Spatrick   if (ExplodedNode *N = C.generateErrorNode()) {
2535e5dd7070Spatrick     if (!BT_BadFree[*CheckKind])
2536e5dd7070Spatrick       BT_BadFree[*CheckKind].reset(new BugType(
2537e5dd7070Spatrick           CheckNames[*CheckKind], "Bad free", categories::MemoryError));
2538e5dd7070Spatrick 
2539e5dd7070Spatrick     SmallString<100> Buf;
2540e5dd7070Spatrick     llvm::raw_svector_ostream Os(Buf);
2541e5dd7070Spatrick 
2542e5dd7070Spatrick     const MemRegion *MR = ArgVal.getAsRegion();
2543e5dd7070Spatrick     while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2544e5dd7070Spatrick       MR = ER->getSuperRegion();
2545e5dd7070Spatrick 
2546e5dd7070Spatrick     Os << "Argument to ";
2547ec727ea7Spatrick     if (!printMemFnName(Os, C, FreeExpr))
2548e5dd7070Spatrick       Os << "deallocator";
2549e5dd7070Spatrick 
2550e5dd7070Spatrick     Os << " is a function pointer";
2551e5dd7070Spatrick 
2552e5dd7070Spatrick     auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2553e5dd7070Spatrick                                                       Os.str(), N);
2554e5dd7070Spatrick     R->markInteresting(MR);
2555e5dd7070Spatrick     R->addRange(Range);
2556e5dd7070Spatrick     C.emitReport(std::move(R));
2557e5dd7070Spatrick   }
2558e5dd7070Spatrick }
2559e5dd7070Spatrick 
2560ec727ea7Spatrick ProgramStateRef
ReallocMemAux(CheckerContext & C,const CallEvent & Call,bool ShouldFreeOnFail,ProgramStateRef State,AllocationFamily Family,bool SuffixWithN) const2561ec727ea7Spatrick MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
2562ec727ea7Spatrick                              bool ShouldFreeOnFail, ProgramStateRef State,
2563ec727ea7Spatrick                              AllocationFamily Family, bool SuffixWithN) const {
2564e5dd7070Spatrick   if (!State)
2565e5dd7070Spatrick     return nullptr;
2566e5dd7070Spatrick 
2567ec727ea7Spatrick   const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
2568ec727ea7Spatrick 
2569e5dd7070Spatrick   if (SuffixWithN && CE->getNumArgs() < 3)
2570e5dd7070Spatrick     return nullptr;
2571e5dd7070Spatrick   else if (CE->getNumArgs() < 2)
2572e5dd7070Spatrick     return nullptr;
2573e5dd7070Spatrick 
2574e5dd7070Spatrick   const Expr *arg0Expr = CE->getArg(0);
2575e5dd7070Spatrick   SVal Arg0Val = C.getSVal(arg0Expr);
2576*12c85518Srobert   if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2577e5dd7070Spatrick     return nullptr;
2578e5dd7070Spatrick   DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
2579e5dd7070Spatrick 
2580e5dd7070Spatrick   SValBuilder &svalBuilder = C.getSValBuilder();
2581e5dd7070Spatrick 
2582*12c85518Srobert   DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(
2583*12c85518Srobert       State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2584e5dd7070Spatrick 
2585e5dd7070Spatrick   // Get the size argument.
2586e5dd7070Spatrick   const Expr *Arg1 = CE->getArg(1);
2587e5dd7070Spatrick 
2588e5dd7070Spatrick   // Get the value of the size argument.
2589e5dd7070Spatrick   SVal TotalSize = C.getSVal(Arg1);
2590e5dd7070Spatrick   if (SuffixWithN)
2591e5dd7070Spatrick     TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2592*12c85518Srobert   if (!isa<DefinedOrUnknownSVal>(TotalSize))
2593e5dd7070Spatrick     return nullptr;
2594e5dd7070Spatrick 
2595e5dd7070Spatrick   // Compare the size argument to 0.
2596e5dd7070Spatrick   DefinedOrUnknownSVal SizeZero =
2597e5dd7070Spatrick       svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),
2598*12c85518Srobert                          svalBuilder.makeIntValWithWidth(
2599*12c85518Srobert                              svalBuilder.getContext().getSizeType(), 0));
2600e5dd7070Spatrick 
2601e5dd7070Spatrick   ProgramStateRef StatePtrIsNull, StatePtrNotNull;
2602e5dd7070Spatrick   std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2603e5dd7070Spatrick   ProgramStateRef StateSizeIsZero, StateSizeNotZero;
2604e5dd7070Spatrick   std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2605e5dd7070Spatrick   // We only assume exceptional states if they are definitely true; if the
2606e5dd7070Spatrick   // state is under-constrained, assume regular realloc behavior.
2607e5dd7070Spatrick   bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2608e5dd7070Spatrick   bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2609e5dd7070Spatrick 
2610e5dd7070Spatrick   // If the ptr is NULL and the size is not 0, the call is equivalent to
2611e5dd7070Spatrick   // malloc(size).
2612e5dd7070Spatrick   if (PrtIsNull && !SizeIsZero) {
2613ec727ea7Spatrick     ProgramStateRef stateMalloc = MallocMemAux(
2614ec727ea7Spatrick         C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2615e5dd7070Spatrick     return stateMalloc;
2616e5dd7070Spatrick   }
2617e5dd7070Spatrick 
2618e5dd7070Spatrick   if (PrtIsNull && SizeIsZero)
2619e5dd7070Spatrick     return State;
2620e5dd7070Spatrick 
2621e5dd7070Spatrick   assert(!PrtIsNull);
2622e5dd7070Spatrick 
2623e5dd7070Spatrick   bool IsKnownToBeAllocated = false;
2624e5dd7070Spatrick 
2625e5dd7070Spatrick   // If the size is 0, free the memory.
2626e5dd7070Spatrick   if (SizeIsZero)
2627e5dd7070Spatrick     // The semantics of the return value are:
2628e5dd7070Spatrick     // If size was equal to 0, either NULL or a pointer suitable to be passed
2629e5dd7070Spatrick     // to free() is returned. We just free the input pointer and do not add
2630e5dd7070Spatrick     // any constrains on the output pointer.
2631ec727ea7Spatrick     if (ProgramStateRef stateFree = FreeMemAux(
2632ec727ea7Spatrick             C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2633e5dd7070Spatrick       return stateFree;
2634e5dd7070Spatrick 
2635e5dd7070Spatrick   // Default behavior.
2636e5dd7070Spatrick   if (ProgramStateRef stateFree =
2637ec727ea7Spatrick           FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2638e5dd7070Spatrick 
2639ec727ea7Spatrick     ProgramStateRef stateRealloc =
2640ec727ea7Spatrick         MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);
2641e5dd7070Spatrick     if (!stateRealloc)
2642e5dd7070Spatrick       return nullptr;
2643e5dd7070Spatrick 
2644e5dd7070Spatrick     OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
2645e5dd7070Spatrick     if (ShouldFreeOnFail)
2646e5dd7070Spatrick       Kind = OAR_FreeOnFailure;
2647e5dd7070Spatrick     else if (!IsKnownToBeAllocated)
2648e5dd7070Spatrick       Kind = OAR_DoNotTrackAfterFailure;
2649e5dd7070Spatrick 
2650ec727ea7Spatrick     // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
2651ec727ea7Spatrick     SymbolRef FromPtr = arg0Val.getLocSymbolInBase();
2652ec727ea7Spatrick     SVal RetVal = C.getSVal(CE);
2653ec727ea7Spatrick     SymbolRef ToPtr = RetVal.getAsSymbol();
2654ec727ea7Spatrick     assert(FromPtr && ToPtr &&
2655ec727ea7Spatrick            "By this point, FreeMemAux and MallocMemAux should have checked "
2656ec727ea7Spatrick            "whether the argument or the return value is symbolic!");
2657ec727ea7Spatrick 
2658e5dd7070Spatrick     // Record the info about the reallocated symbol so that we could properly
2659e5dd7070Spatrick     // process failed reallocation.
2660e5dd7070Spatrick     stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2661e5dd7070Spatrick                                                    ReallocPair(FromPtr, Kind));
2662e5dd7070Spatrick     // The reallocated symbol should stay alive for as long as the new symbol.
2663e5dd7070Spatrick     C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2664e5dd7070Spatrick     return stateRealloc;
2665e5dd7070Spatrick   }
2666e5dd7070Spatrick   return nullptr;
2667e5dd7070Spatrick }
2668e5dd7070Spatrick 
CallocMem(CheckerContext & C,const CallEvent & Call,ProgramStateRef State)2669ec727ea7Spatrick ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
2670ec727ea7Spatrick                                          const CallEvent &Call,
2671e5dd7070Spatrick                                          ProgramStateRef State) {
2672e5dd7070Spatrick   if (!State)
2673e5dd7070Spatrick     return nullptr;
2674e5dd7070Spatrick 
2675ec727ea7Spatrick   if (Call.getNumArgs() < 2)
2676e5dd7070Spatrick     return nullptr;
2677e5dd7070Spatrick 
2678e5dd7070Spatrick   SValBuilder &svalBuilder = C.getSValBuilder();
2679e5dd7070Spatrick   SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
2680ec727ea7Spatrick   SVal TotalSize =
2681ec727ea7Spatrick       evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2682e5dd7070Spatrick 
2683ec727ea7Spatrick   return MallocMemAux(C, Call, TotalSize, zeroVal, State, AF_Malloc);
2684e5dd7070Spatrick }
2685e5dd7070Spatrick 
getAllocationSite(const ExplodedNode * N,SymbolRef Sym,CheckerContext & C)2686e5dd7070Spatrick MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2687e5dd7070Spatrick                                                          SymbolRef Sym,
2688e5dd7070Spatrick                                                          CheckerContext &C) {
2689e5dd7070Spatrick   const LocationContext *LeakContext = N->getLocationContext();
2690e5dd7070Spatrick   // Walk the ExplodedGraph backwards and find the first node that referred to
2691e5dd7070Spatrick   // the tracked symbol.
2692e5dd7070Spatrick   const ExplodedNode *AllocNode = N;
2693e5dd7070Spatrick   const MemRegion *ReferenceRegion = nullptr;
2694e5dd7070Spatrick 
2695e5dd7070Spatrick   while (N) {
2696e5dd7070Spatrick     ProgramStateRef State = N->getState();
2697e5dd7070Spatrick     if (!State->get<RegionState>(Sym))
2698e5dd7070Spatrick       break;
2699e5dd7070Spatrick 
2700e5dd7070Spatrick     // Find the most recent expression bound to the symbol in the current
2701e5dd7070Spatrick     // context.
2702e5dd7070Spatrick     if (!ReferenceRegion) {
2703e5dd7070Spatrick       if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
2704e5dd7070Spatrick         SVal Val = State->getSVal(MR);
2705e5dd7070Spatrick         if (Val.getAsLocSymbol() == Sym) {
2706e5dd7070Spatrick           const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
2707e5dd7070Spatrick           // Do not show local variables belonging to a function other than
2708e5dd7070Spatrick           // where the error is reported.
2709e5dd7070Spatrick           if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
2710e5dd7070Spatrick             ReferenceRegion = MR;
2711e5dd7070Spatrick         }
2712e5dd7070Spatrick       }
2713e5dd7070Spatrick     }
2714e5dd7070Spatrick 
2715e5dd7070Spatrick     // Allocation node, is the last node in the current or parent context in
2716e5dd7070Spatrick     // which the symbol was tracked.
2717e5dd7070Spatrick     const LocationContext *NContext = N->getLocationContext();
2718e5dd7070Spatrick     if (NContext == LeakContext ||
2719e5dd7070Spatrick         NContext->isParentOf(LeakContext))
2720e5dd7070Spatrick       AllocNode = N;
2721e5dd7070Spatrick     N = N->pred_empty() ? nullptr : *(N->pred_begin());
2722e5dd7070Spatrick   }
2723e5dd7070Spatrick 
2724e5dd7070Spatrick   return LeakInfo(AllocNode, ReferenceRegion);
2725e5dd7070Spatrick }
2726e5dd7070Spatrick 
HandleLeak(SymbolRef Sym,ExplodedNode * N,CheckerContext & C) const2727ec727ea7Spatrick void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
2728e5dd7070Spatrick                                CheckerContext &C) const {
2729e5dd7070Spatrick 
2730e5dd7070Spatrick   if (!ChecksEnabled[CK_MallocChecker] &&
2731e5dd7070Spatrick       !ChecksEnabled[CK_NewDeleteLeaksChecker])
2732e5dd7070Spatrick     return;
2733e5dd7070Spatrick 
2734e5dd7070Spatrick   const RefState *RS = C.getState()->get<RegionState>(Sym);
2735e5dd7070Spatrick   assert(RS && "cannot leak an untracked symbol");
2736e5dd7070Spatrick   AllocationFamily Family = RS->getAllocationFamily();
2737e5dd7070Spatrick 
2738e5dd7070Spatrick   if (Family == AF_Alloca)
2739e5dd7070Spatrick     return;
2740e5dd7070Spatrick 
2741*12c85518Srobert   std::optional<MallocChecker::CheckKind> CheckKind =
2742*12c85518Srobert       getCheckIfTracked(Family, true);
2743e5dd7070Spatrick 
2744*12c85518Srobert   if (!CheckKind)
2745e5dd7070Spatrick     return;
2746e5dd7070Spatrick 
2747e5dd7070Spatrick   assert(N);
2748e5dd7070Spatrick   if (!BT_Leak[*CheckKind]) {
2749e5dd7070Spatrick     // Leaks should not be reported if they are post-dominated by a sink:
2750e5dd7070Spatrick     // (1) Sinks are higher importance bugs.
2751e5dd7070Spatrick     // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
2752e5dd7070Spatrick     //     with __noreturn functions such as assert() or exit(). We choose not
2753e5dd7070Spatrick     //     to report leaks on such paths.
2754e5dd7070Spatrick     BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
2755e5dd7070Spatrick                                           categories::MemoryError,
2756e5dd7070Spatrick                                           /*SuppressOnSink=*/true));
2757e5dd7070Spatrick   }
2758e5dd7070Spatrick 
2759e5dd7070Spatrick   // Most bug reports are cached at the location where they occurred.
2760e5dd7070Spatrick   // With leaks, we want to unique them by the location where they were
2761e5dd7070Spatrick   // allocated, and only report a single path.
2762e5dd7070Spatrick   PathDiagnosticLocation LocUsedForUniqueing;
2763e5dd7070Spatrick   const ExplodedNode *AllocNode = nullptr;
2764e5dd7070Spatrick   const MemRegion *Region = nullptr;
2765e5dd7070Spatrick   std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
2766e5dd7070Spatrick 
2767e5dd7070Spatrick   const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
2768e5dd7070Spatrick   if (AllocationStmt)
2769e5dd7070Spatrick     LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
2770e5dd7070Spatrick                                               C.getSourceManager(),
2771e5dd7070Spatrick                                               AllocNode->getLocationContext());
2772e5dd7070Spatrick 
2773e5dd7070Spatrick   SmallString<200> buf;
2774e5dd7070Spatrick   llvm::raw_svector_ostream os(buf);
2775e5dd7070Spatrick   if (Region && Region->canPrintPretty()) {
2776e5dd7070Spatrick     os << "Potential leak of memory pointed to by ";
2777e5dd7070Spatrick     Region->printPretty(os);
2778e5dd7070Spatrick   } else {
2779e5dd7070Spatrick     os << "Potential memory leak";
2780e5dd7070Spatrick   }
2781e5dd7070Spatrick 
2782e5dd7070Spatrick   auto R = std::make_unique<PathSensitiveBugReport>(
2783e5dd7070Spatrick       *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2784e5dd7070Spatrick       AllocNode->getLocationContext()->getDecl());
2785e5dd7070Spatrick   R->markInteresting(Sym);
2786a9ac8606Spatrick   R->addVisitor<MallocBugVisitor>(Sym, true);
2787*12c85518Srobert   if (ShouldRegisterNoOwnershipChangeVisitor)
2788*12c85518Srobert     R->addVisitor<NoOwnershipChangeVisitor>(Sym, this);
2789e5dd7070Spatrick   C.emitReport(std::move(R));
2790e5dd7070Spatrick }
2791e5dd7070Spatrick 
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const2792e5dd7070Spatrick void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
2793e5dd7070Spatrick                                      CheckerContext &C) const
2794e5dd7070Spatrick {
2795e5dd7070Spatrick   ProgramStateRef state = C.getState();
2796e5dd7070Spatrick   RegionStateTy OldRS = state->get<RegionState>();
2797e5dd7070Spatrick   RegionStateTy::Factory &F = state->get_context<RegionState>();
2798e5dd7070Spatrick 
2799e5dd7070Spatrick   RegionStateTy RS = OldRS;
2800e5dd7070Spatrick   SmallVector<SymbolRef, 2> Errors;
2801e5dd7070Spatrick   for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
2802e5dd7070Spatrick     if (SymReaper.isDead(I->first)) {
2803e5dd7070Spatrick       if (I->second.isAllocated() || I->second.isAllocatedOfSizeZero())
2804e5dd7070Spatrick         Errors.push_back(I->first);
2805e5dd7070Spatrick       // Remove the dead symbol from the map.
2806e5dd7070Spatrick       RS = F.remove(RS, I->first);
2807e5dd7070Spatrick     }
2808e5dd7070Spatrick   }
2809e5dd7070Spatrick 
2810e5dd7070Spatrick   if (RS == OldRS) {
2811e5dd7070Spatrick     // We shouldn't have touched other maps yet.
2812e5dd7070Spatrick     assert(state->get<ReallocPairs>() ==
2813e5dd7070Spatrick            C.getState()->get<ReallocPairs>());
2814e5dd7070Spatrick     assert(state->get<FreeReturnValue>() ==
2815e5dd7070Spatrick            C.getState()->get<FreeReturnValue>());
2816e5dd7070Spatrick     return;
2817e5dd7070Spatrick   }
2818e5dd7070Spatrick 
2819e5dd7070Spatrick   // Cleanup the Realloc Pairs Map.
2820e5dd7070Spatrick   ReallocPairsTy RP = state->get<ReallocPairs>();
2821e5dd7070Spatrick   for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
2822e5dd7070Spatrick     if (SymReaper.isDead(I->first) ||
2823e5dd7070Spatrick         SymReaper.isDead(I->second.ReallocatedSym)) {
2824e5dd7070Spatrick       state = state->remove<ReallocPairs>(I->first);
2825e5dd7070Spatrick     }
2826e5dd7070Spatrick   }
2827e5dd7070Spatrick 
2828e5dd7070Spatrick   // Cleanup the FreeReturnValue Map.
2829e5dd7070Spatrick   FreeReturnValueTy FR = state->get<FreeReturnValue>();
2830e5dd7070Spatrick   for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) {
2831e5dd7070Spatrick     if (SymReaper.isDead(I->first) ||
2832e5dd7070Spatrick         SymReaper.isDead(I->second)) {
2833e5dd7070Spatrick       state = state->remove<FreeReturnValue>(I->first);
2834e5dd7070Spatrick     }
2835e5dd7070Spatrick   }
2836e5dd7070Spatrick 
2837e5dd7070Spatrick   // Generate leak node.
2838e5dd7070Spatrick   ExplodedNode *N = C.getPredecessor();
2839e5dd7070Spatrick   if (!Errors.empty()) {
2840e5dd7070Spatrick     static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak");
2841e5dd7070Spatrick     N = C.generateNonFatalErrorNode(C.getState(), &Tag);
2842e5dd7070Spatrick     if (N) {
2843e5dd7070Spatrick       for (SmallVectorImpl<SymbolRef>::iterator
2844e5dd7070Spatrick            I = Errors.begin(), E = Errors.end(); I != E; ++I) {
2845ec727ea7Spatrick         HandleLeak(*I, N, C);
2846e5dd7070Spatrick       }
2847e5dd7070Spatrick     }
2848e5dd7070Spatrick   }
2849e5dd7070Spatrick 
2850e5dd7070Spatrick   C.addTransition(state->set<RegionState>(RS), N);
2851e5dd7070Spatrick }
2852e5dd7070Spatrick 
checkPreCall(const CallEvent & Call,CheckerContext & C) const2853e5dd7070Spatrick void MallocChecker::checkPreCall(const CallEvent &Call,
2854e5dd7070Spatrick                                  CheckerContext &C) const {
2855e5dd7070Spatrick 
2856ec727ea7Spatrick   if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
2857ec727ea7Spatrick     const CXXDeleteExpr *DE = DC->getOriginExpr();
2858ec727ea7Spatrick 
2859ec727ea7Spatrick     if (!ChecksEnabled[CK_NewDeleteChecker])
2860ec727ea7Spatrick       if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
2861ec727ea7Spatrick         checkUseAfterFree(Sym, C, DE->getArgument());
2862ec727ea7Spatrick 
2863ec727ea7Spatrick     if (!isStandardNewDelete(DC->getDecl()))
2864ec727ea7Spatrick       return;
2865ec727ea7Spatrick 
2866ec727ea7Spatrick     ProgramStateRef State = C.getState();
2867ec727ea7Spatrick     bool IsKnownToBeAllocated;
2868ec727ea7Spatrick     State = FreeMemAux(C, DE->getArgument(), Call, State,
2869ec727ea7Spatrick                        /*Hold*/ false, IsKnownToBeAllocated,
2870ec727ea7Spatrick                        (DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2871ec727ea7Spatrick 
2872ec727ea7Spatrick     C.addTransition(State);
2873ec727ea7Spatrick     return;
2874ec727ea7Spatrick   }
2875ec727ea7Spatrick 
2876ec727ea7Spatrick   if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
2877e5dd7070Spatrick     SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2878e5dd7070Spatrick     if (!Sym || checkDoubleDelete(Sym, C))
2879e5dd7070Spatrick       return;
2880e5dd7070Spatrick   }
2881e5dd7070Spatrick 
2882e5dd7070Spatrick   // We will check for double free in the post visit.
2883e5dd7070Spatrick   if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {
2884e5dd7070Spatrick     const FunctionDecl *FD = FC->getDecl();
2885e5dd7070Spatrick     if (!FD)
2886e5dd7070Spatrick       return;
2887e5dd7070Spatrick 
2888ec727ea7Spatrick     if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))
2889e5dd7070Spatrick       return;
2890e5dd7070Spatrick   }
2891e5dd7070Spatrick 
2892e5dd7070Spatrick   // Check if the callee of a method is deleted.
2893e5dd7070Spatrick   if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
2894e5dd7070Spatrick     SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2895e5dd7070Spatrick     if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
2896e5dd7070Spatrick       return;
2897e5dd7070Spatrick   }
2898e5dd7070Spatrick 
2899e5dd7070Spatrick   // Check arguments for being used after free.
2900e5dd7070Spatrick   for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
2901e5dd7070Spatrick     SVal ArgSVal = Call.getArgSVal(I);
2902*12c85518Srobert     if (isa<Loc>(ArgSVal)) {
2903e5dd7070Spatrick       SymbolRef Sym = ArgSVal.getAsSymbol();
2904e5dd7070Spatrick       if (!Sym)
2905e5dd7070Spatrick         continue;
2906e5dd7070Spatrick       if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
2907e5dd7070Spatrick         return;
2908e5dd7070Spatrick     }
2909e5dd7070Spatrick   }
2910e5dd7070Spatrick }
2911e5dd7070Spatrick 
checkPreStmt(const ReturnStmt * S,CheckerContext & C) const2912e5dd7070Spatrick void MallocChecker::checkPreStmt(const ReturnStmt *S,
2913e5dd7070Spatrick                                  CheckerContext &C) const {
2914e5dd7070Spatrick   checkEscapeOnReturn(S, C);
2915e5dd7070Spatrick }
2916e5dd7070Spatrick 
2917e5dd7070Spatrick // In the CFG, automatic destructors come after the return statement.
2918e5dd7070Spatrick // This callback checks for returning memory that is freed by automatic
2919e5dd7070Spatrick // destructors, as those cannot be reached in checkPreStmt().
checkEndFunction(const ReturnStmt * S,CheckerContext & C) const2920e5dd7070Spatrick void MallocChecker::checkEndFunction(const ReturnStmt *S,
2921e5dd7070Spatrick                                      CheckerContext &C) const {
2922e5dd7070Spatrick   checkEscapeOnReturn(S, C);
2923e5dd7070Spatrick }
2924e5dd7070Spatrick 
checkEscapeOnReturn(const ReturnStmt * S,CheckerContext & C) const2925e5dd7070Spatrick void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
2926e5dd7070Spatrick                                         CheckerContext &C) const {
2927e5dd7070Spatrick   if (!S)
2928e5dd7070Spatrick     return;
2929e5dd7070Spatrick 
2930e5dd7070Spatrick   const Expr *E = S->getRetValue();
2931e5dd7070Spatrick   if (!E)
2932e5dd7070Spatrick     return;
2933e5dd7070Spatrick 
2934e5dd7070Spatrick   // Check if we are returning a symbol.
2935e5dd7070Spatrick   ProgramStateRef State = C.getState();
2936e5dd7070Spatrick   SVal RetVal = C.getSVal(E);
2937e5dd7070Spatrick   SymbolRef Sym = RetVal.getAsSymbol();
2938e5dd7070Spatrick   if (!Sym)
2939e5dd7070Spatrick     // If we are returning a field of the allocated struct or an array element,
2940e5dd7070Spatrick     // the callee could still free the memory.
2941e5dd7070Spatrick     // TODO: This logic should be a part of generic symbol escape callback.
2942e5dd7070Spatrick     if (const MemRegion *MR = RetVal.getAsRegion())
2943*12c85518Srobert       if (isa<FieldRegion, ElementRegion>(MR))
2944e5dd7070Spatrick         if (const SymbolicRegion *BMR =
2945e5dd7070Spatrick               dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
2946e5dd7070Spatrick           Sym = BMR->getSymbol();
2947e5dd7070Spatrick 
2948e5dd7070Spatrick   // Check if we are returning freed memory.
2949e5dd7070Spatrick   if (Sym)
2950e5dd7070Spatrick     checkUseAfterFree(Sym, C, E);
2951e5dd7070Spatrick }
2952e5dd7070Spatrick 
2953e5dd7070Spatrick // TODO: Blocks should be either inlined or should call invalidate regions
2954e5dd7070Spatrick // upon invocation. After that's in place, special casing here will not be
2955e5dd7070Spatrick // needed.
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const2956e5dd7070Spatrick void MallocChecker::checkPostStmt(const BlockExpr *BE,
2957e5dd7070Spatrick                                   CheckerContext &C) const {
2958e5dd7070Spatrick 
2959e5dd7070Spatrick   // Scan the BlockDecRefExprs for any object the retain count checker
2960e5dd7070Spatrick   // may be tracking.
2961e5dd7070Spatrick   if (!BE->getBlockDecl()->hasCaptures())
2962e5dd7070Spatrick     return;
2963e5dd7070Spatrick 
2964e5dd7070Spatrick   ProgramStateRef state = C.getState();
2965e5dd7070Spatrick   const BlockDataRegion *R =
2966e5dd7070Spatrick     cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
2967e5dd7070Spatrick 
2968e5dd7070Spatrick   BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
2969e5dd7070Spatrick                                             E = R->referenced_vars_end();
2970e5dd7070Spatrick 
2971e5dd7070Spatrick   if (I == E)
2972e5dd7070Spatrick     return;
2973e5dd7070Spatrick 
2974e5dd7070Spatrick   SmallVector<const MemRegion*, 10> Regions;
2975e5dd7070Spatrick   const LocationContext *LC = C.getLocationContext();
2976e5dd7070Spatrick   MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
2977e5dd7070Spatrick 
2978e5dd7070Spatrick   for ( ; I != E; ++I) {
2979e5dd7070Spatrick     const VarRegion *VR = I.getCapturedRegion();
2980e5dd7070Spatrick     if (VR->getSuperRegion() == R) {
2981e5dd7070Spatrick       VR = MemMgr.getVarRegion(VR->getDecl(), LC);
2982e5dd7070Spatrick     }
2983e5dd7070Spatrick     Regions.push_back(VR);
2984e5dd7070Spatrick   }
2985e5dd7070Spatrick 
2986e5dd7070Spatrick   state =
2987e5dd7070Spatrick     state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
2988e5dd7070Spatrick   C.addTransition(state);
2989e5dd7070Spatrick }
2990e5dd7070Spatrick 
isReleased(SymbolRef Sym,CheckerContext & C)2991e5dd7070Spatrick static bool isReleased(SymbolRef Sym, CheckerContext &C) {
2992e5dd7070Spatrick   assert(Sym);
2993e5dd7070Spatrick   const RefState *RS = C.getState()->get<RegionState>(Sym);
2994e5dd7070Spatrick   return (RS && RS->isReleased());
2995e5dd7070Spatrick }
2996e5dd7070Spatrick 
suppressDeallocationsInSuspiciousContexts(const CallEvent & Call,CheckerContext & C) const2997e5dd7070Spatrick bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
2998ec727ea7Spatrick     const CallEvent &Call, CheckerContext &C) const {
2999ec727ea7Spatrick   if (Call.getNumArgs() == 0)
3000e5dd7070Spatrick     return false;
3001e5dd7070Spatrick 
3002e5dd7070Spatrick   StringRef FunctionStr = "";
3003e5dd7070Spatrick   if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
3004e5dd7070Spatrick     if (const Stmt *Body = FD->getBody())
3005e5dd7070Spatrick       if (Body->getBeginLoc().isValid())
3006e5dd7070Spatrick         FunctionStr =
3007e5dd7070Spatrick             Lexer::getSourceText(CharSourceRange::getTokenRange(
3008e5dd7070Spatrick                                      {FD->getBeginLoc(), Body->getBeginLoc()}),
3009e5dd7070Spatrick                                  C.getSourceManager(), C.getLangOpts());
3010e5dd7070Spatrick 
3011e5dd7070Spatrick   // We do not model the Integer Set Library's retain-count based allocation.
3012e5dd7070Spatrick   if (!FunctionStr.contains("__isl_"))
3013e5dd7070Spatrick     return false;
3014e5dd7070Spatrick 
3015e5dd7070Spatrick   ProgramStateRef State = C.getState();
3016e5dd7070Spatrick 
3017ec727ea7Spatrick   for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments())
3018e5dd7070Spatrick     if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3019e5dd7070Spatrick       if (const RefState *RS = State->get<RegionState>(Sym))
3020e5dd7070Spatrick         State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3021e5dd7070Spatrick 
3022e5dd7070Spatrick   C.addTransition(State);
3023e5dd7070Spatrick   return true;
3024e5dd7070Spatrick }
3025e5dd7070Spatrick 
checkUseAfterFree(SymbolRef Sym,CheckerContext & C,const Stmt * S) const3026e5dd7070Spatrick bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
3027e5dd7070Spatrick                                       const Stmt *S) const {
3028e5dd7070Spatrick 
3029e5dd7070Spatrick   if (isReleased(Sym, C)) {
3030ec727ea7Spatrick     HandleUseAfterFree(C, S->getSourceRange(), Sym);
3031e5dd7070Spatrick     return true;
3032e5dd7070Spatrick   }
3033e5dd7070Spatrick 
3034e5dd7070Spatrick   return false;
3035e5dd7070Spatrick }
3036e5dd7070Spatrick 
checkUseZeroAllocated(SymbolRef Sym,CheckerContext & C,const Stmt * S) const3037e5dd7070Spatrick void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3038e5dd7070Spatrick                                           const Stmt *S) const {
3039e5dd7070Spatrick   assert(Sym);
3040e5dd7070Spatrick 
3041e5dd7070Spatrick   if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {
3042e5dd7070Spatrick     if (RS->isAllocatedOfSizeZero())
3043ec727ea7Spatrick       HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3044e5dd7070Spatrick   }
3045e5dd7070Spatrick   else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3046ec727ea7Spatrick     HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
3047e5dd7070Spatrick   }
3048e5dd7070Spatrick }
3049e5dd7070Spatrick 
checkDoubleDelete(SymbolRef Sym,CheckerContext & C) const3050e5dd7070Spatrick bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const {
3051e5dd7070Spatrick 
3052e5dd7070Spatrick   if (isReleased(Sym, C)) {
3053ec727ea7Spatrick     HandleDoubleDelete(C, Sym);
3054e5dd7070Spatrick     return true;
3055e5dd7070Spatrick   }
3056e5dd7070Spatrick   return false;
3057e5dd7070Spatrick }
3058e5dd7070Spatrick 
3059e5dd7070Spatrick // Check if the location is a freed symbolic region.
checkLocation(SVal l,bool isLoad,const Stmt * S,CheckerContext & C) const3060e5dd7070Spatrick void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3061e5dd7070Spatrick                                   CheckerContext &C) const {
3062e5dd7070Spatrick   SymbolRef Sym = l.getLocSymbolInBase();
3063e5dd7070Spatrick   if (Sym) {
3064e5dd7070Spatrick     checkUseAfterFree(Sym, C, S);
3065e5dd7070Spatrick     checkUseZeroAllocated(Sym, C, S);
3066e5dd7070Spatrick   }
3067e5dd7070Spatrick }
3068e5dd7070Spatrick 
3069e5dd7070Spatrick // If a symbolic region is assumed to NULL (or another constant), stop tracking
3070e5dd7070Spatrick // it - assuming that allocation failed on this path.
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const3071e5dd7070Spatrick ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
3072e5dd7070Spatrick                                               SVal Cond,
3073e5dd7070Spatrick                                               bool Assumption) const {
3074e5dd7070Spatrick   RegionStateTy RS = state->get<RegionState>();
3075e5dd7070Spatrick   for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
3076e5dd7070Spatrick     // If the symbol is assumed to be NULL, remove it from consideration.
3077e5dd7070Spatrick     ConstraintManager &CMgr = state->getConstraintManager();
3078e5dd7070Spatrick     ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
3079e5dd7070Spatrick     if (AllocFailed.isConstrainedTrue())
3080e5dd7070Spatrick       state = state->remove<RegionState>(I.getKey());
3081e5dd7070Spatrick   }
3082e5dd7070Spatrick 
3083e5dd7070Spatrick   // Realloc returns 0 when reallocation fails, which means that we should
3084e5dd7070Spatrick   // restore the state of the pointer being reallocated.
3085e5dd7070Spatrick   ReallocPairsTy RP = state->get<ReallocPairs>();
3086e5dd7070Spatrick   for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
3087e5dd7070Spatrick     // If the symbol is assumed to be NULL, remove it from consideration.
3088e5dd7070Spatrick     ConstraintManager &CMgr = state->getConstraintManager();
3089e5dd7070Spatrick     ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
3090e5dd7070Spatrick     if (!AllocFailed.isConstrainedTrue())
3091e5dd7070Spatrick       continue;
3092e5dd7070Spatrick 
3093e5dd7070Spatrick     SymbolRef ReallocSym = I.getData().ReallocatedSym;
3094e5dd7070Spatrick     if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
3095e5dd7070Spatrick       if (RS->isReleased()) {
3096e5dd7070Spatrick         switch (I.getData().Kind) {
3097e5dd7070Spatrick         case OAR_ToBeFreedAfterFailure:
3098e5dd7070Spatrick           state = state->set<RegionState>(ReallocSym,
3099e5dd7070Spatrick               RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3100e5dd7070Spatrick           break;
3101e5dd7070Spatrick         case OAR_DoNotTrackAfterFailure:
3102e5dd7070Spatrick           state = state->remove<RegionState>(ReallocSym);
3103e5dd7070Spatrick           break;
3104e5dd7070Spatrick         default:
3105e5dd7070Spatrick           assert(I.getData().Kind == OAR_FreeOnFailure);
3106e5dd7070Spatrick         }
3107e5dd7070Spatrick       }
3108e5dd7070Spatrick     }
3109e5dd7070Spatrick     state = state->remove<ReallocPairs>(I.getKey());
3110e5dd7070Spatrick   }
3111e5dd7070Spatrick 
3112e5dd7070Spatrick   return state;
3113e5dd7070Spatrick }
3114e5dd7070Spatrick 
mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent * Call,ProgramStateRef State,SymbolRef & EscapingSymbol) const3115e5dd7070Spatrick bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3116e5dd7070Spatrick                                               const CallEvent *Call,
3117e5dd7070Spatrick                                               ProgramStateRef State,
3118e5dd7070Spatrick                                               SymbolRef &EscapingSymbol) const {
3119e5dd7070Spatrick   assert(Call);
3120e5dd7070Spatrick   EscapingSymbol = nullptr;
3121e5dd7070Spatrick 
3122e5dd7070Spatrick   // For now, assume that any C++ or block call can free memory.
3123e5dd7070Spatrick   // TODO: If we want to be more optimistic here, we'll need to make sure that
3124e5dd7070Spatrick   // regions escape to C++ containers. They seem to do that even now, but for
3125e5dd7070Spatrick   // mysterious reasons.
3126*12c85518Srobert   if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))
3127e5dd7070Spatrick     return true;
3128e5dd7070Spatrick 
3129e5dd7070Spatrick   // Check Objective-C messages by selector name.
3130e5dd7070Spatrick   if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
3131e5dd7070Spatrick     // If it's not a framework call, or if it takes a callback, assume it
3132e5dd7070Spatrick     // can free memory.
3133e5dd7070Spatrick     if (!Call->isInSystemHeader() || Call->argumentsMayEscape())
3134e5dd7070Spatrick       return true;
3135e5dd7070Spatrick 
3136e5dd7070Spatrick     // If it's a method we know about, handle it explicitly post-call.
3137e5dd7070Spatrick     // This should happen before the "freeWhenDone" check below.
3138e5dd7070Spatrick     if (isKnownDeallocObjCMethodName(*Msg))
3139e5dd7070Spatrick       return false;
3140e5dd7070Spatrick 
3141e5dd7070Spatrick     // If there's a "freeWhenDone" parameter, but the method isn't one we know
3142e5dd7070Spatrick     // about, we can't be sure that the object will use free() to deallocate the
3143e5dd7070Spatrick     // memory, so we can't model it explicitly. The best we can do is use it to
3144e5dd7070Spatrick     // decide whether the pointer escapes.
3145*12c85518Srobert     if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
3146e5dd7070Spatrick       return *FreeWhenDone;
3147e5dd7070Spatrick 
3148e5dd7070Spatrick     // If the first selector piece ends with "NoCopy", and there is no
3149e5dd7070Spatrick     // "freeWhenDone" parameter set to zero, we know ownership is being
3150e5dd7070Spatrick     // transferred. Again, though, we can't be sure that the object will use
3151e5dd7070Spatrick     // free() to deallocate the memory, so we can't model it explicitly.
3152e5dd7070Spatrick     StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3153e5dd7070Spatrick     if (FirstSlot.endswith("NoCopy"))
3154e5dd7070Spatrick       return true;
3155e5dd7070Spatrick 
3156e5dd7070Spatrick     // If the first selector starts with addPointer, insertPointer,
3157e5dd7070Spatrick     // or replacePointer, assume we are dealing with NSPointerArray or similar.
3158e5dd7070Spatrick     // This is similar to C++ containers (vector); we still might want to check
3159e5dd7070Spatrick     // that the pointers get freed by following the container itself.
3160e5dd7070Spatrick     if (FirstSlot.startswith("addPointer") ||
3161e5dd7070Spatrick         FirstSlot.startswith("insertPointer") ||
3162e5dd7070Spatrick         FirstSlot.startswith("replacePointer") ||
3163e5dd7070Spatrick         FirstSlot.equals("valueWithPointer")) {
3164e5dd7070Spatrick       return true;
3165e5dd7070Spatrick     }
3166e5dd7070Spatrick 
3167e5dd7070Spatrick     // We should escape receiver on call to 'init'. This is especially relevant
3168e5dd7070Spatrick     // to the receiver, as the corresponding symbol is usually not referenced
3169e5dd7070Spatrick     // after the call.
3170e5dd7070Spatrick     if (Msg->getMethodFamily() == OMF_init) {
3171e5dd7070Spatrick       EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3172e5dd7070Spatrick       return true;
3173e5dd7070Spatrick     }
3174e5dd7070Spatrick 
3175e5dd7070Spatrick     // Otherwise, assume that the method does not free memory.
3176e5dd7070Spatrick     // Most framework methods do not free memory.
3177e5dd7070Spatrick     return false;
3178e5dd7070Spatrick   }
3179e5dd7070Spatrick 
3180e5dd7070Spatrick   // At this point the only thing left to handle is straight function calls.
3181e5dd7070Spatrick   const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
3182e5dd7070Spatrick   if (!FD)
3183e5dd7070Spatrick     return true;
3184e5dd7070Spatrick 
3185e5dd7070Spatrick   // If it's one of the allocation functions we can reason about, we model
3186e5dd7070Spatrick   // its behavior explicitly.
3187ec727ea7Spatrick   if (isMemCall(*Call))
3188e5dd7070Spatrick     return false;
3189e5dd7070Spatrick 
3190e5dd7070Spatrick   // If it's not a system call, assume it frees memory.
3191e5dd7070Spatrick   if (!Call->isInSystemHeader())
3192e5dd7070Spatrick     return true;
3193e5dd7070Spatrick 
3194e5dd7070Spatrick   // White list the system functions whose arguments escape.
3195e5dd7070Spatrick   const IdentifierInfo *II = FD->getIdentifier();
3196e5dd7070Spatrick   if (!II)
3197e5dd7070Spatrick     return true;
3198e5dd7070Spatrick   StringRef FName = II->getName();
3199e5dd7070Spatrick 
3200e5dd7070Spatrick   // White list the 'XXXNoCopy' CoreFoundation functions.
3201e5dd7070Spatrick   // We specifically check these before
3202e5dd7070Spatrick   if (FName.endswith("NoCopy")) {
3203e5dd7070Spatrick     // Look for the deallocator argument. We know that the memory ownership
3204e5dd7070Spatrick     // is not transferred only if the deallocator argument is
3205e5dd7070Spatrick     // 'kCFAllocatorNull'.
3206e5dd7070Spatrick     for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3207e5dd7070Spatrick       const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3208e5dd7070Spatrick       if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3209e5dd7070Spatrick         StringRef DeallocatorName = DE->getFoundDecl()->getName();
3210e5dd7070Spatrick         if (DeallocatorName == "kCFAllocatorNull")
3211e5dd7070Spatrick           return false;
3212e5dd7070Spatrick       }
3213e5dd7070Spatrick     }
3214e5dd7070Spatrick     return true;
3215e5dd7070Spatrick   }
3216e5dd7070Spatrick 
3217e5dd7070Spatrick   // Associating streams with malloced buffers. The pointer can escape if
3218e5dd7070Spatrick   // 'closefn' is specified (and if that function does free memory),
3219e5dd7070Spatrick   // but it will not if closefn is not specified.
3220e5dd7070Spatrick   // Currently, we do not inspect the 'closefn' function (PR12101).
3221e5dd7070Spatrick   if (FName == "funopen")
3222e5dd7070Spatrick     if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3223e5dd7070Spatrick       return false;
3224e5dd7070Spatrick 
3225e5dd7070Spatrick   // Do not warn on pointers passed to 'setbuf' when used with std streams,
3226e5dd7070Spatrick   // these leaks might be intentional when setting the buffer for stdio.
3227e5dd7070Spatrick   // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
3228e5dd7070Spatrick   if (FName == "setbuf" || FName =="setbuffer" ||
3229e5dd7070Spatrick       FName == "setlinebuf" || FName == "setvbuf") {
3230e5dd7070Spatrick     if (Call->getNumArgs() >= 1) {
3231e5dd7070Spatrick       const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
3232e5dd7070Spatrick       if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3233e5dd7070Spatrick         if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3234*12c85518Srobert           if (D->getCanonicalDecl()->getName().contains("std"))
3235e5dd7070Spatrick             return true;
3236e5dd7070Spatrick     }
3237e5dd7070Spatrick   }
3238e5dd7070Spatrick 
3239e5dd7070Spatrick   // A bunch of other functions which either take ownership of a pointer or
3240e5dd7070Spatrick   // wrap the result up in a struct or object, meaning it can be freed later.
3241e5dd7070Spatrick   // (See RetainCountChecker.) Not all the parameters here are invalidated,
3242e5dd7070Spatrick   // but the Malloc checker cannot differentiate between them. The right way
3243e5dd7070Spatrick   // of doing this would be to implement a pointer escapes callback.
3244e5dd7070Spatrick   if (FName == "CGBitmapContextCreate" ||
3245e5dd7070Spatrick       FName == "CGBitmapContextCreateWithData" ||
3246e5dd7070Spatrick       FName == "CVPixelBufferCreateWithBytes" ||
3247e5dd7070Spatrick       FName == "CVPixelBufferCreateWithPlanarBytes" ||
3248e5dd7070Spatrick       FName == "OSAtomicEnqueue") {
3249e5dd7070Spatrick     return true;
3250e5dd7070Spatrick   }
3251e5dd7070Spatrick 
3252e5dd7070Spatrick   if (FName == "postEvent" &&
3253e5dd7070Spatrick       FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
3254e5dd7070Spatrick     return true;
3255e5dd7070Spatrick   }
3256e5dd7070Spatrick 
3257e5dd7070Spatrick   if (FName == "connectImpl" &&
3258e5dd7070Spatrick       FD->getQualifiedNameAsString() == "QObject::connectImpl") {
3259e5dd7070Spatrick     return true;
3260e5dd7070Spatrick   }
3261e5dd7070Spatrick 
3262e5dd7070Spatrick   // Handle cases where we know a buffer's /address/ can escape.
3263e5dd7070Spatrick   // Note that the above checks handle some special cases where we know that
3264e5dd7070Spatrick   // even though the address escapes, it's still our responsibility to free the
3265e5dd7070Spatrick   // buffer.
3266e5dd7070Spatrick   if (Call->argumentsMayEscape())
3267e5dd7070Spatrick     return true;
3268e5dd7070Spatrick 
3269e5dd7070Spatrick   // Otherwise, assume that the function does not free memory.
3270e5dd7070Spatrick   // Most system calls do not free the memory.
3271e5dd7070Spatrick   return false;
3272e5dd7070Spatrick }
3273e5dd7070Spatrick 
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3274e5dd7070Spatrick ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
3275e5dd7070Spatrick                                              const InvalidatedSymbols &Escaped,
3276e5dd7070Spatrick                                              const CallEvent *Call,
3277e5dd7070Spatrick                                              PointerEscapeKind Kind) const {
3278e5dd7070Spatrick   return checkPointerEscapeAux(State, Escaped, Call, Kind,
3279e5dd7070Spatrick                                /*IsConstPointerEscape*/ false);
3280e5dd7070Spatrick }
3281e5dd7070Spatrick 
checkConstPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3282e5dd7070Spatrick ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
3283e5dd7070Spatrick                                               const InvalidatedSymbols &Escaped,
3284e5dd7070Spatrick                                               const CallEvent *Call,
3285e5dd7070Spatrick                                               PointerEscapeKind Kind) const {
3286e5dd7070Spatrick   // If a const pointer escapes, it may not be freed(), but it could be deleted.
3287e5dd7070Spatrick   return checkPointerEscapeAux(State, Escaped, Call, Kind,
3288e5dd7070Spatrick                                /*IsConstPointerEscape*/ true);
3289e5dd7070Spatrick }
3290e5dd7070Spatrick 
checkIfNewOrNewArrayFamily(const RefState * RS)3291e5dd7070Spatrick static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
3292e5dd7070Spatrick   return (RS->getAllocationFamily() == AF_CXXNewArray ||
3293e5dd7070Spatrick           RS->getAllocationFamily() == AF_CXXNew);
3294e5dd7070Spatrick }
3295e5dd7070Spatrick 
checkPointerEscapeAux(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,bool IsConstPointerEscape) const3296e5dd7070Spatrick ProgramStateRef MallocChecker::checkPointerEscapeAux(
3297e5dd7070Spatrick     ProgramStateRef State, const InvalidatedSymbols &Escaped,
3298e5dd7070Spatrick     const CallEvent *Call, PointerEscapeKind Kind,
3299e5dd7070Spatrick     bool IsConstPointerEscape) const {
3300e5dd7070Spatrick   // If we know that the call does not free memory, or we want to process the
3301e5dd7070Spatrick   // call later, keep tracking the top level arguments.
3302e5dd7070Spatrick   SymbolRef EscapingSymbol = nullptr;
3303e5dd7070Spatrick   if (Kind == PSK_DirectEscapeOnCall &&
3304e5dd7070Spatrick       !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3305e5dd7070Spatrick                                                     EscapingSymbol) &&
3306e5dd7070Spatrick       !EscapingSymbol) {
3307e5dd7070Spatrick     return State;
3308e5dd7070Spatrick   }
3309e5dd7070Spatrick 
3310e5dd7070Spatrick   for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
3311e5dd7070Spatrick        E = Escaped.end();
3312e5dd7070Spatrick        I != E; ++I) {
3313e5dd7070Spatrick     SymbolRef sym = *I;
3314e5dd7070Spatrick 
3315e5dd7070Spatrick     if (EscapingSymbol && EscapingSymbol != sym)
3316e5dd7070Spatrick       continue;
3317e5dd7070Spatrick 
3318e5dd7070Spatrick     if (const RefState *RS = State->get<RegionState>(sym))
3319e5dd7070Spatrick       if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3320e5dd7070Spatrick         if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))
3321e5dd7070Spatrick           State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3322e5dd7070Spatrick   }
3323e5dd7070Spatrick   return State;
3324e5dd7070Spatrick }
3325e5dd7070Spatrick 
isArgZERO_SIZE_PTR(ProgramStateRef State,CheckerContext & C,SVal ArgVal) const3326ec727ea7Spatrick bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
3327ec727ea7Spatrick                                        SVal ArgVal) const {
3328ec727ea7Spatrick   if (!KernelZeroSizePtrValue)
3329ec727ea7Spatrick     KernelZeroSizePtrValue =
3330ec727ea7Spatrick         tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor());
3331ec727ea7Spatrick 
3332ec727ea7Spatrick   const llvm::APSInt *ArgValKnown =
3333ec727ea7Spatrick       C.getSValBuilder().getKnownValue(State, ArgVal);
3334ec727ea7Spatrick   return ArgValKnown && *KernelZeroSizePtrValue &&
3335ec727ea7Spatrick          ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3336ec727ea7Spatrick }
3337ec727ea7Spatrick 
findFailedReallocSymbol(ProgramStateRef currState,ProgramStateRef prevState)3338e5dd7070Spatrick static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
3339e5dd7070Spatrick                                          ProgramStateRef prevState) {
3340e5dd7070Spatrick   ReallocPairsTy currMap = currState->get<ReallocPairs>();
3341e5dd7070Spatrick   ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3342e5dd7070Spatrick 
3343e5dd7070Spatrick   for (const ReallocPairsTy::value_type &Pair : prevMap) {
3344e5dd7070Spatrick     SymbolRef sym = Pair.first;
3345e5dd7070Spatrick     if (!currMap.lookup(sym))
3346e5dd7070Spatrick       return sym;
3347e5dd7070Spatrick   }
3348e5dd7070Spatrick 
3349e5dd7070Spatrick   return nullptr;
3350e5dd7070Spatrick }
3351e5dd7070Spatrick 
isReferenceCountingPointerDestructor(const CXXDestructorDecl * DD)3352e5dd7070Spatrick static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {
3353e5dd7070Spatrick   if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) {
3354e5dd7070Spatrick     StringRef N = II->getName();
3355a9ac8606Spatrick     if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3356a9ac8606Spatrick       if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3357a9ac8606Spatrick           N.contains_insensitive("intrusive") ||
3358a9ac8606Spatrick           N.contains_insensitive("shared")) {
3359e5dd7070Spatrick         return true;
3360e5dd7070Spatrick       }
3361e5dd7070Spatrick     }
3362e5dd7070Spatrick   }
3363e5dd7070Spatrick   return false;
3364e5dd7070Spatrick }
3365e5dd7070Spatrick 
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)3366e5dd7070Spatrick PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3367e5dd7070Spatrick                                                    BugReporterContext &BRC,
3368e5dd7070Spatrick                                                    PathSensitiveBugReport &BR) {
3369e5dd7070Spatrick   ProgramStateRef state = N->getState();
3370e5dd7070Spatrick   ProgramStateRef statePrev = N->getFirstPred()->getState();
3371e5dd7070Spatrick 
3372e5dd7070Spatrick   const RefState *RSCurr = state->get<RegionState>(Sym);
3373e5dd7070Spatrick   const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3374e5dd7070Spatrick 
3375e5dd7070Spatrick   const Stmt *S = N->getStmtForDiagnostics();
3376e5dd7070Spatrick   // When dealing with containers, we sometimes want to give a note
3377e5dd7070Spatrick   // even if the statement is missing.
3378e5dd7070Spatrick   if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3379e5dd7070Spatrick     return nullptr;
3380e5dd7070Spatrick 
3381e5dd7070Spatrick   const LocationContext *CurrentLC = N->getLocationContext();
3382e5dd7070Spatrick 
3383e5dd7070Spatrick   // If we find an atomic fetch_add or fetch_sub within the destructor in which
3384e5dd7070Spatrick   // the pointer was released (before the release), this is likely a destructor
3385e5dd7070Spatrick   // of a shared pointer.
3386e5dd7070Spatrick   // Because we don't model atomics, and also because we don't know that the
3387e5dd7070Spatrick   // original reference count is positive, we should not report use-after-frees
3388e5dd7070Spatrick   // on objects deleted in such destructors. This can probably be improved
3389e5dd7070Spatrick   // through better shared pointer modeling.
3390e5dd7070Spatrick   if (ReleaseDestructorLC) {
3391e5dd7070Spatrick     if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
3392e5dd7070Spatrick       AtomicExpr::AtomicOp Op = AE->getOp();
3393e5dd7070Spatrick       if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3394e5dd7070Spatrick           Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3395e5dd7070Spatrick         if (ReleaseDestructorLC == CurrentLC ||
3396e5dd7070Spatrick             ReleaseDestructorLC->isParentOf(CurrentLC)) {
3397e5dd7070Spatrick           BR.markInvalid(getTag(), S);
3398e5dd7070Spatrick         }
3399e5dd7070Spatrick       }
3400e5dd7070Spatrick     }
3401e5dd7070Spatrick   }
3402e5dd7070Spatrick 
3403e5dd7070Spatrick   // FIXME: We will eventually need to handle non-statement-based events
3404e5dd7070Spatrick   // (__attribute__((cleanup))).
3405e5dd7070Spatrick 
3406e5dd7070Spatrick   // Find out if this is an interesting point and what is the kind.
3407e5dd7070Spatrick   StringRef Msg;
3408e5dd7070Spatrick   std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;
3409e5dd7070Spatrick   SmallString<256> Buf;
3410e5dd7070Spatrick   llvm::raw_svector_ostream OS(Buf);
3411e5dd7070Spatrick 
3412e5dd7070Spatrick   if (Mode == Normal) {
3413e5dd7070Spatrick     if (isAllocated(RSCurr, RSPrev, S)) {
3414e5dd7070Spatrick       Msg = "Memory is allocated";
3415e5dd7070Spatrick       StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3416e5dd7070Spatrick           Sym, "Returned allocated memory");
3417e5dd7070Spatrick     } else if (isReleased(RSCurr, RSPrev, S)) {
3418e5dd7070Spatrick       const auto Family = RSCurr->getAllocationFamily();
3419e5dd7070Spatrick       switch (Family) {
3420e5dd7070Spatrick         case AF_Alloca:
3421e5dd7070Spatrick         case AF_Malloc:
3422e5dd7070Spatrick         case AF_CXXNew:
3423e5dd7070Spatrick         case AF_CXXNewArray:
3424e5dd7070Spatrick         case AF_IfNameIndex:
3425e5dd7070Spatrick           Msg = "Memory is released";
3426e5dd7070Spatrick           StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3427e5dd7070Spatrick               Sym, "Returning; memory was released");
3428e5dd7070Spatrick           break;
3429e5dd7070Spatrick         case AF_InnerBuffer: {
3430e5dd7070Spatrick           const MemRegion *ObjRegion =
3431e5dd7070Spatrick               allocation_state::getContainerObjRegion(statePrev, Sym);
3432e5dd7070Spatrick           const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
3433e5dd7070Spatrick           QualType ObjTy = TypedRegion->getValueType();
3434*12c85518Srobert           OS << "Inner buffer of '" << ObjTy << "' ";
3435e5dd7070Spatrick 
3436e5dd7070Spatrick           if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {
3437e5dd7070Spatrick             OS << "deallocated by call to destructor";
3438e5dd7070Spatrick             StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3439e5dd7070Spatrick                 Sym, "Returning; inner buffer was deallocated");
3440e5dd7070Spatrick           } else {
3441e5dd7070Spatrick             OS << "reallocated by call to '";
3442e5dd7070Spatrick             const Stmt *S = RSCurr->getStmt();
3443e5dd7070Spatrick             if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3444a9ac8606Spatrick               OS << MemCallE->getMethodDecl()->getDeclName();
3445e5dd7070Spatrick             } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3446a9ac8606Spatrick               OS << OpCallE->getDirectCallee()->getDeclName();
3447e5dd7070Spatrick             } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
3448e5dd7070Spatrick               auto &CEMgr = BRC.getStateManager().getCallEventManager();
3449e5dd7070Spatrick               CallEventRef<> Call = CEMgr.getSimpleCall(CallE, state, CurrentLC);
3450a9ac8606Spatrick               if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
3451a9ac8606Spatrick                 OS << D->getDeclName();
3452a9ac8606Spatrick               else
3453a9ac8606Spatrick                 OS << "unknown";
3454e5dd7070Spatrick             }
3455e5dd7070Spatrick             OS << "'";
3456e5dd7070Spatrick             StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3457e5dd7070Spatrick                 Sym, "Returning; inner buffer was reallocated");
3458e5dd7070Spatrick           }
3459e5dd7070Spatrick           Msg = OS.str();
3460e5dd7070Spatrick           break;
3461e5dd7070Spatrick         }
3462e5dd7070Spatrick         case AF_None:
3463e5dd7070Spatrick           llvm_unreachable("Unhandled allocation family!");
3464e5dd7070Spatrick       }
3465e5dd7070Spatrick 
3466e5dd7070Spatrick       // See if we're releasing memory while inlining a destructor
3467e5dd7070Spatrick       // (or one of its callees). This turns on various common
3468e5dd7070Spatrick       // false positive suppressions.
3469e5dd7070Spatrick       bool FoundAnyDestructor = false;
3470e5dd7070Spatrick       for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
3471e5dd7070Spatrick         if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {
3472e5dd7070Spatrick           if (isReferenceCountingPointerDestructor(DD)) {
3473e5dd7070Spatrick             // This immediately looks like a reference-counting destructor.
3474e5dd7070Spatrick             // We're bad at guessing the original reference count of the object,
3475e5dd7070Spatrick             // so suppress the report for now.
3476e5dd7070Spatrick             BR.markInvalid(getTag(), DD);
3477e5dd7070Spatrick           } else if (!FoundAnyDestructor) {
3478e5dd7070Spatrick             assert(!ReleaseDestructorLC &&
3479e5dd7070Spatrick                    "There can be only one release point!");
3480e5dd7070Spatrick             // Suspect that it's a reference counting pointer destructor.
3481e5dd7070Spatrick             // On one of the next nodes might find out that it has atomic
3482e5dd7070Spatrick             // reference counting operations within it (see the code above),
3483e5dd7070Spatrick             // and if so, we'd conclude that it likely is a reference counting
3484e5dd7070Spatrick             // pointer destructor.
3485e5dd7070Spatrick             ReleaseDestructorLC = LC->getStackFrame();
3486e5dd7070Spatrick             // It is unlikely that releasing memory is delegated to a destructor
3487e5dd7070Spatrick             // inside a destructor of a shared pointer, because it's fairly hard
3488e5dd7070Spatrick             // to pass the information that the pointer indeed needs to be
3489e5dd7070Spatrick             // released into it. So we're only interested in the innermost
3490e5dd7070Spatrick             // destructor.
3491e5dd7070Spatrick             FoundAnyDestructor = true;
3492e5dd7070Spatrick           }
3493e5dd7070Spatrick         }
3494e5dd7070Spatrick       }
3495e5dd7070Spatrick     } else if (isRelinquished(RSCurr, RSPrev, S)) {
3496e5dd7070Spatrick       Msg = "Memory ownership is transferred";
3497e5dd7070Spatrick       StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");
3498e5dd7070Spatrick     } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3499e5dd7070Spatrick       Mode = ReallocationFailed;
3500e5dd7070Spatrick       Msg = "Reallocation failed";
3501e5dd7070Spatrick       StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3502e5dd7070Spatrick           Sym, "Reallocation failed");
3503e5dd7070Spatrick 
3504e5dd7070Spatrick       if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
3505e5dd7070Spatrick         // Is it possible to fail two reallocs WITHOUT testing in between?
3506e5dd7070Spatrick         assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3507e5dd7070Spatrick           "We only support one failed realloc at a time.");
3508e5dd7070Spatrick         BR.markInteresting(sym);
3509e5dd7070Spatrick         FailedReallocSymbol = sym;
3510e5dd7070Spatrick       }
3511e5dd7070Spatrick     }
3512e5dd7070Spatrick 
3513e5dd7070Spatrick   // We are in a special mode if a reallocation failed later in the path.
3514e5dd7070Spatrick   } else if (Mode == ReallocationFailed) {
3515e5dd7070Spatrick     assert(FailedReallocSymbol && "No symbol to look for.");
3516e5dd7070Spatrick 
3517e5dd7070Spatrick     // Is this is the first appearance of the reallocated symbol?
3518e5dd7070Spatrick     if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3519e5dd7070Spatrick       // We're at the reallocation point.
3520e5dd7070Spatrick       Msg = "Attempt to reallocate memory";
3521e5dd7070Spatrick       StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3522e5dd7070Spatrick           Sym, "Returned reallocated memory");
3523e5dd7070Spatrick       FailedReallocSymbol = nullptr;
3524e5dd7070Spatrick       Mode = Normal;
3525e5dd7070Spatrick     }
3526e5dd7070Spatrick   }
3527e5dd7070Spatrick 
3528e5dd7070Spatrick   if (Msg.empty()) {
3529e5dd7070Spatrick     assert(!StackHint);
3530e5dd7070Spatrick     return nullptr;
3531e5dd7070Spatrick   }
3532e5dd7070Spatrick 
3533e5dd7070Spatrick   assert(StackHint);
3534e5dd7070Spatrick 
3535e5dd7070Spatrick   // Generate the extra diagnostic.
3536e5dd7070Spatrick   PathDiagnosticLocation Pos;
3537e5dd7070Spatrick   if (!S) {
3538e5dd7070Spatrick     assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3539e5dd7070Spatrick     auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
3540e5dd7070Spatrick     if (!PostImplCall)
3541e5dd7070Spatrick       return nullptr;
3542e5dd7070Spatrick     Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
3543e5dd7070Spatrick                                  BRC.getSourceManager());
3544e5dd7070Spatrick   } else {
3545e5dd7070Spatrick     Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),
3546e5dd7070Spatrick                                  N->getLocationContext());
3547e5dd7070Spatrick   }
3548e5dd7070Spatrick 
3549e5dd7070Spatrick   auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
3550e5dd7070Spatrick   BR.addCallStackHint(P, std::move(StackHint));
3551e5dd7070Spatrick   return P;
3552e5dd7070Spatrick }
3553e5dd7070Spatrick 
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const3554e5dd7070Spatrick void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
3555e5dd7070Spatrick                                const char *NL, const char *Sep) const {
3556e5dd7070Spatrick 
3557e5dd7070Spatrick   RegionStateTy RS = State->get<RegionState>();
3558e5dd7070Spatrick 
3559e5dd7070Spatrick   if (!RS.isEmpty()) {
3560e5dd7070Spatrick     Out << Sep << "MallocChecker :" << NL;
3561e5dd7070Spatrick     for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
3562e5dd7070Spatrick       const RefState *RefS = State->get<RegionState>(I.getKey());
3563e5dd7070Spatrick       AllocationFamily Family = RefS->getAllocationFamily();
3564*12c85518Srobert       std::optional<MallocChecker::CheckKind> CheckKind =
3565*12c85518Srobert           getCheckIfTracked(Family);
3566*12c85518Srobert       if (!CheckKind)
3567e5dd7070Spatrick         CheckKind = getCheckIfTracked(Family, true);
3568e5dd7070Spatrick 
3569e5dd7070Spatrick       I.getKey()->dumpToStream(Out);
3570e5dd7070Spatrick       Out << " : ";
3571e5dd7070Spatrick       I.getData().dump(Out);
3572*12c85518Srobert       if (CheckKind)
3573e5dd7070Spatrick         Out << " (" << CheckNames[*CheckKind].getName() << ")";
3574e5dd7070Spatrick       Out << NL;
3575e5dd7070Spatrick     }
3576e5dd7070Spatrick   }
3577e5dd7070Spatrick }
3578e5dd7070Spatrick 
3579e5dd7070Spatrick namespace clang {
3580e5dd7070Spatrick namespace ento {
3581e5dd7070Spatrick namespace allocation_state {
3582e5dd7070Spatrick 
3583e5dd7070Spatrick ProgramStateRef
markReleased(ProgramStateRef State,SymbolRef Sym,const Expr * Origin)3584e5dd7070Spatrick markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
3585e5dd7070Spatrick   AllocationFamily Family = AF_InnerBuffer;
3586e5dd7070Spatrick   return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3587e5dd7070Spatrick }
3588e5dd7070Spatrick 
3589e5dd7070Spatrick } // end namespace allocation_state
3590e5dd7070Spatrick } // end namespace ento
3591e5dd7070Spatrick } // end namespace clang
3592e5dd7070Spatrick 
3593e5dd7070Spatrick // Intended to be used in InnerPointerChecker to register the part of
3594e5dd7070Spatrick // MallocChecker connected to it.
registerInnerPointerCheckerAux(CheckerManager & mgr)3595e5dd7070Spatrick void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
3596e5dd7070Spatrick   MallocChecker *checker = mgr.getChecker<MallocChecker>();
3597e5dd7070Spatrick   checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
3598e5dd7070Spatrick   checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3599e5dd7070Spatrick       mgr.getCurrentCheckerName();
3600e5dd7070Spatrick }
3601e5dd7070Spatrick 
registerDynamicMemoryModeling(CheckerManager & mgr)3602e5dd7070Spatrick void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
3603e5dd7070Spatrick   auto *checker = mgr.registerChecker<MallocChecker>();
3604ec727ea7Spatrick   checker->ShouldIncludeOwnershipAnnotatedFunctions =
3605e5dd7070Spatrick       mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic");
3606*12c85518Srobert   checker->ShouldRegisterNoOwnershipChangeVisitor =
3607*12c85518Srobert       mgr.getAnalyzerOptions().getCheckerBooleanOption(
3608*12c85518Srobert           checker, "AddNoOwnershipChangeNotes");
3609e5dd7070Spatrick }
3610e5dd7070Spatrick 
shouldRegisterDynamicMemoryModeling(const CheckerManager & mgr)3611ec727ea7Spatrick bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
3612e5dd7070Spatrick   return true;
3613e5dd7070Spatrick }
3614e5dd7070Spatrick 
3615e5dd7070Spatrick #define REGISTER_CHECKER(name)                                                 \
3616e5dd7070Spatrick   void ento::register##name(CheckerManager &mgr) {                             \
3617e5dd7070Spatrick     MallocChecker *checker = mgr.getChecker<MallocChecker>();                  \
3618e5dd7070Spatrick     checker->ChecksEnabled[MallocChecker::CK_##name] = true;                   \
3619e5dd7070Spatrick     checker->CheckNames[MallocChecker::CK_##name] =                            \
3620e5dd7070Spatrick         mgr.getCurrentCheckerName();                                           \
3621e5dd7070Spatrick   }                                                                            \
3622e5dd7070Spatrick                                                                                \
3623ec727ea7Spatrick   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
3624e5dd7070Spatrick 
3625e5dd7070Spatrick REGISTER_CHECKER(MallocChecker)
3626e5dd7070Spatrick REGISTER_CHECKER(NewDeleteChecker)
3627e5dd7070Spatrick REGISTER_CHECKER(NewDeleteLeaksChecker)
3628e5dd7070Spatrick REGISTER_CHECKER(MismatchedDeallocatorChecker)
3629