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 a variety of memory management related checkers, such as
10 // leak, double free, and use-after-free.
11 //
12 // The following checkers are defined here:
13 //
14 // * MallocChecker
15 // Despite its name, it models all sorts of memory allocations and
16 // de- or reallocation, including but not limited to malloc, free,
17 // relloc, new, delete. It also reports on a variety of memory misuse
18 // errors.
19 // Many other checkers interact very closely with this checker, in fact,
20 // most are merely options to this one. Other checkers may register
21 // MallocChecker, but do not enable MallocChecker's reports (more details
22 // to follow around its field, ChecksEnabled).
23 // It also has a boolean "Optimistic" checker option, which if set to true
24 // will cause the checker to model user defined memory management related
25 // functions annotated via the attribute ownership_takes, ownership_holds
26 // and ownership_returns.
27 //
28 // * NewDeleteChecker
29 // Enables the modeling of new, new[], delete, delete[] in MallocChecker,
30 // and checks for related double-free and use-after-free errors.
31 //
32 // * NewDeleteLeaksChecker
33 // Checks for leaks related to new, new[], delete, delete[].
34 // Depends on NewDeleteChecker.
35 //
36 // * MismatchedDeallocatorChecker
37 // Enables checking whether memory is deallocated with the correspending
38 // allocation function in MallocChecker, such as malloc() allocated
39 // regions are only freed by free(), new by delete, new[] by delete[].
40 //
41 // InnerPointerChecker interacts very closely with MallocChecker, but unlike
42 // the above checkers, it has it's own file, hence the many InnerPointerChecker
43 // related headers and non-static functions.
44 //
45 //===----------------------------------------------------------------------===//
46
47 #include "AllocationState.h"
48 #include "InterCheckerAPI.h"
49 #include "clang/AST/Attr.h"
50 #include "clang/AST/DeclCXX.h"
51 #include "clang/AST/DeclTemplate.h"
52 #include "clang/AST/Expr.h"
53 #include "clang/AST/ExprCXX.h"
54 #include "clang/AST/ParentMap.h"
55 #include "clang/ASTMatchers/ASTMatchFinder.h"
56 #include "clang/ASTMatchers/ASTMatchers.h"
57 #include "clang/Analysis/ProgramPoint.h"
58 #include "clang/Basic/LLVM.h"
59 #include "clang/Basic/SourceManager.h"
60 #include "clang/Basic/TargetInfo.h"
61 #include "clang/Lex/Lexer.h"
62 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
63 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
64 #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
65 #include "clang/StaticAnalyzer/Core/Checker.h"
66 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
67 #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
68 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
69 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
70 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
71 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
72 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
73 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
74 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
75 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
76 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
77 #include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
78 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
79 #include "llvm/ADT/STLExtras.h"
80 #include "llvm/ADT/SetOperations.h"
81 #include "llvm/ADT/SmallString.h"
82 #include "llvm/ADT/StringExtras.h"
83 #include "llvm/Support/Casting.h"
84 #include "llvm/Support/Compiler.h"
85 #include "llvm/Support/ErrorHandling.h"
86 #include "llvm/Support/raw_ostream.h"
87 #include <climits>
88 #include <functional>
89 #include <optional>
90 #include <utility>
91
92 using namespace clang;
93 using namespace ento;
94 using namespace std::placeholders;
95
96 //===----------------------------------------------------------------------===//
97 // The types of allocation we're modeling. This is used to check whether a
98 // dynamically allocated object is deallocated with the correct function, like
99 // not using operator delete on an object created by malloc(), or alloca regions
100 // aren't ever deallocated manually.
101 //===----------------------------------------------------------------------===//
102
103 namespace {
104
105 // Used to check correspondence between allocators and deallocators.
106 enum AllocationFamily {
107 AF_None,
108 AF_Malloc,
109 AF_CXXNew,
110 AF_CXXNewArray,
111 AF_IfNameIndex,
112 AF_Alloca,
113 AF_InnerBuffer
114 };
115
116 } // end of anonymous namespace
117
118 /// Print names of allocators and deallocators.
119 ///
120 /// \returns true on success.
121 static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E);
122
123 /// Print expected name of an allocator based on the deallocator's family
124 /// derived from the DeallocExpr.
125 static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family);
126
127 /// Print expected name of a deallocator based on the allocator's
128 /// family.
129 static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
130
131 //===----------------------------------------------------------------------===//
132 // The state of a symbol, in terms of memory management.
133 //===----------------------------------------------------------------------===//
134
135 namespace {
136
137 class RefState {
138 enum Kind {
139 // Reference to allocated memory.
140 Allocated,
141 // Reference to zero-allocated memory.
142 AllocatedOfSizeZero,
143 // Reference to released/freed memory.
144 Released,
145 // The responsibility for freeing resources has transferred from
146 // this reference. A relinquished symbol should not be freed.
147 Relinquished,
148 // We are no longer guaranteed to have observed all manipulations
149 // of this pointer/memory. For example, it could have been
150 // passed as a parameter to an opaque function.
151 Escaped
152 };
153
154 const Stmt *S;
155
156 Kind K;
157 AllocationFamily Family;
158
RefState(Kind k,const Stmt * s,AllocationFamily family)159 RefState(Kind k, const Stmt *s, AllocationFamily family)
160 : S(s), K(k), Family(family) {
161 assert(family != AF_None);
162 }
163
164 public:
isAllocated() const165 bool isAllocated() const { return K == Allocated; }
isAllocatedOfSizeZero() const166 bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
isReleased() const167 bool isReleased() const { return K == Released; }
isRelinquished() const168 bool isRelinquished() const { return K == Relinquished; }
isEscaped() const169 bool isEscaped() const { return K == Escaped; }
getAllocationFamily() const170 AllocationFamily getAllocationFamily() const { return Family; }
getStmt() const171 const Stmt *getStmt() const { return S; }
172
operator ==(const RefState & X) const173 bool operator==(const RefState &X) const {
174 return K == X.K && S == X.S && Family == X.Family;
175 }
176
getAllocated(AllocationFamily family,const Stmt * s)177 static RefState getAllocated(AllocationFamily family, const Stmt *s) {
178 return RefState(Allocated, s, family);
179 }
getAllocatedOfSizeZero(const RefState * RS)180 static RefState getAllocatedOfSizeZero(const RefState *RS) {
181 return RefState(AllocatedOfSizeZero, RS->getStmt(),
182 RS->getAllocationFamily());
183 }
getReleased(AllocationFamily family,const Stmt * s)184 static RefState getReleased(AllocationFamily family, const Stmt *s) {
185 return RefState(Released, s, family);
186 }
getRelinquished(AllocationFamily family,const Stmt * s)187 static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
188 return RefState(Relinquished, s, family);
189 }
getEscaped(const RefState * RS)190 static RefState getEscaped(const RefState *RS) {
191 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());
192 }
193
Profile(llvm::FoldingSetNodeID & ID) const194 void Profile(llvm::FoldingSetNodeID &ID) const {
195 ID.AddInteger(K);
196 ID.AddPointer(S);
197 ID.AddInteger(Family);
198 }
199
dump(raw_ostream & OS) const200 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
201 switch (K) {
202 #define CASE(ID) case ID: OS << #ID; break;
203 CASE(Allocated)
204 CASE(AllocatedOfSizeZero)
205 CASE(Released)
206 CASE(Relinquished)
207 CASE(Escaped)
208 }
209 }
210
dump() const211 LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
212 };
213
214 } // end of anonymous namespace
215
216 REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
217
218 /// Check if the memory associated with this symbol was released.
219 static bool isReleased(SymbolRef Sym, CheckerContext &C);
220
221 /// Update the RefState to reflect the new memory allocation.
222 /// The optional \p RetVal parameter specifies the newly allocated pointer
223 /// value; if unspecified, the value of expression \p E is used.
224 static ProgramStateRef
225 MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
226 AllocationFamily Family,
227 std::optional<SVal> RetVal = std::nullopt);
228
229 //===----------------------------------------------------------------------===//
230 // The modeling of memory reallocation.
231 //
232 // The terminology 'toPtr' and 'fromPtr' will be used:
233 // toPtr = realloc(fromPtr, 20);
234 //===----------------------------------------------------------------------===//
235
236 REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
237
238 namespace {
239
240 /// The state of 'fromPtr' after reallocation is known to have failed.
241 enum OwnershipAfterReallocKind {
242 // The symbol needs to be freed (e.g.: realloc)
243 OAR_ToBeFreedAfterFailure,
244 // The symbol has been freed (e.g.: reallocf)
245 OAR_FreeOnFailure,
246 // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where
247 // 'fromPtr' was allocated:
248 // void Haha(int *ptr) {
249 // ptr = realloc(ptr, 67);
250 // // ...
251 // }
252 // ).
253 OAR_DoNotTrackAfterFailure
254 };
255
256 /// Stores information about the 'fromPtr' symbol after reallocation.
257 ///
258 /// This is important because realloc may fail, and that needs special modeling.
259 /// Whether reallocation failed or not will not be known until later, so we'll
260 /// store whether upon failure 'fromPtr' will be freed, or needs to be freed
261 /// later, etc.
262 struct ReallocPair {
263
264 // The 'fromPtr'.
265 SymbolRef ReallocatedSym;
266 OwnershipAfterReallocKind Kind;
267
ReallocPair__anone88413230311::ReallocPair268 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
269 : ReallocatedSym(S), Kind(K) {}
Profile__anone88413230311::ReallocPair270 void Profile(llvm::FoldingSetNodeID &ID) const {
271 ID.AddInteger(Kind);
272 ID.AddPointer(ReallocatedSym);
273 }
operator ==__anone88413230311::ReallocPair274 bool operator==(const ReallocPair &X) const {
275 return ReallocatedSym == X.ReallocatedSym &&
276 Kind == X.Kind;
277 }
278 };
279
280 } // end of anonymous namespace
281
282 REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
283
284 /// Tells if the callee is one of the builtin new/delete operators, including
285 /// placement operators and other standard overloads.
286 static bool isStandardNewDelete(const FunctionDecl *FD);
isStandardNewDelete(const CallEvent & Call)287 static bool isStandardNewDelete(const CallEvent &Call) {
288 if (!Call.getDecl() || !isa<FunctionDecl>(Call.getDecl()))
289 return false;
290 return isStandardNewDelete(cast<FunctionDecl>(Call.getDecl()));
291 }
292
293 //===----------------------------------------------------------------------===//
294 // Definition of the MallocChecker class.
295 //===----------------------------------------------------------------------===//
296
297 namespace {
298
299 class MallocChecker
300 : public Checker<check::DeadSymbols, check::PointerEscape,
301 check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
302 check::EndFunction, check::PreCall, check::PostCall,
303 check::NewAllocator, check::PostStmt<BlockExpr>,
304 check::PostObjCMessage, check::Location, eval::Assume> {
305 public:
306 /// In pessimistic mode, the checker assumes that it does not know which
307 /// functions might free the memory.
308 /// In optimistic mode, the checker assumes that all user-defined functions
309 /// which might free a pointer are annotated.
310 bool ShouldIncludeOwnershipAnnotatedFunctions = false;
311
312 bool ShouldRegisterNoOwnershipChangeVisitor = false;
313
314 /// Many checkers are essentially built into this one, so enabling them will
315 /// make MallocChecker perform additional modeling and reporting.
316 enum CheckKind {
317 /// When a subchecker is enabled but MallocChecker isn't, model memory
318 /// management but do not emit warnings emitted with MallocChecker only
319 /// enabled.
320 CK_MallocChecker,
321 CK_NewDeleteChecker,
322 CK_NewDeleteLeaksChecker,
323 CK_MismatchedDeallocatorChecker,
324 CK_InnerPointerChecker,
325 CK_NumCheckKinds
326 };
327
328 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
329
330 bool ChecksEnabled[CK_NumCheckKinds] = {false};
331 CheckerNameRef CheckNames[CK_NumCheckKinds];
332
333 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
334 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
335 void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;
336 void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
337 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
338 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
339 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
340 void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;
341 ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
342 bool Assumption) const;
343 void checkLocation(SVal l, bool isLoad, const Stmt *S,
344 CheckerContext &C) const;
345
346 ProgramStateRef checkPointerEscape(ProgramStateRef State,
347 const InvalidatedSymbols &Escaped,
348 const CallEvent *Call,
349 PointerEscapeKind Kind) const;
350 ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
351 const InvalidatedSymbols &Escaped,
352 const CallEvent *Call,
353 PointerEscapeKind Kind) const;
354
355 void printState(raw_ostream &Out, ProgramStateRef State,
356 const char *NL, const char *Sep) const override;
357
358 private:
359 mutable std::unique_ptr<BugType> BT_DoubleFree[CK_NumCheckKinds];
360 mutable std::unique_ptr<BugType> BT_DoubleDelete;
361 mutable std::unique_ptr<BugType> BT_Leak[CK_NumCheckKinds];
362 mutable std::unique_ptr<BugType> BT_UseFree[CK_NumCheckKinds];
363 mutable std::unique_ptr<BugType> BT_BadFree[CK_NumCheckKinds];
364 mutable std::unique_ptr<BugType> BT_FreeAlloca[CK_NumCheckKinds];
365 mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
366 mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
367 mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
368
369 #define CHECK_FN(NAME) \
370 void NAME(const CallEvent &Call, CheckerContext &C) const;
371
372 CHECK_FN(checkFree)
373 CHECK_FN(checkIfNameIndex)
374 CHECK_FN(checkBasicAlloc)
375 CHECK_FN(checkKernelMalloc)
376 CHECK_FN(checkCalloc)
377 CHECK_FN(checkAlloca)
378 CHECK_FN(checkStrdup)
379 CHECK_FN(checkIfFreeNameIndex)
380 CHECK_FN(checkCXXNewOrCXXDelete)
381 CHECK_FN(checkGMalloc0)
382 CHECK_FN(checkGMemdup)
383 CHECK_FN(checkGMallocN)
384 CHECK_FN(checkGMallocN0)
385 CHECK_FN(checkReallocN)
386 CHECK_FN(checkOwnershipAttr)
387
388 void checkRealloc(const CallEvent &Call, CheckerContext &C,
389 bool ShouldFreeOnFail) const;
390
391 using CheckFn = std::function<void(const MallocChecker *,
392 const CallEvent &Call, CheckerContext &C)>;
393
394 const CallDescriptionMap<CheckFn> FreeingMemFnMap{
395 {{{"free"}, 1}, &MallocChecker::checkFree},
396 {{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
397 {{{"kfree"}, 1}, &MallocChecker::checkFree},
398 {{{"g_free"}, 1}, &MallocChecker::checkFree},
399 };
400
401 bool isFreeingCall(const CallEvent &Call) const;
402 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);
403
404 friend class NoOwnershipChangeVisitor;
405
406 CallDescriptionMap<CheckFn> AllocatingMemFnMap{
407 {{{"alloca"}, 1}, &MallocChecker::checkAlloca},
408 {{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
409 {{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
410 {{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
411 {{{"calloc"}, 2}, &MallocChecker::checkCalloc},
412 {{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
413 {{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
414 {{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
415 {{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
416 {{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
417 {{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
418 {{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
419 {{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
420 {{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
421 {{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
422 {{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
423 {{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
424 {{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
425 {{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
426 {{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
427 {{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
428 {{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
429 };
430
431 CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
432 {{{"realloc"}, 2},
433 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
434 {{{"reallocf"}, 2},
435 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
436 {{{"g_realloc"}, 2},
437 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
438 {{{"g_try_realloc"}, 2},
439 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
440 {{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
441 {{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
442 };
443
444 bool isMemCall(const CallEvent &Call) const;
445
446 // TODO: Remove mutable by moving the initializtaion to the registry function.
447 mutable std::optional<uint64_t> KernelZeroFlagVal;
448
449 using KernelZeroSizePtrValueTy = std::optional<int>;
450 /// Store the value of macro called `ZERO_SIZE_PTR`.
451 /// The value is initialized at first use, before first use the outer
452 /// Optional is empty, afterwards it contains another Optional that indicates
453 /// if the macro value could be determined, and if yes the value itself.
454 mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
455
456 /// Process C++ operator new()'s allocation, which is the part of C++
457 /// new-expression that goes before the constructor.
458 [[nodiscard]] ProgramStateRef
459 processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
460 AllocationFamily Family) const;
461
462 /// Perform a zero-allocation check.
463 ///
464 /// \param [in] Call The expression that allocates memory.
465 /// \param [in] IndexOfSizeArg Index of the argument that specifies the size
466 /// of the memory that needs to be allocated. E.g. for malloc, this would be
467 /// 0.
468 /// \param [in] RetVal Specifies the newly allocated pointer value;
469 /// if unspecified, the value of expression \p E is used.
470 [[nodiscard]] static ProgramStateRef
471 ProcessZeroAllocCheck(const CallEvent &Call, const unsigned IndexOfSizeArg,
472 ProgramStateRef State,
473 std::optional<SVal> RetVal = std::nullopt);
474
475 /// Model functions with the ownership_returns attribute.
476 ///
477 /// User-defined function may have the ownership_returns attribute, which
478 /// annotates that the function returns with an object that was allocated on
479 /// the heap, and passes the ownertship to the callee.
480 ///
481 /// void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);
482 ///
483 /// It has two parameters:
484 /// - first: name of the resource (e.g. 'malloc')
485 /// - (OPTIONAL) second: size of the allocated region
486 ///
487 /// \param [in] Call The expression that allocates memory.
488 /// \param [in] Att The ownership_returns attribute.
489 /// \param [in] State The \c ProgramState right before allocation.
490 /// \returns The ProgramState right after allocation.
491 [[nodiscard]] ProgramStateRef
492 MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
493 const OwnershipAttr *Att, ProgramStateRef State) const;
494
495 /// Models memory allocation.
496 ///
497 /// \param [in] Call The expression that allocates memory.
498 /// \param [in] SizeEx Size of the memory that needs to be allocated.
499 /// \param [in] Init The value the allocated memory needs to be initialized.
500 /// with. For example, \c calloc initializes the allocated memory to 0,
501 /// malloc leaves it undefined.
502 /// \param [in] State The \c ProgramState right before allocation.
503 /// \returns The ProgramState right after allocation.
504 [[nodiscard]] static ProgramStateRef
505 MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
506 SVal Init, ProgramStateRef State, AllocationFamily Family);
507
508 /// Models memory allocation.
509 ///
510 /// \param [in] Call The expression that allocates memory.
511 /// \param [in] Size Size of the memory that needs to be allocated.
512 /// \param [in] Init The value the allocated memory needs to be initialized.
513 /// with. For example, \c calloc initializes the allocated memory to 0,
514 /// malloc leaves it undefined.
515 /// \param [in] State The \c ProgramState right before allocation.
516 /// \returns The ProgramState right after allocation.
517 [[nodiscard]] static ProgramStateRef
518 MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init,
519 ProgramStateRef State, AllocationFamily Family);
520
521 // Check if this malloc() for special flags. At present that means M_ZERO or
522 // __GFP_ZERO (in which case, treat it like calloc).
523 [[nodiscard]] std::optional<ProgramStateRef>
524 performKernelMalloc(const CallEvent &Call, CheckerContext &C,
525 const ProgramStateRef &State) const;
526
527 /// Model functions with the ownership_takes and ownership_holds attributes.
528 ///
529 /// User-defined function may have the ownership_takes and/or ownership_holds
530 /// attributes, which annotates that the function frees the memory passed as a
531 /// parameter.
532 ///
533 /// void __attribute((ownership_takes(malloc, 1))) my_free(void *);
534 /// void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
535 ///
536 /// They have two parameters:
537 /// - first: name of the resource (e.g. 'malloc')
538 /// - second: index of the parameter the attribute applies to
539 ///
540 /// \param [in] Call The expression that frees memory.
541 /// \param [in] Att The ownership_takes or ownership_holds attribute.
542 /// \param [in] State The \c ProgramState right before allocation.
543 /// \returns The ProgramState right after deallocation.
544 [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,
545 const CallEvent &Call,
546 const OwnershipAttr *Att,
547 ProgramStateRef State) const;
548
549 /// Models memory deallocation.
550 ///
551 /// \param [in] Call The expression that frees memory.
552 /// \param [in] State The \c ProgramState right before allocation.
553 /// \param [in] Num Index of the argument that needs to be freed. This is
554 /// normally 0, but for custom free functions it may be different.
555 /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
556 /// attribute.
557 /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
558 /// to have been allocated, or in other words, the symbol to be freed was
559 /// registered as allocated by this checker. In the following case, \c ptr
560 /// isn't known to be allocated.
561 /// void Haha(int *ptr) {
562 /// ptr = realloc(ptr, 67);
563 /// // ...
564 /// }
565 /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
566 /// we're modeling returns with Null on failure.
567 /// \returns The ProgramState right after deallocation.
568 [[nodiscard]] ProgramStateRef
569 FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,
570 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
571 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
572
573 /// Models memory deallocation.
574 ///
575 /// \param [in] ArgExpr The variable who's pointee needs to be freed.
576 /// \param [in] Call The expression that frees the memory.
577 /// \param [in] State The \c ProgramState right before allocation.
578 /// normally 0, but for custom free functions it may be different.
579 /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
580 /// attribute.
581 /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
582 /// to have been allocated, or in other words, the symbol to be freed was
583 /// registered as allocated by this checker. In the following case, \c ptr
584 /// isn't known to be allocated.
585 /// void Haha(int *ptr) {
586 /// ptr = realloc(ptr, 67);
587 /// // ...
588 /// }
589 /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
590 /// we're modeling returns with Null on failure.
591 /// \returns The ProgramState right after deallocation.
592 [[nodiscard]] ProgramStateRef
593 FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
594 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
595 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
596
597 // TODO: Needs some refactoring, as all other deallocation modeling
598 // functions are suffering from out parameters and messy code due to how
599 // realloc is handled.
600 //
601 /// Models memory reallocation.
602 ///
603 /// \param [in] Call The expression that reallocated memory
604 /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied
605 /// memory should be freed.
606 /// \param [in] State The \c ProgramState right before reallocation.
607 /// \param [in] SuffixWithN Whether the reallocation function we're modeling
608 /// has an '_n' suffix, such as g_realloc_n.
609 /// \returns The ProgramState right after reallocation.
610 [[nodiscard]] ProgramStateRef
611 ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
612 ProgramStateRef State, AllocationFamily Family,
613 bool SuffixWithN = false) const;
614
615 /// Evaluates the buffer size that needs to be allocated.
616 ///
617 /// \param [in] Blocks The amount of blocks that needs to be allocated.
618 /// \param [in] BlockBytes The size of a block.
619 /// \returns The symbolic value of \p Blocks * \p BlockBytes.
620 [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
621 const Expr *Blocks,
622 const Expr *BlockBytes);
623
624 /// Models zero initialized array allocation.
625 ///
626 /// \param [in] Call The expression that reallocated memory
627 /// \param [in] State The \c ProgramState right before reallocation.
628 /// \returns The ProgramState right after allocation.
629 [[nodiscard]] static ProgramStateRef
630 CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State);
631
632 /// See if deallocation happens in a suspicious context. If so, escape the
633 /// pointers that otherwise would have been deallocated and return true.
634 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,
635 CheckerContext &C) const;
636
637 /// If in \p S \p Sym is used, check whether \p Sym was already freed.
638 bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
639
640 /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero
641 /// sized memory region.
642 void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
643 const Stmt *S) const;
644
645 /// If in \p S \p Sym is being freed, check whether \p Sym was already freed.
646 bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
647
648 /// Check if the function is known to free memory, or if it is
649 /// "interesting" and should be modeled explicitly.
650 ///
651 /// \param [out] EscapingSymbol A function might not free memory in general,
652 /// but could be known to free a particular symbol. In this case, false is
653 /// returned and the single escaping symbol is returned through the out
654 /// parameter.
655 ///
656 /// We assume that pointers do not escape through calls to system functions
657 /// not handled by this checker.
658 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,
659 ProgramStateRef State,
660 SymbolRef &EscapingSymbol) const;
661
662 /// Implementation of the checkPointerEscape callbacks.
663 [[nodiscard]] ProgramStateRef
664 checkPointerEscapeAux(ProgramStateRef State,
665 const InvalidatedSymbols &Escaped,
666 const CallEvent *Call, PointerEscapeKind Kind,
667 bool IsConstPointerEscape) const;
668
669 // Implementation of the checkPreStmt and checkEndFunction callbacks.
670 void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
671
672 ///@{
673 /// Tells if a given family/call/symbol is tracked by the current checker.
674 /// Sets CheckKind to the kind of the checker responsible for this
675 /// family/call/symbol.
676 std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
677 bool IsALeakCheck = false) const;
678
679 std::optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
680 bool IsALeakCheck = false) const;
681 ///@}
682 static bool SummarizeValue(raw_ostream &os, SVal V);
683 static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
684
685 void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,
686 const Expr *DeallocExpr,
687 AllocationFamily Family) const;
688
689 void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
690 SourceRange Range) const;
691
692 void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,
693 const Expr *DeallocExpr, const RefState *RS,
694 SymbolRef Sym, bool OwnershipTransferred) const;
695
696 void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
697 const Expr *DeallocExpr, AllocationFamily Family,
698 const Expr *AllocExpr = nullptr) const;
699
700 void HandleUseAfterFree(CheckerContext &C, SourceRange Range,
701 SymbolRef Sym) const;
702
703 void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
704 SymbolRef Sym, SymbolRef PrevSym) const;
705
706 void HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const;
707
708 void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
709 SymbolRef Sym) const;
710
711 void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
712 const Expr *FreeExpr,
713 AllocationFamily Family) const;
714
715 /// Find the location of the allocation for Sym on the path leading to the
716 /// exploded node N.
717 static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
718 CheckerContext &C);
719
720 void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
721
722 /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`.
723 bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
724 SVal ArgVal) const;
725 };
726 } // end anonymous namespace
727
728 //===----------------------------------------------------------------------===//
729 // Definition of NoOwnershipChangeVisitor.
730 //===----------------------------------------------------------------------===//
731
732 namespace {
733 class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
734 // The symbol whose (lack of) ownership change we are interested in.
735 SymbolRef Sym;
736 const MallocChecker &Checker;
737 using OwnerSet = llvm::SmallPtrSet<const MemRegion *, 8>;
738
739 // Collect which entities point to the allocated memory, and could be
740 // responsible for deallocating it.
741 class OwnershipBindingsHandler : public StoreManager::BindingsHandler {
742 SymbolRef Sym;
743 OwnerSet &Owners;
744
745 public:
OwnershipBindingsHandler(SymbolRef Sym,OwnerSet & Owners)746 OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners)
747 : Sym(Sym), Owners(Owners) {}
748
HandleBinding(StoreManager & SMgr,Store Store,const MemRegion * Region,SVal Val)749 bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region,
750 SVal Val) override {
751 if (Val.getAsSymbol() == Sym)
752 Owners.insert(Region);
753 return true;
754 }
755
dump() const756 LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
dumpToStream(llvm::raw_ostream & out) const757 LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const {
758 out << "Owners: {\n";
759 for (const MemRegion *Owner : Owners) {
760 out << " ";
761 Owner->dumpToStream(out);
762 out << ",\n";
763 }
764 out << "}\n";
765 }
766 };
767
768 protected:
getOwnersAtNode(const ExplodedNode * N)769 OwnerSet getOwnersAtNode(const ExplodedNode *N) {
770 OwnerSet Ret;
771
772 ProgramStateRef State = N->getState();
773 OwnershipBindingsHandler Handler{Sym, Ret};
774 State->getStateManager().getStoreManager().iterBindings(State->getStore(),
775 Handler);
776 return Ret;
777 }
778
779 LLVM_DUMP_METHOD static std::string
getFunctionName(const ExplodedNode * CallEnterN)780 getFunctionName(const ExplodedNode *CallEnterN) {
781 if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
782 CallEnterN->getLocationAs<CallEnter>()->getCallExpr()))
783 if (const FunctionDecl *FD = CE->getDirectCallee())
784 return FD->getQualifiedNameAsString();
785 return "";
786 }
787
788 /// Syntactically checks whether the callee is a deallocating function. Since
789 /// we have no path-sensitive information on this call (we would need a
790 /// CallEvent instead of a CallExpr for that), its possible that a
791 /// deallocation function was called indirectly through a function pointer,
792 /// but we are not able to tell, so this is a best effort analysis.
793 /// See namespace `memory_passed_to_fn_call_free_through_fn_ptr` in
794 /// clang/test/Analysis/NewDeleteLeaks.cpp.
isFreeingCallAsWritten(const CallExpr & Call) const795 bool isFreeingCallAsWritten(const CallExpr &Call) const {
796 if (Checker.FreeingMemFnMap.lookupAsWritten(Call) ||
797 Checker.ReallocatingMemFnMap.lookupAsWritten(Call))
798 return true;
799
800 if (const auto *Func =
801 llvm::dyn_cast_or_null<FunctionDecl>(Call.getCalleeDecl()))
802 return MallocChecker::isFreeingOwnershipAttrCall(Func);
803
804 return false;
805 }
806
807 /// Heuristically guess whether the callee intended to free memory. This is
808 /// done syntactically, because we are trying to argue about alternative
809 /// paths of execution, and as a consequence we don't have path-sensitive
810 /// information.
doesFnIntendToHandleOwnership(const Decl * Callee,ASTContext & ACtx)811 bool doesFnIntendToHandleOwnership(const Decl *Callee, ASTContext &ACtx) {
812 using namespace clang::ast_matchers;
813 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
814
815 // Given that the stack frame was entered, the body should always be
816 // theoretically obtainable. In case of body farms, the synthesized body
817 // is not attached to declaration, thus triggering the '!FD->hasBody()'
818 // branch. That said, would a synthesized body ever intend to handle
819 // ownership? As of today they don't. And if they did, how would we
820 // put notes inside it, given that it doesn't match any source locations?
821 if (!FD || !FD->hasBody())
822 return false;
823
824 auto Matches = match(findAll(stmt(anyOf(cxxDeleteExpr().bind("delete"),
825 callExpr().bind("call")))),
826 *FD->getBody(), ACtx);
827 for (BoundNodes Match : Matches) {
828 if (Match.getNodeAs<CXXDeleteExpr>("delete"))
829 return true;
830
831 if (const auto *Call = Match.getNodeAs<CallExpr>("call"))
832 if (isFreeingCallAsWritten(*Call))
833 return true;
834 }
835 // TODO: Ownership might change with an attempt to store the allocated
836 // memory, not only through deallocation. Check for attempted stores as
837 // well.
838 return false;
839 }
840
wasModifiedInFunction(const ExplodedNode * CallEnterN,const ExplodedNode * CallExitEndN)841 bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
842 const ExplodedNode *CallExitEndN) override {
843 if (!doesFnIntendToHandleOwnership(
844 CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
845 CallExitEndN->getState()->getAnalysisManager().getASTContext()))
846 return true;
847
848 if (CallEnterN->getState()->get<RegionState>(Sym) !=
849 CallExitEndN->getState()->get<RegionState>(Sym))
850 return true;
851
852 OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
853 OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
854
855 // Owners in the current set may be purged from the analyzer later on.
856 // If a variable is dead (is not referenced directly or indirectly after
857 // some point), it will be removed from the Store before the end of its
858 // actual lifetime.
859 // This means that if the ownership status didn't change, CurrOwners
860 // must be a superset of, but not necessarily equal to ExitOwners.
861 return !llvm::set_is_subset(ExitOwners, CurrOwners);
862 }
863
emitNote(const ExplodedNode * N)864 static PathDiagnosticPieceRef emitNote(const ExplodedNode *N) {
865 PathDiagnosticLocation L = PathDiagnosticLocation::create(
866 N->getLocation(),
867 N->getState()->getStateManager().getContext().getSourceManager());
868 return std::make_shared<PathDiagnosticEventPiece>(
869 L, "Returning without deallocating memory or storing the pointer for "
870 "later deallocation");
871 }
872
873 PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport & R,const ObjCMethodCall & Call,const ExplodedNode * N)874 maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
875 const ObjCMethodCall &Call,
876 const ExplodedNode *N) override {
877 // TODO: Implement.
878 return nullptr;
879 }
880
881 PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport & R,const CXXConstructorCall & Call,const ExplodedNode * N)882 maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
883 const CXXConstructorCall &Call,
884 const ExplodedNode *N) override {
885 // TODO: Implement.
886 return nullptr;
887 }
888
889 PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport & R,const CallEvent & Call,const ExplodedNode * N)890 maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
891 const ExplodedNode *N) override {
892 // TODO: Factor the logic of "what constitutes as an entity being passed
893 // into a function call" out by reusing the code in
894 // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating
895 // the printing technology in UninitializedObject's FieldChainInfo.
896 ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
897 for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
898 SVal V = Call.getArgSVal(I);
899 if (V.getAsSymbol() == Sym)
900 return emitNote(N);
901 }
902 return nullptr;
903 }
904
905 public:
NoOwnershipChangeVisitor(SymbolRef Sym,const MallocChecker * Checker)906 NoOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)
907 : NoStateChangeFuncVisitor(bugreporter::TrackingKind::Thorough), Sym(Sym),
908 Checker(*Checker) {}
909
Profile(llvm::FoldingSetNodeID & ID) const910 void Profile(llvm::FoldingSetNodeID &ID) const override {
911 static int Tag = 0;
912 ID.AddPointer(&Tag);
913 ID.AddPointer(Sym);
914 }
915 };
916
917 } // end anonymous namespace
918
919 //===----------------------------------------------------------------------===//
920 // Definition of MallocBugVisitor.
921 //===----------------------------------------------------------------------===//
922
923 namespace {
924 /// The bug visitor which allows us to print extra diagnostics along the
925 /// BugReport path. For example, showing the allocation site of the leaked
926 /// region.
927 class MallocBugVisitor final : public BugReporterVisitor {
928 protected:
929 enum NotificationMode { Normal, ReallocationFailed };
930
931 // The allocated region symbol tracked by the main analysis.
932 SymbolRef Sym;
933
934 // The mode we are in, i.e. what kind of diagnostics will be emitted.
935 NotificationMode Mode;
936
937 // A symbol from when the primary region should have been reallocated.
938 SymbolRef FailedReallocSymbol;
939
940 // A C++ destructor stack frame in which memory was released. Used for
941 // miscellaneous false positive suppression.
942 const StackFrameContext *ReleaseDestructorLC;
943
944 bool IsLeak;
945
946 public:
MallocBugVisitor(SymbolRef S,bool isLeak=false)947 MallocBugVisitor(SymbolRef S, bool isLeak = false)
948 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
949 ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
950
getTag()951 static void *getTag() {
952 static int Tag = 0;
953 return &Tag;
954 }
955
Profile(llvm::FoldingSetNodeID & ID) const956 void Profile(llvm::FoldingSetNodeID &ID) const override {
957 ID.AddPointer(getTag());
958 ID.AddPointer(Sym);
959 }
960
961 /// Did not track -> allocated. Other state (released) -> allocated.
isAllocated(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)962 static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
963 const Stmt *Stmt) {
964 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
965 (RSCurr &&
966 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
967 (!RSPrev ||
968 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
969 }
970
971 /// Did not track -> released. Other state (allocated) -> released.
972 /// The statement associated with the release might be missing.
isReleased(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)973 static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
974 const Stmt *Stmt) {
975 bool IsReleased =
976 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
977 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
978 (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
979 return IsReleased;
980 }
981
982 /// Did not track -> relinquished. Other state (allocated) -> relinquished.
isRelinquished(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)983 static inline bool isRelinquished(const RefState *RSCurr,
984 const RefState *RSPrev, const Stmt *Stmt) {
985 return (
986 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
987 (RSCurr && RSCurr->isRelinquished()) &&
988 (!RSPrev || !RSPrev->isRelinquished()));
989 }
990
991 /// If the expression is not a call, and the state change is
992 /// released -> allocated, it must be the realloc return value
993 /// check. If we have to handle more cases here, it might be cleaner just
994 /// to track this extra bit in the state itself.
hasReallocFailed(const RefState * RSCurr,const RefState * RSPrev,const Stmt * Stmt)995 static inline bool hasReallocFailed(const RefState *RSCurr,
996 const RefState *RSPrev,
997 const Stmt *Stmt) {
998 return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
999 (RSCurr &&
1000 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
1001 (RSPrev &&
1002 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
1003 }
1004
1005 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
1006 BugReporterContext &BRC,
1007 PathSensitiveBugReport &BR) override;
1008
getEndPath(BugReporterContext & BRC,const ExplodedNode * EndPathNode,PathSensitiveBugReport & BR)1009 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
1010 const ExplodedNode *EndPathNode,
1011 PathSensitiveBugReport &BR) override {
1012 if (!IsLeak)
1013 return nullptr;
1014
1015 PathDiagnosticLocation L = BR.getLocation();
1016 // Do not add the statement itself as a range in case of leak.
1017 return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
1018 false);
1019 }
1020
1021 private:
1022 class StackHintGeneratorForReallocationFailed
1023 : public StackHintGeneratorForSymbol {
1024 public:
StackHintGeneratorForReallocationFailed(SymbolRef S,StringRef M)1025 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
1026 : StackHintGeneratorForSymbol(S, M) {}
1027
getMessageForArg(const Expr * ArgE,unsigned ArgIndex)1028 std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
1029 // Printed parameters start at 1, not 0.
1030 ++ArgIndex;
1031
1032 SmallString<200> buf;
1033 llvm::raw_svector_ostream os(buf);
1034
1035 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
1036 << " parameter failed";
1037
1038 return std::string(os.str());
1039 }
1040
getMessageForReturn(const CallExpr * CallExpr)1041 std::string getMessageForReturn(const CallExpr *CallExpr) override {
1042 return "Reallocation of returned value failed";
1043 }
1044 };
1045 };
1046 } // end anonymous namespace
1047
1048 // A map from the freed symbol to the symbol representing the return value of
1049 // the free function.
1050 REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
1051
1052 namespace {
1053 class StopTrackingCallback final : public SymbolVisitor {
1054 ProgramStateRef state;
1055
1056 public:
StopTrackingCallback(ProgramStateRef st)1057 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}
getState() const1058 ProgramStateRef getState() const { return state; }
1059
VisitSymbol(SymbolRef sym)1060 bool VisitSymbol(SymbolRef sym) override {
1061 state = state->remove<RegionState>(sym);
1062 return true;
1063 }
1064 };
1065 } // end anonymous namespace
1066
isStandardNewDelete(const FunctionDecl * FD)1067 static bool isStandardNewDelete(const FunctionDecl *FD) {
1068 if (!FD)
1069 return false;
1070
1071 OverloadedOperatorKind Kind = FD->getOverloadedOperator();
1072 if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete &&
1073 Kind != OO_Array_Delete)
1074 return false;
1075
1076 // This is standard if and only if it's not defined in a user file.
1077 SourceLocation L = FD->getLocation();
1078 // If the header for operator delete is not included, it's still defined
1079 // in an invalid source location. Check to make sure we don't crash.
1080 return !L.isValid() ||
1081 FD->getASTContext().getSourceManager().isInSystemHeader(L);
1082 }
1083
1084 //===----------------------------------------------------------------------===//
1085 // Methods of MallocChecker and MallocBugVisitor.
1086 //===----------------------------------------------------------------------===//
1087
isFreeingOwnershipAttrCall(const FunctionDecl * Func)1088 bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {
1089 if (Func->hasAttrs()) {
1090 for (const auto *I : Func->specific_attrs<OwnershipAttr>()) {
1091 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
1092 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)
1093 return true;
1094 }
1095 }
1096 return false;
1097 }
1098
isFreeingCall(const CallEvent & Call) const1099 bool MallocChecker::isFreeingCall(const CallEvent &Call) const {
1100 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))
1101 return true;
1102
1103 if (const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
1104 return isFreeingOwnershipAttrCall(Func);
1105
1106 return false;
1107 }
1108
isMemCall(const CallEvent & Call) const1109 bool MallocChecker::isMemCall(const CallEvent &Call) const {
1110 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||
1111 ReallocatingMemFnMap.lookup(Call))
1112 return true;
1113
1114 if (!ShouldIncludeOwnershipAnnotatedFunctions)
1115 return false;
1116
1117 const auto *Func = dyn_cast<FunctionDecl>(Call.getDecl());
1118 return Func && Func->hasAttr<OwnershipAttr>();
1119 }
1120
1121 std::optional<ProgramStateRef>
performKernelMalloc(const CallEvent & Call,CheckerContext & C,const ProgramStateRef & State) const1122 MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
1123 const ProgramStateRef &State) const {
1124 // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
1125 //
1126 // void *malloc(unsigned long size, struct malloc_type *mtp, int flags);
1127 //
1128 // One of the possible flags is M_ZERO, which means 'give me back an
1129 // allocation which is already zeroed', like calloc.
1130
1131 // 2-argument kmalloc(), as used in the Linux kernel:
1132 //
1133 // void *kmalloc(size_t size, gfp_t flags);
1134 //
1135 // Has the similar flag value __GFP_ZERO.
1136
1137 // This logic is largely cloned from O_CREAT in UnixAPIChecker, maybe some
1138 // code could be shared.
1139
1140 ASTContext &Ctx = C.getASTContext();
1141 llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();
1142
1143 if (!KernelZeroFlagVal) {
1144 switch (OS) {
1145 case llvm::Triple::FreeBSD:
1146 KernelZeroFlagVal = 0x0100;
1147 break;
1148 case llvm::Triple::NetBSD:
1149 KernelZeroFlagVal = 0x0002;
1150 break;
1151 case llvm::Triple::OpenBSD:
1152 KernelZeroFlagVal = 0x0008;
1153 break;
1154 case llvm::Triple::Linux:
1155 // __GFP_ZERO
1156 KernelZeroFlagVal = 0x8000;
1157 break;
1158 default:
1159 // FIXME: We need a more general way of getting the M_ZERO value.
1160 // See also: O_CREAT in UnixAPIChecker.cpp.
1161
1162 // Fall back to normal malloc behavior on platforms where we don't
1163 // know M_ZERO.
1164 return std::nullopt;
1165 }
1166 }
1167
1168 // We treat the last argument as the flags argument, and callers fall-back to
1169 // normal malloc on a None return. This works for the FreeBSD kernel malloc
1170 // as well as Linux kmalloc.
1171 if (Call.getNumArgs() < 2)
1172 return std::nullopt;
1173
1174 const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
1175 const SVal V = C.getSVal(FlagsEx);
1176 if (!isa<NonLoc>(V)) {
1177 // The case where 'V' can be a location can only be due to a bad header,
1178 // so in this case bail out.
1179 return std::nullopt;
1180 }
1181
1182 NonLoc Flags = V.castAs<NonLoc>();
1183 NonLoc ZeroFlag = C.getSValBuilder()
1184 .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
1185 .castAs<NonLoc>();
1186 SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
1187 Flags, ZeroFlag,
1188 FlagsEx->getType());
1189 if (MaskedFlagsUC.isUnknownOrUndef())
1190 return std::nullopt;
1191 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
1192
1193 // Check if maskedFlags is non-zero.
1194 ProgramStateRef TrueState, FalseState;
1195 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);
1196
1197 // If M_ZERO is set, treat this like calloc (initialized).
1198 if (TrueState && !FalseState) {
1199 SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);
1200 return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,
1201 AF_Malloc);
1202 }
1203
1204 return std::nullopt;
1205 }
1206
evalMulForBufferSize(CheckerContext & C,const Expr * Blocks,const Expr * BlockBytes)1207 SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
1208 const Expr *BlockBytes) {
1209 SValBuilder &SB = C.getSValBuilder();
1210 SVal BlocksVal = C.getSVal(Blocks);
1211 SVal BlockBytesVal = C.getSVal(BlockBytes);
1212 ProgramStateRef State = C.getState();
1213 SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,
1214 SB.getContext().getSizeType());
1215 return TotalSize;
1216 }
1217
checkBasicAlloc(const CallEvent & Call,CheckerContext & C) const1218 void MallocChecker::checkBasicAlloc(const CallEvent &Call,
1219 CheckerContext &C) const {
1220 ProgramStateRef State = C.getState();
1221 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1222 AF_Malloc);
1223 State = ProcessZeroAllocCheck(Call, 0, State);
1224 C.addTransition(State);
1225 }
1226
checkKernelMalloc(const CallEvent & Call,CheckerContext & C) const1227 void MallocChecker::checkKernelMalloc(const CallEvent &Call,
1228 CheckerContext &C) const {
1229 ProgramStateRef State = C.getState();
1230 std::optional<ProgramStateRef> MaybeState =
1231 performKernelMalloc(Call, C, State);
1232 if (MaybeState)
1233 State = *MaybeState;
1234 else
1235 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1236 AF_Malloc);
1237 C.addTransition(State);
1238 }
1239
isStandardRealloc(const CallEvent & Call)1240 static bool isStandardRealloc(const CallEvent &Call) {
1241 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1242 assert(FD);
1243 ASTContext &AC = FD->getASTContext();
1244
1245 if (isa<CXXMethodDecl>(FD))
1246 return false;
1247
1248 return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
1249 FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
1250 FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
1251 AC.getSizeType();
1252 }
1253
isGRealloc(const CallEvent & Call)1254 static bool isGRealloc(const CallEvent &Call) {
1255 const FunctionDecl *FD = dyn_cast<FunctionDecl>(Call.getDecl());
1256 assert(FD);
1257 ASTContext &AC = FD->getASTContext();
1258
1259 if (isa<CXXMethodDecl>(FD))
1260 return false;
1261
1262 return FD->getDeclaredReturnType().getDesugaredType(AC) == AC.VoidPtrTy &&
1263 FD->getParamDecl(0)->getType().getDesugaredType(AC) == AC.VoidPtrTy &&
1264 FD->getParamDecl(1)->getType().getDesugaredType(AC) ==
1265 AC.UnsignedLongTy;
1266 }
1267
checkRealloc(const CallEvent & Call,CheckerContext & C,bool ShouldFreeOnFail) const1268 void MallocChecker::checkRealloc(const CallEvent &Call, CheckerContext &C,
1269 bool ShouldFreeOnFail) const {
1270 // HACK: CallDescription currently recognizes non-standard realloc functions
1271 // as standard because it doesn't check the type, or wether its a non-method
1272 // function. This should be solved by making CallDescription smarter.
1273 // Mind that this came from a bug report, and all other functions suffer from
1274 // this.
1275 // https://bugs.llvm.org/show_bug.cgi?id=46253
1276 if (!isStandardRealloc(Call) && !isGRealloc(Call))
1277 return;
1278 ProgramStateRef State = C.getState();
1279 State = ReallocMemAux(C, Call, ShouldFreeOnFail, State, AF_Malloc);
1280 State = ProcessZeroAllocCheck(Call, 1, State);
1281 C.addTransition(State);
1282 }
1283
checkCalloc(const CallEvent & Call,CheckerContext & C) const1284 void MallocChecker::checkCalloc(const CallEvent &Call,
1285 CheckerContext &C) const {
1286 ProgramStateRef State = C.getState();
1287 State = CallocMem(C, Call, State);
1288 State = ProcessZeroAllocCheck(Call, 0, State);
1289 State = ProcessZeroAllocCheck(Call, 1, State);
1290 C.addTransition(State);
1291 }
1292
checkFree(const CallEvent & Call,CheckerContext & C) const1293 void MallocChecker::checkFree(const CallEvent &Call, CheckerContext &C) const {
1294 ProgramStateRef State = C.getState();
1295 bool IsKnownToBeAllocatedMemory = false;
1296 if (suppressDeallocationsInSuspiciousContexts(Call, C))
1297 return;
1298 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1299 AF_Malloc);
1300 C.addTransition(State);
1301 }
1302
checkAlloca(const CallEvent & Call,CheckerContext & C) const1303 void MallocChecker::checkAlloca(const CallEvent &Call,
1304 CheckerContext &C) const {
1305 ProgramStateRef State = C.getState();
1306 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
1307 AF_Alloca);
1308 State = ProcessZeroAllocCheck(Call, 0, State);
1309 C.addTransition(State);
1310 }
1311
checkStrdup(const CallEvent & Call,CheckerContext & C) const1312 void MallocChecker::checkStrdup(const CallEvent &Call,
1313 CheckerContext &C) const {
1314 ProgramStateRef State = C.getState();
1315 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1316 if (!CE)
1317 return;
1318 State = MallocUpdateRefState(C, CE, State, AF_Malloc);
1319
1320 C.addTransition(State);
1321 }
1322
checkIfNameIndex(const CallEvent & Call,CheckerContext & C) const1323 void MallocChecker::checkIfNameIndex(const CallEvent &Call,
1324 CheckerContext &C) const {
1325 ProgramStateRef State = C.getState();
1326 // Should we model this differently? We can allocate a fixed number of
1327 // elements with zeros in the last one.
1328 State =
1329 MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, AF_IfNameIndex);
1330
1331 C.addTransition(State);
1332 }
1333
checkIfFreeNameIndex(const CallEvent & Call,CheckerContext & C) const1334 void MallocChecker::checkIfFreeNameIndex(const CallEvent &Call,
1335 CheckerContext &C) const {
1336 ProgramStateRef State = C.getState();
1337 bool IsKnownToBeAllocatedMemory = false;
1338 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1339 AF_IfNameIndex);
1340 C.addTransition(State);
1341 }
1342
checkCXXNewOrCXXDelete(const CallEvent & Call,CheckerContext & C) const1343 void MallocChecker::checkCXXNewOrCXXDelete(const CallEvent &Call,
1344 CheckerContext &C) const {
1345 ProgramStateRef State = C.getState();
1346 bool IsKnownToBeAllocatedMemory = false;
1347 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1348 if (!CE)
1349 return;
1350
1351 assert(isStandardNewDelete(Call));
1352
1353 // Process direct calls to operator new/new[]/delete/delete[] functions
1354 // as distinct from new/new[]/delete/delete[] expressions that are
1355 // processed by the checkPostStmt callbacks for CXXNewExpr and
1356 // CXXDeleteExpr.
1357 const FunctionDecl *FD = C.getCalleeDecl(CE);
1358 switch (FD->getOverloadedOperator()) {
1359 case OO_New:
1360 State =
1361 MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State, AF_CXXNew);
1362 State = ProcessZeroAllocCheck(Call, 0, State);
1363 break;
1364 case OO_Array_New:
1365 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,
1366 AF_CXXNewArray);
1367 State = ProcessZeroAllocCheck(Call, 0, State);
1368 break;
1369 case OO_Delete:
1370 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1371 AF_CXXNew);
1372 break;
1373 case OO_Array_Delete:
1374 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,
1375 AF_CXXNewArray);
1376 break;
1377 default:
1378 llvm_unreachable("not a new/delete operator");
1379 }
1380
1381 C.addTransition(State);
1382 }
1383
checkGMalloc0(const CallEvent & Call,CheckerContext & C) const1384 void MallocChecker::checkGMalloc0(const CallEvent &Call,
1385 CheckerContext &C) const {
1386 ProgramStateRef State = C.getState();
1387 SValBuilder &svalBuilder = C.getSValBuilder();
1388 SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
1389 State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State, AF_Malloc);
1390 State = ProcessZeroAllocCheck(Call, 0, State);
1391 C.addTransition(State);
1392 }
1393
checkGMemdup(const CallEvent & Call,CheckerContext & C) const1394 void MallocChecker::checkGMemdup(const CallEvent &Call,
1395 CheckerContext &C) const {
1396 ProgramStateRef State = C.getState();
1397 State =
1398 MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State, AF_Malloc);
1399 State = ProcessZeroAllocCheck(Call, 1, State);
1400 C.addTransition(State);
1401 }
1402
checkGMallocN(const CallEvent & Call,CheckerContext & C) const1403 void MallocChecker::checkGMallocN(const CallEvent &Call,
1404 CheckerContext &C) const {
1405 ProgramStateRef State = C.getState();
1406 SVal Init = UndefinedVal();
1407 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1408 State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc);
1409 State = ProcessZeroAllocCheck(Call, 0, State);
1410 State = ProcessZeroAllocCheck(Call, 1, State);
1411 C.addTransition(State);
1412 }
1413
checkGMallocN0(const CallEvent & Call,CheckerContext & C) const1414 void MallocChecker::checkGMallocN0(const CallEvent &Call,
1415 CheckerContext &C) const {
1416 ProgramStateRef State = C.getState();
1417 SValBuilder &SB = C.getSValBuilder();
1418 SVal Init = SB.makeZeroVal(SB.getContext().CharTy);
1419 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
1420 State = MallocMemAux(C, Call, TotalSize, Init, State, AF_Malloc);
1421 State = ProcessZeroAllocCheck(Call, 0, State);
1422 State = ProcessZeroAllocCheck(Call, 1, State);
1423 C.addTransition(State);
1424 }
1425
checkReallocN(const CallEvent & Call,CheckerContext & C) const1426 void MallocChecker::checkReallocN(const CallEvent &Call,
1427 CheckerContext &C) const {
1428 ProgramStateRef State = C.getState();
1429 State = ReallocMemAux(C, Call, /*ShouldFreeOnFail=*/false, State, AF_Malloc,
1430 /*SuffixWithN=*/true);
1431 State = ProcessZeroAllocCheck(Call, 1, State);
1432 State = ProcessZeroAllocCheck(Call, 2, State);
1433 C.addTransition(State);
1434 }
1435
checkOwnershipAttr(const CallEvent & Call,CheckerContext & C) const1436 void MallocChecker::checkOwnershipAttr(const CallEvent &Call,
1437 CheckerContext &C) const {
1438 ProgramStateRef State = C.getState();
1439 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
1440 if (!CE)
1441 return;
1442 const FunctionDecl *FD = C.getCalleeDecl(CE);
1443 if (!FD)
1444 return;
1445 if (ShouldIncludeOwnershipAnnotatedFunctions ||
1446 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
1447 // Check all the attributes, if there are any.
1448 // There can be multiple of these attributes.
1449 if (FD->hasAttrs())
1450 for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
1451 switch (I->getOwnKind()) {
1452 case OwnershipAttr::Returns:
1453 State = MallocMemReturnsAttr(C, Call, I, State);
1454 break;
1455 case OwnershipAttr::Takes:
1456 case OwnershipAttr::Holds:
1457 State = FreeMemAttr(C, Call, I, State);
1458 break;
1459 }
1460 }
1461 }
1462 C.addTransition(State);
1463 }
1464
checkPostCall(const CallEvent & Call,CheckerContext & C) const1465 void MallocChecker::checkPostCall(const CallEvent &Call,
1466 CheckerContext &C) const {
1467 if (C.wasInlined)
1468 return;
1469 if (!Call.getOriginExpr())
1470 return;
1471
1472 ProgramStateRef State = C.getState();
1473
1474 if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {
1475 (*Callback)(this, Call, C);
1476 return;
1477 }
1478
1479 if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {
1480 (*Callback)(this, Call, C);
1481 return;
1482 }
1483
1484 if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {
1485 (*Callback)(this, Call, C);
1486 return;
1487 }
1488
1489 if (isStandardNewDelete(Call)) {
1490 checkCXXNewOrCXXDelete(Call, C);
1491 return;
1492 }
1493
1494 checkOwnershipAttr(Call, C);
1495 }
1496
1497 // Performs a 0-sized allocations check.
ProcessZeroAllocCheck(const CallEvent & Call,const unsigned IndexOfSizeArg,ProgramStateRef State,std::optional<SVal> RetVal)1498 ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
1499 const CallEvent &Call, const unsigned IndexOfSizeArg, ProgramStateRef State,
1500 std::optional<SVal> RetVal) {
1501 if (!State)
1502 return nullptr;
1503
1504 if (!RetVal)
1505 RetVal = Call.getReturnValue();
1506
1507 const Expr *Arg = nullptr;
1508
1509 if (const CallExpr *CE = dyn_cast<CallExpr>(Call.getOriginExpr())) {
1510 Arg = CE->getArg(IndexOfSizeArg);
1511 } else if (const CXXNewExpr *NE =
1512 dyn_cast<CXXNewExpr>(Call.getOriginExpr())) {
1513 if (NE->isArray()) {
1514 Arg = *NE->getArraySize();
1515 } else {
1516 return State;
1517 }
1518 } else
1519 llvm_unreachable("not a CallExpr or CXXNewExpr");
1520
1521 assert(Arg);
1522
1523 auto DefArgVal =
1524 State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();
1525
1526 if (!DefArgVal)
1527 return State;
1528
1529 // Check if the allocation size is 0.
1530 ProgramStateRef TrueState, FalseState;
1531 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
1532 DefinedSVal Zero =
1533 SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
1534
1535 std::tie(TrueState, FalseState) =
1536 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
1537
1538 if (TrueState && !FalseState) {
1539 SymbolRef Sym = RetVal->getAsLocSymbol();
1540 if (!Sym)
1541 return State;
1542
1543 const RefState *RS = State->get<RegionState>(Sym);
1544 if (RS) {
1545 if (RS->isAllocated())
1546 return TrueState->set<RegionState>(Sym,
1547 RefState::getAllocatedOfSizeZero(RS));
1548 else
1549 return State;
1550 } else {
1551 // Case of zero-size realloc. Historically 'realloc(ptr, 0)' is treated as
1552 // 'free(ptr)' and the returned value from 'realloc(ptr, 0)' is not
1553 // tracked. Add zero-reallocated Sym to the state to catch references
1554 // to zero-allocated memory.
1555 return TrueState->add<ReallocSizeZeroSymbols>(Sym);
1556 }
1557 }
1558
1559 // Assume the value is non-zero going forward.
1560 assert(FalseState);
1561 return FalseState;
1562 }
1563
getDeepPointeeType(QualType T)1564 static QualType getDeepPointeeType(QualType T) {
1565 QualType Result = T, PointeeType = T->getPointeeType();
1566 while (!PointeeType.isNull()) {
1567 Result = PointeeType;
1568 PointeeType = PointeeType->getPointeeType();
1569 }
1570 return Result;
1571 }
1572
1573 /// \returns true if the constructor invoked by \p NE has an argument of a
1574 /// pointer/reference to a record type.
hasNonTrivialConstructorCall(const CXXNewExpr * NE)1575 static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) {
1576
1577 const CXXConstructExpr *ConstructE = NE->getConstructExpr();
1578 if (!ConstructE)
1579 return false;
1580
1581 if (!NE->getAllocatedType()->getAsCXXRecordDecl())
1582 return false;
1583
1584 const CXXConstructorDecl *CtorD = ConstructE->getConstructor();
1585
1586 // Iterate over the constructor parameters.
1587 for (const auto *CtorParam : CtorD->parameters()) {
1588
1589 QualType CtorParamPointeeT = CtorParam->getType()->getPointeeType();
1590 if (CtorParamPointeeT.isNull())
1591 continue;
1592
1593 CtorParamPointeeT = getDeepPointeeType(CtorParamPointeeT);
1594
1595 if (CtorParamPointeeT->getAsCXXRecordDecl())
1596 return true;
1597 }
1598
1599 return false;
1600 }
1601
1602 ProgramStateRef
processNewAllocation(const CXXAllocatorCall & Call,CheckerContext & C,AllocationFamily Family) const1603 MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,
1604 CheckerContext &C,
1605 AllocationFamily Family) const {
1606 if (!isStandardNewDelete(Call))
1607 return nullptr;
1608
1609 const CXXNewExpr *NE = Call.getOriginExpr();
1610 const ParentMap &PM = C.getLocationContext()->getParentMap();
1611 ProgramStateRef State = C.getState();
1612
1613 // Non-trivial constructors have a chance to escape 'this', but marking all
1614 // invocations of trivial constructors as escaped would cause too great of
1615 // reduction of true positives, so let's just do that for constructors that
1616 // have an argument of a pointer-to-record type.
1617 if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE))
1618 return State;
1619
1620 // The return value from operator new is bound to a specified initialization
1621 // value (if any) and we don't want to loose this value. So we call
1622 // MallocUpdateRefState() instead of MallocMemAux() which breaks the
1623 // existing binding.
1624 SVal Target = Call.getObjectUnderConstruction();
1625 State = MallocUpdateRefState(C, NE, State, Family, Target);
1626 State = ProcessZeroAllocCheck(Call, 0, State, Target);
1627 return State;
1628 }
1629
checkNewAllocator(const CXXAllocatorCall & Call,CheckerContext & C) const1630 void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,
1631 CheckerContext &C) const {
1632 if (!C.wasInlined) {
1633 ProgramStateRef State = processNewAllocation(
1634 Call, C,
1635 (Call.getOriginExpr()->isArray() ? AF_CXXNewArray : AF_CXXNew));
1636 C.addTransition(State);
1637 }
1638 }
1639
isKnownDeallocObjCMethodName(const ObjCMethodCall & Call)1640 static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
1641 // If the first selector piece is one of the names below, assume that the
1642 // object takes ownership of the memory, promising to eventually deallocate it
1643 // with free().
1644 // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
1645 // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
1646 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
1647 return FirstSlot == "dataWithBytesNoCopy" ||
1648 FirstSlot == "initWithBytesNoCopy" ||
1649 FirstSlot == "initWithCharactersNoCopy";
1650 }
1651
getFreeWhenDoneArg(const ObjCMethodCall & Call)1652 static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
1653 Selector S = Call.getSelector();
1654
1655 // FIXME: We should not rely on fully-constrained symbols being folded.
1656 for (unsigned i = 1; i < S.getNumArgs(); ++i)
1657 if (S.getNameForSlot(i).equals("freeWhenDone"))
1658 return !Call.getArgSVal(i).isZeroConstant();
1659
1660 return std::nullopt;
1661 }
1662
checkPostObjCMessage(const ObjCMethodCall & Call,CheckerContext & C) const1663 void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
1664 CheckerContext &C) const {
1665 if (C.wasInlined)
1666 return;
1667
1668 if (!isKnownDeallocObjCMethodName(Call))
1669 return;
1670
1671 if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
1672 if (!*FreeWhenDone)
1673 return;
1674
1675 if (Call.hasNonZeroCallbackArg())
1676 return;
1677
1678 bool IsKnownToBeAllocatedMemory;
1679 ProgramStateRef State =
1680 FreeMemAux(C, Call.getArgExpr(0), Call, C.getState(),
1681 /*Hold=*/true, IsKnownToBeAllocatedMemory, AF_Malloc,
1682 /*ReturnsNullOnFailure=*/true);
1683
1684 C.addTransition(State);
1685 }
1686
1687 ProgramStateRef
MallocMemReturnsAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const1688 MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
1689 const OwnershipAttr *Att,
1690 ProgramStateRef State) const {
1691 if (!State)
1692 return nullptr;
1693
1694 if (Att->getModule()->getName() != "malloc")
1695 return nullptr;
1696
1697 if (!Att->args().empty()) {
1698 return MallocMemAux(C, Call,
1699 Call.getArgExpr(Att->args_begin()->getASTIndex()),
1700 UndefinedVal(), State, AF_Malloc);
1701 }
1702 return MallocMemAux(C, Call, UnknownVal(), UndefinedVal(), State, AF_Malloc);
1703 }
1704
MallocMemAux(CheckerContext & C,const CallEvent & Call,const Expr * SizeEx,SVal Init,ProgramStateRef State,AllocationFamily Family)1705 ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1706 const CallEvent &Call,
1707 const Expr *SizeEx, SVal Init,
1708 ProgramStateRef State,
1709 AllocationFamily Family) {
1710 if (!State)
1711 return nullptr;
1712
1713 assert(SizeEx);
1714 return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);
1715 }
1716
MallocMemAux(CheckerContext & C,const CallEvent & Call,SVal Size,SVal Init,ProgramStateRef State,AllocationFamily Family)1717 ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
1718 const CallEvent &Call, SVal Size,
1719 SVal Init, ProgramStateRef State,
1720 AllocationFamily Family) {
1721 if (!State)
1722 return nullptr;
1723
1724 const Expr *CE = Call.getOriginExpr();
1725
1726 // We expect the malloc functions to return a pointer.
1727 if (!Loc::isLocType(CE->getType()))
1728 return nullptr;
1729
1730 // Bind the return value to the symbolic value from the heap region.
1731 // TODO: move use of this functions to an EvalCall callback, becasue
1732 // BindExpr() should'nt be used elsewhere.
1733 unsigned Count = C.blockCount();
1734 SValBuilder &SVB = C.getSValBuilder();
1735 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
1736 DefinedSVal RetVal =
1737 ((Family == AF_Alloca) ? SVB.getAllocaRegionVal(CE, LCtx, Count)
1738 : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count)
1739 .castAs<DefinedSVal>());
1740 State = State->BindExpr(CE, C.getLocationContext(), RetVal);
1741
1742 // Fill the region with the initialization value.
1743 State = State->bindDefaultInitial(RetVal, Init, LCtx);
1744
1745 // If Size is somehow undefined at this point, this line prevents a crash.
1746 if (Size.isUndef())
1747 Size = UnknownVal();
1748
1749 // Set the region's extent.
1750 State = setDynamicExtent(State, RetVal.getAsRegion(),
1751 Size.castAs<DefinedOrUnknownSVal>(), SVB);
1752
1753 return MallocUpdateRefState(C, CE, State, Family);
1754 }
1755
MallocUpdateRefState(CheckerContext & C,const Expr * E,ProgramStateRef State,AllocationFamily Family,std::optional<SVal> RetVal)1756 static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
1757 ProgramStateRef State,
1758 AllocationFamily Family,
1759 std::optional<SVal> RetVal) {
1760 if (!State)
1761 return nullptr;
1762
1763 // Get the return value.
1764 if (!RetVal)
1765 RetVal = C.getSVal(E);
1766
1767 // We expect the malloc functions to return a pointer.
1768 if (!RetVal->getAs<Loc>())
1769 return nullptr;
1770
1771 SymbolRef Sym = RetVal->getAsLocSymbol();
1772 // This is a return value of a function that was not inlined, such as malloc()
1773 // or new(). We've checked that in the caller. Therefore, it must be a symbol.
1774 assert(Sym);
1775
1776 // Set the symbol's state to Allocated.
1777 return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
1778 }
1779
FreeMemAttr(CheckerContext & C,const CallEvent & Call,const OwnershipAttr * Att,ProgramStateRef State) const1780 ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
1781 const CallEvent &Call,
1782 const OwnershipAttr *Att,
1783 ProgramStateRef State) const {
1784 if (!State)
1785 return nullptr;
1786
1787 if (Att->getModule()->getName() != "malloc")
1788 return nullptr;
1789
1790 bool IsKnownToBeAllocated = false;
1791
1792 for (const auto &Arg : Att->args()) {
1793 ProgramStateRef StateI =
1794 FreeMemAux(C, Call, State, Arg.getASTIndex(),
1795 Att->getOwnKind() == OwnershipAttr::Holds,
1796 IsKnownToBeAllocated, AF_Malloc);
1797 if (StateI)
1798 State = StateI;
1799 }
1800 return State;
1801 }
1802
FreeMemAux(CheckerContext & C,const CallEvent & Call,ProgramStateRef State,unsigned Num,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure) const1803 ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
1804 const CallEvent &Call,
1805 ProgramStateRef State, unsigned Num,
1806 bool Hold, bool &IsKnownToBeAllocated,
1807 AllocationFamily Family,
1808 bool ReturnsNullOnFailure) const {
1809 if (!State)
1810 return nullptr;
1811
1812 if (Call.getNumArgs() < (Num + 1))
1813 return nullptr;
1814
1815 return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,
1816 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);
1817 }
1818
1819 /// Checks if the previous call to free on the given symbol failed - if free
1820 /// failed, returns true. Also, returns the corresponding return value symbol.
didPreviousFreeFail(ProgramStateRef State,SymbolRef Sym,SymbolRef & RetStatusSymbol)1821 static bool didPreviousFreeFail(ProgramStateRef State,
1822 SymbolRef Sym, SymbolRef &RetStatusSymbol) {
1823 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
1824 if (Ret) {
1825 assert(*Ret && "We should not store the null return symbol");
1826 ConstraintManager &CMgr = State->getConstraintManager();
1827 ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret);
1828 RetStatusSymbol = *Ret;
1829 return FreeFailed.isConstrainedTrue();
1830 }
1831 return false;
1832 }
1833
printMemFnName(raw_ostream & os,CheckerContext & C,const Expr * E)1834 static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E) {
1835 if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
1836 // FIXME: This doesn't handle indirect calls.
1837 const FunctionDecl *FD = CE->getDirectCallee();
1838 if (!FD)
1839 return false;
1840
1841 os << *FD;
1842 if (!FD->isOverloadedOperator())
1843 os << "()";
1844 return true;
1845 }
1846
1847 if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
1848 if (Msg->isInstanceMessage())
1849 os << "-";
1850 else
1851 os << "+";
1852 Msg->getSelector().print(os);
1853 return true;
1854 }
1855
1856 if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
1857 os << "'"
1858 << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
1859 << "'";
1860 return true;
1861 }
1862
1863 if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
1864 os << "'"
1865 << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
1866 << "'";
1867 return true;
1868 }
1869
1870 return false;
1871 }
1872
printExpectedAllocName(raw_ostream & os,AllocationFamily Family)1873 static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family) {
1874
1875 switch(Family) {
1876 case AF_Malloc: os << "malloc()"; return;
1877 case AF_CXXNew: os << "'new'"; return;
1878 case AF_CXXNewArray: os << "'new[]'"; return;
1879 case AF_IfNameIndex: os << "'if_nameindex()'"; return;
1880 case AF_InnerBuffer: os << "container-specific allocator"; return;
1881 case AF_Alloca:
1882 case AF_None: llvm_unreachable("not a deallocation expression");
1883 }
1884 }
1885
printExpectedDeallocName(raw_ostream & os,AllocationFamily Family)1886 static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
1887 switch(Family) {
1888 case AF_Malloc: os << "free()"; return;
1889 case AF_CXXNew: os << "'delete'"; return;
1890 case AF_CXXNewArray: os << "'delete[]'"; return;
1891 case AF_IfNameIndex: os << "'if_freenameindex()'"; return;
1892 case AF_InnerBuffer: os << "container-specific deallocator"; return;
1893 case AF_Alloca:
1894 case AF_None: llvm_unreachable("suspicious argument");
1895 }
1896 }
1897
FreeMemAux(CheckerContext & C,const Expr * ArgExpr,const CallEvent & Call,ProgramStateRef State,bool Hold,bool & IsKnownToBeAllocated,AllocationFamily Family,bool ReturnsNullOnFailure) const1898 ProgramStateRef MallocChecker::FreeMemAux(
1899 CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
1900 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
1901 AllocationFamily Family, bool ReturnsNullOnFailure) const {
1902
1903 if (!State)
1904 return nullptr;
1905
1906 SVal ArgVal = C.getSVal(ArgExpr);
1907 if (!isa<DefinedOrUnknownSVal>(ArgVal))
1908 return nullptr;
1909 DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
1910
1911 // Check for null dereferences.
1912 if (!isa<Loc>(location))
1913 return nullptr;
1914
1915 // The explicit NULL case, no operation is performed.
1916 ProgramStateRef notNullState, nullState;
1917 std::tie(notNullState, nullState) = State->assume(location);
1918 if (nullState && !notNullState)
1919 return nullptr;
1920
1921 // Unknown values could easily be okay
1922 // Undefined values are handled elsewhere
1923 if (ArgVal.isUnknownOrUndef())
1924 return nullptr;
1925
1926 const MemRegion *R = ArgVal.getAsRegion();
1927 const Expr *ParentExpr = Call.getOriginExpr();
1928
1929 // NOTE: We detected a bug, but the checker under whose name we would emit the
1930 // error could be disabled. Generally speaking, the MallocChecker family is an
1931 // integral part of the Static Analyzer, and disabling any part of it should
1932 // only be done under exceptional circumstances, such as frequent false
1933 // positives. If this is the case, we can reasonably believe that there are
1934 // serious faults in our understanding of the source code, and even if we
1935 // don't emit an warning, we should terminate further analysis with a sink
1936 // node.
1937
1938 // Nonlocs can't be freed, of course.
1939 // Non-region locations (labels and fixed addresses) also shouldn't be freed.
1940 if (!R) {
1941 // Exception:
1942 // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source
1943 // code. In that case, the ZERO_SIZE_PTR defines a special value used for a
1944 // zero-sized memory block which is allowed to be freed, despite not being a
1945 // null pointer.
1946 if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))
1947 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1948 Family);
1949 return nullptr;
1950 }
1951
1952 R = R->StripCasts();
1953
1954 // Blocks might show up as heap data, but should not be free()d
1955 if (isa<BlockDataRegion>(R)) {
1956 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1957 Family);
1958 return nullptr;
1959 }
1960
1961 const MemSpaceRegion *MS = R->getMemorySpace();
1962
1963 // Parameters, locals, statics, globals, and memory returned by
1964 // __builtin_alloca() shouldn't be freed.
1965 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
1966 // Regions returned by malloc() are represented by SymbolicRegion objects
1967 // within HeapSpaceRegion. Of course, free() can work on memory allocated
1968 // outside the current function, so UnknownSpaceRegion is also a
1969 // possibility here.
1970
1971 if (isa<AllocaRegion>(R))
1972 HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
1973 else
1974 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
1975 Family);
1976
1977 return nullptr;
1978 }
1979
1980 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
1981 // Various cases could lead to non-symbol values here.
1982 // For now, ignore them.
1983 if (!SrBase)
1984 return nullptr;
1985
1986 SymbolRef SymBase = SrBase->getSymbol();
1987 const RefState *RsBase = State->get<RegionState>(SymBase);
1988 SymbolRef PreviousRetStatusSymbol = nullptr;
1989
1990 IsKnownToBeAllocated =
1991 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
1992
1993 if (RsBase) {
1994
1995 // Memory returned by alloca() shouldn't be freed.
1996 if (RsBase->getAllocationFamily() == AF_Alloca) {
1997 HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
1998 return nullptr;
1999 }
2000
2001 // Check for double free first.
2002 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&
2003 !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
2004 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
2005 SymBase, PreviousRetStatusSymbol);
2006 return nullptr;
2007
2008 // If the pointer is allocated or escaped, but we are now trying to free it,
2009 // check that the call to free is proper.
2010 } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
2011 RsBase->isEscaped()) {
2012
2013 // Check if an expected deallocation function matches the real one.
2014 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;
2015 if (!DeallocMatchesAlloc) {
2016 HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,
2017 RsBase, SymBase, Hold);
2018 return nullptr;
2019 }
2020
2021 // Check if the memory location being freed is the actual location
2022 // allocated, or an offset.
2023 RegionOffset Offset = R->getAsOffset();
2024 if (Offset.isValid() &&
2025 !Offset.hasSymbolicOffset() &&
2026 Offset.getOffset() != 0) {
2027 const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
2028 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2029 Family, AllocExpr);
2030 return nullptr;
2031 }
2032 }
2033 }
2034
2035 if (SymBase->getType()->isFunctionPointerType()) {
2036 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
2037 Family);
2038 return nullptr;
2039 }
2040
2041 // Clean out the info on previous call to free return info.
2042 State = State->remove<FreeReturnValue>(SymBase);
2043
2044 // Keep track of the return value. If it is NULL, we will know that free
2045 // failed.
2046 if (ReturnsNullOnFailure) {
2047 SVal RetVal = C.getSVal(ParentExpr);
2048 SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
2049 if (RetStatusSymbol) {
2050 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
2051 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
2052 }
2053 }
2054
2055 // If we don't know anything about this symbol, a free on it may be totally
2056 // valid. If this is the case, lets assume that the allocation family of the
2057 // freeing function is the same as the symbols allocation family, and go with
2058 // that.
2059 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));
2060
2061 // Normal free.
2062 if (Hold)
2063 return State->set<RegionState>(SymBase,
2064 RefState::getRelinquished(Family,
2065 ParentExpr));
2066
2067 return State->set<RegionState>(SymBase,
2068 RefState::getReleased(Family, ParentExpr));
2069 }
2070
2071 std::optional<MallocChecker::CheckKind>
getCheckIfTracked(AllocationFamily Family,bool IsALeakCheck) const2072 MallocChecker::getCheckIfTracked(AllocationFamily Family,
2073 bool IsALeakCheck) const {
2074 switch (Family) {
2075 case AF_Malloc:
2076 case AF_Alloca:
2077 case AF_IfNameIndex: {
2078 if (ChecksEnabled[CK_MallocChecker])
2079 return CK_MallocChecker;
2080 return std::nullopt;
2081 }
2082 case AF_CXXNew:
2083 case AF_CXXNewArray: {
2084 if (IsALeakCheck) {
2085 if (ChecksEnabled[CK_NewDeleteLeaksChecker])
2086 return CK_NewDeleteLeaksChecker;
2087 }
2088 else {
2089 if (ChecksEnabled[CK_NewDeleteChecker])
2090 return CK_NewDeleteChecker;
2091 }
2092 return std::nullopt;
2093 }
2094 case AF_InnerBuffer: {
2095 if (ChecksEnabled[CK_InnerPointerChecker])
2096 return CK_InnerPointerChecker;
2097 return std::nullopt;
2098 }
2099 case AF_None: {
2100 llvm_unreachable("no family");
2101 }
2102 }
2103 llvm_unreachable("unhandled family");
2104 }
2105
2106 std::optional<MallocChecker::CheckKind>
getCheckIfTracked(CheckerContext & C,SymbolRef Sym,bool IsALeakCheck) const2107 MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
2108 bool IsALeakCheck) const {
2109 if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
2110 return CK_MallocChecker;
2111
2112 const RefState *RS = C.getState()->get<RegionState>(Sym);
2113 assert(RS);
2114 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);
2115 }
2116
SummarizeValue(raw_ostream & os,SVal V)2117 bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
2118 if (std::optional<nonloc::ConcreteInt> IntVal =
2119 V.getAs<nonloc::ConcreteInt>())
2120 os << "an integer (" << IntVal->getValue() << ")";
2121 else if (std::optional<loc::ConcreteInt> ConstAddr =
2122 V.getAs<loc::ConcreteInt>())
2123 os << "a constant address (" << ConstAddr->getValue() << ")";
2124 else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
2125 os << "the address of the label '" << Label->getLabel()->getName() << "'";
2126 else
2127 return false;
2128
2129 return true;
2130 }
2131
SummarizeRegion(raw_ostream & os,const MemRegion * MR)2132 bool MallocChecker::SummarizeRegion(raw_ostream &os,
2133 const MemRegion *MR) {
2134 switch (MR->getKind()) {
2135 case MemRegion::FunctionCodeRegionKind: {
2136 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
2137 if (FD)
2138 os << "the address of the function '" << *FD << '\'';
2139 else
2140 os << "the address of a function";
2141 return true;
2142 }
2143 case MemRegion::BlockCodeRegionKind:
2144 os << "block text";
2145 return true;
2146 case MemRegion::BlockDataRegionKind:
2147 // FIXME: where the block came from?
2148 os << "a block";
2149 return true;
2150 default: {
2151 const MemSpaceRegion *MS = MR->getMemorySpace();
2152
2153 if (isa<StackLocalsSpaceRegion>(MS)) {
2154 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2155 const VarDecl *VD;
2156 if (VR)
2157 VD = VR->getDecl();
2158 else
2159 VD = nullptr;
2160
2161 if (VD)
2162 os << "the address of the local variable '" << VD->getName() << "'";
2163 else
2164 os << "the address of a local stack variable";
2165 return true;
2166 }
2167
2168 if (isa<StackArgumentsSpaceRegion>(MS)) {
2169 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2170 const VarDecl *VD;
2171 if (VR)
2172 VD = VR->getDecl();
2173 else
2174 VD = nullptr;
2175
2176 if (VD)
2177 os << "the address of the parameter '" << VD->getName() << "'";
2178 else
2179 os << "the address of a parameter";
2180 return true;
2181 }
2182
2183 if (isa<GlobalsSpaceRegion>(MS)) {
2184 const VarRegion *VR = dyn_cast<VarRegion>(MR);
2185 const VarDecl *VD;
2186 if (VR)
2187 VD = VR->getDecl();
2188 else
2189 VD = nullptr;
2190
2191 if (VD) {
2192 if (VD->isStaticLocal())
2193 os << "the address of the static variable '" << VD->getName() << "'";
2194 else
2195 os << "the address of the global variable '" << VD->getName() << "'";
2196 } else
2197 os << "the address of a global variable";
2198 return true;
2199 }
2200
2201 return false;
2202 }
2203 }
2204 }
2205
HandleNonHeapDealloc(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family) const2206 void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
2207 SourceRange Range,
2208 const Expr *DeallocExpr,
2209 AllocationFamily Family) const {
2210
2211 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2212 C.addSink();
2213 return;
2214 }
2215
2216 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2217 if (!CheckKind)
2218 return;
2219
2220 if (ExplodedNode *N = C.generateErrorNode()) {
2221 if (!BT_BadFree[*CheckKind])
2222 BT_BadFree[*CheckKind].reset(new BugType(
2223 CheckNames[*CheckKind], "Bad free", categories::MemoryError));
2224
2225 SmallString<100> buf;
2226 llvm::raw_svector_ostream os(buf);
2227
2228 const MemRegion *MR = ArgVal.getAsRegion();
2229 while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2230 MR = ER->getSuperRegion();
2231
2232 os << "Argument to ";
2233 if (!printMemFnName(os, C, DeallocExpr))
2234 os << "deallocator";
2235
2236 os << " is ";
2237 bool Summarized = MR ? SummarizeRegion(os, MR)
2238 : SummarizeValue(os, ArgVal);
2239 if (Summarized)
2240 os << ", which is not memory allocated by ";
2241 else
2242 os << "not memory allocated by ";
2243
2244 printExpectedAllocName(os, Family);
2245
2246 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2247 os.str(), N);
2248 R->markInteresting(MR);
2249 R->addRange(Range);
2250 C.emitReport(std::move(R));
2251 }
2252 }
2253
HandleFreeAlloca(CheckerContext & C,SVal ArgVal,SourceRange Range) const2254 void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
2255 SourceRange Range) const {
2256
2257 std::optional<MallocChecker::CheckKind> CheckKind;
2258
2259 if (ChecksEnabled[CK_MallocChecker])
2260 CheckKind = CK_MallocChecker;
2261 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])
2262 CheckKind = CK_MismatchedDeallocatorChecker;
2263 else {
2264 C.addSink();
2265 return;
2266 }
2267
2268 if (ExplodedNode *N = C.generateErrorNode()) {
2269 if (!BT_FreeAlloca[*CheckKind])
2270 BT_FreeAlloca[*CheckKind].reset(new BugType(
2271 CheckNames[*CheckKind], "Free alloca()", categories::MemoryError));
2272
2273 auto R = std::make_unique<PathSensitiveBugReport>(
2274 *BT_FreeAlloca[*CheckKind],
2275 "Memory allocated by alloca() should not be deallocated", N);
2276 R->markInteresting(ArgVal.getAsRegion());
2277 R->addRange(Range);
2278 C.emitReport(std::move(R));
2279 }
2280 }
2281
HandleMismatchedDealloc(CheckerContext & C,SourceRange Range,const Expr * DeallocExpr,const RefState * RS,SymbolRef Sym,bool OwnershipTransferred) const2282 void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,
2283 SourceRange Range,
2284 const Expr *DeallocExpr,
2285 const RefState *RS, SymbolRef Sym,
2286 bool OwnershipTransferred) const {
2287
2288 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
2289 C.addSink();
2290 return;
2291 }
2292
2293 if (ExplodedNode *N = C.generateErrorNode()) {
2294 if (!BT_MismatchedDealloc)
2295 BT_MismatchedDealloc.reset(
2296 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],
2297 "Bad deallocator", categories::MemoryError));
2298
2299 SmallString<100> buf;
2300 llvm::raw_svector_ostream os(buf);
2301
2302 const Expr *AllocExpr = cast<Expr>(RS->getStmt());
2303 SmallString<20> AllocBuf;
2304 llvm::raw_svector_ostream AllocOs(AllocBuf);
2305 SmallString<20> DeallocBuf;
2306 llvm::raw_svector_ostream DeallocOs(DeallocBuf);
2307
2308 if (OwnershipTransferred) {
2309 if (printMemFnName(DeallocOs, C, DeallocExpr))
2310 os << DeallocOs.str() << " cannot";
2311 else
2312 os << "Cannot";
2313
2314 os << " take ownership of memory";
2315
2316 if (printMemFnName(AllocOs, C, AllocExpr))
2317 os << " allocated by " << AllocOs.str();
2318 } else {
2319 os << "Memory";
2320 if (printMemFnName(AllocOs, C, AllocExpr))
2321 os << " allocated by " << AllocOs.str();
2322
2323 os << " should be deallocated by ";
2324 printExpectedDeallocName(os, RS->getAllocationFamily());
2325
2326 if (printMemFnName(DeallocOs, C, DeallocExpr))
2327 os << ", not " << DeallocOs.str();
2328 }
2329
2330 auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
2331 os.str(), N);
2332 R->markInteresting(Sym);
2333 R->addRange(Range);
2334 R->addVisitor<MallocBugVisitor>(Sym);
2335 C.emitReport(std::move(R));
2336 }
2337 }
2338
HandleOffsetFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * DeallocExpr,AllocationFamily Family,const Expr * AllocExpr) const2339 void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
2340 SourceRange Range, const Expr *DeallocExpr,
2341 AllocationFamily Family,
2342 const Expr *AllocExpr) const {
2343
2344 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2345 C.addSink();
2346 return;
2347 }
2348
2349 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2350 if (!CheckKind)
2351 return;
2352
2353 ExplodedNode *N = C.generateErrorNode();
2354 if (!N)
2355 return;
2356
2357 if (!BT_OffsetFree[*CheckKind])
2358 BT_OffsetFree[*CheckKind].reset(new BugType(
2359 CheckNames[*CheckKind], "Offset free", categories::MemoryError));
2360
2361 SmallString<100> buf;
2362 llvm::raw_svector_ostream os(buf);
2363 SmallString<20> AllocNameBuf;
2364 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
2365
2366 const MemRegion *MR = ArgVal.getAsRegion();
2367 assert(MR && "Only MemRegion based symbols can have offset free errors");
2368
2369 RegionOffset Offset = MR->getAsOffset();
2370 assert((Offset.isValid() &&
2371 !Offset.hasSymbolicOffset() &&
2372 Offset.getOffset() != 0) &&
2373 "Only symbols with a valid offset can have offset free errors");
2374
2375 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
2376
2377 os << "Argument to ";
2378 if (!printMemFnName(os, C, DeallocExpr))
2379 os << "deallocator";
2380 os << " is offset by "
2381 << offsetBytes
2382 << " "
2383 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
2384 << " from the start of ";
2385 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))
2386 os << "memory allocated by " << AllocNameOs.str();
2387 else
2388 os << "allocated memory";
2389
2390 auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
2391 os.str(), N);
2392 R->markInteresting(MR->getBaseRegion());
2393 R->addRange(Range);
2394 C.emitReport(std::move(R));
2395 }
2396
HandleUseAfterFree(CheckerContext & C,SourceRange Range,SymbolRef Sym) const2397 void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
2398 SymbolRef Sym) const {
2399
2400 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&
2401 !ChecksEnabled[CK_InnerPointerChecker]) {
2402 C.addSink();
2403 return;
2404 }
2405
2406 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2407 if (!CheckKind)
2408 return;
2409
2410 if (ExplodedNode *N = C.generateErrorNode()) {
2411 if (!BT_UseFree[*CheckKind])
2412 BT_UseFree[*CheckKind].reset(new BugType(
2413 CheckNames[*CheckKind], "Use-after-free", categories::MemoryError));
2414
2415 AllocationFamily AF =
2416 C.getState()->get<RegionState>(Sym)->getAllocationFamily();
2417
2418 auto R = std::make_unique<PathSensitiveBugReport>(
2419 *BT_UseFree[*CheckKind],
2420 AF == AF_InnerBuffer
2421 ? "Inner pointer of container used after re/deallocation"
2422 : "Use of memory after it is freed",
2423 N);
2424
2425 R->markInteresting(Sym);
2426 R->addRange(Range);
2427 R->addVisitor<MallocBugVisitor>(Sym);
2428
2429 if (AF == AF_InnerBuffer)
2430 R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
2431
2432 C.emitReport(std::move(R));
2433 }
2434 }
2435
HandleDoubleFree(CheckerContext & C,SourceRange Range,bool Released,SymbolRef Sym,SymbolRef PrevSym) const2436 void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2437 bool Released, SymbolRef Sym,
2438 SymbolRef PrevSym) const {
2439
2440 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2441 C.addSink();
2442 return;
2443 }
2444
2445 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2446 if (!CheckKind)
2447 return;
2448
2449 if (ExplodedNode *N = C.generateErrorNode()) {
2450 if (!BT_DoubleFree[*CheckKind])
2451 BT_DoubleFree[*CheckKind].reset(new BugType(
2452 CheckNames[*CheckKind], "Double free", categories::MemoryError));
2453
2454 auto R = std::make_unique<PathSensitiveBugReport>(
2455 *BT_DoubleFree[*CheckKind],
2456 (Released ? "Attempt to free released memory"
2457 : "Attempt to free non-owned memory"),
2458 N);
2459 R->addRange(Range);
2460 R->markInteresting(Sym);
2461 if (PrevSym)
2462 R->markInteresting(PrevSym);
2463 R->addVisitor<MallocBugVisitor>(Sym);
2464 C.emitReport(std::move(R));
2465 }
2466 }
2467
HandleDoubleDelete(CheckerContext & C,SymbolRef Sym) const2468 void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
2469
2470 if (!ChecksEnabled[CK_NewDeleteChecker]) {
2471 C.addSink();
2472 return;
2473 }
2474
2475 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2476 if (!CheckKind)
2477 return;
2478
2479 if (ExplodedNode *N = C.generateErrorNode()) {
2480 if (!BT_DoubleDelete)
2481 BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],
2482 "Double delete",
2483 categories::MemoryError));
2484
2485 auto R = std::make_unique<PathSensitiveBugReport>(
2486 *BT_DoubleDelete, "Attempt to delete released memory", N);
2487
2488 R->markInteresting(Sym);
2489 R->addVisitor<MallocBugVisitor>(Sym);
2490 C.emitReport(std::move(R));
2491 }
2492 }
2493
HandleUseZeroAlloc(CheckerContext & C,SourceRange Range,SymbolRef Sym) const2494 void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
2495 SymbolRef Sym) const {
2496
2497 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {
2498 C.addSink();
2499 return;
2500 }
2501
2502 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
2503
2504 if (!CheckKind)
2505 return;
2506
2507 if (ExplodedNode *N = C.generateErrorNode()) {
2508 if (!BT_UseZerroAllocated[*CheckKind])
2509 BT_UseZerroAllocated[*CheckKind].reset(
2510 new BugType(CheckNames[*CheckKind], "Use of zero allocated",
2511 categories::MemoryError));
2512
2513 auto R = std::make_unique<PathSensitiveBugReport>(
2514 *BT_UseZerroAllocated[*CheckKind],
2515 "Use of memory allocated with size zero", N);
2516
2517 R->addRange(Range);
2518 if (Sym) {
2519 R->markInteresting(Sym);
2520 R->addVisitor<MallocBugVisitor>(Sym);
2521 }
2522 C.emitReport(std::move(R));
2523 }
2524 }
2525
HandleFunctionPtrFree(CheckerContext & C,SVal ArgVal,SourceRange Range,const Expr * FreeExpr,AllocationFamily Family) const2526 void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
2527 SourceRange Range,
2528 const Expr *FreeExpr,
2529 AllocationFamily Family) const {
2530 if (!ChecksEnabled[CK_MallocChecker]) {
2531 C.addSink();
2532 return;
2533 }
2534
2535 std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
2536 if (!CheckKind)
2537 return;
2538
2539 if (ExplodedNode *N = C.generateErrorNode()) {
2540 if (!BT_BadFree[*CheckKind])
2541 BT_BadFree[*CheckKind].reset(new BugType(
2542 CheckNames[*CheckKind], "Bad free", categories::MemoryError));
2543
2544 SmallString<100> Buf;
2545 llvm::raw_svector_ostream Os(Buf);
2546
2547 const MemRegion *MR = ArgVal.getAsRegion();
2548 while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
2549 MR = ER->getSuperRegion();
2550
2551 Os << "Argument to ";
2552 if (!printMemFnName(Os, C, FreeExpr))
2553 Os << "deallocator";
2554
2555 Os << " is a function pointer";
2556
2557 auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
2558 Os.str(), N);
2559 R->markInteresting(MR);
2560 R->addRange(Range);
2561 C.emitReport(std::move(R));
2562 }
2563 }
2564
2565 ProgramStateRef
ReallocMemAux(CheckerContext & C,const CallEvent & Call,bool ShouldFreeOnFail,ProgramStateRef State,AllocationFamily Family,bool SuffixWithN) const2566 MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,
2567 bool ShouldFreeOnFail, ProgramStateRef State,
2568 AllocationFamily Family, bool SuffixWithN) const {
2569 if (!State)
2570 return nullptr;
2571
2572 const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
2573
2574 if (SuffixWithN && CE->getNumArgs() < 3)
2575 return nullptr;
2576 else if (CE->getNumArgs() < 2)
2577 return nullptr;
2578
2579 const Expr *arg0Expr = CE->getArg(0);
2580 SVal Arg0Val = C.getSVal(arg0Expr);
2581 if (!isa<DefinedOrUnknownSVal>(Arg0Val))
2582 return nullptr;
2583 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
2584
2585 SValBuilder &svalBuilder = C.getSValBuilder();
2586
2587 DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(
2588 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));
2589
2590 // Get the size argument.
2591 const Expr *Arg1 = CE->getArg(1);
2592
2593 // Get the value of the size argument.
2594 SVal TotalSize = C.getSVal(Arg1);
2595 if (SuffixWithN)
2596 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));
2597 if (!isa<DefinedOrUnknownSVal>(TotalSize))
2598 return nullptr;
2599
2600 // Compare the size argument to 0.
2601 DefinedOrUnknownSVal SizeZero =
2602 svalBuilder.evalEQ(State, TotalSize.castAs<DefinedOrUnknownSVal>(),
2603 svalBuilder.makeIntValWithWidth(
2604 svalBuilder.getContext().getSizeType(), 0));
2605
2606 ProgramStateRef StatePtrIsNull, StatePtrNotNull;
2607 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);
2608 ProgramStateRef StateSizeIsZero, StateSizeNotZero;
2609 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);
2610 // We only assume exceptional states if they are definitely true; if the
2611 // state is under-constrained, assume regular realloc behavior.
2612 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
2613 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
2614
2615 // If the ptr is NULL and the size is not 0, the call is equivalent to
2616 // malloc(size).
2617 if (PrtIsNull && !SizeIsZero) {
2618 ProgramStateRef stateMalloc = MallocMemAux(
2619 C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);
2620 return stateMalloc;
2621 }
2622
2623 if (PrtIsNull && SizeIsZero)
2624 return State;
2625
2626 assert(!PrtIsNull);
2627
2628 bool IsKnownToBeAllocated = false;
2629
2630 // If the size is 0, free the memory.
2631 if (SizeIsZero)
2632 // The semantics of the return value are:
2633 // If size was equal to 0, either NULL or a pointer suitable to be passed
2634 // to free() is returned. We just free the input pointer and do not add
2635 // any constrains on the output pointer.
2636 if (ProgramStateRef stateFree = FreeMemAux(
2637 C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))
2638 return stateFree;
2639
2640 // Default behavior.
2641 if (ProgramStateRef stateFree =
2642 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {
2643
2644 ProgramStateRef stateRealloc =
2645 MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);
2646 if (!stateRealloc)
2647 return nullptr;
2648
2649 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
2650 if (ShouldFreeOnFail)
2651 Kind = OAR_FreeOnFailure;
2652 else if (!IsKnownToBeAllocated)
2653 Kind = OAR_DoNotTrackAfterFailure;
2654
2655 // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size).
2656 SymbolRef FromPtr = arg0Val.getLocSymbolInBase();
2657 SVal RetVal = C.getSVal(CE);
2658 SymbolRef ToPtr = RetVal.getAsSymbol();
2659 assert(FromPtr && ToPtr &&
2660 "By this point, FreeMemAux and MallocMemAux should have checked "
2661 "whether the argument or the return value is symbolic!");
2662
2663 // Record the info about the reallocated symbol so that we could properly
2664 // process failed reallocation.
2665 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr,
2666 ReallocPair(FromPtr, Kind));
2667 // The reallocated symbol should stay alive for as long as the new symbol.
2668 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);
2669 return stateRealloc;
2670 }
2671 return nullptr;
2672 }
2673
CallocMem(CheckerContext & C,const CallEvent & Call,ProgramStateRef State)2674 ProgramStateRef MallocChecker::CallocMem(CheckerContext &C,
2675 const CallEvent &Call,
2676 ProgramStateRef State) {
2677 if (!State)
2678 return nullptr;
2679
2680 if (Call.getNumArgs() < 2)
2681 return nullptr;
2682
2683 SValBuilder &svalBuilder = C.getSValBuilder();
2684 SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
2685 SVal TotalSize =
2686 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));
2687
2688 return MallocMemAux(C, Call, TotalSize, zeroVal, State, AF_Malloc);
2689 }
2690
getAllocationSite(const ExplodedNode * N,SymbolRef Sym,CheckerContext & C)2691 MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
2692 SymbolRef Sym,
2693 CheckerContext &C) {
2694 const LocationContext *LeakContext = N->getLocationContext();
2695 // Walk the ExplodedGraph backwards and find the first node that referred to
2696 // the tracked symbol.
2697 const ExplodedNode *AllocNode = N;
2698 const MemRegion *ReferenceRegion = nullptr;
2699
2700 while (N) {
2701 ProgramStateRef State = N->getState();
2702 if (!State->get<RegionState>(Sym))
2703 break;
2704
2705 // Find the most recent expression bound to the symbol in the current
2706 // context.
2707 if (!ReferenceRegion) {
2708 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {
2709 SVal Val = State->getSVal(MR);
2710 if (Val.getAsLocSymbol() == Sym) {
2711 const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>();
2712 // Do not show local variables belonging to a function other than
2713 // where the error is reported.
2714 if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame()))
2715 ReferenceRegion = MR;
2716 }
2717 }
2718 }
2719
2720 // Allocation node, is the last node in the current or parent context in
2721 // which the symbol was tracked.
2722 const LocationContext *NContext = N->getLocationContext();
2723 if (NContext == LeakContext ||
2724 NContext->isParentOf(LeakContext))
2725 AllocNode = N;
2726 N = N->pred_empty() ? nullptr : *(N->pred_begin());
2727 }
2728
2729 return LeakInfo(AllocNode, ReferenceRegion);
2730 }
2731
HandleLeak(SymbolRef Sym,ExplodedNode * N,CheckerContext & C) const2732 void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
2733 CheckerContext &C) const {
2734
2735 if (!ChecksEnabled[CK_MallocChecker] &&
2736 !ChecksEnabled[CK_NewDeleteLeaksChecker])
2737 return;
2738
2739 const RefState *RS = C.getState()->get<RegionState>(Sym);
2740 assert(RS && "cannot leak an untracked symbol");
2741 AllocationFamily Family = RS->getAllocationFamily();
2742
2743 if (Family == AF_Alloca)
2744 return;
2745
2746 std::optional<MallocChecker::CheckKind> CheckKind =
2747 getCheckIfTracked(Family, true);
2748
2749 if (!CheckKind)
2750 return;
2751
2752 assert(N);
2753 if (!BT_Leak[*CheckKind]) {
2754 // Leaks should not be reported if they are post-dominated by a sink:
2755 // (1) Sinks are higher importance bugs.
2756 // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending
2757 // with __noreturn functions such as assert() or exit(). We choose not
2758 // to report leaks on such paths.
2759 BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",
2760 categories::MemoryError,
2761 /*SuppressOnSink=*/true));
2762 }
2763
2764 // Most bug reports are cached at the location where they occurred.
2765 // With leaks, we want to unique them by the location where they were
2766 // allocated, and only report a single path.
2767 PathDiagnosticLocation LocUsedForUniqueing;
2768 const ExplodedNode *AllocNode = nullptr;
2769 const MemRegion *Region = nullptr;
2770 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
2771
2772 const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
2773 if (AllocationStmt)
2774 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
2775 C.getSourceManager(),
2776 AllocNode->getLocationContext());
2777
2778 SmallString<200> buf;
2779 llvm::raw_svector_ostream os(buf);
2780 if (Region && Region->canPrintPretty()) {
2781 os << "Potential leak of memory pointed to by ";
2782 Region->printPretty(os);
2783 } else {
2784 os << "Potential memory leak";
2785 }
2786
2787 auto R = std::make_unique<PathSensitiveBugReport>(
2788 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
2789 AllocNode->getLocationContext()->getDecl());
2790 R->markInteresting(Sym);
2791 R->addVisitor<MallocBugVisitor>(Sym, true);
2792 if (ShouldRegisterNoOwnershipChangeVisitor)
2793 R->addVisitor<NoOwnershipChangeVisitor>(Sym, this);
2794 C.emitReport(std::move(R));
2795 }
2796
checkDeadSymbols(SymbolReaper & SymReaper,CheckerContext & C) const2797 void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
2798 CheckerContext &C) const
2799 {
2800 ProgramStateRef state = C.getState();
2801 RegionStateTy OldRS = state->get<RegionState>();
2802 RegionStateTy::Factory &F = state->get_context<RegionState>();
2803
2804 RegionStateTy RS = OldRS;
2805 SmallVector<SymbolRef, 2> Errors;
2806 for (auto [Sym, State] : RS) {
2807 if (SymReaper.isDead(Sym)) {
2808 if (State.isAllocated() || State.isAllocatedOfSizeZero())
2809 Errors.push_back(Sym);
2810 // Remove the dead symbol from the map.
2811 RS = F.remove(RS, Sym);
2812 }
2813 }
2814
2815 if (RS == OldRS) {
2816 // We shouldn't have touched other maps yet.
2817 assert(state->get<ReallocPairs>() ==
2818 C.getState()->get<ReallocPairs>());
2819 assert(state->get<FreeReturnValue>() ==
2820 C.getState()->get<FreeReturnValue>());
2821 return;
2822 }
2823
2824 // Cleanup the Realloc Pairs Map.
2825 ReallocPairsTy RP = state->get<ReallocPairs>();
2826 for (auto [Sym, ReallocPair] : RP) {
2827 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {
2828 state = state->remove<ReallocPairs>(Sym);
2829 }
2830 }
2831
2832 // Cleanup the FreeReturnValue Map.
2833 FreeReturnValueTy FR = state->get<FreeReturnValue>();
2834 for (auto [Sym, RetSym] : FR) {
2835 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {
2836 state = state->remove<FreeReturnValue>(Sym);
2837 }
2838 }
2839
2840 // Generate leak node.
2841 ExplodedNode *N = C.getPredecessor();
2842 if (!Errors.empty()) {
2843 static CheckerProgramPointTag Tag("MallocChecker", "DeadSymbolsLeak");
2844 N = C.generateNonFatalErrorNode(C.getState(), &Tag);
2845 if (N) {
2846 for (SymbolRef Sym : Errors) {
2847 HandleLeak(Sym, N, C);
2848 }
2849 }
2850 }
2851
2852 C.addTransition(state->set<RegionState>(RS), N);
2853 }
2854
checkPreCall(const CallEvent & Call,CheckerContext & C) const2855 void MallocChecker::checkPreCall(const CallEvent &Call,
2856 CheckerContext &C) const {
2857
2858 if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
2859 const CXXDeleteExpr *DE = DC->getOriginExpr();
2860
2861 if (!ChecksEnabled[CK_NewDeleteChecker])
2862 if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
2863 checkUseAfterFree(Sym, C, DE->getArgument());
2864
2865 if (!isStandardNewDelete(DC->getDecl()))
2866 return;
2867
2868 ProgramStateRef State = C.getState();
2869 bool IsKnownToBeAllocated;
2870 State = FreeMemAux(C, DE->getArgument(), Call, State,
2871 /*Hold*/ false, IsKnownToBeAllocated,
2872 (DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));
2873
2874 C.addTransition(State);
2875 return;
2876 }
2877
2878 if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
2879 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();
2880 if (!Sym || checkDoubleDelete(Sym, C))
2881 return;
2882 }
2883
2884 // We will check for double free in the post visit.
2885 if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) {
2886 const FunctionDecl *FD = FC->getDecl();
2887 if (!FD)
2888 return;
2889
2890 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))
2891 return;
2892 }
2893
2894 // Check if the callee of a method is deleted.
2895 if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
2896 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();
2897 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))
2898 return;
2899 }
2900
2901 // Check arguments for being used after free.
2902 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
2903 SVal ArgSVal = Call.getArgSVal(I);
2904 if (isa<Loc>(ArgSVal)) {
2905 SymbolRef Sym = ArgSVal.getAsSymbol();
2906 if (!Sym)
2907 continue;
2908 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
2909 return;
2910 }
2911 }
2912 }
2913
checkPreStmt(const ReturnStmt * S,CheckerContext & C) const2914 void MallocChecker::checkPreStmt(const ReturnStmt *S,
2915 CheckerContext &C) const {
2916 checkEscapeOnReturn(S, C);
2917 }
2918
2919 // In the CFG, automatic destructors come after the return statement.
2920 // This callback checks for returning memory that is freed by automatic
2921 // destructors, as those cannot be reached in checkPreStmt().
checkEndFunction(const ReturnStmt * S,CheckerContext & C) const2922 void MallocChecker::checkEndFunction(const ReturnStmt *S,
2923 CheckerContext &C) const {
2924 checkEscapeOnReturn(S, C);
2925 }
2926
checkEscapeOnReturn(const ReturnStmt * S,CheckerContext & C) const2927 void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
2928 CheckerContext &C) const {
2929 if (!S)
2930 return;
2931
2932 const Expr *E = S->getRetValue();
2933 if (!E)
2934 return;
2935
2936 // Check if we are returning a symbol.
2937 ProgramStateRef State = C.getState();
2938 SVal RetVal = C.getSVal(E);
2939 SymbolRef Sym = RetVal.getAsSymbol();
2940 if (!Sym)
2941 // If we are returning a field of the allocated struct or an array element,
2942 // the callee could still free the memory.
2943 // TODO: This logic should be a part of generic symbol escape callback.
2944 if (const MemRegion *MR = RetVal.getAsRegion())
2945 if (isa<FieldRegion, ElementRegion>(MR))
2946 if (const SymbolicRegion *BMR =
2947 dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
2948 Sym = BMR->getSymbol();
2949
2950 // Check if we are returning freed memory.
2951 if (Sym)
2952 checkUseAfterFree(Sym, C, E);
2953 }
2954
2955 // TODO: Blocks should be either inlined or should call invalidate regions
2956 // upon invocation. After that's in place, special casing here will not be
2957 // needed.
checkPostStmt(const BlockExpr * BE,CheckerContext & C) const2958 void MallocChecker::checkPostStmt(const BlockExpr *BE,
2959 CheckerContext &C) const {
2960
2961 // Scan the BlockDecRefExprs for any object the retain count checker
2962 // may be tracking.
2963 if (!BE->getBlockDecl()->hasCaptures())
2964 return;
2965
2966 ProgramStateRef state = C.getState();
2967 const BlockDataRegion *R =
2968 cast<BlockDataRegion>(C.getSVal(BE).getAsRegion());
2969
2970 auto ReferencedVars = R->referenced_vars();
2971 if (ReferencedVars.empty())
2972 return;
2973
2974 SmallVector<const MemRegion*, 10> Regions;
2975 const LocationContext *LC = C.getLocationContext();
2976 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
2977
2978 for (const auto &Var : ReferencedVars) {
2979 const VarRegion *VR = Var.getCapturedRegion();
2980 if (VR->getSuperRegion() == R) {
2981 VR = MemMgr.getVarRegion(VR->getDecl(), LC);
2982 }
2983 Regions.push_back(VR);
2984 }
2985
2986 state =
2987 state->scanReachableSymbols<StopTrackingCallback>(Regions).getState();
2988 C.addTransition(state);
2989 }
2990
isReleased(SymbolRef Sym,CheckerContext & C)2991 static bool isReleased(SymbolRef Sym, CheckerContext &C) {
2992 assert(Sym);
2993 const RefState *RS = C.getState()->get<RegionState>(Sym);
2994 return (RS && RS->isReleased());
2995 }
2996
suppressDeallocationsInSuspiciousContexts(const CallEvent & Call,CheckerContext & C) const2997 bool MallocChecker::suppressDeallocationsInSuspiciousContexts(
2998 const CallEvent &Call, CheckerContext &C) const {
2999 if (Call.getNumArgs() == 0)
3000 return false;
3001
3002 StringRef FunctionStr = "";
3003 if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
3004 if (const Stmt *Body = FD->getBody())
3005 if (Body->getBeginLoc().isValid())
3006 FunctionStr =
3007 Lexer::getSourceText(CharSourceRange::getTokenRange(
3008 {FD->getBeginLoc(), Body->getBeginLoc()}),
3009 C.getSourceManager(), C.getLangOpts());
3010
3011 // We do not model the Integer Set Library's retain-count based allocation.
3012 if (!FunctionStr.contains("__isl_"))
3013 return false;
3014
3015 ProgramStateRef State = C.getState();
3016
3017 for (const Expr *Arg : cast<CallExpr>(Call.getOriginExpr())->arguments())
3018 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())
3019 if (const RefState *RS = State->get<RegionState>(Sym))
3020 State = State->set<RegionState>(Sym, RefState::getEscaped(RS));
3021
3022 C.addTransition(State);
3023 return true;
3024 }
3025
checkUseAfterFree(SymbolRef Sym,CheckerContext & C,const Stmt * S) const3026 bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
3027 const Stmt *S) const {
3028
3029 if (isReleased(Sym, C)) {
3030 HandleUseAfterFree(C, S->getSourceRange(), Sym);
3031 return true;
3032 }
3033
3034 return false;
3035 }
3036
checkUseZeroAllocated(SymbolRef Sym,CheckerContext & C,const Stmt * S) const3037 void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3038 const Stmt *S) const {
3039 assert(Sym);
3040
3041 if (const RefState *RS = C.getState()->get<RegionState>(Sym)) {
3042 if (RS->isAllocatedOfSizeZero())
3043 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);
3044 }
3045 else if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym)) {
3046 HandleUseZeroAlloc(C, S->getSourceRange(), Sym);
3047 }
3048 }
3049
checkDoubleDelete(SymbolRef Sym,CheckerContext & C) const3050 bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const {
3051
3052 if (isReleased(Sym, C)) {
3053 HandleDoubleDelete(C, Sym);
3054 return true;
3055 }
3056 return false;
3057 }
3058
3059 // Check if the location is a freed symbolic region.
checkLocation(SVal l,bool isLoad,const Stmt * S,CheckerContext & C) const3060 void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
3061 CheckerContext &C) const {
3062 SymbolRef Sym = l.getLocSymbolInBase();
3063 if (Sym) {
3064 checkUseAfterFree(Sym, C, S);
3065 checkUseZeroAllocated(Sym, C, S);
3066 }
3067 }
3068
3069 // If a symbolic region is assumed to NULL (or another constant), stop tracking
3070 // it - assuming that allocation failed on this path.
evalAssume(ProgramStateRef state,SVal Cond,bool Assumption) const3071 ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
3072 SVal Cond,
3073 bool Assumption) const {
3074 RegionStateTy RS = state->get<RegionState>();
3075 for (SymbolRef Sym : llvm::make_first_range(RS)) {
3076 // If the symbol is assumed to be NULL, remove it from consideration.
3077 ConstraintManager &CMgr = state->getConstraintManager();
3078 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3079 if (AllocFailed.isConstrainedTrue())
3080 state = state->remove<RegionState>(Sym);
3081 }
3082
3083 // Realloc returns 0 when reallocation fails, which means that we should
3084 // restore the state of the pointer being reallocated.
3085 ReallocPairsTy RP = state->get<ReallocPairs>();
3086 for (auto [Sym, ReallocPair] : RP) {
3087 // If the symbol is assumed to be NULL, remove it from consideration.
3088 ConstraintManager &CMgr = state->getConstraintManager();
3089 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);
3090 if (!AllocFailed.isConstrainedTrue())
3091 continue;
3092
3093 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;
3094 if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
3095 if (RS->isReleased()) {
3096 switch (ReallocPair.Kind) {
3097 case OAR_ToBeFreedAfterFailure:
3098 state = state->set<RegionState>(ReallocSym,
3099 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
3100 break;
3101 case OAR_DoNotTrackAfterFailure:
3102 state = state->remove<RegionState>(ReallocSym);
3103 break;
3104 default:
3105 assert(ReallocPair.Kind == OAR_FreeOnFailure);
3106 }
3107 }
3108 }
3109 state = state->remove<ReallocPairs>(Sym);
3110 }
3111
3112 return state;
3113 }
3114
mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent * Call,ProgramStateRef State,SymbolRef & EscapingSymbol) const3115 bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
3116 const CallEvent *Call,
3117 ProgramStateRef State,
3118 SymbolRef &EscapingSymbol) const {
3119 assert(Call);
3120 EscapingSymbol = nullptr;
3121
3122 // For now, assume that any C++ or block call can free memory.
3123 // TODO: If we want to be more optimistic here, we'll need to make sure that
3124 // regions escape to C++ containers. They seem to do that even now, but for
3125 // mysterious reasons.
3126 if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))
3127 return true;
3128
3129 // Check Objective-C messages by selector name.
3130 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) {
3131 // If it's not a framework call, or if it takes a callback, assume it
3132 // can free memory.
3133 if (!Call->isInSystemHeader() || Call->argumentsMayEscape())
3134 return true;
3135
3136 // If it's a method we know about, handle it explicitly post-call.
3137 // This should happen before the "freeWhenDone" check below.
3138 if (isKnownDeallocObjCMethodName(*Msg))
3139 return false;
3140
3141 // If there's a "freeWhenDone" parameter, but the method isn't one we know
3142 // about, we can't be sure that the object will use free() to deallocate the
3143 // memory, so we can't model it explicitly. The best we can do is use it to
3144 // decide whether the pointer escapes.
3145 if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
3146 return *FreeWhenDone;
3147
3148 // If the first selector piece ends with "NoCopy", and there is no
3149 // "freeWhenDone" parameter set to zero, we know ownership is being
3150 // transferred. Again, though, we can't be sure that the object will use
3151 // free() to deallocate the memory, so we can't model it explicitly.
3152 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
3153 if (FirstSlot.ends_with("NoCopy"))
3154 return true;
3155
3156 // If the first selector starts with addPointer, insertPointer,
3157 // or replacePointer, assume we are dealing with NSPointerArray or similar.
3158 // This is similar to C++ containers (vector); we still might want to check
3159 // that the pointers get freed by following the container itself.
3160 if (FirstSlot.starts_with("addPointer") ||
3161 FirstSlot.starts_with("insertPointer") ||
3162 FirstSlot.starts_with("replacePointer") ||
3163 FirstSlot.equals("valueWithPointer")) {
3164 return true;
3165 }
3166
3167 // We should escape receiver on call to 'init'. This is especially relevant
3168 // to the receiver, as the corresponding symbol is usually not referenced
3169 // after the call.
3170 if (Msg->getMethodFamily() == OMF_init) {
3171 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();
3172 return true;
3173 }
3174
3175 // Otherwise, assume that the method does not free memory.
3176 // Most framework methods do not free memory.
3177 return false;
3178 }
3179
3180 // At this point the only thing left to handle is straight function calls.
3181 const FunctionDecl *FD = cast<SimpleFunctionCall>(Call)->getDecl();
3182 if (!FD)
3183 return true;
3184
3185 // If it's one of the allocation functions we can reason about, we model
3186 // its behavior explicitly.
3187 if (isMemCall(*Call))
3188 return false;
3189
3190 // If it's not a system call, assume it frees memory.
3191 if (!Call->isInSystemHeader())
3192 return true;
3193
3194 // White list the system functions whose arguments escape.
3195 const IdentifierInfo *II = FD->getIdentifier();
3196 if (!II)
3197 return true;
3198 StringRef FName = II->getName();
3199
3200 // White list the 'XXXNoCopy' CoreFoundation functions.
3201 // We specifically check these before
3202 if (FName.ends_with("NoCopy")) {
3203 // Look for the deallocator argument. We know that the memory ownership
3204 // is not transferred only if the deallocator argument is
3205 // 'kCFAllocatorNull'.
3206 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {
3207 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();
3208 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) {
3209 StringRef DeallocatorName = DE->getFoundDecl()->getName();
3210 if (DeallocatorName == "kCFAllocatorNull")
3211 return false;
3212 }
3213 }
3214 return true;
3215 }
3216
3217 // Associating streams with malloced buffers. The pointer can escape if
3218 // 'closefn' is specified (and if that function does free memory),
3219 // but it will not if closefn is not specified.
3220 // Currently, we do not inspect the 'closefn' function (PR12101).
3221 if (FName == "funopen")
3222 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))
3223 return false;
3224
3225 // Do not warn on pointers passed to 'setbuf' when used with std streams,
3226 // these leaks might be intentional when setting the buffer for stdio.
3227 // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer
3228 if (FName == "setbuf" || FName =="setbuffer" ||
3229 FName == "setlinebuf" || FName == "setvbuf") {
3230 if (Call->getNumArgs() >= 1) {
3231 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
3232 if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
3233 if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
3234 if (D->getCanonicalDecl()->getName().contains("std"))
3235 return true;
3236 }
3237 }
3238
3239 // A bunch of other functions which either take ownership of a pointer or
3240 // wrap the result up in a struct or object, meaning it can be freed later.
3241 // (See RetainCountChecker.) Not all the parameters here are invalidated,
3242 // but the Malloc checker cannot differentiate between them. The right way
3243 // of doing this would be to implement a pointer escapes callback.
3244 if (FName == "CGBitmapContextCreate" ||
3245 FName == "CGBitmapContextCreateWithData" ||
3246 FName == "CVPixelBufferCreateWithBytes" ||
3247 FName == "CVPixelBufferCreateWithPlanarBytes" ||
3248 FName == "OSAtomicEnqueue") {
3249 return true;
3250 }
3251
3252 if (FName == "postEvent" &&
3253 FD->getQualifiedNameAsString() == "QCoreApplication::postEvent") {
3254 return true;
3255 }
3256
3257 if (FName == "connectImpl" &&
3258 FD->getQualifiedNameAsString() == "QObject::connectImpl") {
3259 return true;
3260 }
3261
3262 if (FName == "singleShotImpl" &&
3263 FD->getQualifiedNameAsString() == "QTimer::singleShotImpl") {
3264 return true;
3265 }
3266
3267 // Handle cases where we know a buffer's /address/ can escape.
3268 // Note that the above checks handle some special cases where we know that
3269 // even though the address escapes, it's still our responsibility to free the
3270 // buffer.
3271 if (Call->argumentsMayEscape())
3272 return true;
3273
3274 // Otherwise, assume that the function does not free memory.
3275 // Most system calls do not free the memory.
3276 return false;
3277 }
3278
checkPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3279 ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
3280 const InvalidatedSymbols &Escaped,
3281 const CallEvent *Call,
3282 PointerEscapeKind Kind) const {
3283 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3284 /*IsConstPointerEscape*/ false);
3285 }
3286
checkConstPointerEscape(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind) const3287 ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
3288 const InvalidatedSymbols &Escaped,
3289 const CallEvent *Call,
3290 PointerEscapeKind Kind) const {
3291 // If a const pointer escapes, it may not be freed(), but it could be deleted.
3292 return checkPointerEscapeAux(State, Escaped, Call, Kind,
3293 /*IsConstPointerEscape*/ true);
3294 }
3295
checkIfNewOrNewArrayFamily(const RefState * RS)3296 static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
3297 return (RS->getAllocationFamily() == AF_CXXNewArray ||
3298 RS->getAllocationFamily() == AF_CXXNew);
3299 }
3300
checkPointerEscapeAux(ProgramStateRef State,const InvalidatedSymbols & Escaped,const CallEvent * Call,PointerEscapeKind Kind,bool IsConstPointerEscape) const3301 ProgramStateRef MallocChecker::checkPointerEscapeAux(
3302 ProgramStateRef State, const InvalidatedSymbols &Escaped,
3303 const CallEvent *Call, PointerEscapeKind Kind,
3304 bool IsConstPointerEscape) const {
3305 // If we know that the call does not free memory, or we want to process the
3306 // call later, keep tracking the top level arguments.
3307 SymbolRef EscapingSymbol = nullptr;
3308 if (Kind == PSK_DirectEscapeOnCall &&
3309 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,
3310 EscapingSymbol) &&
3311 !EscapingSymbol) {
3312 return State;
3313 }
3314
3315 for (SymbolRef sym : Escaped) {
3316 if (EscapingSymbol && EscapingSymbol != sym)
3317 continue;
3318
3319 if (const RefState *RS = State->get<RegionState>(sym))
3320 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
3321 if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))
3322 State = State->set<RegionState>(sym, RefState::getEscaped(RS));
3323 }
3324 return State;
3325 }
3326
isArgZERO_SIZE_PTR(ProgramStateRef State,CheckerContext & C,SVal ArgVal) const3327 bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
3328 SVal ArgVal) const {
3329 if (!KernelZeroSizePtrValue)
3330 KernelZeroSizePtrValue =
3331 tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor());
3332
3333 const llvm::APSInt *ArgValKnown =
3334 C.getSValBuilder().getKnownValue(State, ArgVal);
3335 return ArgValKnown && *KernelZeroSizePtrValue &&
3336 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;
3337 }
3338
findFailedReallocSymbol(ProgramStateRef currState,ProgramStateRef prevState)3339 static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
3340 ProgramStateRef prevState) {
3341 ReallocPairsTy currMap = currState->get<ReallocPairs>();
3342 ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
3343
3344 for (const ReallocPairsTy::value_type &Pair : prevMap) {
3345 SymbolRef sym = Pair.first;
3346 if (!currMap.lookup(sym))
3347 return sym;
3348 }
3349
3350 return nullptr;
3351 }
3352
isReferenceCountingPointerDestructor(const CXXDestructorDecl * DD)3353 static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {
3354 if (const IdentifierInfo *II = DD->getParent()->getIdentifier()) {
3355 StringRef N = II->getName();
3356 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
3357 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
3358 N.contains_insensitive("intrusive") ||
3359 N.contains_insensitive("shared")) {
3360 return true;
3361 }
3362 }
3363 }
3364 return false;
3365 }
3366
VisitNode(const ExplodedNode * N,BugReporterContext & BRC,PathSensitiveBugReport & BR)3367 PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
3368 BugReporterContext &BRC,
3369 PathSensitiveBugReport &BR) {
3370 ProgramStateRef state = N->getState();
3371 ProgramStateRef statePrev = N->getFirstPred()->getState();
3372
3373 const RefState *RSCurr = state->get<RegionState>(Sym);
3374 const RefState *RSPrev = statePrev->get<RegionState>(Sym);
3375
3376 const Stmt *S = N->getStmtForDiagnostics();
3377 // When dealing with containers, we sometimes want to give a note
3378 // even if the statement is missing.
3379 if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
3380 return nullptr;
3381
3382 const LocationContext *CurrentLC = N->getLocationContext();
3383
3384 // If we find an atomic fetch_add or fetch_sub within the destructor in which
3385 // the pointer was released (before the release), this is likely a destructor
3386 // of a shared pointer.
3387 // Because we don't model atomics, and also because we don't know that the
3388 // original reference count is positive, we should not report use-after-frees
3389 // on objects deleted in such destructors. This can probably be improved
3390 // through better shared pointer modeling.
3391 if (ReleaseDestructorLC) {
3392 if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
3393 AtomicExpr::AtomicOp Op = AE->getOp();
3394 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
3395 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
3396 if (ReleaseDestructorLC == CurrentLC ||
3397 ReleaseDestructorLC->isParentOf(CurrentLC)) {
3398 BR.markInvalid(getTag(), S);
3399 }
3400 }
3401 }
3402 }
3403
3404 // FIXME: We will eventually need to handle non-statement-based events
3405 // (__attribute__((cleanup))).
3406
3407 // Find out if this is an interesting point and what is the kind.
3408 StringRef Msg;
3409 std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;
3410 SmallString<256> Buf;
3411 llvm::raw_svector_ostream OS(Buf);
3412
3413 if (Mode == Normal) {
3414 if (isAllocated(RSCurr, RSPrev, S)) {
3415 Msg = "Memory is allocated";
3416 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3417 Sym, "Returned allocated memory");
3418 } else if (isReleased(RSCurr, RSPrev, S)) {
3419 const auto Family = RSCurr->getAllocationFamily();
3420 switch (Family) {
3421 case AF_Alloca:
3422 case AF_Malloc:
3423 case AF_CXXNew:
3424 case AF_CXXNewArray:
3425 case AF_IfNameIndex:
3426 Msg = "Memory is released";
3427 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3428 Sym, "Returning; memory was released");
3429 break;
3430 case AF_InnerBuffer: {
3431 const MemRegion *ObjRegion =
3432 allocation_state::getContainerObjRegion(statePrev, Sym);
3433 const auto *TypedRegion = cast<TypedValueRegion>(ObjRegion);
3434 QualType ObjTy = TypedRegion->getValueType();
3435 OS << "Inner buffer of '" << ObjTy << "' ";
3436
3437 if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {
3438 OS << "deallocated by call to destructor";
3439 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3440 Sym, "Returning; inner buffer was deallocated");
3441 } else {
3442 OS << "reallocated by call to '";
3443 const Stmt *S = RSCurr->getStmt();
3444 if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
3445 OS << MemCallE->getMethodDecl()->getDeclName();
3446 } else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
3447 OS << OpCallE->getDirectCallee()->getDeclName();
3448 } else if (const auto *CallE = dyn_cast<CallExpr>(S)) {
3449 auto &CEMgr = BRC.getStateManager().getCallEventManager();
3450 CallEventRef<> Call =
3451 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});
3452 if (const auto *D = dyn_cast_or_null<NamedDecl>(Call->getDecl()))
3453 OS << D->getDeclName();
3454 else
3455 OS << "unknown";
3456 }
3457 OS << "'";
3458 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3459 Sym, "Returning; inner buffer was reallocated");
3460 }
3461 Msg = OS.str();
3462 break;
3463 }
3464 case AF_None:
3465 llvm_unreachable("Unhandled allocation family!");
3466 }
3467
3468 // See if we're releasing memory while inlining a destructor
3469 // (or one of its callees). This turns on various common
3470 // false positive suppressions.
3471 bool FoundAnyDestructor = false;
3472 for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {
3473 if (const auto *DD = dyn_cast<CXXDestructorDecl>(LC->getDecl())) {
3474 if (isReferenceCountingPointerDestructor(DD)) {
3475 // This immediately looks like a reference-counting destructor.
3476 // We're bad at guessing the original reference count of the object,
3477 // so suppress the report for now.
3478 BR.markInvalid(getTag(), DD);
3479 } else if (!FoundAnyDestructor) {
3480 assert(!ReleaseDestructorLC &&
3481 "There can be only one release point!");
3482 // Suspect that it's a reference counting pointer destructor.
3483 // On one of the next nodes might find out that it has atomic
3484 // reference counting operations within it (see the code above),
3485 // and if so, we'd conclude that it likely is a reference counting
3486 // pointer destructor.
3487 ReleaseDestructorLC = LC->getStackFrame();
3488 // It is unlikely that releasing memory is delegated to a destructor
3489 // inside a destructor of a shared pointer, because it's fairly hard
3490 // to pass the information that the pointer indeed needs to be
3491 // released into it. So we're only interested in the innermost
3492 // destructor.
3493 FoundAnyDestructor = true;
3494 }
3495 }
3496 }
3497 } else if (isRelinquished(RSCurr, RSPrev, S)) {
3498 Msg = "Memory ownership is transferred";
3499 StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");
3500 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
3501 Mode = ReallocationFailed;
3502 Msg = "Reallocation failed";
3503 StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
3504 Sym, "Reallocation failed");
3505
3506 if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
3507 // Is it possible to fail two reallocs WITHOUT testing in between?
3508 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&
3509 "We only support one failed realloc at a time.");
3510 BR.markInteresting(sym);
3511 FailedReallocSymbol = sym;
3512 }
3513 }
3514
3515 // We are in a special mode if a reallocation failed later in the path.
3516 } else if (Mode == ReallocationFailed) {
3517 assert(FailedReallocSymbol && "No symbol to look for.");
3518
3519 // Is this is the first appearance of the reallocated symbol?
3520 if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
3521 // We're at the reallocation point.
3522 Msg = "Attempt to reallocate memory";
3523 StackHint = std::make_unique<StackHintGeneratorForSymbol>(
3524 Sym, "Returned reallocated memory");
3525 FailedReallocSymbol = nullptr;
3526 Mode = Normal;
3527 }
3528 }
3529
3530 if (Msg.empty()) {
3531 assert(!StackHint);
3532 return nullptr;
3533 }
3534
3535 assert(StackHint);
3536
3537 // Generate the extra diagnostic.
3538 PathDiagnosticLocation Pos;
3539 if (!S) {
3540 assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
3541 auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
3542 if (!PostImplCall)
3543 return nullptr;
3544 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),
3545 BRC.getSourceManager());
3546 } else {
3547 Pos = PathDiagnosticLocation(S, BRC.getSourceManager(),
3548 N->getLocationContext());
3549 }
3550
3551 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
3552 BR.addCallStackHint(P, std::move(StackHint));
3553 return P;
3554 }
3555
printState(raw_ostream & Out,ProgramStateRef State,const char * NL,const char * Sep) const3556 void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
3557 const char *NL, const char *Sep) const {
3558
3559 RegionStateTy RS = State->get<RegionState>();
3560
3561 if (!RS.isEmpty()) {
3562 Out << Sep << "MallocChecker :" << NL;
3563 for (auto [Sym, Data] : RS) {
3564 const RefState *RefS = State->get<RegionState>(Sym);
3565 AllocationFamily Family = RefS->getAllocationFamily();
3566 std::optional<MallocChecker::CheckKind> CheckKind =
3567 getCheckIfTracked(Family);
3568 if (!CheckKind)
3569 CheckKind = getCheckIfTracked(Family, true);
3570
3571 Sym->dumpToStream(Out);
3572 Out << " : ";
3573 Data.dump(Out);
3574 if (CheckKind)
3575 Out << " (" << CheckNames[*CheckKind].getName() << ")";
3576 Out << NL;
3577 }
3578 }
3579 }
3580
3581 namespace clang {
3582 namespace ento {
3583 namespace allocation_state {
3584
3585 ProgramStateRef
markReleased(ProgramStateRef State,SymbolRef Sym,const Expr * Origin)3586 markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
3587 AllocationFamily Family = AF_InnerBuffer;
3588 return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
3589 }
3590
3591 } // end namespace allocation_state
3592 } // end namespace ento
3593 } // end namespace clang
3594
3595 // Intended to be used in InnerPointerChecker to register the part of
3596 // MallocChecker connected to it.
registerInnerPointerCheckerAux(CheckerManager & mgr)3597 void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
3598 MallocChecker *checker = mgr.getChecker<MallocChecker>();
3599 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
3600 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
3601 mgr.getCurrentCheckerName();
3602 }
3603
registerDynamicMemoryModeling(CheckerManager & mgr)3604 void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
3605 auto *checker = mgr.registerChecker<MallocChecker>();
3606 checker->ShouldIncludeOwnershipAnnotatedFunctions =
3607 mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic");
3608 checker->ShouldRegisterNoOwnershipChangeVisitor =
3609 mgr.getAnalyzerOptions().getCheckerBooleanOption(
3610 checker, "AddNoOwnershipChangeNotes");
3611 }
3612
shouldRegisterDynamicMemoryModeling(const CheckerManager & mgr)3613 bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
3614 return true;
3615 }
3616
3617 #define REGISTER_CHECKER(name) \
3618 void ento::register##name(CheckerManager &mgr) { \
3619 MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
3620 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
3621 checker->CheckNames[MallocChecker::CK_##name] = \
3622 mgr.getCurrentCheckerName(); \
3623 } \
3624 \
3625 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
3626
3627 REGISTER_CHECKER(MallocChecker)
3628 REGISTER_CHECKER(NewDeleteChecker)
3629 REGISTER_CHECKER(NewDeleteLeaksChecker)
3630 REGISTER_CHECKER(MismatchedDeallocatorChecker)
3631