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