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