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