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