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