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