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 StackFrameContext *ReleaseFunctionLC;
989
990 bool IsLeak;
991
992public:
993 MallocBugVisitor(SymbolRef S, bool isLeak = false)
994 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
995 ReleaseFunctionLC(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.getLocationContext());
1495 State = State->BindExpr(CE, C.getLocationContext(), 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.getLocationContext());
1743
1744 assert(Arg);
1745
1746 auto DefArgVal =
1747 State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
1748
1749 if (!DefArgVal)
1750 return State;
1751
1752 // Check if the allocation size is 0.
1753 ProgramStateRef TrueState, FalseState;
1754 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1755 DefinedSVal Zero =
1756 SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
1757
1758 std::tie(TrueState, FalseState) =
1759 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
1760
1761 if (TrueState && !FalseState) {
1762 SymbolRef Sym = RetVal->getAsLocSymbol();
1763 if (!Sym)
1764 return State;
1765
1766 const RefState *RS = State->get<RegionState>(Sym);
1767 if (RS) {
1768 if (RS->isAllocated())
1769 return TrueState->set<RegionState>(
1770 Sym, RefState::getAllocatedOfSizeZero(RS));
1771 return State;
1772 }
1773 // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as
1774 // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not
1775 // tracked. Add zero-reallocated Sym to the state to catch references
1776 // to zero-allocated memory.
1777 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1778 }
1779
1780 // Assume the value is non-zero going forward.
1781 assert(FalseState);
1782 return FalseState;
1783}
1784
1786 QualType Result = T, PointeeType = T->getPointeeType();
1787 while (!PointeeType.isNull()) {
1788 Result = PointeeType;
1789 PointeeType = PointeeType->getPointeeType();
1790 }
1791 return Result;
1792}
1793
1794/// \returns true if the constructor invoked by \p NE has an argument of a
1795/// pointer/reference to a record type.
1797
1798 const CXXConstructExpr *ConstructE = NE->getConstructExpr();
1799 if (!ConstructE)
1800 return false;
1801
1802 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1803 return false;
1804
1805 const CXXConstructorDecl *CtorD = ConstructE->getConstructor();
1806
1807 // Iterate over the constructor parameters.
1808 for (const auto *CtorParam : CtorD->parameters()) {
1809
1810 QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType();
1811 if (CtorParamPointeeT.isNull())
1812 continue;
1813
1814 CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT);
1815
1816 if (CtorParamPointeeT->getAsCXXRecordDecl())
1817 return true;
1818 }
1819
1820 return false;
1821}
1822
1824MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
1825 CheckerContext &C,
1826 AllocationFamily Family) const {
1828 return nullptr;
1829
1830 const CXXNewExpr *NE = Call.getOriginExpr();
1831 const ParentMap &PM = C.getLocationContext()->getParentMap();
1832 ProgramStateRef State = C.getState();
1833
1834 // Non-trivial constructors have a chance to escape 'this', but marking all
1835 // invocations of trivial constructors as escaped would cause too great of
1836 // reduction of true positives, so let's just do that for constructors that
1837 // have an argument of a pointer-to-record type.
1839 return State;
1840
1841 // The return value from operator new is bound to a specified initialization
1842 // value (if any) and we don't want to loose this value. So we call
1843 // MallocUpdateRefState() instead of MallocMemAux() which breaks the
1844 // existing binding.
1845 SVal Target = Call.getObjectUnderConstruction();
1846 if (Call.getOriginExpr()->isArray()) {
1847 if (auto SizeEx = NE->getArraySize())
1848 checkTaintedness(C, Call, C.getSVal(*SizeEx), State,
1849 AllocationFamily(AF_CXXNewArray));
1850 }
1851
1852 State = MallocUpdateRefState(C, NE, State, Family, Target);
1853 State = ProcessZeroAllocCheck(C, Call, 0, State, Target);
1854 return State;
1855}
1856
1857void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
1858 CheckerContext &C) const {
1859 if (!C.wasInlined) {
1860 ProgramStateRef State = processNewAllocation(
1861 Call, C,
1862 AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray
1863 : AF_CXXNew));
1864 C.addTransition(State);
1865 }
1866}
1867
1869 // If the first selector piece is one of the names below, assume that the
1870 // object takes ownership of the memory, promising to eventually deallocate it
1871 // with free().
1872 // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
1873 // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
1874 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1875 return FirstSlot == "dataWithBytesNoCopy" ||
1876 FirstSlot == "initWithBytesNoCopy" ||
1877 FirstSlot == "initWithCharactersNoCopy";
1878}
1879
1880static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
1881 Selector S = Call.getSelector();
1882
1883 // FIXME: We should not rely on fully-constrained symbols being folded.
1884 for (unsigned i = 1; i < S.getNumArgs(); ++i)
1885 if (S.getNameForSlot(i) == "freeWhenDone")
1886 return !Call.getArgSVal(i).isZeroConstant();
1887
1888 return std::nullopt;
1889}
1890
1891void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
1892 CheckerContext &C) const {
1893 if (C.wasInlined)
1894 return;
1895
1897 return;
1898
1899 if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
1900 if (!*FreeWhenDone)
1901 return;
1902
1903 if (Call.hasNonZeroCallbackArg())
1904 return;
1905
1906 bool IsKnownToBeAllocatedMemory;
1907 ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(),
1908 /*Hold=*/true, IsKnownToBeAllocatedMemory,
1909 AllocationFamily(AF_Malloc),
1910 /*ReturnsNullOnFailure=*/true);
1911
1912 C.addTransition(State);
1913}
1914
1916MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
1917 const OwnershipAttr *Att,
1918 ProgramStateRef State) const {
1919 if (!State)
1920 return nullptr;
1921
1922 auto attrClassName = Att->getModule()->getName();
1923 auto Family = AllocationFamily(AF_Custom, attrClassName);
1924
1925 if (!Att->args().empty()) {
1926 return MallocMemAux(C, Call,
1927 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1928 UnknownVal(), State, Family);
1929 }
1930 return MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, Family);
1931}
1932
1933ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
1934 const CallEvent &Call,
1935 ProgramStateRef State,
1936 bool isAlloca) const {
1937 const Expr *CE = Call.getOriginExpr();
1938
1939 // We expect the allocation functions to return a pointer.
1940 if (!Loc::isLocType(CE->getType()))
1941 return nullptr;
1942
1943 unsigned Count = C.blockCount();
1944 SValBuilder &SVB = C.getSValBuilder();
1945 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1946 DefinedSVal RetVal =
1947 isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
1948 : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
1949 CE->getType(), Count);
1950 return State->BindExpr(CE, C.getLocationContext(), RetVal);
1951}
1952
1953ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1954 const CallEvent &Call,
1955 const Expr *SizeEx, SVal Init,
1956 ProgramStateRef State,
1957 AllocationFamily Family) const {
1958 if (!State)
1959 return nullptr;
1960
1961 assert(SizeEx);
1962 return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
1963}
1964
1965void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,
1966 CheckerContext &C,
1967 llvm::ArrayRef<SymbolRef> TaintedSyms,
1968 AllocationFamily Family) const {
1969 if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {
1970 auto R =
1971 std::make_unique<PathSensitiveBugReport>(TaintedAllocChecker, Msg, N);
1972 for (const auto *TaintedSym : TaintedSyms) {
1973 R->markInteresting(TaintedSym);
1974 }
1975 C.emitReport(std::move(R));
1976 }
1977}
1978
1979void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,
1980 const SVal SizeSVal, ProgramStateRef State,
1981 AllocationFamily Family) const {
1982 if (!TaintedAllocChecker.isEnabled())
1983 return;
1984 std::vector<SymbolRef> TaintedSyms =
1985 taint::getTaintedSymbols(State, SizeSVal);
1986 if (TaintedSyms.empty())
1987 return;
1988
1989 SValBuilder &SVB = C.getSValBuilder();
1990 QualType SizeTy = SVB.getContext().getSizeType();
1991 QualType CmpTy = SVB.getConditionType();
1992 // In case the symbol is tainted, we give a warning if the
1993 // size is larger than SIZE_MAX/4
1994 BasicValueFactory &BVF = SVB.getBasicValueFactory();
1995 const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);
1996 NonLoc MaxLength =
1997 SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));
1998 std::optional<NonLoc> SizeNL = SizeSVal.getAs<NonLoc>();
1999 auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)
2000 .getAs<DefinedOrUnknownSVal>();
2001 if (!Cmp)
2002 return;
2003 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);
2004 if (!StateTooLarge && StateNotTooLarge) {
2005 // We can prove that size is not too large so there is no issue.
2006 return;
2007 }
2008
2009 std::string Callee = "Memory allocation function";
2010 if (Call.getCalleeIdentifier())
2011 Callee = Call.getCalleeIdentifier()->getName().str();
2012 reportTaintBug(
2013 Callee + " is called with a tainted (potentially attacker controlled) "
2014 "value. Make sure the value is bound checked.",
2015 State, C, TaintedSyms, Family);
2016}
2017
2018ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
2019 const CallEvent &Call, SVal Size,
2020 SVal Init, ProgramStateRef State,
2021 AllocationFamily Family) const {
2022 if (!State)
2023 return nullptr;
2024
2025 const Expr *CE = Call.getOriginExpr();
2026
2027 // We expect the malloc functions to return a pointer.
2028 // Should have been already checked.
2029 assert(Loc::isLocType(CE->getType()) &&
2030 "Allocation functions must return a pointer");
2031
2032 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
2033 SVal RetVal = State->getSVal(CE, C.getLocationContext());
2034
2035 // Fill the region with the initialization value.
2036 State = State->bindDefaultInitial(RetVal, Init, LCtx);
2037
2038 // If Size is somehow undefined at this point, this line prevents a crash.
2039 if (Size.isUndef())
2040 Size = UnknownVal();
2041
2042 checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));
2043
2044 // Set the region's extent.
2045 State = setDynamicExtent(State, RetVal.getAsRegion(),
2046 Size.castAs<DefinedOrUnknownSVal>());
2047
2048 return MallocUpdateRefState(C, CE, State, Family);
2049}
2050
2052 ProgramStateRef State,
2053 AllocationFamily Family,
2054 std::optional<SVal> RetVal) {
2055 if (!State)
2056 return nullptr;
2057
2058 // Get the return value.
2059 if (!RetVal)
2060 RetVal = State->getSVal(E, C.getLocationContext());
2061
2062 // We expect the malloc functions to return a pointer.
2063 if (!RetVal->getAs<Loc>())
2064 return nullptr;
2065
2066 SymbolRef Sym = RetVal->getAsLocSymbol();
2067
2068 // NOTE: If this was an `alloca()` call, then `RetVal` holds an
2069 // `AllocaRegion`, so `Sym` will be a nullpointer because `AllocaRegion`s do
2070 // not have an associated symbol. However, this distinct region type means
2071 // that we don't need to store anything about them in `RegionState`.
2072
2073 if (Sym)
2074 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
2075
2076 return State;
2077}
2078
2079ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
2080 const CallEvent &Call,
2081 const OwnershipAttr *Att,
2082 ProgramStateRef State) const {
2083 if (!State)
2084 return nullptr;
2085
2086 auto attrClassName = Att->getModule()->getName();
2087 auto Family = AllocationFamily(AF_Custom, attrClassName);
2088
2089 bool IsKnownToBeAllocated = false;
2090
2091 for (const auto &Arg : Att->args()) {
2092 ProgramStateRef StateI =
2093 FreeMemAux(C, Call, State, Arg.getASTIndex(),
2094 Att->getOwnKind() == OwnershipAttr::Holds,
2095 IsKnownToBeAllocated, Family);
2096 if (StateI)
2097 State = StateI;
2098 }
2099 return State;
2100}
2101
2102ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
2103 const CallEvent &Call,
2104 ProgramStateRef State, unsigned Num,
2105 bool Hold, bool &IsKnownToBeAllocated,
2106 AllocationFamily Family,
2107 bool ReturnsNullOnFailure) const {
2108 if (!State)
2109 return nullptr;
2110
2111 if (Call.getNumArgs() < (Num + 1))
2112 return nullptr;
2113
2114 return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,
2115 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
2116}
2117
2118/// Checks if the previous call to free on the given symbol failed - if free
2119/// failed, returns true. Also, returns the corresponding return value symbol.
2121 SymbolRef Sym, SymbolRef &RetStatusSymbol) {
2122 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
2123 if (Ret) {
2124 assert(*Ret && "We should not store the null return symbol");
2125 ConstraintManager &CMgr = State->getConstraintManager();
2126 ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);
2127 RetStatusSymbol = *Ret;
2128 return FreeFailed.isConstrainedTrue();
2129 }
2130 return false;
2131}
2132
2133static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C,
2134 const Expr *E) {
2135 const CallExpr *CE = dyn_cast<CallExpr>(E);
2136
2137 if (!CE)
2138 return;
2139
2140 const FunctionDecl *FD = CE->getDirectCallee();
2141 if (!FD)
2142 return;
2143
2144 // Only one ownership_takes attribute is allowed.
2145 for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
2146 if (I->getOwnKind() != OwnershipAttr::Takes)
2147 continue;
2148
2149 os << ", which takes ownership of '" << I->getModule()->getName() << '\'';
2150 break;
2151 }
2152}
2153
2154static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
2155 if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
2156 // FIXME: This doesn't handle indirect calls.
2157 const FunctionDecl *FD = CE->getDirectCallee();
2158 if (!FD)
2159 return false;
2160
2161 os << '\'' << *FD;
2162
2163 if (!FD->isOverloadedOperator())
2164 os << "()";
2165
2166 os << '\'';
2167 return true;
2168 }
2169
2170 if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
2171 if (Msg->isInstanceMessage())
2172 os << "-";
2173 else
2174 os << "+";
2175 Msg->getSelector().print(os);
2176 return true;
2177 }
2178
2179 if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
2180 os << "'"
2181 << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
2182 << "'";
2183 return true;
2184 }
2185
2186 if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
2187 os << "'"
2188 << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
2189 << "'";
2190 return true;
2191 }
2192
2193 return false;
2194}
2195
2196static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
2197
2198 switch (Family.Kind) {
2199 case AF_Malloc:
2200 os << "'malloc()'";
2201 return;
2202 case AF_CXXNew:
2203 os << "'new'";
2204 return;
2205 case AF_CXXNewArray:
2206 os << "'new[]'";
2207 return;
2208 case AF_IfNameIndex:
2209 os << "'if_nameindex()'";
2210 return;
2211 case AF_InnerBuffer:
2212 os << "container-specific allocator";
2213 return;
2214 case AF_Custom:
2215 os << Family.CustomName.value();
2216 return;
2217 case AF_Alloca:
2218 case AF_None:
2219 assert(false && "not a deallocation expression");
2220 }
2221}
2222
2223static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
2224 switch (Family.Kind) {
2225 case AF_Malloc:
2226 os << "'free()'";
2227 return;
2228 case AF_CXXNew:
2229 os << "'delete'";
2230 return;
2231 case AF_CXXNewArray:
2232 os << "'delete[]'";
2233 return;
2234 case AF_IfNameIndex:
2235 os << "'if_freenameindex()'";
2236 return;
2237 case AF_InnerBuffer:
2238 os << "container-specific deallocator";
2239 return;
2240 case AF_Custom:
2241 os << "function that takes ownership of '" << Family.CustomName.value()
2242 << "\'";
2243 return;
2244 case AF_Alloca:
2245 case AF_None:
2246 assert(false && "not a deallocation expression");
2247 }
2248}
2249
2251MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
2252 const CallEvent &Call, ProgramStateRef State,
2253 bool Hold, bool &IsKnownToBeAllocated,
2254 AllocationFamily Family, bool ReturnsNullOnFailure,
2255 std::optional<SVal> ArgValOpt) const {
2256
2257 if (!State)
2258 return nullptr;
2259
2260 SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr));
2261 if (!isa<DefinedOrUnknownSVal>(ArgVal))
2262 return nullptr;
2263 DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
2264
2265 // Check for null dereferences.
2266 if (!isa<Loc>(location))
2267 return nullptr;
2268
2269 // The explicit NULL case, no operation is performed.
2270 ProgramStateRef notNullState, nullState;
2271 std::tie(notNullState, nullState) = State->assume(location);
2272 if (nullState && !notNullState)
2273 return nullptr;
2274
2275 // Unknown values could easily be okay
2276 // Undefined values are handled elsewhere
2277 if (ArgVal.isUnknownOrUndef())
2278 return nullptr;
2279
2280 const MemRegion *R = ArgVal.getAsRegion();
2281 const Expr *ParentExpr = Call.getOriginExpr();
2282
2283 // NOTE: We detected a bug, but the checker under whose name we would emit the
2284 // error could be disabled. Generally speaking, the MallocChecker family is an
2285 // integral part of the Static Analyzer, and disabling any part of it should
2286 // only be done under exceptional circumstances, such as frequent false
2287 // positives. If this is the case, we can reasonably believe that there are
2288 // serious faults in our understanding of the source code, and even if we
2289 // don't emit an warning, we should terminate further analysis with a sink
2290 // node.
2291
2292 // Nonlocs can't be freed, of course.
2293 // Non-region locations (labels and fixed addresses) also shouldn't be freed.
2294 if (!R) {
2295 // Exception:
2296 // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source
2297 // code. In that case, the ZERO_SIZE_PTR defines a special value used for a
2298 // zero-sized memory block which is allowed to be freed, despite not being a
2299 // null pointer.
2300 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))
2301 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2302 Family);
2303 return nullptr;
2304 }
2305
2306 R = R->StripCasts();
2307
2308 // Blocks might show up as heap data, but should not be free()d
2309 if (isa<BlockDataRegion>(R)) {
2310 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2311 Family);
2312 return nullptr;
2313 }
2314
2315 // Parameters, locals, statics, globals, and memory returned by
2316 // __builtin_alloca() shouldn't be freed.
2317 if (!R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {
2318 // Regions returned by malloc() are represented by SymbolicRegion objects
2319 // within HeapSpaceRegion. Of course, free() can work on memory allocated
2320 // outside the current function, so UnknownSpaceRegion is also a
2321 // possibility here.
2322
2323 if (isa<AllocaRegion>(R))
2324 HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
2325 else
2326 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2327 Family);
2328
2329 return nullptr;
2330 }
2331
2332 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
2333 // Various cases could lead to non-symbol values here.
2334 // For now, ignore them.
2335 if (!SrBase)
2336 return nullptr;
2337
2338 SymbolRef SymBase = SrBase->getSymbol();
2339 const RefState *RsBase = State->get<RegionState>(SymBase);
2340 SymbolRef PreviousRetStatusSymbol = nullptr;
2341
2342 IsKnownToBeAllocated =
2343 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
2344
2345 if (RsBase) {
2346
2347 // Memory returned by alloca() shouldn't be freed.
2348 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {
2349 HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
2350 return nullptr;
2351 }
2352
2353 // Check for double free first.
2354 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2355 !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
2356 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2357 SymBase, PreviousRetStatusSymbol);
2358 return nullptr;
2359 }
2360
2361 // If the pointer is allocated or escaped, but we are now trying to free it,
2362 // check that the call to free is proper.
2363 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2364 RsBase->isEscaped()) {
2365
2366 // Check if an expected deallocation function matches the real one.
2367 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2368 if (!DeallocMatchesAlloc) {
2369 HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,
2370 RsBase, SymBase, Hold);
2371 return nullptr;
2372 }
2373
2374 // Check if the memory location being freed is the actual location
2375 // allocated, or an offset.
2376 RegionOffset Offset = R->getAsOffset();
2377 if (Offset.isValid() &&
2378 !Offset.hasSymbolicOffset() &&
2379 Offset.getOffset() != 0) {
2380 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2381 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2382 Family, AllocExpr);
2383 return nullptr;
2384 }
2385 }
2386 }
2387
2388 if (SymBase->getType()->isFunctionPointerType()) {
2389 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2390 Family);
2391 return nullptr;
2392 }
2393
2394 // Clean out the info on previous call to free return info.
2395 State = State->remove<FreeReturnValue>(SymBase);
2396
2397 // Keep track of the return value. If it is NULL, we will know that free
2398 // failed.
2399 if (ReturnsNullOnFailure) {
2400 SVal RetVal = C.getSVal(ParentExpr);
2401 SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
2402 if (RetStatusSymbol) {
2403 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2404 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2405 }
2406 }
2407
2408 // If we don't know anything about this symbol, a free on it may be totally
2409 // valid. If this is the case, lets assume that the allocation family of the
2410 // freeing function is the same as the symbols allocation family, and go with
2411 // that.
2412 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2413
2414 // Assume that after memory is freed, it contains unknown values. This
2415 // conforts languages standards, since reading from freed memory is considered
2416 // UB and may result in arbitrary value.
2417 State = State->invalidateRegions({location}, Call.getCFGElementRef(),
2418 C.blockCount(), C.getLocationContext(),
2419 /*CausesPointerEscape=*/false,
2420 /*InvalidatedSymbols=*/nullptr);
2421
2422 // Normal free.
2423 if (Hold)
2424 return State->set<RegionState>(SymBase,
2425 RefState::getRelinquished(Family,
2426 ParentExpr));
2427
2428 return State->set<RegionState>(SymBase,
2429 RefState::getReleased(Family, ParentExpr));
2430}
2431
2432template <class T>
2433const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family) const {
2434 switch (Family.Kind) {
2435 case AF_Malloc:
2436 case AF_Alloca:
2437 case AF_Custom:
2438 case AF_IfNameIndex:
2439 return MallocChecker.getAs<T>();
2440 case AF_CXXNew:
2441 case AF_CXXNewArray: {
2442 const T *ND = NewDeleteChecker.getAs<T>();
2443 const T *NDL = NewDeleteLeaksChecker.getAs<T>();
2444 // Bugs corresponding to C++ new/delete allocations are split between these
2445 // two frontends.
2446 if constexpr (std::is_same_v<T, CheckerFrontend>) {
2447 assert(ND && NDL && "Casting to CheckerFrontend always succeeds");
2448 // Prefer NewDelete unless it's disabled and NewDeleteLeaks is enabled.
2449 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;
2450 }
2451 assert(!(ND && NDL) &&
2452 "NewDelete and NewDeleteLeaks must not share a bug type");
2453 return ND ? ND : NDL;
2454 }
2455 case AF_InnerBuffer:
2456 return InnerPointerChecker.getAs<T>();
2457 case AF_None:
2458 assert(false && "no family");
2459 return nullptr;
2460 }
2461 assert(false && "unhandled family");
2462 return nullptr;
2463}
2464template <class T>
2465const T *MallocChecker::getRelevantFrontendAs(CheckerContext &C,
2466 SymbolRef Sym) const {
2467 if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2468 return MallocChecker.getAs<T>();
2469
2470 const RefState *RS = C.getState()->get<RegionState>(Sym);
2471 assert(RS);
2472 return getRelevantFrontendAs<T>(RS->getAllocationFamily());
2473}
2474
2475bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
2476 if (std::optional<nonloc::ConcreteInt> IntVal =
2477 V.getAs<nonloc::ConcreteInt>())
2478 os << "an integer (" << IntVal->getValue() << ")";
2479 else if (std::optional<loc::ConcreteInt> ConstAddr =
2480 V.getAs<loc::ConcreteInt>())
2481 os << "a constant address (" << ConstAddr->getValue() << ")";
2482 else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
2483 os << "the address of the label '" << Label->getLabel()->getName() << "'";
2484 else
2485 return false;
2486
2487 return true;
2488}
2489
2490bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,
2491 const MemRegion *MR) {
2492 switch (MR->getKind()) {
2493 case MemRegion::FunctionCodeRegionKind: {
2494 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2495 if (FD)
2496 os << "the address of the function '" << *FD << '\'';
2497 else
2498 os << "the address of a function";
2499 return true;
2500 }
2501 case MemRegion::BlockCodeRegionKind:
2502 os << "block text";
2503 return true;
2504 case MemRegion::BlockDataRegionKind:
2505 // FIXME: where the block came from?
2506 os << "a block";
2507 return true;
2508 default: {
2509 const MemSpaceRegion *MS = MR->getMemorySpace(State);
2510
2512 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2513 const VarDecl *VD;
2514 if (VR)
2515 VD = VR->getDecl();
2516 else
2517 VD = nullptr;
2518
2519 if (VD)
2520 os << "the address of the local variable '" << VD->getName() << "'";
2521 else
2522 os << "the address of a local stack variable";
2523 return true;
2524 }
2525
2527 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2528 const VarDecl *VD;
2529 if (VR)
2530 VD = VR->getDecl();
2531 else
2532 VD = nullptr;
2533
2534 if (VD)
2535 os << "the address of the parameter '" << VD->getName() << "'";
2536 else
2537 os << "the address of a parameter";
2538 return true;
2539 }
2540
2541 if (isa<GlobalsSpaceRegion>(MS)) {
2542 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2543 const VarDecl *VD;
2544 if (VR)
2545 VD = VR->getDecl();
2546 else
2547 VD = nullptr;
2548
2549 if (VD) {
2550 if (VD->isStaticLocal())
2551 os << "the address of the static variable '" << VD->getName() << "'";
2552 else
2553 os << "the address of the global variable '" << VD->getName() << "'";
2554 } else
2555 os << "the address of a global variable";
2556 return true;
2557 }
2558
2559 return false;
2560 }
2561 }
2562}
2563
2564void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
2565 SourceRange Range,
2566 const Expr *DeallocExpr,
2567 AllocationFamily Family) const {
2568 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2569 if (!Frontend)
2570 return;
2571 if (!Frontend->isEnabled()) {
2572 C.addSink();
2573 return;
2574 }
2575
2576 if (ExplodedNode *N = C.generateErrorNode()) {
2577 SmallString<100> buf;
2578 llvm::raw_svector_ostream os(buf);
2579
2580 const MemRegion *MR = ArgVal.getAsRegion();
2581 while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2582 MR = ER->getSuperRegion();
2583
2584 os << "Argument to ";
2585 if (!printMemFnName(os, C, DeallocExpr))
2586 os << "deallocator";
2587
2588 os << " is ";
2589 bool Summarized =
2590 MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);
2591 if (Summarized)
2592 os << ", which is not memory allocated by ";
2593 else
2594 os << "not memory allocated by ";
2595
2596 printExpectedAllocName(os, Family);
2597
2598 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2599 os.str(), N);
2600 R->markInteresting(MR);
2601 R->addRange(Range);
2602 C.emitReport(std::move(R));
2603 }
2604}
2605
2606void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
2607 SourceRange Range) const {
2608 const FreeAlloca *Frontend;
2609
2610 if (MallocChecker.isEnabled())
2611 Frontend = &MallocChecker;
2612 else if (MismatchedDeallocatorChecker.isEnabled())
2613 Frontend = &MismatchedDeallocatorChecker;
2614 else {
2615 C.addSink();
2616 return;
2617 }
2618
2619 if (ExplodedNode *N = C.generateErrorNode()) {
2620 auto R = std::make_unique<PathSensitiveBugReport>(
2621 Frontend->FreeAllocaBug,
2622 "Memory allocated by 'alloca()' should not be deallocated", N);
2623 R->markInteresting(ArgVal.getAsRegion());
2624 R->addRange(Range);
2625 C.emitReport(std::move(R));
2626 }
2627}
2628
2629void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2630 SourceRange Range,
2631 const Expr *DeallocExpr,
2632 const RefState *RS, SymbolRef Sym,
2633 bool OwnershipTransferred) const {
2634 if (!MismatchedDeallocatorChecker.isEnabled()) {
2635 C.addSink();
2636 return;
2637 }
2638
2639 if (ExplodedNode *N = C.generateErrorNode()) {
2640 SmallString<100> buf;
2641 llvm::raw_svector_ostream os(buf);
2642
2643 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2644 SmallString<20> AllocBuf;
2645 llvm::raw_svector_ostream AllocOs(AllocBuf);
2646 SmallString<20> DeallocBuf;
2647 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2648
2649 if (OwnershipTransferred) {
2650 if (printMemFnName(DeallocOs, C, DeallocExpr))
2651 os << DeallocOs.str() << " cannot";
2652 else
2653 os << "Cannot";
2654
2655 os << " take ownership of memory";
2656
2657 if (printMemFnName(AllocOs, C, AllocExpr))
2658 os << " allocated by " << AllocOs.str();
2659 } else {
2660 os << "Memory";
2661 if (printMemFnName(AllocOs, C, AllocExpr))
2662 os << " allocated by " << AllocOs.str();
2663
2664 os << " should be deallocated by ";
2665 printExpectedDeallocName(os, RS->getAllocationFamily());
2666
2667 if (printMemFnName(DeallocOs, C, DeallocExpr))
2668 os << ", not " << DeallocOs.str();
2669
2670 printOwnershipTakesList(os, C, DeallocExpr);
2671 }
2672
2673 auto R = std::make_unique<PathSensitiveBugReport>(
2674 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);
2675 R->markInteresting(Sym);
2676 R->addRange(Range);
2677 R->addVisitor<MallocBugVisitor>(Sym);
2678 C.emitReport(std::move(R));
2679 }
2680}
2681
2682void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
2683 SourceRange Range, const Expr *DeallocExpr,
2684 AllocationFamily Family,
2685 const Expr *AllocExpr) const {
2686 const OffsetFree *Frontend = getRelevantFrontendAs<OffsetFree>(Family);
2687 if (!Frontend)
2688 return;
2689 if (!Frontend->isEnabled()) {
2690 C.addSink();
2691 return;
2692 }
2693
2694 ExplodedNode *N = C.generateErrorNode();
2695 if (!N)
2696 return;
2697
2698 SmallString<100> buf;
2699 llvm::raw_svector_ostream os(buf);
2700 SmallString<20> AllocNameBuf;
2701 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2702
2703 const MemRegion *MR = ArgVal.getAsRegion();
2704 assert(MR && "Only MemRegion based symbols can have offset free errors");
2705
2706 RegionOffset Offset = MR->getAsOffset();
2707 assert((Offset.isValid() &&
2708 !Offset.hasSymbolicOffset() &&
2709 Offset.getOffset() != 0) &&
2710 "Only symbols with a valid offset can have offset free errors");
2711
2712 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
2713
2714 os << "Argument to ";
2715 if (!printMemFnName(os, C, DeallocExpr))
2716 os << "deallocator";
2717 os << " is offset by "
2718 << offsetBytes
2719 << " "
2720 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2721 << " from the start of ";
2722 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2723 os << "memory allocated by " << AllocNameOs.str();
2724 else
2725 os << "allocated memory";
2726
2727 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->OffsetFreeBug,
2728 os.str(), N);
2729 R->markInteresting(MR->getBaseRegion());
2730 R->addRange(Range);
2731 C.emitReport(std::move(R));
2732}
2733
2734void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
2735 SymbolRef Sym) const {
2736 const UseFree *Frontend = getRelevantFrontendAs<UseFree>(C, Sym);
2737 if (!Frontend)
2738 return;
2739 if (!Frontend->isEnabled()) {
2740 C.addSink();
2741 return;
2742 }
2743
2744 if (ExplodedNode *N = C.generateErrorNode()) {
2745 AllocationFamily AF =
2746 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2747
2748 auto R = std::make_unique<PathSensitiveBugReport>(
2749 Frontend->UseFreeBug,
2750 AF.Kind == AF_InnerBuffer
2751 ? "Inner pointer of container used after re/deallocation"
2752 : "Use of memory after it is released",
2753 N);
2754
2755 R->markInteresting(Sym);
2756 R->addRange(Range);
2757 R->addVisitor<MallocBugVisitor>(Sym);
2758
2759 if (AF.Kind == AF_InnerBuffer)
2761
2762 C.emitReport(std::move(R));
2763 }
2764}
2765
2766void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2767 bool Released, SymbolRef Sym,
2768 SymbolRef PrevSym) const {
2769 const DoubleFree *Frontend = getRelevantFrontendAs<DoubleFree>(C, Sym);
2770 if (!Frontend)
2771 return;
2772 if (!Frontend->isEnabled()) {
2773 C.addSink();
2774 return;
2775 }
2776
2777 if (ExplodedNode *N = C.generateErrorNode()) {
2778 auto R = std::make_unique<PathSensitiveBugReport>(
2779 Frontend->DoubleFreeBug,
2780 (Released ? "Attempt to release already released memory"
2781 : "Attempt to release non-owned memory"),
2782 N);
2783 if (Range.isValid())
2784 R->addRange(Range);
2785 R->markInteresting(Sym);
2786 if (PrevSym)
2787 R->markInteresting(PrevSym);
2788 R->addVisitor<MallocBugVisitor>(Sym);
2789 C.emitReport(std::move(R));
2790 }
2791}
2792
2793void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
2794 SymbolRef Sym) const {
2795 const UseZeroAllocated *Frontend =
2796 getRelevantFrontendAs<UseZeroAllocated>(C, Sym);
2797 if (!Frontend)
2798 return;
2799 if (!Frontend->isEnabled()) {
2800 C.addSink();
2801 return;
2802 }
2803
2804 if (ExplodedNode *N = C.generateErrorNode()) {
2805 auto R = std::make_unique<PathSensitiveBugReport>(
2806 Frontend->UseZeroAllocatedBug, "Use of memory allocated with size zero",
2807 N);
2808
2809 R->addRange(Range);
2810 if (Sym) {
2811 R->markInteresting(Sym);
2812 R->addVisitor<MallocBugVisitor>(Sym);
2813 }
2814 C.emitReport(std::move(R));
2815 }
2816}
2817
2818void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
2819 SourceRange Range,
2820 const Expr *FreeExpr,
2821 AllocationFamily Family) const {
2822 const BadFree *Frontend = getRelevantFrontendAs<BadFree>(Family);
2823 if (!Frontend)
2824 return;
2825 if (!Frontend->isEnabled()) {
2826 C.addSink();
2827 return;
2828 }
2829
2830 if (ExplodedNode *N = C.generateErrorNode()) {
2831 SmallString<100> Buf;
2832 llvm::raw_svector_ostream Os(Buf);
2833
2834 const MemRegion *MR = ArgVal.getAsRegion();
2835 while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2836 MR = ER->getSuperRegion();
2837
2838 Os << "Argument to ";
2839 if (!printMemFnName(Os, C, FreeExpr))
2840 Os << "deallocator";
2841
2842 Os << " is a function pointer";
2843
2844 auto R = std::make_unique<PathSensitiveBugReport>(Frontend->BadFreeBug,
2845 Os.str(), N);
2846 R->markInteresting(MR);
2847 R->addRange(Range);
2848 C.emitReport(std::move(R));
2849 }
2850}
2851
2853MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
2854 bool ShouldFreeOnFail, ProgramStateRef State,
2855 AllocationFamily Family, bool SuffixWithN) const {
2856 if (!State)
2857 return nullptr;
2858
2859 const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
2860
2861 if ((SuffixWithN && CE->getNumArgs() < 3) || CE->getNumArgs() < 2)
2862 return nullptr;
2863
2864 const Expr *arg0Expr = CE->getArg(0);
2865 SVal Arg0Val = C.getSVal(arg0Expr);
2866 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2867 return nullptr;
2868 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
2869
2870 SValBuilder &svalBuilder = C.getSValBuilder();
2871
2872 DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(
2873 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2874
2875 // Get the size argument.
2876 const Expr *Arg1 = CE->getArg(1);
2877
2878 // Get the value of the size argument.
2879 SVal TotalSize = C.getSVal(Arg1);
2880 if (SuffixWithN)
2881 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2882 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2883 return nullptr;
2884
2885 // Compare the size argument to 0.
2886 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(
2887 State, TotalSize.castAs<DefinedOrUnknownSVal>(),
2888 svalBuilder.makeIntValWithWidth(
2889 svalBuilder.getContext().getCanonicalSizeType(), 0));
2890
2891 ProgramStateRef StatePtrIsNull, StatePtrNotNull;
2892 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2893 ProgramStateRef StateSizeIsZero, StateSizeNotZero;
2894 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2895 // We only assume exceptional states if they are definitely true; if the
2896 // state is under-constrained, assume regular realloc behavior.
2897 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2898 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2899
2900 // If the ptr is NULL and the size is not 0, the call is equivalent to
2901 // malloc(size).
2902 if (PrtIsNull && !SizeIsZero) {
2903 ProgramStateRef stateMalloc = MallocMemAux(
2904 C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2905 return stateMalloc;
2906 }
2907
2908 // Proccess as allocation of 0 bytes.
2909 if (PrtIsNull && SizeIsZero)
2910 return State;
2911
2912 assert(!PrtIsNull);
2913
2914 bool IsKnownToBeAllocated = false;
2915
2916 // If the size is 0, free the memory.
2917 if (SizeIsZero)
2918 // The semantics of the return value are:
2919 // If size was equal to 0, either NULL or a pointer suitable to be passed
2920 // to free() is returned. We just free the input pointer and do not add
2921 // any constrains on the output pointer.
2922 if (ProgramStateRef stateFree = FreeMemAux(
2923 C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2924 return stateFree;
2925
2926 // Default behavior.
2927 if (ProgramStateRef stateFree =
2928 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2929
2930 ProgramStateRef stateRealloc =
2931 MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);
2932 if (!stateRealloc)
2933 return nullptr;
2934
2935 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
2936 if (ShouldFreeOnFail)
2937 Kind = OAR_FreeOnFailure;
2938 else if (!IsKnownToBeAllocated)
2939 Kind = OAR_DoNotTrackAfterFailure;
2940
2941 // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
2942 SymbolRef FromPtr = arg0Val.getLocSymbolInBase();
2943 SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());
2944 SymbolRef ToPtr = RetVal.getAsSymbol();
2945 assert(FromPtr && ToPtr &&
2946 "By this point, FreeMemAux and MallocMemAux should have checked "
2947 "whether the argument or the return value is symbolic!");
2948
2949 // Record the info about the reallocated symbol so that we could properly
2950 // process failed reallocation.
2951 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2952 ReallocPair(FromPtr, Kind));
2953 // The reallocated symbol should stay alive for as long as the new symbol.
2954 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2955 return stateRealloc;
2956 }
2957 return nullptr;
2958}
2959
2960ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
2961 const CallEvent &Call,
2962 ProgramStateRef State) const {
2963 if (!State)
2964 return nullptr;
2965
2966 if (Call.getNumArgs() < 2)
2967 return nullptr;
2968
2969 SValBuilder &svalBuilder = C.getSValBuilder();
2970 SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
2971 SVal TotalSize =
2972 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2973
2974 return MallocMemAux(C, Call, TotalSize, zeroVal, State,
2975 AllocationFamily(AF_Malloc));
2976}
2977
2978MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2979 SymbolRef Sym,
2980 CheckerContext &C) {
2981 const LocationContext *LeakContext = N->getLocationContext();
2982 // Walk the ExplodedGraph backwards and find the first node that referred to
2983 // the tracked symbol.
2984 const ExplodedNode *AllocNode = N;
2985 const MemRegion *ReferenceRegion = nullptr;
2986
2987 while (N) {
2988 ProgramStateRef State = N->getState();
2989 if (!State->get<RegionState>(Sym))
2990 break;
2991
2992 // Find the most recent expression bound to the symbol in the current
2993 // context.
2994 if (!ReferenceRegion) {
2995 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
2996 SVal Val = State->getSVal(MR);
2997 if (Val.getAsLocSymbol() == Sym) {
2998 const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
2999 // Do not show local variables belonging to a function other than
3000 // where the error is reported.
3001 if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
3002 ReferenceRegion = MR;
3003 }
3004 }
3005 }
3006
3007 // Allocation node, is the last node in the current or parent context in
3008 // which the symbol was tracked.
3009 const LocationContext *NContext = N->getLocationContext();
3010 if (NContext == LeakContext ||
3011 NContext->isParentOf(LeakContext))
3012 AllocNode = N;
3013 N = N->pred_empty() ? nullptr : *(N->pred_begin());
3014 }
3015
3016 return LeakInfo(AllocNode, ReferenceRegion);
3017}
3018
3019void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
3020 CheckerContext &C) const {
3021 assert(N && "HandleLeak is only called with a non-null node");
3022
3023 const RefState *RS = C.getState()->get<RegionState>(Sym);
3024 assert(RS && "cannot leak an untracked symbol");
3025 AllocationFamily Family = RS->getAllocationFamily();
3026
3027 if (Family.Kind == AF_Alloca)
3028 return;
3029
3030 const Leak *Frontend = getRelevantFrontendAs<Leak>(Family);
3031 // Note that for leaks we don't add a sink when the relevant frontend is
3032 // disabled because the leak is reported with a non-fatal error node, while
3033 // the sink would be the "silent" alternative of a (fatal) error node.
3034 if (!Frontend || !Frontend->isEnabled())
3035 return;
3036
3037 // Most bug reports are cached at the location where they occurred.
3038 // With leaks, we want to unique them by the location where they were
3039 // allocated, and only report a single path.
3040 PathDiagnosticLocation LocUsedForUniqueing;
3041 const ExplodedNode *AllocNode = nullptr;
3042 const MemRegion *Region = nullptr;
3043 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
3044
3045 const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
3046 if (AllocationStmt)
3047 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
3048 C.getSourceManager(),
3049 AllocNode->getLocationContext());
3050
3051 SmallString<200> buf;
3052 llvm::raw_svector_ostream os(buf);
3053 if (Region && Region->canPrintPretty()) {
3054 os << "Potential leak of memory pointed to by ";
3055 Region->printPretty(os);
3056 } else {
3057 os << "Potential memory leak";
3058 }
3059
3060 auto R = std::make_unique<PathSensitiveBugReport>(
3061 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,
3062 AllocNode->getLocationContext()->getDecl());
3063 R->markInteresting(Sym);
3064 R->addVisitor<MallocBugVisitor>(Sym, true);
3065 if (ShouldRegisterNoOwnershipChangeVisitor)
3066 R->addVisitor<NoMemOwnershipChangeVisitor>(Sym, this);
3067 C.emitReport(std::move(R));
3068}
3069
3070void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
3071 CheckerContext &C) const
3072{
3073 ProgramStateRef state = C.getState();
3074 RegionStateTy OldRS = state->get<RegionState>();
3075 RegionStateTy::Factory &F = state->get_context<RegionState>();
3076
3077 RegionStateTy RS = OldRS;
3078 SmallVector<SymbolRef, 2> Errors;
3079 for (auto [Sym, State] : RS) {
3080 if (SymReaper.isDead(Sym)) {
3081 if (State.isAllocated() || State.isAllocatedOfSizeZero())
3082 Errors.push_back(Sym);
3083 // Remove the dead symbol from the map.
3084 RS = F.remove(RS, Sym);
3085 }
3086 }
3087
3088 if (RS == OldRS) {
3089 // We shouldn't have touched other maps yet.
3090 assert(state->get<ReallocPairs>() ==
3091 C.getState()->get<ReallocPairs>());
3092 assert(state->get<FreeReturnValue>() ==
3093 C.getState()->get<FreeReturnValue>());
3094 return;
3095 }
3096
3097 // Cleanup the Realloc Pairs Map.
3098 ReallocPairsTy RP = state->get<ReallocPairs>();
3099 for (auto [Sym, ReallocPair] : RP) {
3100 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {
3101 state = state->remove<ReallocPairs>(Sym);
3102 }
3103 }
3104
3105 // Cleanup the FreeReturnValue Map.
3106 FreeReturnValueTy FR = state->get<FreeReturnValue>();
3107 for (auto [Sym, RetSym] : FR) {
3108 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {
3109 state = state->remove<FreeReturnValue>(Sym);
3110 }
3111 }
3112
3113 // Generate leak node.
3114 ExplodedNode *N = C.getPredecessor();
3115 if (!Errors.empty()) {
3116 N = C.generateNonFatalErrorNode(C.getState());
3117 if (N) {
3118 for (SymbolRef Sym : Errors) {
3119 HandleLeak(Sym, N, C);
3120 }
3121 }
3122 }
3123
3124 C.addTransition(state->set<RegionState>(RS), N);
3125}
3126
3127// Allowlist of owning smart pointers we want to recognize.
3128// Start with unique_ptr and shared_ptr; weak_ptr is excluded intentionally
3129// because it does not own the pointee.
3130static bool isSmartPtrName(StringRef Name) {
3131 return Name == "unique_ptr" || Name == "shared_ptr";
3132}
3133
3134// Check if a type is a smart owning pointer type.
3135static bool isSmartPtrType(QualType QT) {
3136 QT = QT->getCanonicalTypeUnqualified();
3137
3138 if (const auto *TST = QT->getAs<TemplateSpecializationType>()) {
3139 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
3140 if (!TD)
3141 return false;
3142
3143 const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl());
3144 if (!ND)
3145 return false;
3146
3147 // For broader coverage we recognize all template classes with names that
3148 // match the allowlist even if they are not declared in namespace 'std'.
3149 return isSmartPtrName(ND->getName());
3150 }
3151
3152 return false;
3153}
3154
3155/// Helper struct for collecting smart owning pointer field regions.
3156/// This allows both hasSmartPtrField and
3157/// collectSmartPtrFieldRegions to share the same traversal logic,
3158/// ensuring consistency.
3162 llvm::SmallPtrSetImpl<const MemRegion *> *Out;
3163
3165 llvm::SmallPtrSetImpl<const MemRegion *> &Out)
3166 : Reg(Reg), C(&C), Out(&Out) {}
3167
3168 void consume(const FieldDecl *FD) {
3169 SVal L = C->getState()->getLValue(FD, loc::MemRegionVal(Reg));
3170 if (const MemRegion *FR = L.getAsRegion())
3171 Out->insert(FR);
3172 }
3173
3174 std::optional<FieldConsumer> switchToBase(const CXXRecordDecl *BaseDecl,
3175 bool IsVirtual) {
3176 // Get the base class region
3177 SVal BaseL =
3178 C->getState()->getLValue(BaseDecl, Reg->getAs<SubRegion>(), IsVirtual);
3179 if (const MemRegion *BaseObjRegion = BaseL.getAsRegion()) {
3180 // Return a consumer for the base class
3181 return FieldConsumer{BaseObjRegion, *C, *Out};
3182 }
3183 return std::nullopt;
3184 }
3185};
3186
3187/// Check if a record type has smart owning pointer fields (directly or in base
3188/// classes). When FC is provided, also collect the field regions.
3189///
3190/// This function has dual behavior:
3191/// - When FC is nullopt: Returns true if smart pointer fields are found
3192/// - When FC is provided: Always returns false, but collects field regions
3193/// as a side effect through the FieldConsumer
3194///
3195/// Note: When FC is provided, the return value should be ignored since the
3196/// function performs full traversal for collection and always returns false
3197/// to avoid early termination.
3198static bool hasSmartPtrField(const CXXRecordDecl *CRD,
3199 std::optional<FieldConsumer> FC = std::nullopt) {
3200 // Check direct fields
3201 for (const FieldDecl *FD : CRD->fields()) {
3202 if (isSmartPtrType(FD->getType())) {
3203 if (!FC)
3204 return true;
3205 FC->consume(FD);
3206 }
3207 }
3208
3209 // Check fields from base classes
3210 for (const CXXBaseSpecifier &BaseSpec : CRD->bases()) {
3211 if (const CXXRecordDecl *BaseDecl =
3212 BaseSpec.getType()->getAsCXXRecordDecl()) {
3213 std::optional<FieldConsumer> NewFC;
3214 if (FC) {
3215 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());
3216 if (!NewFC)
3217 continue;
3218 }
3219 bool Found = hasSmartPtrField(BaseDecl, NewFC);
3220 if (Found && !FC)
3221 return true;
3222 }
3223 }
3224 return false;
3225}
3226
3227/// Check if an expression is an rvalue record type passed by value.
3228static bool isRvalueByValueRecord(const Expr *AE) {
3229 if (AE->isGLValue())
3230 return false;
3231
3232 QualType T = AE->getType();
3233 if (!T->isRecordType() || T->isReferenceType())
3234 return false;
3235
3236 // Accept common temp/construct forms but don't overfit.
3239}
3240
3241/// Check if an expression is an rvalue record with smart owning pointer fields
3242/// passed by value.
3244 if (!isRvalueByValueRecord(AE))
3245 return false;
3246
3247 const auto *CRD = AE->getType()->getAsCXXRecordDecl();
3248 return CRD && hasSmartPtrField(CRD);
3249}
3250
3251/// Check if a CXXRecordDecl has a name matching recognized smart pointer names.
3252static bool isSmartPtrRecord(const CXXRecordDecl *RD) {
3253 if (!RD)
3254 return false;
3255
3256 // Check the record name directly and accept both std and custom smart pointer
3257 // implementations for broader coverage
3258 return isSmartPtrName(RD->getName());
3259}
3260
3261/// Check if a call is a constructor of a smart owning pointer class that
3262/// accepts pointer parameters.
3263static bool isSmartPtrCall(const CallEvent &Call) {
3264 // Only check for smart pointer constructor calls
3265 const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Call.getDecl());
3266 if (!CD)
3267 return false;
3268
3269 const auto *RD = CD->getParent();
3270 if (!isSmartPtrRecord(RD))
3271 return false;
3272
3273 // Check if constructor takes a pointer parameter
3274 for (const auto *Param : CD->parameters()) {
3275 QualType ParamType = Param->getType();
3276 if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&
3277 !ParamType->isVoidPointerType()) {
3278 return true;
3279 }
3280 }
3281
3282 return false;
3283}
3284
3285/// Collect memory regions of smart owning pointer fields from a record type
3286/// (including fields from base classes).
3287static void
3290 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {
3291 if (!Reg)
3292 return;
3293
3294 const auto *CRD = RecQT->getAsCXXRecordDecl();
3295 if (!CRD)
3296 return;
3297
3298 FieldConsumer FC{Reg, C, Out};
3299 hasSmartPtrField(CRD, FC);
3300}
3301
3302/// Handle smart pointer constructor calls by escaping allocated symbols
3303/// that are passed as pointer arguments to the constructor.
3304ProgramStateRef MallocChecker::handleSmartPointerConstructorArguments(
3305 const CallEvent &Call, ProgramStateRef State) const {
3306 const auto *CD = cast<CXXConstructorDecl>(Call.getDecl());
3307 for (unsigned I = 0, E = std::min(Call.getNumArgs(), CD->getNumParams());
3308 I != E; ++I) {
3309 const Expr *ArgExpr = Call.getArgExpr(I);
3310 if (!ArgExpr)
3311 continue;
3312
3313 QualType ParamType = CD->getParamDecl(I)->getType();
3314 if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&
3315 !ParamType->isVoidPointerType()) {
3316 // This argument is a pointer being passed to smart pointer constructor
3317 SVal ArgVal = Call.getArgSVal(I);
3318 SymbolRef Sym = ArgVal.getAsSymbol();
3319 if (Sym && State->contains<RegionState>(Sym)) {
3320 const RefState *RS = State->get<RegionState>(Sym);
3321 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {
3322 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3323 }
3324 }
3325 }
3326 }
3327 return State;
3328}
3329
3330/// Handle all smart pointer related processing in function calls.
3331/// This includes both direct smart pointer constructor calls and by-value
3332/// arguments containing smart pointer fields.
3333ProgramStateRef MallocChecker::handleSmartPointerRelatedCalls(
3334 const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
3335
3336 // Handle direct smart pointer constructor calls first
3337 if (isSmartPtrCall(Call)) {
3338 return handleSmartPointerConstructorArguments(Call, State);
3339 }
3340
3341 // Handle smart pointer fields in by-value record arguments
3342 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;
3343 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3344 const Expr *AE = Call.getArgExpr(I);
3345 if (!AE)
3346 continue;
3347 AE = AE->IgnoreParenImpCasts();
3348
3350 continue;
3351
3352 // Find a region for the argument.
3353 SVal ArgVal = Call.getArgSVal(I);
3354 const MemRegion *ArgRegion = ArgVal.getAsRegion();
3355 // Collect direct smart owning pointer field regions
3356 collectSmartPtrFieldRegions(ArgRegion, AE->getType(), C,
3357 SmartPtrFieldRoots);
3358 }
3359
3360 // Escape symbols reachable from smart pointer fields
3361 if (!SmartPtrFieldRoots.empty()) {
3362 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(
3363 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());
3364 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(
3365 SmartPtrFieldRootsVec, State);
3366 }
3367
3368 return State;
3369}
3370
3371void MallocChecker::checkPostCall(const CallEvent &Call,
3372 CheckerContext &C) const {
3373 // Handle existing post-call handlers first
3374 if (const auto *PostFN = PostFnMap.lookup(Call)) {
3375 (*PostFN)(this, C.getState(), Call, C);
3376 return; // Post-handler already called addTransition, we're done
3377 }
3378
3379 // Handle smart pointer related processing only if no post-handler was called
3380 C.addTransition(handleSmartPointerRelatedCalls(Call, C, C.getState()));
3381}
3382
3383void MallocChecker::checkPreCall(const CallEvent &Call,
3384 CheckerContext &C) const {
3385
3386 if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
3387 const CXXDeleteExpr *DE = DC->getOriginExpr();
3388
3389 // FIXME: I don't see a good reason for restricting the check against
3390 // use-after-free violations to the case when NewDeleteChecker is disabled.
3391 // (However, if NewDeleteChecker is enabled, perhaps it would be better to
3392 // do this check a bit later?)
3393 if (!NewDeleteChecker.isEnabled())
3394 if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
3395 checkUseAfterFree(Sym, C, DE->getArgument());
3396
3397 if (!isStandardNewDelete(DC->getDecl()))
3398 return;
3399
3400 ProgramStateRef State = C.getState();
3401 bool IsKnownToBeAllocated;
3402 State = FreeMemAux(
3403 C, DE->getArgument(), Call, State,
3404 /*Hold*/ false, IsKnownToBeAllocated,
3405 AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
3406
3407 C.addTransition(State);
3408 return;
3409 }
3410
3411 // If we see a `CXXDestructorCall` (that is, an _implicit_ destructor call)
3412 // to a region that's symbolic and known to be already freed, then it must be
3413 // implicitly triggered by a `delete` expression. In this situation we should
3414 // emit a `DoubleFree` report _now_ (before entering the call to the
3415 // destructor) because otherwise the destructor call can trigger a
3416 // use-after-free bug (by accessing any member variable) and that would be
3417 // (technically valid, but) less user-friendly report than the `DoubleFree`.
3418 if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
3419 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
3420 if (!Sym)
3421 return;
3422 if (isReleased(Sym, C)) {
3423 HandleDoubleFree(C, SourceRange(), /*Released=*/true, Sym,
3424 /*PrevSym=*/nullptr);
3425 return;
3426 }
3427 }
3428
3429 // We need to handle getline pre-conditions here before the pointed region
3430 // gets invalidated by StreamChecker
3431 if (const auto *PreFN = PreFnMap.lookup(Call)) {
3432 (*PreFN)(this, C.getState(), Call, C);
3433 return;
3434 }
3435
3436 // We will check for double free in the `evalCall` callback.
3437 // FIXME: It would be more logical to emit double free and use-after-free
3438 // reports via the same pathway (because double free is essentially a specia
3439 // case of use-after-free).
3440 if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {
3441 const FunctionDecl *FD = FC->getDecl();
3442 if (!FD)
3443 return;
3444
3445 // FIXME: I suspect we should remove `MallocChecker.isEnabled() &&` because
3446 // it's fishy that the enabled/disabled state of one frontend may influence
3447 // reports produced by other frontends.
3448 if (MallocChecker.isEnabled() && isFreeingCall(Call))
3449 return;
3450 }
3451
3452 // Check if the callee of a method is deleted.
3453 if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
3454 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
3455 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
3456 return;
3457 }
3458
3459 // Check arguments for being used after free.
3460 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
3461 SVal ArgSVal = Call.getArgSVal(I);
3462 if (isa<Loc>(ArgSVal)) {
3463 SymbolRef Sym = ArgSVal.getAsSymbol(/*IncludeBaseRegions=*/true);
3464 if (!Sym)
3465 continue;
3466 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
3467 return;
3468 }
3469 }
3470}
3471
3472void MallocChecker::checkPreStmt(const ReturnStmt *S,
3473 CheckerContext &C) const {
3474 checkEscapeOnReturn(S, C);
3475}
3476
3477// In the CFG, automatic destructors come after the return statement.
3478// This callback checks for returning memory that is freed by automatic
3479// destructors, as those cannot be reached in checkPreStmt().
3480void MallocChecker::checkEndFunction(const ReturnStmt *S,
3481 CheckerContext &C) const {
3482 checkEscapeOnReturn(S, C);
3483}
3484
3485void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
3486 CheckerContext &C) const {
3487 if (!S)
3488 return;
3489
3490 const Expr *E = S->getRetValue();
3491 if (!E)
3492 return;
3493
3494 // Check if we are returning a symbol.
3495 ProgramStateRef State = C.getState();
3496 SVal RetVal = C.getSVal(E);
3497 SymbolRef Sym = RetVal.getAsSymbol();
3498 if (!Sym)
3499 // If we are returning a field of the allocated struct or an array element,
3500 // the callee could still free the memory.
3501 if (const MemRegion *MR = RetVal.getAsRegion())
3503 if (const SymbolicRegion *BMR =
3504 dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
3505 Sym = BMR->getSymbol();
3506
3507 // Check if we are returning freed memory.
3508 if (Sym)
3509 checkUseAfterFree(Sym, C, E);
3510}
3511
3512// TODO: Blocks should be either inlined or should call invalidate regions
3513// upon invocation. After that's in place, special casing here will not be
3514// needed.
3515void MallocChecker::checkPostStmt(const BlockExpr *BE,
3516 CheckerContext &C) const {
3517
3518 // Scan the BlockDecRefExprs for any object the retain count checker
3519 // may be tracking.
3520 if (!BE->getBlockDecl()->hasCaptures())
3521 return;
3522
3523 ProgramStateRef state = C.getState();
3524 const BlockDataRegion *R =
3525 cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
3526
3527 auto ReferencedVars = R->referenced_vars();
3528 if (ReferencedVars.empty())
3529 return;
3530
3531 SmallVector<const MemRegion*, 10> Regions;
3532 const LocationContext *LC = C.getLocationContext();
3533 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
3534
3535 for (const auto &Var : ReferencedVars) {
3536 const VarRegion *VR = Var.getCapturedRegion();
3537 if (VR->getSuperRegion() == R) {
3538 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
3539 }
3540 Regions.push_back(VR);
3541 }
3542
3543 state =
3544 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
3545 C.addTransition(state);
3546}
3547
3549 assert(Sym);
3550 const RefState *RS = C.getState()->get<RegionState>(Sym);
3551 return (RS && RS->isReleased());
3552}
3553
3554bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
3555 const CallEvent &Call, CheckerContext &C) const {
3556 if (Call.getNumArgs() == 0)
3557 return false;
3558
3559 StringRef FunctionStr = "";
3560 if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
3561 if (const Stmt *Body = FD->getBody())
3562 if (Body->getBeginLoc().isValid())
3563 FunctionStr =
3565 {FD->getBeginLoc(), Body->getBeginLoc()}),
3566 C.getSourceManager(), C.getLangOpts());
3567
3568 // We do not model the Integer Set Library's retain-count based allocation.
3569 if (!FunctionStr.contains("__isl_"))
3570 return false;
3571
3572 ProgramStateRef State = C.getState();
3573
3574 for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments())
3575 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3576 if (const RefState *RS = State->get<RegionState>(Sym))
3577 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3578
3579 C.addTransition(State);
3580 return true;
3581}
3582
3583bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
3584 const Stmt *S) const {
3585
3586 if (isReleased(Sym, C)) {
3587 HandleUseAfterFree(C, S->getSourceRange(), Sym);
3588 return true;
3589 }
3590
3591 return false;
3592}
3593
3594void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3595 const Stmt *S) const {
3596 assert(Sym);
3597
3598 if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {
3599 if (RS->isAllocatedOfSizeZero())
3600 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3601 }
3602 else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3603 HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
3604 }
3605}
3606
3607// Check if the location is a freed symbolic region.
3608void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3609 CheckerContext &C) const {
3610 SymbolRef Sym = l.getLocSymbolInBase();
3611 if (Sym) {
3612 checkUseAfterFree(Sym, C, S);
3613 checkUseZeroAllocated(Sym, C, S);
3614 }
3615}
3616
3617// If a symbolic region is assumed to NULL (or another constant), stop tracking
3618// it - assuming that allocation failed on this path.
3619ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
3620 SVal Cond,
3621 bool Assumption) const {
3622 RegionStateTy RS = state->get<RegionState>();
3623 for (SymbolRef Sym : llvm::make_first_range(RS)) {
3624 // If the symbol is assumed to be NULL, remove it from consideration.
3625 ConstraintManager &CMgr = state->getConstraintManager();
3626 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3627 if (AllocFailed.isConstrainedTrue())
3628 state = state->remove<RegionState>(Sym);
3629 }
3630
3631 // Realloc returns 0 when reallocation fails, which means that we should
3632 // restore the state of the pointer being reallocated.
3633 ReallocPairsTy RP = state->get<ReallocPairs>();
3634 for (auto [Sym, ReallocPair] : RP) {
3635 // If the symbol is assumed to be NULL, remove it from consideration.
3636 ConstraintManager &CMgr = state->getConstraintManager();
3637 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3638 if (!AllocFailed.isConstrainedTrue())
3639 continue;
3640
3641 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3642 if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
3643 if (RS->isReleased()) {
3644 switch (ReallocPair.Kind) {
3645 case OAR_ToBeFreedAfterFailure:
3646 state = state->set<RegionState>(ReallocSym,
3647 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3648 break;
3649 case OAR_DoNotTrackAfterFailure:
3650 state = state->remove<RegionState>(ReallocSym);
3651 break;
3652 default:
3653 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3654 }
3655 }
3656 }
3657 state = state->remove<ReallocPairs>(Sym);
3658 }
3659
3660 return state;
3661}
3662
3663bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3664 const CallEvent *Call,
3665 ProgramStateRef State,
3666 SymbolRef &EscapingSymbol) const {
3667 assert(Call);
3668 EscapingSymbol = nullptr;
3669
3670 // For now, assume that any C++ or block call can free memory.
3671 // TODO: If we want to be more optimistic here, we'll need to make sure that
3672 // regions escape to C++ containers. They seem to do that even now, but for
3673 // mysterious reasons.
3675 return true;
3676
3677 // Check Objective-C messages by selector name.
3678 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
3679 // If it's not a framework call, or if it takes a callback, assume it
3680 // can free memory.
3681 if (!Call->isInSystemHeader() || Call->argumentsMayEscape())
3682 return true;
3683
3684 // If it's a method we know about, handle it explicitly post-call.
3685 // This should happen before the "freeWhenDone" check below.
3687 return false;
3688
3689 // If there's a "freeWhenDone" parameter, but the method isn't one we know
3690 // about, we can't be sure that the object will use free() to deallocate the
3691 // memory, so we can't model it explicitly. The best we can do is use it to
3692 // decide whether the pointer escapes.
3693 if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
3694 return *FreeWhenDone;
3695
3696 // If the first selector piece ends with "NoCopy", and there is no
3697 // "freeWhenDone" parameter set to zero, we know ownership is being
3698 // transferred. Again, though, we can't be sure that the object will use
3699 // free() to deallocate the memory, so we can't model it explicitly.
3700 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3701 if (FirstSlot.ends_with("NoCopy"))
3702 return true;
3703
3704 // If the first selector starts with addPointer, insertPointer,
3705 // or replacePointer, assume we are dealing with NSPointerArray or similar.
3706 // This is similar to C++ containers (vector); we still might want to check
3707 // that the pointers get freed by following the container itself.
3708 if (FirstSlot.starts_with("addPointer") ||
3709 FirstSlot.starts_with("insertPointer") ||
3710 FirstSlot.starts_with("replacePointer") ||
3711 FirstSlot == "valueWithPointer") {
3712 return true;
3713 }
3714
3715 // We should escape receiver on call to 'init'. This is especially relevant
3716 // to the receiver, as the corresponding symbol is usually not referenced
3717 // after the call.
3718 if (Msg->getMethodFamily() == OMF_init) {
3719 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3720 return true;
3721 }
3722
3723 // Otherwise, assume that the method does not free memory.
3724 // Most framework methods do not free memory.
3725 return false;
3726 }
3727
3728 // At this point the only thing left to handle is straight function calls.
3729 const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
3730 if (!FD)
3731 return true;
3732
3733 // If it's one of the allocation functions we can reason about, we model
3734 // its behavior explicitly.
3735 if (isMemCall(*Call))
3736 return false;
3737
3738 // If it's not a system call, assume it frees memory.
3739 if (!Call->isInSystemHeader())
3740 return true;
3741
3742 // White list the system functions whose arguments escape.
3743 const IdentifierInfo *II = FD->getIdentifier();
3744 if (!II)
3745 return true;
3746 StringRef FName = II->getName();
3747
3748 // White list the 'XXXNoCopy' CoreFoundation functions.
3749 // We specifically check these before
3750 if (FName.ends_with("NoCopy")) {
3751 // Look for the deallocator argument. We know that the memory ownership
3752 // is not transferred only if the deallocator argument is
3753 // 'kCFAllocatorNull'.
3754 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3755 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3756 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3757 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3758 if (DeallocatorName == "kCFAllocatorNull")
3759 return false;
3760 }
3761 }
3762 return true;
3763 }
3764
3765 // Associating streams with malloced buffers. The pointer can escape if
3766 // 'closefn' is specified (and if that function does free memory),
3767 // but it will not if closefn is not specified.
3768 // Currently, we do not inspect the 'closefn' function (PR12101).
3769 if (FName == "funopen")
3770 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3771 return false;
3772
3773 // Do not warn on pointers passed to 'setbuf' when used with std streams,
3774 // these leaks might be intentional when setting the buffer for stdio.
3775 // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
3776 if (FName == "setbuf" || FName =="setbuffer" ||
3777 FName == "setlinebuf" || FName == "setvbuf") {
3778 if (Call->getNumArgs() >= 1) {
3779 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
3780 if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3781 if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3782 if (D->getCanonicalDecl()->getName().contains("std"))
3783 return true;
3784 }
3785 }
3786
3787 // A bunch of other functions which either take ownership of a pointer or
3788 // wrap the result up in a struct or object, meaning it can be freed later.
3789 // (See RetainCountChecker.) Not all the parameters here are invalidated,
3790 // but the Malloc checker cannot differentiate between them. The right way
3791 // of doing this would be to implement a pointer escapes callback.
3792 if (FName == "CGBitmapContextCreate" ||
3793 FName == "CGBitmapContextCreateWithData" ||
3794 FName == "CVPixelBufferCreateWithBytes" ||
3795 FName == "CVPixelBufferCreateWithPlanarBytes" ||
3796 FName == "OSAtomicEnqueue") {
3797 return true;
3798 }
3799
3800 if (FName == "postEvent" &&
3801 FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
3802 return true;
3803 }
3804
3805 if (FName == "connectImpl" &&
3806 FD->getQualifiedNameAsString() == "QObject::connectImpl") {
3807 return true;
3808 }
3809
3810 if (FName == "singleShotImpl" &&
3811 FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") {
3812 return true;
3813 }
3814
3815 // Protobuf function declared in `generated_message_util.h` that takes
3816 // ownership of the second argument. As the first and third arguments are
3817 // allocation arenas and won't be tracked by this checker, there is no reason
3818 // to set `EscapingSymbol`. (Also, this is an implementation detail of
3819 // Protobuf, so it's better to be a bit more permissive.)
3820 if (FName == "GetOwnedMessageInternal") {
3821 return true;
3822 }
3823
3824 // Handle cases where we know a buffer's /address/ can escape.
3825 // Note that the above checks handle some special cases where we know that
3826 // even though the address escapes, it's still our responsibility to free the
3827 // buffer.
3828 if (Call->argumentsMayEscape())
3829 return true;
3830
3831 // Otherwise, assume that the function does not free memory.
3832 // Most system calls do not free the memory.
3833 return false;
3834}
3835
3836ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
3837 const InvalidatedSymbols &Escaped,
3838 const CallEvent *Call,
3839 PointerEscapeKind Kind) const {
3840 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3841 /*IsConstPointerEscape*/ false);
3842}
3843
3844ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
3845 const InvalidatedSymbols &Escaped,
3846 const CallEvent *Call,
3847 PointerEscapeKind Kind) const {
3848 // If a const pointer escapes, it may not be freed(), but it could be deleted.
3849 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3850 /*IsConstPointerEscape*/ true);
3851}
3852
3853static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
3854 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||
3855 RS->getAllocationFamily().Kind == AF_CXXNew);
3856}
3857
3858ProgramStateRef MallocChecker::checkPointerEscapeAux(
3859 ProgramStateRef State, const InvalidatedSymbols &Escaped,
3860 const CallEvent *Call, PointerEscapeKind Kind,
3861 bool IsConstPointerEscape) const {
3862 // If we know that the call does not free memory, or we want to process the
3863 // call later, keep tracking the top level arguments.
3864 SymbolRef EscapingSymbol = nullptr;
3865 if (Kind == PSK_DirectEscapeOnCall &&
3866 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3867 EscapingSymbol) &&
3868 !EscapingSymbol) {
3869 return State;
3870 }
3871
3872 for (SymbolRef sym : Escaped) {
3873 if (EscapingSymbol && EscapingSymbol != sym)
3874 continue;
3875
3876 if (const RefState *RS = State->get<RegionState>(sym))
3877 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3878 if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))
3879 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3880 }
3881 return State;
3882}
3883
3884bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
3885 SVal ArgVal) const {
3886 if (!KernelZeroSizePtrValue)
3887 KernelZeroSizePtrValue =
3888 tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor());
3889
3890 const llvm::APSInt *ArgValKnown =
3891 C.getSValBuilder().getKnownValue(State, ArgVal);
3892 return ArgValKnown && *KernelZeroSizePtrValue &&
3893 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3894}
3895
3897 ProgramStateRef prevState) {
3898 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3899 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3900
3901 for (const ReallocPairsTy::value_type &Pair : prevMap) {
3902 SymbolRef sym = Pair.first;
3903 if (!currMap.lookup(sym))
3904 return sym;
3905 }
3906
3907 return nullptr;
3908}
3909
3911 if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) {
3912 StringRef N = II->getName();
3913 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3914 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3915 N.contains_insensitive("intrusive") ||
3916 N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
3917 return true;
3918 }
3919 }
3920 }
3921 return false;
3922}
3923
3924PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3925 BugReporterContext &BRC,
3926 PathSensitiveBugReport &BR) {
3927 ProgramStateRef state = N->getState();
3928 ProgramStateRef statePrev = N->getFirstPred()->getState();
3929
3930 const RefState *RSCurr = state->get<RegionState>(Sym);
3931 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3932
3933 const Stmt *S = N->getStmtForDiagnostics();
3934 // When dealing with containers, we sometimes want to give a note
3935 // even if the statement is missing.
3936 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))
3937 return nullptr;
3938
3939 const LocationContext *CurrentLC = N->getLocationContext();
3940
3941 // If we find an atomic fetch_add or fetch_sub within the function in which
3942 // the pointer was released (before the release), this is likely a release
3943 // point of reference-counted object (like shared pointer).
3944 //
3945 // Because we don't model atomics, and also because we don't know that the
3946 // original reference count is positive, we should not report use-after-frees
3947 // on objects deleted in such functions. This can probably be improved
3948 // through better shared pointer modeling.
3949 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||
3950 ReleaseFunctionLC->isParentOf(CurrentLC))) {
3951 if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
3952 // Check for manual use of atomic builtins.
3953 AtomicExpr::AtomicOp Op = AE->getOp();
3954 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3955 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3956 BR.markInvalid(getTag(), S);
3957 // After report is considered invalid there is no need to proceed
3958 // futher.
3959 return nullptr;
3960 }
3961 } else if (const auto *CE = dyn_cast<CallExpr>(S)) {
3962 // Check for `std::atomic` and such. This covers both regular method calls
3963 // and operator calls.
3964 if (const auto *MD =
3965 dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) {
3966 const CXXRecordDecl *RD = MD->getParent();
3967 // A bit wobbly with ".contains()" because it may be like
3968 // "__atomic_base" or something.
3969 if (StringRef(RD->getNameAsString()).contains("atomic")) {
3970 BR.markInvalid(getTag(), S);
3971 // After report is considered invalid there is no need to proceed
3972 // futher.
3973 return nullptr;
3974 }
3975 }
3976 }
3977 }
3978
3979 // FIXME: We will eventually need to handle non-statement-based events
3980 // (__attribute__((cleanup))).
3981
3982 // Find out if this is an interesting point and what is the kind.
3983 StringRef Msg;
3984 std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;
3985 SmallString<256> Buf;
3986 llvm::raw_svector_ostream OS(Buf);
3987
3988 if (Mode == Normal) {
3989 if (isAllocated(RSCurr, RSPrev, S)) {
3990 Msg = "Memory is allocated";
3991 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3992 Sym, "Returned allocated memory");
3993 } else if (isReleased(RSCurr, RSPrev, S)) {
3994 const auto Family = RSCurr->getAllocationFamily();
3995 switch (Family.Kind) {
3996 case AF_Alloca:
3997 case AF_Malloc:
3998 case AF_Custom:
3999 case AF_CXXNew:
4000 case AF_CXXNewArray:
4001 case AF_IfNameIndex:
4002 Msg = "Memory is released";
4003 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4004 Sym, "Returning; memory was released");
4005 break;
4006 case AF_InnerBuffer: {
4007 const MemRegion *ObjRegion =
4009 const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
4010 QualType ObjTy = TypedRegion->getValueType();
4011 OS << "Inner buffer of '" << ObjTy << "' ";
4012
4014 OS << "deallocated by call to destructor";
4015 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4016 Sym, "Returning; inner buffer was deallocated");
4017 } else {
4018 OS << "reallocated by call to '";
4019 const Stmt *S = RSCurr->getStmt();
4020 if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
4021 OS << MemCallE->getMethodDecl()->getDeclName();
4022 } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
4023 OS << OpCallE->getDirectCallee()->getDeclName();
4024 } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
4025 auto &CEMgr = BRC.getStateManager().getCallEventManager();
4026 CallEventRef<> Call =
4027 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
4028 if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
4029 OS << D->getDeclName();
4030 else
4031 OS << "unknown";
4032 }
4033 OS << "'";
4034 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4035 Sym, "Returning; inner buffer was reallocated");
4036 }
4037 Msg = OS.str();
4038 break;
4039 }
4040 case AF_None:
4041 assert(false && "Unhandled allocation family!");
4042 return nullptr;
4043 }
4044
4045 // Record the stack frame that is _responsible_ for this memory release
4046 // event. This will be used by the false positive suppression heuristics
4047 // that recognize the release points of reference-counted objects.
4048 //
4049 // Usually (e.g. in C) we say that the _responsible_ stack frame is the
4050 // current innermost stack frame:
4051 ReleaseFunctionLC = CurrentLC->getStackFrame();
4052 // ...but if the stack contains a destructor call, then we say that the
4053 // outermost destructor stack frame is the _responsible_ one:
4054 for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
4055 if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {
4057 // This immediately looks like a reference-counting destructor.
4058 // We're bad at guessing the original reference count of the
4059 // object, so suppress the report for now.
4060 BR.markInvalid(getTag(), DD);
4061
4062 // After report is considered invalid there is no need to proceed
4063 // futher.
4064 return nullptr;
4065 }
4066
4067 // Switch suspection to outer destructor to catch patterns like:
4068 // (note that class name is distorted to bypass
4069 // isReferenceCountingPointerDestructor() logic)
4070 //
4071 // SmartPointr::~SmartPointr() {
4072 // if (refcount.fetch_sub(1) == 1)
4073 // release_resources();
4074 // }
4075 // void SmartPointr::release_resources() {
4076 // free(buffer);
4077 // }
4078 //
4079 // This way ReleaseFunctionLC will point to outermost destructor and
4080 // it would be possible to catch wider range of FP.
4081 //
4082 // NOTE: it would be great to support smth like that in C, since
4083 // currently patterns like following won't be supressed:
4084 //
4085 // void doFree(struct Data *data) { free(data); }
4086 // void putData(struct Data *data)
4087 // {
4088 // if (refPut(data))
4089 // doFree(data);
4090 // }
4091 ReleaseFunctionLC = LC->getStackFrame();
4092 }
4093 }
4094
4095 } else if (isRelinquished(RSCurr, RSPrev, S)) {
4096 Msg = "Memory ownership is transferred";
4097 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");
4098 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
4099 Mode = ReallocationFailed;
4100 Msg = "Reallocation failed";
4101 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
4102 Sym, "Reallocation failed");
4103
4104 if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
4105 // Is it possible to fail two reallocs WITHOUT testing in between?
4106 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
4107 "We only support one failed realloc at a time.");
4108 BR.markInteresting(sym);
4109 FailedReallocSymbol = sym;
4110 }
4111 }
4112
4113 // We are in a special mode if a reallocation failed later in the path.
4114 } else if (Mode == ReallocationFailed) {
4115 assert(FailedReallocSymbol && "No symbol to look for.");
4116
4117 // Is this is the first appearance of the reallocated symbol?
4118 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
4119 // We're at the reallocation point.
4120 Msg = "Attempt to reallocate memory";
4121 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
4122 Sym, "Returned reallocated memory");
4123 FailedReallocSymbol = nullptr;
4124 Mode = Normal;
4125 }
4126 }
4127
4128 if (Msg.empty()) {
4129 assert(!StackHint);
4130 return nullptr;
4131 }
4132
4133 assert(StackHint);
4134
4135 // Generate the extra diagnostic.
4136 PathDiagnosticLocation Pos;
4137 if (!S) {
4138 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);
4139 auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
4140 if (!PostImplCall)
4141 return nullptr;
4142 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
4143 BRC.getSourceManager());
4144 } else {
4145 Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),
4146 N->getLocationContext());
4147 }
4148
4149 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
4150 BR.addCallStackHint(P, std::move(StackHint));
4151 return P;
4152}
4153
4154void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
4155 const char *NL, const char *Sep) const {
4156
4157 RegionStateTy RS = State->get<RegionState>();
4158
4159 if (!RS.isEmpty()) {
4160 Out << Sep << "MallocChecker :" << NL;
4161 for (auto [Sym, Data] : RS) {
4162 const RefState *RefS = State->get<RegionState>(Sym);
4163 AllocationFamily Family = RefS->getAllocationFamily();
4164
4165 const CheckerFrontend *Frontend =
4166 getRelevantFrontendAs<CheckerFrontend>(Family);
4167
4168 Sym->dumpToStream(Out);
4169 Out << " : ";
4170 Data.dump(Out);
4171 if (Frontend && Frontend->isEnabled())
4172 Out << " (" << Frontend->getName() << ")";
4173 Out << NL;
4174 }
4175 }
4176}
4177
4178namespace clang {
4179namespace ento {
4180namespace allocation_state {
4181
4183markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
4184 AllocationFamily Family(AF_InnerBuffer);
4185 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
4186}
4187
4188} // end namespace allocation_state
4189} // end namespace ento
4190} // end namespace clang
4191
4192// Intended to be used in InnerPointerChecker to register the part of
4193// MallocChecker connected to it.
4195 Mgr.getChecker<MallocChecker>()->InnerPointerChecker.enable(Mgr);
4196}
4197
4198void ento::registerDynamicMemoryModeling(CheckerManager &Mgr) {
4199 auto *Chk = Mgr.getChecker<MallocChecker>();
4200 // FIXME: This is a "hidden" undocumented frontend but there are public
4201 // checker options which are attached to it.
4202 CheckerNameRef DMMName = Mgr.getCurrentCheckerName();
4203 Chk->ShouldIncludeOwnershipAnnotatedFunctions =
4204 Mgr.getAnalyzerOptions().getCheckerBooleanOption(DMMName, "Optimistic");
4205 Chk->ShouldRegisterNoOwnershipChangeVisitor =
4206 Mgr.getAnalyzerOptions().getCheckerBooleanOption(
4207 DMMName, "AddNoOwnershipChangeNotes");
4208}
4209
4210bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
4211 return true;
4212}
4213
4214#define REGISTER_CHECKER(NAME) \
4215 void ento::register##NAME(CheckerManager &Mgr) { \
4216 Mgr.getChecker<MallocChecker>()->NAME.enable(Mgr); \
4217 } \
4218 \
4219 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }
4220
4221// TODO: NewDelete and NewDeleteLeaks shouldn't be registered when not in C++.
4222REGISTER_CHECKER(MallocChecker)
4223REGISTER_CHECKER(NewDeleteChecker)
4224REGISTER_CHECKER(NewDeleteLeaksChecker)
4225REGISTER_CHECKER(MismatchedDeallocatorChecker)
4226REGISTER_CHECKER(TaintedAllocChecker)
#define V(N, I)
#define REGISTER_CHECKER(name)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
#define X(type, name)
Definition Value.h:97
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::Target Target
Definition MachO.h:51
static bool isRvalueByValueRecordWithSmartPtr(const Expr *AE)
Check if an expression is an rvalue record with smart owning pointer fields passed by value.
static bool isFromStdNamespace(const CallEvent &Call)
static bool isStandardNew(const FunctionDecl *FD)
static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)
static QualType getDeepPointeeType(QualType T)
static bool isReleased(SymbolRef Sym, CheckerContext &C)
Check if the memory associated with this symbol was released.
static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)
Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.
static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)
Collect memory regions of smart owning pointer fields from a record type (including fields from base ...
static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)
Check if a record type has smart owning pointer fields (directly or in base classes).
static bool isStandardDelete(const FunctionDecl *FD)
static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)
static bool isSmartPtrType(QualType QT)
static bool isStandardNewDelete(const T &FD)
Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...
static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)
static bool isRvalueByValueRecord(const Expr *AE)
Check if an expression is an rvalue record type passed by value.
#define BUGTYPE_PROVIDER(NAME, DEF)
static bool isGRealloc(const CallEvent &Call)
static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)
#define CASE(ID)
static bool isSmartPtrRecord(const CXXRecordDecl *RD)
Check if a CXXRecordDecl has a name matching recognized smart pointer names.
#define CHECK_FN(NAME)
static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)
Print expected name of a deallocator based on the allocator's family.
static bool isStandardRealloc(const CallEvent &Call)
static bool isSmartPtrCall(const CallEvent &Call)
Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.
static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)
Checks if the previous call to free on the given symbol failed - if free failed, returns true.
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)
Update the RefState to reflect the new memory allocation.
static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)
Print names of allocators and deallocators.
static bool isSmartPtrName(StringRef Name)
static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)
static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)
static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)
static bool checkIfNewOrNewArrayFamily(const RefState *RS)
#define SM(sm)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
Defines the SourceManager interface.
__DEVICE__ long long abs(long long __n)
__device__ __2f16 float __ockl_bool s
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
SourceManager & getSourceManager()
Definition ASTContext.h:858
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:916
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
Definition Decl.h:4793
const BlockDecl * getBlockDecl() const
Definition Expr.h:6683
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Represents binding an expression to a temporary.
Definition ExprCXX.h:1494
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1612
Represents a C++ constructor within a class.
Definition DeclCXX.h:2611
Represents a delete expression for memory deallocation and destructor calls, e.g.
Definition ExprCXX.h:2627
bool isArrayForm() const
Definition ExprCXX.h:2653
Represents a C++ destructor within a class.
Definition DeclCXX.h:2876
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2262
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
Definition ExprCXX.h:2356
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:1900
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:449
bool hasAttrs() const
Definition DeclBase.h:518
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:546
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition DeclBase.h:559
SourceLocation getLocation() const
Definition DeclBase.h:439
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h: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:3095
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition Expr.cpp:3090
QualType getType() const
Definition Expr.h:144
Represents a member of a struct/union/class.
Definition Decl.h:3160
Represents a function declaration or definition.
Definition Decl.h:2000
const ParmVarDecl * getParamDecl(unsigned i) const
Definition Decl.h:2797
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3280
ArrayRef< ParmVarDecl * > parameters() const
Definition Decl.h:2774
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
Definition Decl.h:2933
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition Decl.cpp:4131
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:2862
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition Decl.cpp:3200
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:1038
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
Represents a prvalue temporary that is written into memory so that a reference can bind to it.
Definition ExprCXX.h:4921
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:1680
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition Decl.h:317
An expression that sends a message to the given Objective-C object or class.
Definition ExprObjC.h:937
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:4530
Expr * getRetValue()
Definition Stmt.h:3179
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp: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:713
bool isFunctionPointerType() const
Definition TypeBase.h:8692
bool isPointerType() const
Definition TypeBase.h:8625
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:753
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9218
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:1208
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 LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:584
A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...
Definition Checker.h:514
CheckerNameRef getName() const
Definition Checker.h:524
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static bool isLocType(QualType T)
Definition SVals.h:262
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
Definition MemRegion.h:1416
Kind getKind() const
Definition MemRegion.h:203
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
Represents any expression that calls an Objective-C method.
Definition CallEvent.h:1261
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)
void markInvalid(const void *Tag, const void *Data)
Marks the current report as invalid, meaning that it is probably a false positive and should not be r...
CallEventManager & getCallEventManager()
bool hasSymbolicOffset() const
Definition MemRegion.h:83
int64_t getOffset() const
Definition MemRegion.h:85
DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)
Conjure a symbol representing heap allocated memory region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)
Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
bool isUnknownOrUndef() const
Definition SVals.h:109
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition SVals.cpp:103
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition SVals.cpp:67
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
SymbolRef getLocSymbolInBase() const
Get the symbol in the SVal or its base region.
Definition SVals.cpp:79
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:83
SubRegion - A region that subsets another larger region.
Definition MemRegion.h:474
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
Definition MemRegion.h:487
virtual void dumpToStream(raw_ostream &os) const
Definition SymExpr.h:81
virtual QualType getType() const =0
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolRef getSymbol() const
It might return null.
Definition MemRegion.h:827
const VarDecl * getDecl() const override=0
const StackFrameContext * getStackFrame() const
It might return null.
Defines the clang::TargetInfo interface.
__inline void unsigned int _2
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr
Matches delete expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)
Matches if the node or any descendant matches.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)
std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)
This function provides an additional visitor that augments the bug report with information relevant t...
const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)
'Sym' represents a pointer to the inner buffer of a container object.
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
Definition Taint.cpp:170
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
@ PSK_DirectEscapeOnCall
The pointer has been passed to a function call directly.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)
Set the dynamic extent Extent of the region MR.
void registerInnerPointerCheckerAux(CheckerManager &Mgr)
Register the part of MallocChecker connected to InnerPointerChecker.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)
std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)
Try to parse the value of a defined preprocessor macro.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool NE(InterpState &S, CodePtr OpPC)
Definition Interp.h:1312
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:1746
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