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