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