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