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