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

source code of clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp