clang 22.0.0git
MallocChecker.cpp
Go to the documentation of this file.
1//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a variety of memory management related checkers, such as
10// leak, double free, and use-after-free.
11//
12// The following checkers are defined here:
13//
14// * MallocChecker
15// Despite its name, it models all sorts of memory allocations and
16// de- or reallocation, including but not limited to malloc, free,
17// relloc, new, delete. It also reports on a variety of memory misuse
18// errors.
19// Many other checkers interact very closely with this checker, in fact,
20// most are merely options to this one. Other checkers may register
21// MallocChecker, but do not enable MallocChecker's reports (more details
22// to follow around its field, ChecksEnabled).
23// It also has a boolean "Optimistic" checker option, which if set to true
24// will cause the checker to model user defined memory management related
25// functions annotated via the attribute ownership_takes, ownership_holds
26// and ownership_returns.
27//
28// * NewDeleteChecker
29// Enables the modeling of new, new[], delete, delete[] in MallocChecker,
30// and checks for related double-free and use-after-free errors.
31//
32// * NewDeleteLeaksChecker
33// Checks for leaks related to new, new[], delete, delete[].
34// Depends on NewDeleteChecker.
35//
36// * MismatchedDeallocatorChecker
37// Enables checking whether memory is deallocated with the corresponding
38// allocation function in MallocChecker, such as malloc() allocated
39// regions are only freed by free(), new by delete, new[] by delete[].
40//
41// InnerPointerChecker interacts very closely with MallocChecker, but unlike
42// the above checkers, it has it's own file, hence the many InnerPointerChecker
43// related headers and non-static functions.
44//
45//===----------------------------------------------------------------------===//
46
47#include "AllocationState.h"
48#include "InterCheckerAPI.h"
50#include "clang/AST/Attr.h"
51#include "clang/AST/DeclCXX.h"
53#include "clang/AST/Expr.h"
54#include "clang/AST/ExprCXX.h"
55#include "clang/AST/ParentMap.h"
59#include "clang/Basic/LLVM.h"
62#include "clang/Lex/Lexer.h"
80#include "llvm/ADT/STLExtras.h"
81#include "llvm/ADT/SmallVector.h"
82#include "llvm/ADT/StringExtras.h"
83#include "llvm/Support/Casting.h"
84#include "llvm/Support/Compiler.h"
85#include "llvm/Support/ErrorHandling.h"
86#include "llvm/Support/raw_ostream.h"
87#include <functional>
88#include <optional>
89#include <utility>
90
91using namespace clang;
92using namespace ento;
93using namespace std::placeholders;
94
95//===----------------------------------------------------------------------===//
96// The types of allocation we're modeling. This is used to check whether a
97// dynamically allocated object is deallocated with the correct function, like
98// not using operator delete on an object created by malloc(), or alloca regions
99// aren't ever deallocated manually.
100//===----------------------------------------------------------------------===//
101
102namespace {
103
104// Used to check correspondence between allocators and deallocators.
105enum AllocationFamilyKind {
106 AF_None,
107 AF_Malloc,
108 AF_CXXNew,
109 AF_CXXNewArray,
110 AF_IfNameIndex,
111 AF_Alloca,
112 AF_InnerBuffer,
113 AF_Custom,
114};
115
116struct AllocationFamily {
117 AllocationFamilyKind Kind;
118 std::optional<StringRef> CustomName;
119
120 explicit AllocationFamily(AllocationFamilyKind AKind,
121 std::optional<StringRef> Name = std::nullopt)
122 : Kind(AKind), CustomName(Name) {
123 assert((Kind != AF_Custom || CustomName.has_value()) &&
124 "Custom family must specify also the name");
125
126 // Preseve previous behavior when "malloc" class means AF_Malloc
127 if (Kind == AF_Custom && CustomName.value() == "malloc") {
128 Kind = AF_Malloc;
129 CustomName = std::nullopt;
130 }
131 }
132
133 bool operator==(const AllocationFamily &Other) const {
134 return std::tie(Kind, CustomName) == std::tie(Other.Kind, Other.CustomName);
135 }
136
137 bool operator!=(const AllocationFamily &Other) const {
138 return !(*this == Other);
139 }
140
141 void Profile(llvm::FoldingSetNodeID &ID) const {
142 ID.AddInteger(Kind);
143
144 if (Kind == AF_Custom)
145 ID.AddString(CustomName.value());
146 }
147};
148
149} // end of anonymous namespace
150
151/// Print names of allocators and deallocators.
152///
153/// \returns true on success.
154static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);
155
156/// Print expected name of an allocator based on the deallocator's family
157/// derived from the DeallocExpr.
158static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);
159
160/// Print expected name of a deallocator based on the allocator's
161/// family.
162static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
163
164//===----------------------------------------------------------------------===//
165// The state of a symbol, in terms of memory management.
166//===----------------------------------------------------------------------===//
167
168namespace {
169
170class RefState {
171 enum Kind {
172 // Reference to allocated memory.
173 Allocated,
174 // Reference to zero-allocated memory.
175 AllocatedOfSizeZero,
176 // Reference to released/freed memory.
177 Released,
178 // The responsibility for freeing resources has transferred from
179 // this reference. A relinquished symbol should not be freed.
180 Relinquished,
181 // We are no longer guaranteed to have observed all manipulations
182 // of this pointer/memory. For example, it could have been
183 // passed as a parameter to an opaque function.
184 Escaped
185 };
186
187 const Stmt *S;
188
189 Kind K;
190 AllocationFamily Family;
191
192 RefState(Kind k, const Stmt *s, AllocationFamily family)
193 : S(s), K(k), Family(family) {
194 assert(family.Kind != AF_None);
195 }
196
197public:
198 bool isAllocated() const { return K == Allocated; }
199 bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
200 bool isReleased() const { return K == Released; }
201 bool isRelinquished() const { return K == Relinquished; }
202 bool isEscaped() const { return K == Escaped; }
203 AllocationFamily getAllocationFamily() const { return Family; }
204 const Stmt *getStmt() const { return S; }
205
206 bool operator==(const RefState &X) const {
207 return K == X.K && S == X.S && Family == X.Family;
208 }
209
210 static RefState getAllocated(AllocationFamily family, const Stmt *s) {
211 return RefState(Allocated, s, family);
212 }
213 static RefState getAllocatedOfSizeZero(const RefState *RS) {
214 return RefState(AllocatedOfSizeZero, RS->getStmt(),
215 RS->getAllocationFamily());
216 }
217 static RefState getReleased(AllocationFamily family, const Stmt *s) {
218 return RefState(Released, s, family);
219 }
220 static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
221 return RefState(Relinquished, s, family);
222 }
223 static RefState getEscaped(const RefState *RS) {
224 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
225 }
226
227 void Profile(llvm::FoldingSetNodeID &ID) const {
228 ID.AddInteger(K);
229 ID.AddPointer(S);
230 Family.Profile(ID);
231 }
232
233 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
234 switch (K) {
235#define CASE(ID) case ID: OS << #ID; break;
236 CASE(Allocated)
237 CASE(AllocatedOfSizeZero)
238 CASE(Released)
239 CASE(Relinquished)
240 CASE(Escaped)
241 }
242 }
243
244 LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
245};
246
247} // end of anonymous namespace
248
249REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
250
251/// Check if the memory associated with this symbol was released.
252static bool isReleased(SymbolRef Sym, CheckerContext &C);
253
254/// Update the RefState to reflect the new memory allocation.
255/// The optional \p RetVal parameter specifies the newly allocated pointer
256/// value; if unspecified, the value of expression \p E is used.
257static ProgramStateRef
259 AllocationFamily Family,
260 std::optional<SVal> RetVal = std::nullopt);
261
262//===----------------------------------------------------------------------===//
263// The modeling of memory reallocation.
264//
265// The terminology 'toPtr' and 'fromPtr' will be used:
266// toPtr = realloc(fromPtr, 20);
267//===----------------------------------------------------------------------===//
268
269REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
270
271namespace {
272
273/// The state of 'fromPtr' after reallocation is known to have failed.
274enum OwnershipAfterReallocKind {
275 // The symbol needs to be freed (e.g.: realloc)
276 OAR_ToBeFreedAfterFailure,
277 // The symbol has been freed (e.g.: reallocf)
278 OAR_FreeOnFailure,
279 // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where
280 // 'fromPtr' was allocated:
281 // void Haha(int *ptr) {
282 // ptr = realloc(ptr, 67);
283 // // ...
284 // }
285 // ).
286 OAR_DoNotTrackAfterFailure
287};
288
289/// Stores information about the 'fromPtr' symbol after reallocation.
290///
291/// This is important because realloc may fail, and that needs special modeling.
292/// Whether reallocation failed or not will not be known until later, so we'll
293/// store whether upon failure 'fromPtr' will be freed, or needs to be freed
294/// later, etc.
295struct ReallocPair {
296
297 // The 'fromPtr'.
298 SymbolRef ReallocatedSym;
299 OwnershipAfterReallocKind Kind;
300
301 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
302 : ReallocatedSym(S), Kind(K) {}
303 void Profile(llvm::FoldingSetNodeID &ID) const {
304 ID.AddInteger(Kind);
305 ID.AddPointer(ReallocatedSym);
306 }
307 bool operator==(const ReallocPair &X) const {
308 return ReallocatedSym == X.ReallocatedSym &&
309 Kind == X.Kind;
310 }
311};
312
313} // end of anonymous namespace
314
315REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
316
317static bool isStandardNew(const FunctionDecl *FD);
318static bool isStandardNew(const CallEvent &Call) {
319 if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))
320 return false;
321 return isStandardNew(cast<FunctionDecl>(Call.getDecl()));
322}
323
324static bool isStandardDelete(const FunctionDecl *FD);
325static bool isStandardDelete(const CallEvent &Call) {
326 if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))
327 return false;
328 return isStandardDelete(cast<FunctionDecl>(Call.getDecl()));
329}
330
331/// Tells if the callee is one of the builtin new/delete operators, including
332/// placement operators and other standard overloads.
333template <typename T> static bool isStandardNewDelete(const T &FD) {
334 return isStandardDelete(FD) || isStandardNew(FD);
335}
336
337namespace {
338
339//===----------------------------------------------------------------------===//
340// Utility classes that provide access to the bug types and can model that some
341// of the bug types are shared by multiple checker frontends.
342//===----------------------------------------------------------------------===//
343
344#define BUGTYPE_PROVIDER(NAME, DEF) \
345 struct NAME : virtual public CheckerFrontend { \
346 BugType NAME##Bug{this, DEF, categories::MemoryError}; \
347 };
348
349BUGTYPE_PROVIDER(DoubleFree, "Double free")
350
351struct Leak : virtual public CheckerFrontend {
352 // Leaks should not be reported if they are post-dominated by a sink:
353 // (1) Sinks are higher importance bugs.
354 // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
355 // with __noreturn functions such as assert() or exit(). We choose not
356 // to report leaks on such paths.
357 BugType LeakBug{this, "Memory leak", categories::MemoryError,
358 /*SuppressOnSink=*/true};
359};
360
361BUGTYPE_PROVIDER(UseFree, "Use-after-free")
362BUGTYPE_PROVIDER(BadFree, "Bad free")
363BUGTYPE_PROVIDER(FreeAlloca, "Free 'alloca()'")
364BUGTYPE_PROVIDER(MismatchedDealloc, "Bad deallocator")
365BUGTYPE_PROVIDER(OffsetFree, "Offset free")
366BUGTYPE_PROVIDER(UseZeroAllocated, "Use of zero allocated")
367
368#undef BUGTYPE_PROVIDER
369
370template <typename... BT_PROVIDERS>
371struct DynMemFrontend : virtual public CheckerFrontend, public BT_PROVIDERS... {
372 template <typename T> const T *getAs() const {
373 if constexpr (std::is_same_v<T, CheckerFrontend> ||
374 (std::is_same_v<T, BT_PROVIDERS> || ...))
375 return static_cast<const T *>(this);
376 return nullptr;
377 }
378};
379
380//===----------------------------------------------------------------------===//
381// Definition of the MallocChecker class.
382//===----------------------------------------------------------------------===//
383
384class MallocChecker
385 : public CheckerFamily<
386 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,
387 check::PreStmt<ReturnStmt>, check::EndFunction, check::PreCall,
388 check::PostCall, eval::Call, check::NewAllocator,
389 check::PostStmt<BlockExpr>, check::PostObjCMessage, check::Location,
390 eval::Assume> {
391public:
392 /// In pessimistic mode, the checker assumes that it does not know which
393 /// functions might free the memory.
394 /// In optimistic mode, the checker assumes that all user-defined functions
395 /// which might free a pointer are annotated.
396 bool ShouldIncludeOwnershipAnnotatedFunctions = false;
397
398 bool ShouldRegisterNoOwnershipChangeVisitor = false;
399
400 // This checker family implements many bug types and frontends, and several
401 // bug types are shared between multiple frontends, so most of the frontends
402 // are declared with the helper class DynMemFrontend.
403 // FIXME: There is no clear reason for separating NewDelete vs NewDeleteLeaks
404 // while e.g. MallocChecker covers both non-leak and leak bugs together. It
405 // would be nice to redraw the boundaries between the frontends in a more
406 // logical way.
407 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
408 UseZeroAllocated>
409 MallocChecker;
410 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
411 NewDeleteChecker;
412 DynMemFrontend<Leak> NewDeleteLeaksChecker;
413 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
414 DynMemFrontend<UseFree> InnerPointerChecker;
415 // This last frontend is associated with a single bug type which is not used
416 // elsewhere and has a different bug category, so it's declared separately.
417 CheckerFrontendWithBugType TaintedAllocChecker{"Tainted Memory Allocation",
419
420 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
421
422 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
423 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
424 bool evalCall(const CallEvent &Call, CheckerContext &C) const;
425
427 handleSmartPointerConstructorArguments(const CallEvent &Call,
428 ProgramStateRef State) const;
429 ProgramStateRef handleSmartPointerRelatedCalls(const CallEvent &Call,
430 CheckerContext &C,
431 ProgramStateRef State) const;
432 void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
433 void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
434 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
435 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
436 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
437 void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;
438 ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
439 bool Assumption) const;
440 void checkLocation(SVal l, bool isLoad, const Stmt *S,
441 CheckerContext &C) const;
442
443 ProgramStateRef checkPointerEscape(ProgramStateRef State,
444 const InvalidatedSymbols &Escaped,
445 const CallEvent *Call,
446 PointerEscapeKind Kind) const;
447 ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
448 const InvalidatedSymbols &Escaped,
449 const CallEvent *Call,
450 PointerEscapeKind Kind) const;
451
452 void printState(raw_ostream &Out, ProgramStateRef State,
453 const char *NL, const char *Sep) const override;
454
455 StringRef getDebugTag() const override { return "MallocChecker"; }
456
457private:
458#define CHECK_FN(NAME) \
459 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \
460 const;
461
462 CHECK_FN(checkFree)
463 CHECK_FN(checkIfNameIndex)
464 CHECK_FN(checkBasicAlloc)
465 CHECK_FN(checkKernelMalloc)
466 CHECK_FN(checkCalloc)
467 CHECK_FN(checkAlloca)
468 CHECK_FN(checkStrdup)
469 CHECK_FN(checkIfFreeNameIndex)
470 CHECK_FN(checkCXXNewOrCXXDelete)
471 CHECK_FN(checkGMalloc0)
472 CHECK_FN(checkGMemdup)
473 CHECK_FN(checkGMallocN)
474 CHECK_FN(checkGMallocN0)
475 CHECK_FN(preGetDelimOrGetLine)
476 CHECK_FN(checkGetDelimOrGetLine)
477 CHECK_FN(checkReallocN)
478 CHECK_FN(checkOwnershipAttr)
479
480 void checkRealloc(ProgramStateRef State, const CallEvent &Call,
481 CheckerContext &C, bool ShouldFreeOnFail) const;
482
483 using CheckFn =
484 std::function<void(const class MallocChecker *, ProgramStateRef State,
485 const CallEvent &Call, CheckerContext &C)>;
486
487 const CallDescriptionMap<CheckFn> PreFnMap{
488 // NOTE: the following CallDescription also matches the C++ standard
489 // library function std::getline(); the callback will filter it out.
490 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
491 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
492 };
493
494 const CallDescriptionMap<CheckFn> PostFnMap{
495 // NOTE: the following CallDescription also matches the C++ standard
496 // library function std::getline(); the callback will filter it out.
497 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
498 {{CDM::CLibrary, {"getdelim"}, 4},
499 &MallocChecker::checkGetDelimOrGetLine},
500 };
501
502 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
503 {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},
504 {{CDM::CLibrary, {"if_freenameindex"}, 1},
505 &MallocChecker::checkIfFreeNameIndex},
506 {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},
507 {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},
508 };
509
510 bool isFreeingCall(const CallEvent &Call) const;
511 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);
512 static bool isFreeingOwnershipAttrCall(const CallEvent &Call);
513 static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);
514 static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);
515
516 friend class NoMemOwnershipChangeVisitor;
517
518 CallDescriptionMap<CheckFn> AllocaMemFnMap{
519 {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},
520 {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},
521 // The line for "alloca" also covers "__builtin_alloca", but the
522 // _with_align variant must be listed separately because it takes an
523 // extra argument:
524 {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},
525 &MallocChecker::checkAlloca},
526 };
527
528 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
529 {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
530 {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
531 {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},
532 {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
533 {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},
534 {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},
535 {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},
536 {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
537 {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
538 {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
539 {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
540 {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
541 {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
542 {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
543 {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
544 {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
545 {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
546 {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
547 {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
548 {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
549 };
550
551 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
552 {{CDM::CLibrary, {"realloc"}, 2},
553 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
554 {{CDM::CLibrary, {"reallocf"}, 2},
555 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},
556 {{CDM::CLibrary, {"g_realloc"}, 2},
557 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
558 {{CDM::CLibrary, {"g_try_realloc"}, 2},
559 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},
560 {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
561 {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
562 };
563
564 bool isMemCall(const CallEvent &Call) const;
565 bool hasOwnershipReturns(const CallEvent &Call) const;
566 bool hasOwnershipTakesHolds(const CallEvent &Call) const;
567 void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C,
568 llvm::ArrayRef<SymbolRef> TaintedSyms,
569 AllocationFamily Family) const;
570
571 void checkTaintedness(CheckerContext &C, const CallEvent &Call,
572 const SVal SizeSVal, ProgramStateRef State,
573 AllocationFamily Family) const;
574
575 // TODO: Remove mutable by moving the initializtaion to the registry function.
576 mutable std::optional<uint64_t> KernelZeroFlagVal;
577
578 using KernelZeroSizePtrValueTy = std::optional<int>;
579 /// Store the value of macro called `ZERO_SIZE_PTR`.
580 /// The value is initialized at first use, before first use the outer
581 /// Optional is empty, afterwards it contains another Optional that indicates
582 /// if the macro value could be determined, and if yes the value itself.
583 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
584
585 /// Process C++ operator new()'s allocation, which is the part of C++
586 /// new-expression that goes before the constructor.
587 [[nodiscard]] ProgramStateRef
588 processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
589 AllocationFamily Family) const;
590
591 /// Perform a zero-allocation check.
592 ///
593 /// \param [in] Call The expression that allocates memory.
594 /// \param [in] IndexOfSizeArg Index of the argument that specifies the size
595 /// of the memory that needs to be allocated. E.g. for malloc, this would be
596 /// 0.
597 /// \param [in] RetVal Specifies the newly allocated pointer value;
598 /// if unspecified, the value of expression \p E is used.
599 [[nodiscard]] static ProgramStateRef
600 ProcessZeroAllocCheck(CheckerContext &C, const CallEvent &Call,
601 const unsigned IndexOfSizeArg, ProgramStateRef State,
602 std::optional<SVal> RetVal = std::nullopt);
603
604 /// Model functions with the ownership_returns attribute.
605 ///
606 /// User-defined function may have the ownership_returns attribute, which
607 /// annotates that the function returns with an object that was allocated on
608 /// the heap, and passes the ownertship to the callee.
609 ///
610 /// void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);
611 ///
612 /// It has two parameters:
613 /// - first: name of the resource (e.g. 'malloc')
614 /// - (OPTIONAL) second: size of the allocated region
615 ///
616 /// \param [in] Call The expression that allocates memory.
617 /// \param [in] Att The ownership_returns attribute.
618 /// \param [in] State The \c ProgramState right before allocation.
619 /// \returns The ProgramState right after allocation.
620 [[nodiscard]] ProgramStateRef
621 MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
622 const OwnershipAttr *Att, ProgramStateRef State) const;
623 /// Models memory allocation.
624 ///
625 /// \param [in] C Checker context.
626 /// \param [in] Call The expression that allocates memory.
627 /// \param [in] State The \c ProgramState right before allocation.
628 /// \param [in] isAlloca Is the allocation function alloca-like
629 /// \returns The ProgramState with returnValue bound
630 [[nodiscard]] ProgramStateRef MallocBindRetVal(CheckerContext &C,
631 const CallEvent &Call,
632 ProgramStateRef State,
633 bool isAlloca) const;
634
635 /// Models memory allocation.
636 ///
637 /// \param [in] Call The expression that allocates memory.
638 /// \param [in] SizeEx Size of the memory that needs to be allocated.
639 /// \param [in] Init The value the allocated memory needs to be initialized.
640 /// with. For example, \c calloc initializes the allocated memory to 0,
641 /// malloc leaves it undefined.
642 /// \param [in] State The \c ProgramState right before allocation.
643 /// \returns The ProgramState right after allocation.
644 [[nodiscard]] ProgramStateRef
645 MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
646 SVal Init, ProgramStateRef State, AllocationFamily Family) const;
647
648 /// Models memory allocation.
649 ///
650 /// \param [in] Call The expression that allocates memory.
651 /// \param [in] Size Size of the memory that needs to be allocated.
652 /// \param [in] Init The value the allocated memory needs to be initialized.
653 /// with. For example, \c calloc initializes the allocated memory to 0,
654 /// malloc leaves it undefined.
655 /// \param [in] State The \c ProgramState right before allocation.
656 /// \returns The ProgramState right after allocation.
657 [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C,
658 const CallEvent &Call, SVal Size,
659 SVal Init, ProgramStateRef State,
660 AllocationFamily Family) const;
661
662 // Check if this malloc() for special flags. At present that means M_ZERO or
663 // __GFP_ZERO (in which case, treat it like calloc).
664 [[nodiscard]] std::optional<ProgramStateRef>
665 performKernelMalloc(const CallEvent &Call, CheckerContext &C,
666 const ProgramStateRef &State) const;
667
668 /// Model functions with the ownership_takes and ownership_holds attributes.
669 ///
670 /// User-defined function may have the ownership_takes and/or ownership_holds
671 /// attributes, which annotates that the function frees the memory passed as a
672 /// parameter.
673 ///
674 /// void __attribute((ownership_takes(malloc, 1))) my_free(void *);
675 /// void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
676 ///
677 /// They have two parameters:
678 /// - first: name of the resource (e.g. 'malloc')
679 /// - second: index of the parameter the attribute applies to
680 ///
681 /// \param [in] Call The expression that frees memory.
682 /// \param [in] Att The ownership_takes or ownership_holds attribute.
683 /// \param [in] State The \c ProgramState right before allocation.
684 /// \returns The ProgramState right after deallocation.
685 [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,
686 const CallEvent &Call,
687 const OwnershipAttr *Att,
688 ProgramStateRef State) const;
689
690 /// Models memory deallocation.
691 ///
692 /// \param [in] Call The expression that frees memory.
693 /// \param [in] State The \c ProgramState right before allocation.
694 /// \param [in] Num Index of the argument that needs to be freed. This is
695 /// normally 0, but for custom free functions it may be different.
696 /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
697 /// attribute.
698 /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
699 /// to have been allocated, or in other words, the symbol to be freed was
700 /// registered as allocated by this checker. In the following case, \c ptr
701 /// isn't known to be allocated.
702 /// void Haha(int *ptr) {
703 /// ptr = realloc(ptr, 67);
704 /// // ...
705 /// }
706 /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
707 /// we're modeling returns with Null on failure.
708 /// \returns The ProgramState right after deallocation.
709 [[nodiscard]] ProgramStateRef
710 FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,
711 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
712 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
713
714 /// Models memory deallocation.
715 ///
716 /// \param [in] ArgExpr The variable who's pointee needs to be freed.
717 /// \param [in] Call The expression that frees the memory.
718 /// \param [in] State The \c ProgramState right before allocation.
719 /// normally 0, but for custom free functions it may be different.
720 /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
721 /// attribute.
722 /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
723 /// to have been allocated, or in other words, the symbol to be freed was
724 /// registered as allocated by this checker. In the following case, \c ptr
725 /// isn't known to be allocated.
726 /// void Haha(int *ptr) {
727 /// ptr = realloc(ptr, 67);
728 /// // ...
729 /// }
730 /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
731 /// we're modeling returns with Null on failure.
732 /// \param [in] ArgValOpt Optional value to use for the argument instead of
733 /// the one obtained from ArgExpr.
734 /// \returns The ProgramState right after deallocation.
735 [[nodiscard]] ProgramStateRef
736 FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
737 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
738 AllocationFamily Family, bool ReturnsNullOnFailure = false,
739 std::optional<SVal> ArgValOpt = {}) const;
740
741 // TODO: Needs some refactoring, as all other deallocation modeling
742 // functions are suffering from out parameters and messy code due to how
743 // realloc is handled.
744 //
745 /// Models memory reallocation.
746 ///
747 /// \param [in] Call The expression that reallocated memory
748 /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied
749 /// memory should be freed.
750 /// \param [in] State The \c ProgramState right before reallocation.
751 /// \param [in] SuffixWithN Whether the reallocation function we're modeling
752 /// has an '_n' suffix, such as g_realloc_n.
753 /// \returns The ProgramState right after reallocation.
754 [[nodiscard]] ProgramStateRef
755 ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
756 ProgramStateRef State, AllocationFamily Family,
757 bool SuffixWithN = false) const;
758
759 /// Evaluates the buffer size that needs to be allocated.
760 ///
761 /// \param [in] Blocks The amount of blocks that needs to be allocated.
762 /// \param [in] BlockBytes The size of a block.
763 /// \returns The symbolic value of \p Blocks * \p BlockBytes.
764 [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
765 const Expr *Blocks,
766 const Expr *BlockBytes);
767
768 /// Models zero initialized array allocation.
769 ///
770 /// \param [in] Call The expression that reallocated memory
771 /// \param [in] State The \c ProgramState right before reallocation.
772 /// \returns The ProgramState right after allocation.
773 [[nodiscard]] ProgramStateRef CallocMem(CheckerContext &C,
774 const CallEvent &Call,
775 ProgramStateRef State) const;
776
777 /// See if deallocation happens in a suspicious context. If so, escape the
778 /// pointers that otherwise would have been deallocated and return true.
779 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,
780 CheckerContext &C) const;
781
782 /// If in \p S \p Sym is used, check whether \p Sym was already freed.
783 bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
784
785 /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero
786 /// sized memory region.
787 void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
788 const Stmt *S) const;
789
790 /// Check if the function is known to free memory, or if it is
791 /// "interesting" and should be modeled explicitly.
792 ///
793 /// \param [out] EscapingSymbol A function might not free memory in general,
794 /// but could be known to free a particular symbol. In this case, false is
795 /// returned and the single escaping symbol is returned through the out
796 /// parameter.
797 ///
798 /// We assume that pointers do not escape through calls to system functions
799 /// not handled by this checker.
800 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
801 ProgramStateRef State,
802 SymbolRef &EscapingSymbol) const;
803
804 /// Implementation of the checkPointerEscape callbacks.
805 [[nodiscard]] ProgramStateRef
806 checkPointerEscapeAux(ProgramStateRef State,
807 const InvalidatedSymbols &Escaped,
808 const CallEvent *Call, PointerEscapeKind Kind,
809 bool IsConstPointerEscape) const;
810
811 // Implementation of the checkPreStmt and checkEndFunction callbacks.
812 void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
813
814 ///@{
815 /// Returns a pointer to the checker frontend corresponding to the given
816 /// family or symbol. The template argument T may be either CheckerFamily or
817 /// a BUGTYPE_PROVIDER class; in the latter case the query is restricted to
818 /// frontends that descend from that PROVIDER class (i.e. can emit that bug
819 /// type). Note that this may return a frontend which is disabled.
820 template <class T>
821 const T *getRelevantFrontendAs(AllocationFamily Family) const;
822
823 template <class T>
824 const T *getRelevantFrontendAs(CheckerContext &C, SymbolRef Sym) const;
825 ///@}
826 static bool SummarizeValue(raw_ostream &os, SVal V);
827 static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,
828 const MemRegion *MR);
829
830 void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
831 const Expr *DeallocExpr,
832 AllocationFamily Family) const;
833
834 void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
835 SourceRange Range) const;
836
837 void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,
838 const Expr *DeallocExpr, const RefState *RS,
839 SymbolRef Sym, bool OwnershipTransferred) const;
840
841 void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
842 const Expr *DeallocExpr, AllocationFamily Family,
843 const Expr *AllocExpr = nullptr) const;
844
845 void HandleUseAfterFree(CheckerContext &C, SourceRange Range,
846 SymbolRef Sym) const;
847
848 void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
849 SymbolRef Sym, SymbolRef PrevSym) const;
850
851 void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
852 SymbolRef Sym) const;
853
854 void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
855 const Expr *FreeExpr,
856 AllocationFamily Family) const;
857
858 /// Find the location of the allocation for Sym on the path leading to the
859 /// exploded node N.
860 static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
861 CheckerContext &C);
862
863 void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
864
865 /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`.
866 bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
867 SVal ArgVal) const;
868};
869} // end anonymous namespace
870
871//===----------------------------------------------------------------------===//
872// Definition of NoOwnershipChangeVisitor.
873//===----------------------------------------------------------------------===//
874
875namespace {
876class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor {
877protected:
878 /// Syntactically checks whether the callee is a deallocating function. Since
879 /// we have no path-sensitive information on this call (we would need a
880 /// CallEvent instead of a CallExpr for that), its possible that a
881 /// deallocation function was called indirectly through a function pointer,
882 /// but we are not able to tell, so this is a best effort analysis.
883 /// See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in
884 /// clang/test/Analysis/NewDeleteLeaks.cpp.
885 bool isFreeingCallAsWritten(const CallExpr &Call) const {
886 const auto *MallocChk = static_cast<const MallocChecker *>(&Checker);
887 if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) ||
888 MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))
889 return true;
890
891 if (const auto *Func =
892 llvm::dyn_cast_or_null<FunctionDecl>(Call.getCalleeDecl()))
893 return MallocChecker::isFreeingOwnershipAttrCall(Func);
894
895 return false;
896 }
897
898 bool hasResourceStateChanged(ProgramStateRef CallEnterState,
899 ProgramStateRef CallExitEndState) final {
900 return CallEnterState->get<RegionState>(Sym) !=
901 CallExitEndState->get<RegionState>(Sym);
902 }
903
904 /// Heuristically guess whether the callee intended to free memory. This is
905 /// done syntactically, because we are trying to argue about alternative
906 /// paths of execution, and as a consequence we don't have path-sensitive
907 /// information.
908 bool doesFnIntendToHandleOwnership(const Decl *Callee,
909 ASTContext &ACtx) final {
910 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
911
912 // Given that the stack frame was entered, the body should always be
913 // theoretically obtainable. In case of body farms, the synthesized body
914 // is not attached to declaration, thus triggering the '!FD->hasBody()'
915 // branch. That said, would a synthesized body ever intend to handle
916 // ownership? As of today they don't. And if they did, how would we
917 // put notes inside it, given that it doesn't match any source locations?
918 if (!FD || !FD->hasBody())
919 return false;
920 using namespace clang::ast_matchers;
921
922 auto Matches = match(findAll(stmt(anyOf(cxxDeleteExpr().bind("delete"),
923 callExpr().bind("call")))),
924 *FD->getBody(), ACtx);
925 for (BoundNodes Match : Matches) {
926 if (Match.getNodeAs<CXXDeleteExpr>("delete"))
927 return true;
928
929 if (const auto *Call = Match.getNodeAs<CallExpr>("call"))
930 if (isFreeingCallAsWritten(*Call))
931 return true;
932 }
933 // TODO: Ownership might change with an attempt to store the allocated
934 // memory, not only through deallocation. Check for attempted stores as
935 // well.
936 return false;
937 }
938
939 PathDiagnosticPieceRef emitNote(const ExplodedNode *N) final {
940 PathDiagnosticLocation L = PathDiagnosticLocation::create(
941 N->getLocation(),
942 N->getState()->getStateManager().getContext().getSourceManager());
943 return std::make_shared<PathDiagnosticEventPiece>(
944 L, "Returning without deallocating memory or storing the pointer for "
945 "later deallocation");
946 }
947
948public:
949 NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
950 : NoOwnershipChangeVisitor(Sym, Checker) {}
951
952 void Profile(llvm::FoldingSetNodeID &ID) const override {
953 static int Tag = 0;
954 ID.AddPointer(&Tag);
955 ID.AddPointer(Sym);
956 }
957};
958
959} // end anonymous namespace
960
961//===----------------------------------------------------------------------===//
962// Definition of MallocBugVisitor.
963//===----------------------------------------------------------------------===//
964
965namespace {
966/// The bug visitor which allows us to print extra diagnostics along the
967/// BugReport path. For example, showing the allocation site of the leaked
968/// region.
969class MallocBugVisitor final : public BugReporterVisitor {
970protected:
971 enum NotificationMode { Normal, ReallocationFailed };
972
973 // The allocated region symbol tracked by the main analysis.
974 SymbolRef Sym;
975
976 // The mode we are in, i.e. what kind of diagnostics will be emitted.
977 NotificationMode Mode;
978
979 // A symbol from when the primary region should have been reallocated.
980 SymbolRef FailedReallocSymbol;
981
982 // A release function stack frame in which memory was released. Used for
983 // miscellaneous false positive suppression.
984 const StackFrameContext *ReleaseFunctionLC;
985
986 bool IsLeak;
987
988public:
989 MallocBugVisitor(SymbolRef S, bool isLeak = false)
990 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
991 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}
992
993 static void *getTag() {
994 static int Tag = 0;
995 return &Tag;
996 }
997
998 void Profile(llvm::FoldingSetNodeID &ID) const override {
999 ID.AddPointer(getTag());
1000 ID.AddPointer(Sym);
1001 }
1002
1003 /// Did not track -> allocated. Other state (released) -> allocated.
1004 static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
1005 const Stmt *Stmt) {
1006 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
1007 (RSCurr &&
1008 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1009 (!RSPrev ||
1010 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1011 }
1012
1013 /// Did not track -> released. Other state (allocated) -> released.
1014 /// The statement associated with the release might be missing.
1015 static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
1016 const Stmt *Stmt) {
1017 bool IsReleased =
1018 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
1019 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
1020 (!Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));
1021 return IsReleased;
1022 }
1023
1024 /// Did not track -> relinquished. Other state (allocated) -> relinquished.
1025 static inline bool isRelinquished(const RefState *RSCurr,
1026 const RefState *RSPrev, const Stmt *Stmt) {
1027 return (
1028 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
1029 (RSCurr && RSCurr->isRelinquished()) &&
1030 (!RSPrev || !RSPrev->isRelinquished()));
1031 }
1032
1033 /// If the expression is not a call, and the state change is
1034 /// released -> allocated, it must be the realloc return value
1035 /// check. If we have to handle more cases here, it might be cleaner just
1036 /// to track this extra bit in the state itself.
1037 static inline bool hasReallocFailed(const RefState *RSCurr,
1038 const RefState *RSPrev,
1039 const Stmt *Stmt) {
1040 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
1041 (RSCurr &&
1042 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1043 (RSPrev &&
1044 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1045 }
1046
1047 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1048 BugReporterContext &BRC,
1049 PathSensitiveBugReport &BR) override;
1050
1051 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
1052 const ExplodedNode *EndPathNode,
1053 PathSensitiveBugReport &BR) override {
1054 if (!IsLeak)
1055 return nullptr;
1056
1057 PathDiagnosticLocation L = BR.getLocation();
1058 // Do not add the statement itself as a range in case of leak.
1059 return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
1060 false);
1061 }
1062
1063private:
1064 class StackHintGeneratorForReallocationFailed
1065 : public StackHintGeneratorForSymbol {
1066 public:
1067 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
1068 : StackHintGeneratorForSymbol(S, M) {}
1069
1070 std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
1071 // Printed parameters start at 1, not 0.
1072 ++ArgIndex;
1073
1074 SmallString<200> buf;
1075 llvm::raw_svector_ostream os(buf);
1076
1077 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1078 << " parameter failed";
1079
1080 return std::string(os.str());
1081 }
1082
1083 std::string getMessageForReturn(const CallExpr *CallExpr) override {
1084 return "Reallocation of returned value failed";
1085 }
1086 };
1087};
1088} // end anonymous namespace
1089
1090// A map from the freed symbol to the symbol representing the return value of
1091// the free function.
1093
1094namespace {
1095class StopTrackingCallback final : public SymbolVisitor {
1096 ProgramStateRef state;
1097
1098public:
1099 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
1100 ProgramStateRef getState() const { return state; }
1101
1102 bool VisitSymbol(SymbolRef sym) override {
1103 state = state->remove<RegionState>(sym);
1104 return true;
1105 }
1106};
1107
1108/// EscapeTrackedCallback - A SymbolVisitor that marks allocated symbols as
1109/// escaped.
1110///
1111/// This visitor is used to suppress false positive leak reports when smart
1112/// pointers are nested in temporary objects passed by value to functions. When
1113/// the analyzer can't see the destructor calls for temporary objects, it may
1114/// incorrectly report leaks for memory that will be properly freed by the smart
1115/// pointer destructors.
1116///
1117/// The visitor traverses reachable symbols from a given set of memory regions
1118/// (typically smart pointer field regions) and marks any allocated symbols as
1119/// escaped. Escaped symbols are not reported as leaks by checkDeadSymbols.
1120class EscapeTrackedCallback final : public SymbolVisitor {
1121 ProgramStateRef State;
1122
1123 explicit EscapeTrackedCallback(ProgramStateRef S) : State(std::move(S)) {}
1124
1125public:
1126 bool VisitSymbol(SymbolRef Sym) override {
1127 if (const RefState *RS = State->get<RegionState>(Sym)) {
1128 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {
1129 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
1130 }
1131 }
1132 return true;
1133 }
1134
1135 /// Escape tracked regions reachable from the given roots.
1136 static ProgramStateRef
1137 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,
1138 ProgramStateRef State) {
1139 if (Roots.empty())
1140 return State;
1141
1142 // scanReachableSymbols is expensive, so we use a single visitor for all
1143 // roots
1144 SmallVector<const MemRegion *, 10> Regions;
1145 EscapeTrackedCallback Visitor(State);
1146 for (const MemRegion *R : Roots) {
1147 Regions.push_back(R);
1148 }
1149 State->scanReachableSymbols(Regions, Visitor);
1150 return Visitor.State;
1151 }
1152
1153 friend class SymbolVisitor;
1154};
1155} // end anonymous namespace
1156
1157static bool isStandardNew(const FunctionDecl *FD) {
1158 if (!FD)
1159 return false;
1160
1162 if (Kind != OO_New && Kind != OO_Array_New)
1163 return false;
1164
1165 // This is standard if and only if it's not defined in a user file.
1166 SourceLocation L = FD->getLocation();
1167 // If the header for operator delete is not included, it's still defined
1168 // in an invalid source location. Check to make sure we don't crash.
1169 return !L.isValid() ||
1171}
1172
1173static bool isStandardDelete(const FunctionDecl *FD) {
1174 if (!FD)
1175 return false;
1176
1178 if (Kind != OO_Delete && Kind != OO_Array_Delete)
1179 return false;
1180
1181 bool HasBody = FD->hasBody(); // Prefer using the definition.
1182
1183 // This is standard if and only if it's not defined in a user file.
1184 SourceLocation L = FD->getLocation();
1185
1186 // If the header for operator delete is not included, it's still defined
1187 // in an invalid source location. Check to make sure we don't crash.
1188 const auto &SM = FD->getASTContext().getSourceManager();
1189 return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));
1190}
1191
1192//===----------------------------------------------------------------------===//
1193// Methods of MallocChecker and MallocBugVisitor.
1194//===----------------------------------------------------------------------===//
1195
1196bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) {
1197 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1198
1199 return Func && isFreeingOwnershipAttrCall(Func);
1200}
1201
1202bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {
1203 if (Func->hasAttrs()) {
1204 for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
1205 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1206 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1207 return true;
1208 }
1209 }
1210 return false;
1211}
1212
1213bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
1214 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1215 return true;
1216
1217 return isFreeingOwnershipAttrCall(Call);
1218}
1219
1220bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) {
1221 const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
1222
1223 return Func && isAllocatingOwnershipAttrCall(Func);
1224}
1225
1226bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) {
1227 for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
1228 if (I->getOwnKind() == OwnershipAttr::Returns)
1229 return true;
1230 }
1231
1232 return false;
1233}
1234
1235bool MallocChecker::isMemCall(const CallEvent &Call) const {
1236 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1237 AllocaMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1238 return true;
1239
1240 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1241 return false;
1242
1243 const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());
1244 return Func && Func->hasAttr<OwnershipAttr>();
1245}
1246
1247std::optional<ProgramStateRef>
1248MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
1249 const ProgramStateRef &State) const {
1250 // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
1251 //
1252 // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);
1253 //
1254 // One of the possible flags is M_ZERO, which means 'give me back an
1255 // allocation which is already zeroed', like calloc.
1256
1257 // 2-argument kmalloc(), as used in the Linux kernel:
1258 //
1259 // void *kmalloc(size_t size, gfp_t flags);
1260 //
1261 // Has the similar flag value __GFP_ZERO.
1262
1263 // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some
1264 // code could be shared.
1265
1266 ASTContext &Ctx = C.getASTContext();
1267 llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();
1268
1269 if (!KernelZeroFlagVal) {
1270 switch (OS) {
1271 case llvm::Triple::FreeBSD:
1272 KernelZeroFlagVal = 0x0100;
1273 break;
1274 case llvm::Triple::NetBSD:
1275 KernelZeroFlagVal = 0x0002;
1276 break;
1277 case llvm::Triple::OpenBSD:
1278 KernelZeroFlagVal = 0x0008;
1279 break;
1280 case llvm::Triple::Linux:
1281 // __GFP_ZERO
1282 KernelZeroFlagVal = 0x8000;
1283 break;
1284 default:
1285 // FIXME: We need a more general way of getting the M_ZERO value.
1286 // See also: O_CREAT in UnixAPIChecker.cpp.
1287
1288 // Fall back to normal malloc behavior on platforms where we don't
1289 // know M_ZERO.
1290 return std::nullopt;
1291 }
1292 }
1293
1294 // We treat the last argument as the flags argument, and callers fall-back to
1295 // normal malloc on a None return. This works for the FreeBSD kernel malloc
1296 // as well as Linux kmalloc.
1297 if (Call.getNumArgs() < 2)
1298 return std::nullopt;
1299
1300 const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
1301 const SVal V = C.getSVal(FlagsEx);
1302 if (!isa<NonLoc>(V)) {
1303 // The case where 'V' can be a location can only be due to a bad header,
1304 // so in this case bail out.
1305 return std::nullopt;
1306 }
1307
1308 NonLoc Flags = V.castAs<NonLoc>();
1309 NonLoc ZeroFlag = C.getSValBuilder()
1310 .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
1311 .castAs<NonLoc>();
1312 SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
1313 Flags, ZeroFlag,
1314 FlagsEx->getType());
1315 if (MaskedFlagsUC.isUnknownOrUndef())
1316 return std::nullopt;
1317 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1318
1319 // Check if maskedFlags is non-zero.
1320 ProgramStateRef TrueState, FalseState;
1321 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1322
1323 // If M_ZERO is set, treat this like calloc (initialized).
1324 if (TrueState && !FalseState) {
1325 SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
1326 return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,
1327 AllocationFamily(AF_Malloc));
1328 }
1329
1330 return std::nullopt;
1331}
1332
1333SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
1334 const Expr *BlockBytes) {
1335 SValBuilder &SB = C.getSValBuilder();
1336 SVal BlocksVal = C.getSVal(Blocks);
1337 SVal BlockBytesVal = C.getSVal(BlockBytes);
1338 ProgramStateRef State = C.getState();
1339 SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1341 return TotalSize;
1342}
1343
1344void MallocChecker::checkBasicAlloc(ProgramStateRef State,
1345 const CallEvent &Call,
1346 CheckerContext &C) const {
1347 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1348 AllocationFamily(AF_Malloc));
1349 State = ProcessZeroAllocCheck(C, Call, 0, State);
1350 C.addTransition(State);
1351}
1352
1353void MallocChecker::checkKernelMalloc(ProgramStateRef State,
1354 const CallEvent &Call,
1355 CheckerContext &C) const {
1356 std::optional<ProgramStateRef> MaybeState =
1357 performKernelMalloc(Call, C, State);
1358 if (MaybeState)
1359 State = *MaybeState;
1360 else
1361 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1362 AllocationFamily(AF_Malloc));
1363 C.addTransition(State);
1364}
1365
1366static bool isStandardRealloc(const CallEvent &Call) {
1367 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1368 assert(FD);
1369 ASTContext &AC = FD->getASTContext();
1370 return AC.hasSameType(FD->getDeclaredReturnType(), AC.VoidPtrTy) &&
1371 AC.hasSameType(FD->getParamDecl(0)->getType(), AC.VoidPtrTy) &&
1372 AC.hasSameType(FD->getParamDecl(1)->getType(), AC.getSizeType());
1373}
1374
1375static bool isGRealloc(const CallEvent &Call) {
1376 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1377 assert(FD);
1378 ASTContext &AC = FD->getASTContext();
1379
1380 return AC.hasSameType(FD->getDeclaredReturnType(), AC.VoidPtrTy) &&
1381 AC.hasSameType(FD->getParamDecl(0)->getType(), AC.VoidPtrTy) &&
1383}
1384
1385void MallocChecker::checkRealloc(ProgramStateRef State, const CallEvent &Call,
1386 CheckerContext &C,
1387 bool ShouldFreeOnFail) const {
1388 // Ignore calls to functions whose type does not match the expected type of
1389 // either the standard realloc or g_realloc from GLib.
1390 // FIXME: Should we perform this kind of checking consistently for each
1391 // function? If yes, then perhaps extend the `CallDescription` interface to
1392 // handle this.
1394 return;
1395
1396 State = ReallocMemAux(C, Call, ShouldFreeOnFail, State,
1397 AllocationFamily(AF_Malloc));
1398 State = ProcessZeroAllocCheck(C, Call, 1, State);
1399 C.addTransition(State);
1400}
1401
1402void MallocChecker::checkCalloc(ProgramStateRef State, const CallEvent &Call,
1403 CheckerContext &C) const {
1404 State = CallocMem(C, Call, State);
1405 State = ProcessZeroAllocCheck(C, Call, 0, State);
1406 State = ProcessZeroAllocCheck(C, Call, 1, State);
1407 C.addTransition(State);
1408}
1409
1410void MallocChecker::checkFree(ProgramStateRef State, const CallEvent &Call,
1411 CheckerContext &C) const {
1412 bool IsKnownToBeAllocatedMemory = false;
1413 if (suppressDeallocationsInSuspiciousContexts(Call, C))
1414 return;
1415 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1416 AllocationFamily(AF_Malloc));
1417 C.addTransition(State);
1418}
1419
1420void MallocChecker::checkAlloca(ProgramStateRef State, const CallEvent &Call,
1421 CheckerContext &C) const {
1422 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1423 AllocationFamily(AF_Alloca));
1424 State = ProcessZeroAllocCheck(C, Call, 0, State);
1425 C.addTransition(State);
1426}
1427
1428void MallocChecker::checkStrdup(ProgramStateRef State, const CallEvent &Call,
1429 CheckerContext &C) const {
1430 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1431 if (!CE)
1432 return;
1433 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,
1434 AllocationFamily(AF_Malloc));
1435
1436 C.addTransition(State);
1437}
1438
1439void MallocChecker::checkIfNameIndex(ProgramStateRef State,
1440 const CallEvent &Call,
1441 CheckerContext &C) const {
1442 // Should we model this differently? We can allocate a fixed number of
1443 // elements with zeros in the last one.
1444 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,
1445 AllocationFamily(AF_IfNameIndex));
1446
1447 C.addTransition(State);
1448}
1449
1450void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,
1451 const CallEvent &Call,
1452 CheckerContext &C) const {
1453 bool IsKnownToBeAllocatedMemory = false;
1454 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1455 AllocationFamily(AF_IfNameIndex));
1456 C.addTransition(State);
1457}
1458
1460 const FunctionDecl *FD) {
1461 // Checking for signature:
1462 // void* operator new ( std::size_t count, void* ptr );
1463 // void* operator new[]( std::size_t count, void* ptr );
1464 if (CE->getNumArgs() != 2 || (FD->getOverloadedOperator() != OO_New &&
1465 FD->getOverloadedOperator() != OO_Array_New))
1466 return nullptr;
1467 auto BuffType = FD->getParamDecl(1)->getType();
1468 if (BuffType.isNull() || !BuffType->isVoidPointerType())
1469 return nullptr;
1470 return CE->getArg(1);
1471}
1472
1473void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,
1474 const CallEvent &Call,
1475 CheckerContext &C) const {
1476 bool IsKnownToBeAllocatedMemory = false;
1477 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1478 if (!CE)
1479 return;
1480
1481 assert(isStandardNewDelete(Call));
1482
1483 // Process direct calls to operator new/new[]/delete/delete[] functions
1484 // as distinct from new/new[]/delete/delete[] expressions that are
1485 // processed by the checkPostStmt callbacks for CXXNewExpr and
1486 // CXXDeleteExpr.
1487 const FunctionDecl *FD = C.getCalleeDecl(CE);
1488 if (const auto *BufArg = getPlacementNewBufferArg(CE, FD)) {
1489 // Placement new does not allocate memory
1490 auto RetVal = State->getSVal(BufArg, Call.getLocationContext());
1491 State = State->BindExpr(CE, C.getLocationContext(), RetVal);
1492 C.addTransition(State);
1493 return;
1494 }
1495
1496 switch (FD->getOverloadedOperator()) {
1497 case OO_New:
1498 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1499 AllocationFamily(AF_CXXNew));
1500 State = ProcessZeroAllocCheck(C, Call, 0, State);
1501 break;
1502 case OO_Array_New:
1503 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1504 AllocationFamily(AF_CXXNewArray));
1505 State = ProcessZeroAllocCheck(C, Call, 0, State);
1506 break;
1507 case OO_Delete:
1508 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1509 AllocationFamily(AF_CXXNew));
1510 break;
1511 case OO_Array_Delete:
1512 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1513 AllocationFamily(AF_CXXNewArray));
1514 break;
1515 default:
1516 assert(false && "not a new/delete operator");
1517 return;
1518 }
1519
1520 C.addTransition(State);
1521}
1522
1523void MallocChecker::checkGMalloc0(ProgramStateRef State, const CallEvent &Call,
1524 CheckerContext &C) const {
1525 SValBuilder &svalBuilder = C.getSValBuilder();
1526 SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
1527 State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State,
1528 AllocationFamily(AF_Malloc));
1529 State = ProcessZeroAllocCheck(C, Call, 0, State);
1530 C.addTransition(State);
1531}
1532
1533void MallocChecker::checkGMemdup(ProgramStateRef State, const CallEvent &Call,
1534 CheckerContext &C) const {
1535 State = MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State,
1536 AllocationFamily(AF_Malloc));
1537 State = ProcessZeroAllocCheck(C, Call, 1, State);
1538 C.addTransition(State);
1539}
1540
1541void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,
1542 CheckerContext &C) const {
1543 SVal Init = UndefinedVal();
1544 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1545 State = MallocMemAux(C, Call, TotalSize, Init, State,
1546 AllocationFamily(AF_Malloc));
1547 State = ProcessZeroAllocCheck(C, Call, 0, State);
1548 State = ProcessZeroAllocCheck(C, Call, 1, State);
1549 C.addTransition(State);
1550}
1551
1552void MallocChecker::checkGMallocN0(ProgramStateRef State, const CallEvent &Call,
1553 CheckerContext &C) const {
1554 SValBuilder &SB = C.getSValBuilder();
1555 SVal Init = SB.makeZeroVal(SB.getContext().CharTy);
1556 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1557 State = MallocMemAux(C, Call, TotalSize, Init, State,
1558 AllocationFamily(AF_Malloc));
1559 State = ProcessZeroAllocCheck(C, Call, 0, State);
1560 State = ProcessZeroAllocCheck(C, Call, 1, State);
1561 C.addTransition(State);
1562}
1563
1564static bool isFromStdNamespace(const CallEvent &Call) {
1565 const Decl *FD = Call.getDecl();
1566 assert(FD && "a CallDescription cannot match a call without a Decl");
1567 return FD->isInStdNamespace();
1568}
1569
1570void MallocChecker::preGetDelimOrGetLine(ProgramStateRef State,
1571 const CallEvent &Call,
1572 CheckerContext &C) const {
1573 // Discard calls to the C++ standard library function std::getline(), which
1574 // is completely unrelated to the POSIX getline() that we're checking.
1576 return;
1577
1578 const auto LinePtr = getPointeeVal(Call.getArgSVal(0), State);
1579 if (!LinePtr)
1580 return;
1581
1582 // FreeMemAux takes IsKnownToBeAllocated as an output parameter, and it will
1583 // be true after the call if the symbol was registered by this checker.
1584 // We do not need this value here, as FreeMemAux will take care
1585 // of reporting any violation of the preconditions.
1586 bool IsKnownToBeAllocated = false;
1587 State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false,
1588 IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,
1589 LinePtr);
1590 if (State)
1591 C.addTransition(State);
1592}
1593
1594void MallocChecker::checkGetDelimOrGetLine(ProgramStateRef State,
1595 const CallEvent &Call,
1596 CheckerContext &C) const {
1597 // Discard calls to the C++ standard library function std::getline(), which
1598 // is completely unrelated to the POSIX getline() that we're checking.
1600 return;
1601
1602 // Handle the post-conditions of getline and getdelim:
1603 // Register the new conjured value as an allocated buffer.
1604 const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1605 if (!CE)
1606 return;
1607
1608 const auto LinePtrOpt = getPointeeVal(Call.getArgSVal(0), State);
1609 const auto SizeOpt = getPointeeVal(Call.getArgSVal(1), State);
1610 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
1611 SizeOpt->isUnknownOrUndef())
1612 return;
1613
1614 const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
1615 const auto Size = SizeOpt->getAs<DefinedSVal>();
1616 const MemRegion *LinePtrReg = LinePtr->getAsRegion();
1617 if (!LinePtrReg)
1618 return;
1619
1620 State = setDynamicExtent(State, LinePtrReg, *Size);
1621 C.addTransition(MallocUpdateRefState(C, CE, State,
1622 AllocationFamily(AF_Malloc), *LinePtr));
1623}
1624
1625void MallocChecker::checkReallocN(ProgramStateRef State, const CallEvent &Call,
1626 CheckerContext &C) const {
1627 State = ReallocMemAux(C, Call, /*ShouldFreeOnFail=*/false, State,
1628 AllocationFamily(AF_Malloc),
1629 /*SuffixWithN=*/true);
1630 State = ProcessZeroAllocCheck(C, Call, 1, State);
1631 State = ProcessZeroAllocCheck(C, Call, 2, State);
1632 C.addTransition(State);
1633}
1634
1635void MallocChecker::checkOwnershipAttr(ProgramStateRef State,
1636 const CallEvent &Call,
1637 CheckerContext &C) const {
1638 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1639 if (!CE)
1640 return;
1641 const FunctionDecl *FD = C.getCalleeDecl(CE);
1642 if (!FD)
1643 return;
1644 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1645 MismatchedDeallocatorChecker.isEnabled()) {
1646 // Check all the attributes, if there are any.
1647 // There can be multiple of these attributes.
1648 if (FD->hasAttrs())
1649 for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
1650 switch (I->getOwnKind()) {
1651 case OwnershipAttr::Returns:
1652 State = MallocMemReturnsAttr(C, Call, I, State);
1653 break;
1654 case OwnershipAttr::Takes:
1655 case OwnershipAttr::Holds:
1656 State = FreeMemAttr(C, Call, I, State);
1657 break;
1658 }
1659 }
1660 }
1661 C.addTransition(State);
1662}
1663
1664bool MallocChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
1665 if (!Call.getOriginExpr())
1666 return false;
1667
1668 ProgramStateRef State = C.getState();
1669
1670 if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1671 (*Callback)(this, State, Call, C);
1672 return true;
1673 }
1674
1675 if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1676 State = MallocBindRetVal(C, Call, State, false);
1677 (*Callback)(this, State, Call, C);
1678 return true;
1679 }
1680
1681 if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1682 State = MallocBindRetVal(C, Call, State, false);
1683 (*Callback)(this, State, Call, C);
1684 return true;
1685 }
1686
1687 if (isStandardNew(Call)) {
1688 State = MallocBindRetVal(C, Call, State, false);
1689 checkCXXNewOrCXXDelete(State, Call, C);
1690 return true;
1691 }
1692
1693 if (isStandardDelete(Call)) {
1694 checkCXXNewOrCXXDelete(State, Call, C);
1695 return true;
1696 }
1697
1698 if (const CheckFn *Callback = AllocaMemFnMap.lookup(Call)) {
1699 State = MallocBindRetVal(C, Call, State, true);
1700 (*Callback)(this, State, Call, C);
1701 return true;
1702 }
1703
1704 if (isFreeingOwnershipAttrCall(Call)) {
1705 checkOwnershipAttr(State, Call, C);
1706 return true;
1707 }
1708
1709 if (isAllocatingOwnershipAttrCall(Call)) {
1710 State = MallocBindRetVal(C, Call, State, 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>(Call.getOriginExpr())) {
1728 Arg = CE->getArg(IndexOfSizeArg);
1729 } else if (const CXXNewExpr *NE =
1730 dyn_cast<CXXNewExpr>(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(Call.getOriginExpr(), C.getLocationContext());
1743
1744 assert(Arg);
1745
1746 auto DefArgVal =
1747 State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
1748
1749 if (!DefArgVal)
1750 return State;
1751
1752 // Check if the allocation size is 0.
1753 ProgramStateRef TrueState, FalseState;
1754 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1755 DefinedSVal Zero =
1756 SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
1757
1758 std::tie(TrueState, FalseState) =
1759 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, 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>(Sym);
1767 if (RS) {
1768 if (RS->isAllocated())
1769 return TrueState->set<RegionState>(
1770 Sym, 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>(Sym);
1778 }
1779
1780 // Assume the value is non-zero going forward.
1781 assert(FalseState);
1782 return FalseState;
1783}
1784
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.
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(CtorParamPointeeT);
1815
1816 if (CtorParamPointeeT->getAsCXXRecordDecl())
1817 return true;
1818 }
1819
1820 return false;
1821}
1822
1824MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
1825 CheckerContext &C,
1826 AllocationFamily Family) const {
1828 return nullptr;
1829
1830 const CXXNewExpr *NE = Call.getOriginExpr();
1831 const ParentMap &PM = C.getLocationContext()->getParentMap();
1832 ProgramStateRef State = C.getState();
1833
1834 // Non-trivial constructors have a chance to escape 'this', but marking all
1835 // invocations of trivial constructors as escaped would cause too great of
1836 // reduction of true positives, so let's just do that for constructors that
1837 // have an argument of a pointer-to-record type.
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, C.getSVal(*SizeEx), State,
1849 AllocationFamily(AF_CXXNewArray));
1850 }
1851
1852 State = MallocUpdateRefState(C, NE, State, Family, Target);
1853 State = ProcessZeroAllocCheck(C, Call, 0, State, 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 AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1863 : AF_CXXNew));
1864 C.addTransition(State);
1865 }
1866}
1867
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(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(i) == "freeWhenDone")
1886 return !Call.getArgSVal(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
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, Call.getArgExpr(0), Call, C.getState(),
1908 /*Hold=*/true, IsKnownToBeAllocatedMemory,
1909 AllocationFamily(AF_Malloc),
1910 /*ReturnsNullOnFailure=*/true);
1911
1912 C.addTransition(State);
1913}
1914
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 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1928 UnknownVal(), State, Family);
1929 }
1930 return MallocMemAux(C, Call, UnknownVal(), 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(CE->getType()))
1941 return nullptr;
1942
1943 unsigned Count = C.blockCount();
1944 SValBuilder &SVB = C.getSValBuilder();
1945 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1946 DefinedSVal RetVal =
1947 isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
1948 : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
1949 CE->getType(), Count);
1950 return State->BindExpr(CE, C.getLocationContext(), 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, C.getSVal(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, this)) {
1970 auto R =
1971 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
1972 for (const auto *TaintedSym : TaintedSyms) {
1973 R->markInteresting(TaintedSym);
1974 }
1975 C.emitReport(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, 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(SizeTy);
1996 NonLoc MaxLength =
1997 SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
1998 std::optional<NonLoc> SizeNL = SizeSVal.getAs<NonLoc>();
1999 auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2000 .getAs<DefinedOrUnknownSVal>();
2001 if (!Cmp)
2002 return;
2003 auto [StateTooLarge, StateNotTooLarge] = State->assume(*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 Callee + " is called with a tainted (potentially attacker controlled) "
2014 "value. Make sure the value is bound checked.",
2015 State, C, TaintedSyms, Family);
2016}
2017
2018ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
2019 const CallEvent &Call, SVal Size,
2020 SVal Init, ProgramStateRef State,
2021 AllocationFamily Family) const {
2022 if (!State)
2023 return nullptr;
2024
2025 const Expr *CE = Call.getOriginExpr();
2026
2027 // We expect the malloc functions to return a pointer.
2028 // Should have been already checked.
2029 assert(Loc::isLocType(CE->getType()) &&
2030 "Allocation functions must return a pointer");
2031
2032 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
2033 SVal RetVal = State->getSVal(CE, C.getLocationContext());
2034
2035 // Fill the region with the initialization value.
2036 State = State->bindDefaultInitial(RetVal, Init, LCtx);
2037
2038 // If Size is somehow undefined at this point, this line prevents a crash.
2039 if (Size.isUndef())
2040 Size = UnknownVal();
2041
2042 checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));
2043
2044 // Set the region's extent.
2045 State = setDynamicExtent(State, RetVal.getAsRegion(),
2046 Size.castAs<DefinedOrUnknownSVal>());
2047
2048 return MallocUpdateRefState(C, CE, State, Family);
2049}
2050
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, C.getLocationContext());
2061
2062 // We expect the malloc functions to return a pointer.
2063 if (!RetVal->getAs<Loc>())
2064 return nullptr;
2065
2066 SymbolRef Sym = RetVal->getAsLocSymbol();
2067
2068 // NOTE: If this was an `alloca()` call, then `RetVal` holds an
2069 // `AllocaRegion`, so `Sym` will be a nullpointer because `AllocaRegion`s do
2070 // not have an associated symbol. However, this distinct region type means
2071 // that we don't need to store anything about them in `RegionState`.
2072
2073 if (Sym)
2074 return State->set<RegionState>(Sym, RefState::getAllocated(Family, 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, Arg.getASTIndex(),
2094 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, Call.getArgExpr(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.
2121 SymbolRef Sym, SymbolRef &RetStatusSymbol) {
2122 const SymbolRef *Ret = State->get<FreeReturnValue>(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, *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>(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>(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>(E)) {
2171 if (Msg->isInstanceMessage())
2172 os << "-";
2173 else
2174 os << "+";
2175 Msg->getSelector().print(os);
2176 return true;
2177 }
2178
2179 if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2180 os << "'"
2181 << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
2182 << "'";
2183 return true;
2184 }
2185
2186 if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
2187 os << "'"
2188 << getOperatorSpelling(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
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(C.getSVal(ArgExpr));
2261 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2262 return nullptr;
2263 DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
2264
2265 // Check for null dereferences.
2266 if (!isa<Loc>(location))
2267 return nullptr;
2268
2269 // The explicit NULL case, no operation is performed.
2270 ProgramStateRef notNullState, nullState;
2271 std::tie(notNullState, nullState) = State->assume(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, ArgExpr->getSourceRange(), 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>(R)) {
2310 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), 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>(R))
2324 HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
2325 else
2326 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2327 Family);
2328
2329 return nullptr;
2330 }
2331
2332 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(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>(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, ArgExpr->getSourceRange());
2350 return nullptr;
2351 }
2352
2353 // Check for double free first.
2354 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2355 !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
2356 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2357 SymBase, 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, ArgExpr->getSourceRange(), ParentExpr,
2370 RsBase, SymBase, 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>(RsBase->getStmt());
2381 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2382 Family, AllocExpr);
2383 return nullptr;
2384 }
2385 }
2386 }
2387
2388 if (SymBase->getType()->isFunctionPointerType()) {
2389 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), 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>(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(ParentExpr);
2401 SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
2402 if (RetStatusSymbol) {
2403 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2404 State = State->set<FreeReturnValue>(SymBase, 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({location}, Call.getCFGElementRef(),
2418 C.blockCount(), C.getLocationContext(),
2419 /*CausesPointerEscape=*/false,
2420 /*InvalidatedSymbols=*/nullptr);
2421
2422 // Normal free.
2423 if (Hold)
2424 return State->set<RegionState>(SymBase,
2425 RefState::getRelinquished(Family,
2426 ParentExpr));
2427
2428 return State->set<RegionState>(SymBase,
2429 RefState::getReleased(Family, 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>(Sym))
2468 return MallocChecker.getAs<T>();
2469
2470 const RefState *RS = C.getState()->get<RegionState>(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>(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
2512 const VarRegion *VR = dyn_cast<VarRegion>(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
2527 const VarRegion *VR = dyn_cast<VarRegion>(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>(MS)) {
2542 const VarRegion *VR = dyn_cast<VarRegion>(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>(MR))
2582 MR = ER->getSuperRegion();
2583
2584 os << "Argument to ";
2585 if (!printMemFnName(os, C, DeallocExpr))
2586 os << "deallocator";
2587
2588 os << " is ";
2589 bool Summarized =
2590 MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, 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>(Frontend->BadFreeBug,
2599 os.str(), N);
2600 R->markInteresting(MR);
2601 R->addRange(Range);
2602 C.emitReport(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 Frontend->FreeAllocaBug,
2622 "Memory allocated by 'alloca()' should not be deallocated", N);
2623 R->markInteresting(ArgVal.getAsRegion());
2624 R->addRange(Range);
2625 C.emitReport(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>(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(DeallocOs, C, DeallocExpr))
2651 os << DeallocOs.str() << " cannot";
2652 else
2653 os << "Cannot";
2654
2655 os << " take ownership of memory";
2656
2657 if (printMemFnName(AllocOs, C, AllocExpr))
2658 os << " allocated by " << AllocOs.str();
2659 } else {
2660 os << "Memory";
2661 if (printMemFnName(AllocOs, C, AllocExpr))
2662 os << " allocated by " << AllocOs.str();
2663
2664 os << " should be deallocated by ";
2665 printExpectedDeallocName(os, RS->getAllocationFamily());
2666
2667 if (printMemFnName(DeallocOs, C, DeallocExpr))
2668 os << ", not " << DeallocOs.str();
2669
2670 printOwnershipTakesList(os, C, DeallocExpr);
2671 }
2672
2673 auto R = std::make_unique<PathSensitiveBugReport>(
2674 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2675 R->markInteresting(Sym);
2676 R->addRange(Range);
2677 R->addVisitor<MallocBugVisitor>(Sym);
2678 C.emitReport(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, DeallocExpr))
2716 os << "deallocator";
2717 os << " is offset by "
2718 << offsetBytes
2719 << " "
2720 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2721 << " from the start of ";
2722 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2723 os << "memory allocated by " << AllocNameOs.str();
2724 else
2725 os << "allocated memory";
2726
2727 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2728 os.str(), N);
2729 R->markInteresting(MR->getBaseRegion());
2730 R->addRange(Range);
2731 C.emitReport(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>(Sym)->getAllocationFamily();
2747
2748 auto R = std::make_unique<PathSensitiveBugReport>(
2749 Frontend->UseFreeBug,
2750 AF.Kind == AF_InnerBuffer
2751 ? "Inner pointer of container used after re/deallocation"
2752 : "Use of memory after it is released",
2753 N);
2754
2755 R->markInteresting(Sym);
2756 R->addRange(Range);
2757 R->addVisitor<MallocBugVisitor>(Sym);
2758
2759 if (AF.Kind == AF_InnerBuffer)
2761
2762 C.emitReport(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 Frontend->DoubleFreeBug,
2780 (Released ? "Attempt to release already released memory"
2781 : "Attempt to release non-owned memory"),
2782 N);
2783 if (Range.isValid())
2784 R->addRange(Range);
2785 R->markInteresting(Sym);
2786 if (PrevSym)
2787 R->markInteresting(PrevSym);
2788 R->addVisitor<MallocBugVisitor>(Sym);
2789 C.emitReport(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 Frontend->UseZeroAllocatedBug, "Use of memory allocated with size zero",
2807 N);
2808
2809 R->addRange(Range);
2810 if (Sym) {
2811 R->markInteresting(Sym);
2812 R->addVisitor<MallocBugVisitor>(Sym);
2813 }
2814 C.emitReport(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>(MR))
2836 MR = ER->getSuperRegion();
2837
2838 Os << "Argument to ";
2839 if (!printMemFnName(Os, C, FreeExpr))
2840 Os << "deallocator";
2841
2842 Os << " is a function pointer";
2843
2844 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2845 Os.str(), N);
2846 R->markInteresting(MR);
2847 R->addRange(Range);
2848 C.emitReport(std::move(R));
2849 }
2850}
2851
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>(Call.getOriginExpr());
2860
2861 if ((SuffixWithN && CE->getNumArgs() < 3) || CE->getNumArgs() < 2)
2862 return nullptr;
2863
2864 const Expr *arg0Expr = CE->getArg(0);
2865 SVal Arg0Val = C.getSVal(arg0Expr);
2866 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2867 return nullptr;
2868 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
2869
2870 SValBuilder &svalBuilder = C.getSValBuilder();
2871
2872 DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(
2873 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2874
2875 // Get the size argument.
2876 const Expr *Arg1 = CE->getArg(1);
2877
2878 // Get the value of the size argument.
2879 SVal TotalSize = C.getSVal(Arg1);
2880 if (SuffixWithN)
2881 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2882 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2883 return nullptr;
2884
2885 // Compare the size argument to 0.
2886 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2887 State, TotalSize.castAs<DefinedOrUnknownSVal>(),
2888 svalBuilder.makeIntValWithWidth(
2889 svalBuilder.getContext().getCanonicalSizeType(), 0));
2890
2891 ProgramStateRef StatePtrIsNull, StatePtrNotNull;
2892 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2893 ProgramStateRef StateSizeIsZero, StateSizeNotZero;
2894 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(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, TotalSize, UndefinedVal(), 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, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2924 return stateFree;
2925
2926 // Default behavior.
2927 if (ProgramStateRef stateFree =
2928 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2929
2930 ProgramStateRef stateRealloc =
2931 MallocMemAux(C, Call, TotalSize, UnknownVal(), 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(CE, C.getLocationContext());
2944 SymbolRef ToPtr = RetVal.getAsSymbol();
2945 assert(FromPtr && ToPtr &&
2946 "By this point, FreeMemAux and MallocMemAux should have checked "
2947 "whether the argument or the return value is symbolic!");
2948
2949 // Record the info about the reallocated symbol so that we could properly
2950 // process failed reallocation.
2951 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2952 ReallocPair(FromPtr, Kind));
2953 // The reallocated symbol should stay alive for as long as the new symbol.
2954 C.getSymbolManager().addSymbolDependency(ToPtr, 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(svalBuilder.getContext().CharTy);
2971 SVal TotalSize =
2972 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2973
2974 return MallocMemAux(C, Call, TotalSize, zeroVal, State,
2975 AllocationFamily(AF_Malloc));
2976}
2977
2978MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2979 SymbolRef Sym,
2980 CheckerContext &C) {
2981 const LocationContext *LeakContext = N->getLocationContext();
2982 // Walk the ExplodedGraph backwards and find the first node that referred to
2983 // the tracked symbol.
2984 const ExplodedNode *AllocNode = N;
2985 const MemRegion *ReferenceRegion = nullptr;
2986
2987 while (N) {
2988 ProgramStateRef State = N->getState();
2989 if (!State->get<RegionState>(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(MR);
2997 if (Val.getAsLocSymbol() == Sym) {
2998 const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
2999 // Do not show local variables belonging to a function other than
3000 // where the error is reported.
3001 if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
3002 ReferenceRegion = MR;
3003 }
3004 }
3005 }
3006
3007 // Allocation node, is the last node in the current or parent context in
3008 // which the symbol was tracked.
3009 const LocationContext *NContext = N->getLocationContext();
3010 if (NContext == LeakContext ||
3011 NContext->isParentOf(LeakContext))
3012 AllocNode = N;
3013 N = N->pred_empty() ? nullptr : *(N->pred_begin());
3014 }
3015
3016 return LeakInfo(AllocNode, ReferenceRegion);
3017}
3018
3019void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
3020 CheckerContext &C) const {
3021 assert(N && "HandleLeak is only called with a non-null node");
3022
3023 const RefState *RS = C.getState()->get<RegionState>(Sym);
3024 assert(RS && "cannot leak an untracked symbol");
3025 AllocationFamily Family = RS->getAllocationFamily();
3026
3027 if (Family.Kind == AF_Alloca)
3028 return;
3029
3030 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3031 // Note that for leaks we don't add a sink when the relevant frontend is
3032 // disabled because the leak is reported with a non-fatal error node, while
3033 // the sink would be the "silent" alternative of a (fatal) error node.
3034 if (!Frontend || !Frontend->isEnabled())
3035 return;
3036
3037 // Most bug reports are cached at the location where they occurred.
3038 // With leaks, we want to unique them by the location where they were
3039 // allocated, and only report a single path.
3040 PathDiagnosticLocation LocUsedForUniqueing;
3041 const ExplodedNode *AllocNode = nullptr;
3042 const MemRegion *Region = nullptr;
3043 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
3044
3045 const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
3046 if (AllocationStmt)
3047 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
3048 C.getSourceManager(),
3049 AllocNode->getLocationContext());
3050
3051 SmallString<200> buf;
3052 llvm::raw_svector_ostream os(buf);
3053 if (Region && Region->canPrintPretty()) {
3054 os << "Potential leak of memory pointed to by ";
3055 Region->printPretty(os);
3056 } else {
3057 os << "Potential memory leak";
3058 }
3059
3060 auto R = std::make_unique<PathSensitiveBugReport>(
3061 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3062 AllocNode->getLocationContext()->getDecl());
3063 R->markInteresting(Sym);
3064 R->addVisitor<MallocBugVisitor>(Sym, true);
3065 if (ShouldRegisterNoOwnershipChangeVisitor)
3066 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym, this);
3067 C.emitReport(std::move(R));
3068}
3069
3070void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3071 CheckerContext &C) const
3072{
3073 ProgramStateRef state = C.getState();
3074 RegionStateTy OldRS = state->get<RegionState>();
3075 RegionStateTy::Factory &F = state->get_context<RegionState>();
3076
3077 RegionStateTy RS = OldRS;
3078 SmallVector<SymbolRef, 2> Errors;
3079 for (auto [Sym, State] : RS) {
3080 if (SymReaper.isDead(Sym)) {
3081 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3082 Errors.push_back(Sym);
3083 // Remove the dead symbol from the map.
3084 RS = F.remove(RS, Sym);
3085 }
3086 }
3087
3088 if (RS == OldRS) {
3089 // We shouldn't have touched other maps yet.
3090 assert(state->get<ReallocPairs>() ==
3091 C.getState()->get<ReallocPairs>());
3092 assert(state->get<FreeReturnValue>() ==
3093 C.getState()->get<FreeReturnValue>());
3094 return;
3095 }
3096
3097 // Cleanup the Realloc Pairs Map.
3098 ReallocPairsTy RP = state->get<ReallocPairs>();
3099 for (auto [Sym, ReallocPair] : RP) {
3100 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {
3101 state = state->remove<ReallocPairs>(Sym);
3102 }
3103 }
3104
3105 // Cleanup the FreeReturnValue Map.
3106 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3107 for (auto [Sym, RetSym] : FR) {
3108 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {
3109 state = state->remove<FreeReturnValue>(Sym);
3110 }
3111 }
3112
3113 // Generate leak node.
3114 ExplodedNode *N = C.getPredecessor();
3115 if (!Errors.empty()) {
3116 N = C.generateNonFatalErrorNode(C.getState());
3117 if (N) {
3118 for (SymbolRef Sym : Errors) {
3119 HandleLeak(Sym, N, C);
3120 }
3121 }
3122 }
3123
3124 C.addTransition(state->set<RegionState>(RS), N);
3125}
3126
3127// Allowlist of owning smart pointers we want to recognize.
3128// Start with unique_ptr and shared_ptr; weak_ptr is excluded intentionally
3129// because it does not own the pointee.
3130static bool isSmartPtrName(StringRef Name) {
3131 return Name == "unique_ptr" || Name == "shared_ptr";
3132}
3133
3134// Check if a type is a smart owning pointer type.
3135static bool isSmartPtrType(QualType QT) {
3136 QT = QT->getCanonicalTypeUnqualified();
3137
3138 if (const auto *TST = QT->getAs<TemplateSpecializationType>()) {
3139 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3140 if (!TD)
3141 return false;
3142
3143 const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl());
3144 if (!ND)
3145 return false;
3146
3147 // For broader coverage we recognize all template classes with names that
3148 // match the allowlist even if they are not declared in namespace 'std'.
3149 return isSmartPtrName(ND->getName());
3150 }
3151
3152 return false;
3153}
3154
3155/// Helper struct for collecting smart owning pointer field regions.
3156/// This allows both hasSmartPtrField and
3157/// collectSmartPtrFieldRegions to share the same traversal logic,
3158/// ensuring consistency.
3162 llvm::SmallPtrSetImpl<const MemRegion *> *Out;
3163
3165 llvm::SmallPtrSetImpl<const MemRegion *> &Out)
3166 : Reg(Reg), C(&C), Out(&Out) {}
3167
3168 void consume(const FieldDecl *FD) {
3169 SVal L = C->getState()->getLValue(FD, loc::MemRegionVal(Reg));
3170 if (const MemRegion *FR = L.getAsRegion())
3171 Out->insert(FR);
3172 }
3173
3174 std::optional<FieldConsumer> switchToBase(const CXXRecordDecl *BaseDecl,
3175 bool IsVirtual) {
3176 // Get the base class region
3177 SVal BaseL =
3178 C->getState()->getLValue(BaseDecl, Reg->getAs<SubRegion>(), IsVirtual);
3179 if (const MemRegion *BaseObjRegion = BaseL.getAsRegion()) {
3180 // Return a consumer for the base class
3181 return FieldConsumer{BaseObjRegion, *C, *Out};
3182 }
3183 return std::nullopt;
3184 }
3185};
3186
3187/// Check if a record type has smart owning pointer fields (directly or in base
3188/// classes). When FC is provided, also collect the field regions.
3189///
3190/// This function has dual behavior:
3191/// - When FC is nullopt: Returns true if smart pointer fields are found
3192/// - When FC is provided: Always returns false, but collects field regions
3193/// as a side effect through the FieldConsumer
3194///
3195/// Note: When FC is provided, the return value should be ignored since the
3196/// function performs full traversal for collection and always returns false
3197/// to avoid early termination.
3198static bool hasSmartPtrField(const CXXRecordDecl *CRD,
3199 std::optional<FieldConsumer> FC = std::nullopt) {
3200 // Check direct fields
3201 for (const FieldDecl *FD : CRD->fields()) {
3202 if (isSmartPtrType(FD->getType())) {
3203 if (!FC)
3204 return true;
3205 FC->consume(FD);
3206 }
3207 }
3208
3209 // Check fields from base classes
3210 for (const CXXBaseSpecifier &BaseSpec : CRD->bases()) {
3211 if (const CXXRecordDecl *BaseDecl =
3212 BaseSpec.getType()->getAsCXXRecordDecl()) {
3213 std::optional<FieldConsumer> NewFC;
3214 if (FC) {
3215 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3216 if (!NewFC)
3217 continue;
3218 }
3219 bool Found = hasSmartPtrField(BaseDecl, NewFC);
3220 if (Found && !FC)
3221 return true;
3222 }
3223 }
3224 return false;
3225}
3226
3227/// Check if an expression is an rvalue record type passed by value.
3228static bool isRvalueByValueRecord(const Expr *AE) {
3229 if (AE->isGLValue())
3230 return false;
3231
3232 QualType T = AE->getType();
3233 if (!T->isRecordType() || T->isReferenceType())
3234 return false;
3235
3236 // Accept common temp/construct forms but don't overfit.
3239}
3240
3241/// Check if an expression is an rvalue record with smart owning pointer fields
3242/// passed by value.
3244 if (!isRvalueByValueRecord(AE))
3245 return false;
3246
3247 const auto *CRD = AE->getType()->getAsCXXRecordDecl();
3248 return CRD && hasSmartPtrField(CRD);
3249}
3250
3251/// Check if a CXXRecordDecl has a name matching recognized smart pointer names.
3252static bool isSmartPtrRecord(const CXXRecordDecl *RD) {
3253 if (!RD)
3254 return false;
3255
3256 // Check the record name directly and accept both std and custom smart pointer
3257 // implementations for broader coverage
3258 return isSmartPtrName(RD->getName());
3259}
3260
3261/// Check if a call is a constructor of a smart owning pointer class that
3262/// accepts pointer parameters.
3263static bool isSmartPtrCall(const CallEvent &Call) {
3264 // Only check for smart pointer constructor calls
3265 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Call.getDecl());
3266 if (!CD)
3267 return false;
3268
3269 const auto *RD = CD->getParent();
3270 if (!isSmartPtrRecord(RD))
3271 return false;
3272
3273 // Check if constructor takes a pointer parameter
3274 for (const auto *Param : CD->parameters()) {
3275 QualType ParamType = Param->getType();
3276 if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&
3277 !ParamType->isVoidPointerType()) {
3278 return true;
3279 }
3280 }
3281
3282 return false;
3283}
3284
3285/// Collect memory regions of smart owning pointer fields from a record type
3286/// (including fields from base classes).
3287static void
3290 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3291 if (!Reg)
3292 return;
3293
3294 const auto *CRD = RecQT->getAsCXXRecordDecl();
3295 if (!CRD)
3296 return;
3297
3298 FieldConsumer FC{Reg, C, Out};
3299 hasSmartPtrField(CRD, FC);
3300}
3301
3302/// Handle smart pointer constructor calls by escaping allocated symbols
3303/// that are passed as pointer arguments to the constructor.
3304ProgramStateRef MallocChecker::handleSmartPointerConstructorArguments(
3305 const CallEvent &Call, ProgramStateRef State) const {
3306 const auto *CD = cast<CXXConstructorDecl>(Call.getDecl());
3307 for (unsigned I = 0, E = std::min(Call.getNumArgs(), CD->getNumParams());
3308 I != E; ++I) {
3309 const Expr *ArgExpr = Call.getArgExpr(I);
3310 if (!ArgExpr)
3311 continue;
3312
3313 QualType ParamType = CD->getParamDecl(I)->getType();
3314 if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&
3315 !ParamType->isVoidPointerType()) {
3316 // This argument is a pointer being passed to smart pointer constructor
3317 SVal ArgVal = Call.getArgSVal(I);
3318 SymbolRef Sym = ArgVal.getAsSymbol();
3319 if (Sym && State->contains<RegionState>(Sym)) {
3320 const RefState *RS = State->get<RegionState>(Sym);
3321 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3322 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3323 }
3324 }
3325 }
3326 }
3327 return State;
3328}
3329
3330/// Handle all smart pointer related processing in function calls.
3331/// This includes both direct smart pointer constructor calls and by-value
3332/// arguments containing smart pointer fields.
3333ProgramStateRef MallocChecker::handleSmartPointerRelatedCalls(
3334 const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
3335
3336 // Handle direct smart pointer constructor calls first
3337 if (isSmartPtrCall(Call)) {
3338 return handleSmartPointerConstructorArguments(Call, State);
3339 }
3340
3341 // Handle smart pointer fields in by-value record arguments
3342 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3343 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3344 const Expr *AE = Call.getArgExpr(I);
3345 if (!AE)
3346 continue;
3347 AE = AE->IgnoreParenImpCasts();
3348
3350 continue;
3351
3352 // Find a region for the argument.
3353 SVal ArgVal = Call.getArgSVal(I);
3354 const MemRegion *ArgRegion = ArgVal.getAsRegion();
3355 // Collect direct smart owning pointer field regions
3356 collectSmartPtrFieldRegions(ArgRegion, AE->getType(), C,
3357 SmartPtrFieldRoots);
3358 }
3359
3360 // Escape symbols reachable from smart pointer fields
3361 if (!SmartPtrFieldRoots.empty()) {
3362 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3363 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3364 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3365 SmartPtrFieldRootsVec, State);
3366 }
3367
3368 return State;
3369}
3370
3371void MallocChecker::checkPostCall(const CallEvent &Call,
3372 CheckerContext &C) const {
3373 // Handle existing post-call handlers first
3374 if (const auto *PostFN = PostFnMap.lookup(Call)) {
3375 (*PostFN)(this, C.getState(), Call, C);
3376 return; // Post-handler already called addTransition, we're done
3377 }
3378
3379 // Handle smart pointer related processing only if no post-handler was called
3380 C.addTransition(handleSmartPointerRelatedCalls(Call, C, C.getState()));
3381}
3382
3383void MallocChecker::checkPreCall(const CallEvent &Call,
3384 CheckerContext &C) const {
3385
3386 if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
3387 const CXXDeleteExpr *DE = DC->getOriginExpr();
3388
3389 // FIXME: I don't see a good reason for restricting the check against
3390 // use-after-free violations to the case when NewDeleteChecker is disabled.
3391 // (However, if NewDeleteChecker is enabled, perhaps it would be better to
3392 // do this check a bit later?)
3393 if (!NewDeleteChecker.isEnabled())
3394 if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
3395 checkUseAfterFree(Sym, C, DE->getArgument());
3396
3397 if (!isStandardNewDelete(DC->getDecl()))
3398 return;
3399
3400 ProgramStateRef State = C.getState();
3401 bool IsKnownToBeAllocated;
3402 State = FreeMemAux(
3403 C, DE->getArgument(), Call, State,
3404 /*Hold*/ false, IsKnownToBeAllocated,
3405 AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3406
3407 C.addTransition(State);
3408 return;
3409 }
3410
3411 // If we see a `CXXDestructorCall` (that is, an _implicit_ destructor call)
3412 // to a region that's symbolic and known to be already freed, then it must be
3413 // implicitly triggered by a `delete` expression. In this situation we should
3414 // emit a `DoubleFree` report _now_ (before entering the call to the
3415 // destructor) because otherwise the destructor call can trigger a
3416 // use-after-free bug (by accessing any member variable) and that would be
3417 // (technically valid, but) less user-friendly report than the `DoubleFree`.
3418 if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
3419 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3420 if (!Sym)
3421 return;
3422 if (isReleased(Sym, C)) {
3423 HandleDoubleFree(C, SourceRange(), /*Released=*/true, Sym,
3424 /*PrevSym=*/nullptr);
3425 return;
3426 }
3427 }
3428
3429 // We need to handle getline pre-conditions here before the pointed region
3430 // gets invalidated by StreamChecker
3431 if (const auto *PreFN = PreFnMap.lookup(Call)) {
3432 (*PreFN)(this, C.getState(), Call, C);
3433 return;
3434 }
3435
3436 // We will check for double free in the `evalCall` callback.
3437 // FIXME: It would be more logical to emit double free and use-after-free
3438 // reports via the same pathway (because double free is essentially a specia
3439 // case of use-after-free).
3440 if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {
3441 const FunctionDecl *FD = FC->getDecl();
3442 if (!FD)
3443 return;
3444
3445 // FIXME: I suspect we should remove `MallocChecker.isEnabled() &&` because
3446 // it's fishy that the enabled/disabled state of one frontend may influence
3447 // reports produced by other frontends.
3448 if (MallocChecker.isEnabled() && isFreeingCall(Call))
3449 return;
3450 }
3451
3452 // Check if the callee of a method is deleted.
3453 if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
3454 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3455 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
3456 return;
3457 }
3458
3459 // Check arguments for being used after free.
3460 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3461 SVal ArgSVal = Call.getArgSVal(I);
3462 if (isa<Loc>(ArgSVal)) {
3463 SymbolRef Sym = ArgSVal.getAsSymbol(/*IncludeBaseRegions=*/true);
3464 if (!Sym)
3465 continue;
3466 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
3467 return;
3468 }
3469 }
3470}
3471
3472void MallocChecker::checkPreStmt(const ReturnStmt *S,
3473 CheckerContext &C) const {
3474 checkEscapeOnReturn(S, C);
3475}
3476
3477// In the CFG, automatic destructors come after the return statement.
3478// This callback checks for returning memory that is freed by automatic
3479// destructors, as those cannot be reached in checkPreStmt().
3480void MallocChecker::checkEndFunction(const ReturnStmt *S,
3481 CheckerContext &C) const {
3482 checkEscapeOnReturn(S, C);
3483}
3484
3485void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
3486 CheckerContext &C) const {
3487 if (!S)
3488 return;
3489
3490 const Expr *E = S->getRetValue();
3491 if (!E)
3492 return;
3493
3494 // Check if we are returning a symbol.
3495 ProgramStateRef State = C.getState();
3496 SVal RetVal = C.getSVal(E);
3497 SymbolRef Sym = RetVal.getAsSymbol();
3498 if (!Sym)
3499 // If we are returning a field of the allocated struct or an array element,
3500 // the callee could still free the memory.
3501 if (const MemRegion *MR = RetVal.getAsRegion())
3503 if (const SymbolicRegion *BMR =
3504 dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
3505 Sym = BMR->getSymbol();
3506
3507 // Check if we are returning freed memory.
3508 if (Sym)
3509 checkUseAfterFree(Sym, C, E);
3510}
3511
3512// TODO: Blocks should be either inlined or should call invalidate regions
3513// upon invocation. After that's in place, special casing here will not be
3514// needed.
3515void MallocChecker::checkPostStmt(const BlockExpr *BE,
3516 CheckerContext &C) const {
3517
3518 // Scan the BlockDecRefExprs for any object the retain count checker
3519 // may be tracking.
3520 if (!BE->getBlockDecl()->hasCaptures())
3521 return;
3522
3523 ProgramStateRef state = C.getState();
3524 const BlockDataRegion *R =
3525 cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
3526
3527 auto ReferencedVars = R->referenced_vars();
3528 if (ReferencedVars.empty())
3529 return;
3530
3531 SmallVector<const MemRegion*, 10> Regions;
3532 const LocationContext *LC = C.getLocationContext();
3533 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
3534
3535 for (const auto &Var : ReferencedVars) {
3536 const VarRegion *VR = Var.getCapturedRegion();
3537 if (VR->getSuperRegion() == R) {
3538 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
3539 }
3540 Regions.push_back(VR);
3541 }
3542
3543 state =
3544 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3545 C.addTransition(state);
3546}
3547
3549 assert(Sym);
3550 const RefState *RS = C.getState()->get<RegionState>(Sym);
3551 return (RS && RS->isReleased());
3552}
3553
3554bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3555 const CallEvent &Call, CheckerContext &C) const {
3556 if (Call.getNumArgs() == 0)
3557 return false;
3558
3559 StringRef FunctionStr = "";
3560 if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
3561 if (const Stmt *Body = FD->getBody())
3562 if (Body->getBeginLoc().isValid())
3563 FunctionStr =
3565 {FD->getBeginLoc(), Body->getBeginLoc()}),
3566 C.getSourceManager(), C.getLangOpts());
3567
3568 // We do not model the Integer Set Library's retain-count based allocation.
3569 if (!FunctionStr.contains("__isl_"))
3570 return false;
3571
3572 ProgramStateRef State = C.getState();
3573
3574 for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments())
3575 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3576 if (const RefState *RS = State->get<RegionState>(Sym))
3577 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3578
3579 C.addTransition(State);
3580 return true;
3581}
3582
3583bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
3584 const Stmt *S) const {
3585
3586 if (isReleased(Sym, C)) {
3587 HandleUseAfterFree(C, S->getSourceRange(), Sym);
3588 return true;
3589 }
3590
3591 return false;
3592}
3593
3594void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3595 const Stmt *S) const {
3596 assert(Sym);
3597
3598 if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {
3599 if (RS->isAllocatedOfSizeZero())
3600 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3601 }
3602 else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3603 HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
3604 }
3605}
3606
3607// Check if the location is a freed symbolic region.
3608void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3609 CheckerContext &C) const {
3610 SymbolRef Sym = l.getLocSymbolInBase();
3611 if (Sym) {
3612 checkUseAfterFree(Sym, C, S);
3613 checkUseZeroAllocated(Sym, C, S);
3614 }
3615}
3616
3617// If a symbolic region is assumed to NULL (or another constant), stop tracking
3618// it - assuming that allocation failed on this path.
3619ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
3620 SVal Cond,
3621 bool Assumption) const {
3622 RegionStateTy RS = state->get<RegionState>();
3623 for (SymbolRef Sym : llvm::make_first_range(RS)) {
3624 // If the symbol is assumed to be NULL, remove it from consideration.
3625 ConstraintManager &CMgr = state->getConstraintManager();
3626 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3627 if (AllocFailed.isConstrainedTrue())
3628 state = state->remove<RegionState>(Sym);
3629 }
3630
3631 // Realloc returns 0 when reallocation fails, which means that we should
3632 // restore the state of the pointer being reallocated.
3633 ReallocPairsTy RP = state->get<ReallocPairs>();
3634 for (auto [Sym, ReallocPair] : RP) {
3635 // If the symbol is assumed to be NULL, remove it from consideration.
3636 ConstraintManager &CMgr = state->getConstraintManager();
3637 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3638 if (!AllocFailed.isConstrainedTrue())
3639 continue;
3640
3641 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3642 if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
3643 if (RS->isReleased()) {
3644 switch (ReallocPair.Kind) {
3645 case OAR_ToBeFreedAfterFailure:
3646 state = state->set<RegionState>(ReallocSym,
3647 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3648 break;
3649 case OAR_DoNotTrackAfterFailure:
3650 state = state->remove<RegionState>(ReallocSym);
3651 break;
3652 default:
3653 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3654 }
3655 }
3656 }
3657 state = state->remove<ReallocPairs>(Sym);
3658 }
3659
3660 return state;
3661}
3662
3663bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3664 const CallEvent *Call,
3665 ProgramStateRef State,
3666 SymbolRef &EscapingSymbol) const {
3667 assert(Call);
3668 EscapingSymbol = nullptr;
3669
3670 // For now, assume that any C++ or block call can free memory.
3671 // TODO: If we want to be more optimistic here, we'll need to make sure that
3672 // regions escape to C++ containers. They seem to do that even now, but for
3673 // mysterious reasons.
3675 return true;
3676
3677 // Check Objective-C messages by selector name.
3678 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
3679 // If it's not a framework call, or if it takes a callback, assume it
3680 // can free memory.
3681 if (!Call->isInSystemHeader() || Call->argumentsMayEscape())
3682 return true;
3683
3684 // If it's a method we know about, handle it explicitly post-call.
3685 // This should happen before the "freeWhenDone" check below.
3687 return false;
3688
3689 // If there's a "freeWhenDone" parameter, but the method isn't one we know
3690 // about, we can't be sure that the object will use free() to deallocate the
3691 // memory, so we can't model it explicitly. The best we can do is use it to
3692 // decide whether the pointer escapes.
3693 if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
3694 return *FreeWhenDone;
3695
3696 // If the first selector piece ends with "NoCopy", and there is no
3697 // "freeWhenDone" parameter set to zero, we know ownership is being
3698 // transferred. Again, though, we can't be sure that the object will use
3699 // free() to deallocate the memory, so we can't model it explicitly.
3700 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3701 if (FirstSlot.ends_with("NoCopy"))
3702 return true;
3703
3704 // If the first selector starts with addPointer, insertPointer,
3705 // or replacePointer, assume we are dealing with NSPointerArray or similar.
3706 // This is similar to C++ containers (vector); we still might want to check
3707 // that the pointers get freed by following the container itself.
3708 if (FirstSlot.starts_with("addPointer") ||
3709 FirstSlot.starts_with("insertPointer") ||
3710 FirstSlot.starts_with("replacePointer") ||
3711 FirstSlot == "valueWithPointer") {
3712 return true;
3713 }
3714
3715 // We should escape receiver on call to 'init'. This is especially relevant
3716 // to the receiver, as the corresponding symbol is usually not referenced
3717 // after the call.
3718 if (Msg->getMethodFamily() == OMF_init) {
3719 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3720 return true;
3721 }
3722
3723 // Otherwise, assume that the method does not free memory.
3724 // Most framework methods do not free memory.
3725 return false;
3726 }
3727
3728 // At this point the only thing left to handle is straight function calls.
3729 const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
3730 if (!FD)
3731 return true;
3732
3733 // If it's one of the allocation functions we can reason about, we model
3734 // its behavior explicitly.
3735 if (isMemCall(*Call))
3736 return false;
3737
3738 // If it's not a system call, assume it frees memory.
3739 if (!Call->isInSystemHeader())
3740 return true;
3741
3742 // White list the system functions whose arguments escape.
3743 const IdentifierInfo *II = FD->getIdentifier();
3744 if (!II)
3745 return true;
3746 StringRef FName = II->getName();
3747
3748 // White list the 'XXXNoCopy' CoreFoundation functions.
3749 // We specifically check these before
3750 if (FName.ends_with("NoCopy")) {
3751 // Look for the deallocator argument. We know that the memory ownership
3752 // is not transferred only if the deallocator argument is
3753 // 'kCFAllocatorNull'.
3754 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3755 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3756 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3757 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3758 if (DeallocatorName == "kCFAllocatorNull")
3759 return false;
3760 }
3761 }
3762 return true;
3763 }
3764
3765 // Associating streams with malloced buffers. The pointer can escape if
3766 // 'closefn' is specified (and if that function does free memory),
3767 // but it will not if closefn is not specified.
3768 // Currently, we do not inspect the 'closefn' function (PR12101).
3769 if (FName == "funopen")
3770 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3771 return false;
3772
3773 // Do not warn on pointers passed to 'setbuf' when used with std streams,
3774 // these leaks might be intentional when setting the buffer for stdio.
3775 // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
3776 if (FName == "setbuf" || FName =="setbuffer" ||
3777 FName == "setlinebuf" || FName == "setvbuf") {
3778 if (Call->getNumArgs() >= 1) {
3779 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
3780 if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3781 if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3782 if (D->getCanonicalDecl()->getName().contains("std"))
3783 return true;
3784 }
3785 }
3786
3787 // A bunch of other functions which either take ownership of a pointer or
3788 // wrap the result up in a struct or object, meaning it can be freed later.
3789 // (See RetainCountChecker.) Not all the parameters here are invalidated,
3790 // but the Malloc checker cannot differentiate between them. The right way
3791 // of doing this would be to implement a pointer escapes callback.
3792 if (FName == "CGBitmapContextCreate" ||
3793 FName == "CGBitmapContextCreateWithData" ||
3794 FName == "CVPixelBufferCreateWithBytes" ||
3795 FName == "CVPixelBufferCreateWithPlanarBytes" ||
3796 FName == "OSAtomicEnqueue") {
3797 return true;
3798 }
3799
3800 if (FName == "postEvent" &&
3801 FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
3802 return true;
3803 }
3804
3805 if (FName == "connectImpl" &&
3806 FD->getQualifiedNameAsString() == "QObject::connectImpl") {
3807 return true;
3808 }
3809
3810 if (FName == "singleShotImpl" &&
3811 FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") {
3812 return true;
3813 }
3814
3815 // Handle cases where we know a buffer's /address/ can escape.
3816 // Note that the above checks handle some special cases where we know that
3817 // even though the address escapes, it's still our responsibility to free the
3818 // buffer.
3819 if (Call->argumentsMayEscape())
3820 return true;
3821
3822 // Otherwise, assume that the function does not free memory.
3823 // Most system calls do not free the memory.
3824 return false;
3825}
3826
3827ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
3828 const InvalidatedSymbols &Escaped,
3829 const CallEvent *Call,
3830 PointerEscapeKind Kind) const {
3831 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3832 /*IsConstPointerEscape*/ false);
3833}
3834
3835ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
3836 const InvalidatedSymbols &Escaped,
3837 const CallEvent *Call,
3838 PointerEscapeKind Kind) const {
3839 // If a const pointer escapes, it may not be freed(), but it could be deleted.
3840 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3841 /*IsConstPointerEscape*/ true);
3842}
3843
3844static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
3845 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3846 RS->getAllocationFamily().Kind == AF_CXXNew);
3847}
3848
3849ProgramStateRef MallocChecker::checkPointerEscapeAux(
3850 ProgramStateRef State, const InvalidatedSymbols &Escaped,
3851 const CallEvent *Call, PointerEscapeKind Kind,
3852 bool IsConstPointerEscape) const {
3853 // If we know that the call does not free memory, or we want to process the
3854 // call later, keep tracking the top level arguments.
3855 SymbolRef EscapingSymbol = nullptr;
3856 if (Kind == PSK_DirectEscapeOnCall &&
3857 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3858 EscapingSymbol) &&
3859 !EscapingSymbol) {
3860 return State;
3861 }
3862
3863 for (SymbolRef sym : Escaped) {
3864 if (EscapingSymbol && EscapingSymbol != sym)
3865 continue;
3866
3867 if (const RefState *RS = State->get<RegionState>(sym))
3868 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3869 if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))
3870 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3871 }
3872 return State;
3873}
3874
3875bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
3876 SVal ArgVal) const {
3877 if (!KernelZeroSizePtrValue)
3878 KernelZeroSizePtrValue =
3879 tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor());
3880
3881 const llvm::APSInt *ArgValKnown =
3882 C.getSValBuilder().getKnownValue(State, ArgVal);
3883 return ArgValKnown && *KernelZeroSizePtrValue &&
3884 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3885}
3886
3888 ProgramStateRef prevState) {
3889 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3890 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3891
3892 for (const ReallocPairsTy::value_type &Pair : prevMap) {
3893 SymbolRef sym = Pair.first;
3894 if (!currMap.lookup(sym))
3895 return sym;
3896 }
3897
3898 return nullptr;
3899}
3900
3902 if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) {
3903 StringRef N = II->getName();
3904 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3905 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3906 N.contains_insensitive("intrusive") ||
3907 N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
3908 return true;
3909 }
3910 }
3911 }
3912 return false;
3913}
3914
3915PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3916 BugReporterContext &BRC,
3917 PathSensitiveBugReport &BR) {
3918 ProgramStateRef state = N->getState();
3919 ProgramStateRef statePrev = N->getFirstPred()->getState();
3920
3921 const RefState *RSCurr = state->get<RegionState>(Sym);
3922 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3923
3924 const Stmt *S = N->getStmtForDiagnostics();
3925 // When dealing with containers, we sometimes want to give a note
3926 // even if the statement is missing.
3927 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3928 return nullptr;
3929
3930 const LocationContext *CurrentLC = N->getLocationContext();
3931
3932 // If we find an atomic fetch_add or fetch_sub within the function in which
3933 // the pointer was released (before the release), this is likely a release
3934 // point of reference-counted object (like shared pointer).
3935 //
3936 // Because we don't model atomics, and also because we don't know that the
3937 // original reference count is positive, we should not report use-after-frees
3938 // on objects deleted in such functions. This can probably be improved
3939 // through better shared pointer modeling.
3940 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3941 ReleaseFunctionLC->isParentOf(CurrentLC))) {
3942 if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
3943 // Check for manual use of atomic builtins.
3944 AtomicExpr::AtomicOp Op = AE->getOp();
3945 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3946 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3947 BR.markInvalid(getTag(), S);
3948 // After report is considered invalid there is no need to proceed
3949 // futher.
3950 return nullptr;
3951 }
3952 } else if (const auto *CE = dyn_cast<CallExpr>(S)) {
3953 // Check for `std::atomic` and such. This covers both regular method calls
3954 // and operator calls.
3955 if (const auto *MD =
3956 dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) {
3957 const CXXRecordDecl *RD = MD->getParent();
3958 // A bit wobbly with ".contains()" because it may be like
3959 // "__atomic_base" or something.
3960 if (StringRef(RD->getNameAsString()).contains("atomic")) {
3961 BR.markInvalid(getTag(), S);
3962 // After report is considered invalid there is no need to proceed
3963 // futher.
3964 return nullptr;
3965 }
3966 }
3967 }
3968 }
3969
3970 // FIXME: We will eventually need to handle non-statement-based events
3971 // (__attribute__((cleanup))).
3972
3973 // Find out if this is an interesting point and what is the kind.
3974 StringRef Msg;
3975 std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;
3976 SmallString<256> Buf;
3977 llvm::raw_svector_ostream OS(Buf);
3978
3979 if (Mode == Normal) {
3980 if (isAllocated(RSCurr, RSPrev, S)) {
3981 Msg = "Memory is allocated";
3982 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3983 Sym, "Returned allocated memory");
3984 } else if (isReleased(RSCurr, RSPrev, S)) {
3985 const auto Family = RSCurr->getAllocationFamily();
3986 switch (Family.Kind) {
3987 case AF_Alloca:
3988 case AF_Malloc:
3989 case AF_Custom:
3990 case AF_CXXNew:
3991 case AF_CXXNewArray:
3992 case AF_IfNameIndex:
3993 Msg = "Memory is released";
3994 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3995 Sym, "Returning; memory was released");
3996 break;
3997 case AF_InnerBuffer: {
3998 const MemRegion *ObjRegion =
4000 const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
4001 QualType ObjTy = TypedRegion->getValueType();
4002 OS << "Inner buffer of '" << ObjTy << "' ";
4003
4005 OS << "deallocated by call to destructor";
4006 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4007 Sym, "Returning; inner buffer was deallocated");
4008 } else {
4009 OS << "reallocated by call to '";
4010 const Stmt *S = RSCurr->getStmt();
4011 if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4012 OS << MemCallE->getMethodDecl()->getDeclName();
4013 } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4014 OS << OpCallE->getDirectCallee()->getDeclName();
4015 } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
4016 auto &CEMgr = BRC.getStateManager().getCallEventManager();
4017 CallEventRef<> Call =
4018 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
4019 if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
4020 OS << D->getDeclName();
4021 else
4022 OS << "unknown";
4023 }
4024 OS << "'";
4025 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4026 Sym, "Returning; inner buffer was reallocated");
4027 }
4028 Msg = OS.str();
4029 break;
4030 }
4031 case AF_None:
4032 assert(false && "Unhandled allocation family!");
4033 return nullptr;
4034 }
4035
4036 // Record the stack frame that is _responsible_ for this memory release
4037 // event. This will be used by the false positive suppression heuristics
4038 // that recognize the release points of reference-counted objects.
4039 //
4040 // Usually (e.g. in C) we say that the _responsible_ stack frame is the
4041 // current innermost stack frame:
4042 ReleaseFunctionLC = CurrentLC->getStackFrame();
4043 // ...but if the stack contains a destructor call, then we say that the
4044 // outermost destructor stack frame is the _responsible_ one:
4045 for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
4046 if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {
4048 // This immediately looks like a reference-counting destructor.
4049 // We're bad at guessing the original reference count of the
4050 // object, so suppress the report for now.
4051 BR.markInvalid(getTag(), DD);
4052
4053 // After report is considered invalid there is no need to proceed
4054 // futher.
4055 return nullptr;
4056 }
4057
4058 // Switch suspection to outer destructor to catch patterns like:
4059 // (note that class name is distorted to bypass
4060 // isReferenceCountingPointerDestructor() logic)
4061 //
4062 // SmartPointr::~SmartPointr() {
4063 // if (refcount.fetch_sub(1) == 1)
4064 // release_resources();
4065 // }
4066 // void SmartPointr::release_resources() {
4067 // free(buffer);
4068 // }
4069 //
4070 // This way ReleaseFunctionLC will point to outermost destructor and
4071 // it would be possible to catch wider range of FP.
4072 //
4073 // NOTE: it would be great to support smth like that in C, since
4074 // currently patterns like following won't be supressed:
4075 //
4076 // void doFree(struct Data *data) { free(data); }
4077 // void putData(struct Data *data)
4078 // {
4079 // if (refPut(data))
4080 // doFree(data);
4081 // }
4082 ReleaseFunctionLC = LC->getStackFrame();
4083 }
4084 }
4085
4086 } else if (isRelinquished(RSCurr, RSPrev, S)) {
4087 Msg = "Memory ownership is transferred";
4088 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");
4089 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4090 Mode = ReallocationFailed;
4091 Msg = "Reallocation failed";
4092 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4093 Sym, "Reallocation failed");
4094
4095 if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
4096 // Is it possible to fail two reallocs WITHOUT testing in between?
4097 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4098 "We only support one failed realloc at a time.");
4099 BR.markInteresting(sym);
4100 FailedReallocSymbol = sym;
4101 }
4102 }
4103
4104 // We are in a special mode if a reallocation failed later in the path.
4105 } else if (Mode == ReallocationFailed) {
4106 assert(FailedReallocSymbol && "No symbol to look for.");
4107
4108 // Is this is the first appearance of the reallocated symbol?
4109 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4110 // We're at the reallocation point.
4111 Msg = "Attempt to reallocate memory";
4112 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4113 Sym, "Returned reallocated memory");
4114 FailedReallocSymbol = nullptr;
4115 Mode = Normal;
4116 }
4117 }
4118
4119 if (Msg.empty()) {
4120 assert(!StackHint);
4121 return nullptr;
4122 }
4123
4124 assert(StackHint);
4125
4126 // Generate the extra diagnostic.
4127 PathDiagnosticLocation Pos;
4128 if (!S) {
4129 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4130 auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
4131 if (!PostImplCall)
4132 return nullptr;
4133 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4134 BRC.getSourceManager());
4135 } else {
4136 Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),
4137 N->getLocationContext());
4138 }
4139
4140 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
4141 BR.addCallStackHint(P, std::move(StackHint));
4142 return P;
4143}
4144
4145void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
4146 const char *NL, const char *Sep) const {
4147
4148 RegionStateTy RS = State->get<RegionState>();
4149
4150 if (!RS.isEmpty()) {
4151 Out << Sep << "MallocChecker :" << NL;
4152 for (auto [Sym, Data] : RS) {
4153 const RefState *RefS = State->get<RegionState>(Sym);
4154 AllocationFamily Family = RefS->getAllocationFamily();
4155
4156 const CheckerFrontend *Frontend =
4157 getRelevantFrontendAs<CheckerFrontend>(Family);
4158
4159 Sym->dumpToStream(Out);
4160 Out << " : ";
4161 Data.dump(Out);
4162 if (Frontend && Frontend->isEnabled())
4163 Out << " (" << Frontend->getName() << ")";
4164 Out << NL;
4165 }
4166 }
4167}
4168
4169namespace clang {
4170namespace ento {
4171namespace allocation_state {
4172
4174markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
4175 AllocationFamily Family(AF_InnerBuffer);
4176 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4177}
4178
4179} // end namespace allocation_state
4180} // end namespace ento
4181} // end namespace clang
4182
4183// Intended to be used in InnerPointerChecker to register the part of
4184// MallocChecker connected to it.
4186 Mgr.getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4187}
4188
4189void ento::registerDynamicMemoryModeling(CheckerManager &Mgr) {
4190 auto *Chk = Mgr.getChecker<MallocChecker>();
4191 // FIXME: This is a "hidden" undocumented frontend but there are public
4192 // checker options which are attached to it.
4193 CheckerNameRef DMMName = Mgr.getCurrentCheckerName();
4194 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4195 Mgr.getAnalyzerOptions().getCheckerBooleanOption(DMMName, "Optimistic");
4196 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4197 Mgr.getAnalyzerOptions().getCheckerBooleanOption(
4198 DMMName, "AddNoOwnershipChangeNotes");
4199}
4200
4201bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
4202 return true;
4203}
4204
4205#define REGISTER_CHECKER(NAME) \
4206 void ento::register##NAME(CheckerManager &Mgr) { \
4207 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4208 } \
4209 \
4210 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4211
4212// TODO: NewDelete and NewDeleteLeaks shouldn't be registered when not in C++.
4213REGISTER_CHECKER(MallocChecker)
4214REGISTER_CHECKER(NewDeleteChecker)
4215REGISTER_CHECKER(NewDeleteLeaksChecker)
4216REGISTER_CHECKER(MismatchedDeallocatorChecker)
4217REGISTER_CHECKER(TaintedAllocChecker)
#define V(N, I)
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
#define X(type, name)
Definition Value.h:97
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
Definition MachO.h:51
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
#define CASE(ID)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
#define CHECK_FN(NAME)
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define SM(sm)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:188
SourceManager & getSourceManager()
Definition ASTContext.h:801
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
CanQualType VoidPtrTy
CanQualType getCanonicalSizeType() const
CanQualType UnsignedLongTy
CanQualType CharTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:859
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
Definition Decl.h:4753
const BlockDecl * getBlockDecl() const
Definition Expr.h:6572
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Represents binding an expression to a temporary.
Definition ExprCXX.h:1494
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1612
Represents a C++ constructor within a class.
Definition DeclCXX.h:2604
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition ExprCXX.h:2620
bool isArrayForm() const
Definition ExprCXX.h:2646
Represents a C++ destructor within a class.
Definition DeclCXX.h:2869
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2255
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2349
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
base_class_range bases()
Definition DeclCXX.h:608
Represents a C++ functional cast expression that builds a temporary object.
Definition ExprCXX.h:1901
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2879
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3083
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3062
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3070
static CharSourceRange getTokenRange(SourceRange R)
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool isInStdNamespace() const
Definition DeclBase.cpp:427
bool hasAttrs() const
Definition DeclBase.h:518
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:524
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:559
SourceLocation getLocation() const
Definition DeclBase.h:439
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:830
This represents one expression.
Definition Expr.h:112
bool isGLValue() const
Definition Expr.h:287
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3078
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3073
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3157
Represents a function declaration or definition.
Definition Decl.h:1999
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2794
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3271
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2771
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
Definition Decl.h:2930
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition Decl.cpp:4071
QualType getDeclaredReturnType() const
Get the declared return type, which may differ from the actual return type if the return type is dedu...
Definition Decl.h:2859
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3191
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3789
Describes an C or C++ initializer list.
Definition Expr.h:5235
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Definition Lexer.cpp:1020
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4914
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition Decl.h:294
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:300
std::string getQualifiedNameAsString() const
Definition Decl.cpp:1680
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:316
An expression that sends a message to the given Objective-C object or class.
Definition ExprObjC.h:940
bool isConsumedExpr(Expr *E) const
Kind getKind() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
field_range fields() const
Definition Decl.h:4512
Expr * getRetValue()
Definition Stmt.h:3187
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
The base class of all kinds of template declarations (e.g., class, function, etc.).
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isVoidPointerType() const
Definition Type.cpp:712
bool isFunctionPointerType() const
Definition TypeBase.h:8647
bool isPointerType() const
Definition TypeBase.h:8580
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9159
QualType getType() const
Definition Decl.h:722
bool isStaticLocal() const
Returns true if a variable with function scope is a static local variable.
Definition Decl.h:1207
APSIntPtr getMaxValue(const llvm::APSInt &v)
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
ProgramStateManager & getStateManager() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
An immutable map from CallDescriptions to arbitrary data.
CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:584
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
Definition Checker.h:514
CheckerNameRef getName() const
Definition Checker.h:524
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
Definition SVals.h:262
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
bool hasMemorySpace(ProgramStateRef State) const
Definition MemRegion.h:148
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
Definition MemRegion.h:1416
Kind getKind() const
Definition MemRegion.h:203
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1250
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
bool hasSymbolicOffset() const
Definition MemRegion.h:83
int64_t getOffset() const
Definition MemRegion.h:85
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
bool isUnknownOrUndef() const
Definition SVals.h:109
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition SVals.cpp:103
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition SVals.cpp:67
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
Definition SVals.cpp:79
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:83
SubRegion - A region that subsets another larger region.
Definition MemRegion.h:474
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
Definition MemRegion.h:487
virtual void dumpToStream(raw_ostream &os) const
Definition SymExpr.h:81
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
Definition MemRegion.h:827
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
Definition Taint.cpp:170
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1260
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
Definition Sema.h:816
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition CallGraph.h:204
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
Expr * Cond
};
bool operator!=(CanQual< T > x, CanQual< U > y)
const FunctionProtoType * T
const char * getOperatorSpelling(OverloadedOperatorKind Operator)
Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1745
int const char * function
Definition c++config.h:31
Helper struct for collecting smart owning pointer field regions.
void consume(const FieldDecl *FD)
std::optional< FieldConsumer > switchToBase(const CXXRecordDecl *BaseDecl, bool IsVirtual)
FieldConsumer(const MemRegion *Reg, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
llvm::SmallPtrSetImpl< const MemRegion * > * Out
CheckerContext * C
const MemRegion * Reg