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