/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Analysis/RetainSummaryManager.h
Line | Count | Source (jump to first uncovered line) |
1 | | //=== RetainSummaryManager.h - Summaries for reference counting ---*- 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 summaries implementation for retain counting, which |
10 | | // implements a reference count checker for Core Foundation and Cocoa |
11 | | // on (Mac OS X). |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H |
16 | | #define LLVM_CLANG_ANALYSIS_RETAINSUMMARYMANAGER_H |
17 | | |
18 | | #include "llvm/ADT/DenseMap.h" |
19 | | #include "llvm/ADT/FoldingSet.h" |
20 | | #include "llvm/ADT/ImmutableMap.h" |
21 | | #include "clang/AST/Attr.h" |
22 | | #include "clang/AST/DeclCXX.h" |
23 | | #include "clang/AST/DeclObjC.h" |
24 | | #include "clang/AST/ParentMap.h" |
25 | | #include "clang/Analysis/AnyCall.h" |
26 | | #include "clang/Analysis/SelectorExtras.h" |
27 | | #include "llvm/ADT/STLExtras.h" |
28 | | |
29 | | using namespace clang; |
30 | | |
31 | | namespace clang { |
32 | | namespace ento { |
33 | | |
34 | | /// Determines the object kind of a tracked object. |
35 | | enum class ObjKind { |
36 | | /// Indicates that the tracked object is a CF object. |
37 | | CF, |
38 | | |
39 | | /// Indicates that the tracked object is an Objective-C object. |
40 | | ObjC, |
41 | | |
42 | | /// Indicates that the tracked object could be a CF or Objective-C object. |
43 | | AnyObj, |
44 | | |
45 | | /// Indicates that the tracked object is a generalized object. |
46 | | Generalized, |
47 | | |
48 | | /// Indicates that the tracking object is a descendant of a |
49 | | /// referenced-counted OSObject, used in the Darwin kernel. |
50 | | OS |
51 | | }; |
52 | | |
53 | | enum ArgEffectKind { |
54 | | /// There is no effect. |
55 | | DoNothing, |
56 | | |
57 | | /// The argument is treated as if an -autorelease message had been sent to |
58 | | /// the referenced object. |
59 | | Autorelease, |
60 | | |
61 | | /// The argument is treated as if the referenced object was deallocated. |
62 | | Dealloc, |
63 | | |
64 | | /// The argument has its reference count decreased by 1. |
65 | | DecRef, |
66 | | |
67 | | /// The argument has its reference count decreased by 1 to model |
68 | | /// a transferred bridge cast under ARC. |
69 | | DecRefBridgedTransferred, |
70 | | |
71 | | /// The argument has its reference count increased by 1. |
72 | | IncRef, |
73 | | |
74 | | /// The argument is a pointer to a retain-counted object; on exit, the new |
75 | | /// value of the pointer is a +0 value. |
76 | | UnretainedOutParameter, |
77 | | |
78 | | /// The argument is a pointer to a retain-counted object; on exit, the new |
79 | | /// value of the pointer is a +1 value. |
80 | | RetainedOutParameter, |
81 | | |
82 | | /// The argument is a pointer to a retain-counted object; on exit, the new |
83 | | /// value of the pointer is a +1 value iff the return code is zero. |
84 | | RetainedOutParameterOnZero, |
85 | | |
86 | | /// The argument is a pointer to a retain-counted object; on exit, the new |
87 | | /// value of the pointer is a +1 value iff the return code is non-zero. |
88 | | RetainedOutParameterOnNonZero, |
89 | | |
90 | | /// The argument is treated as potentially escaping, meaning that |
91 | | /// even when its reference count hits 0 it should be treated as still |
92 | | /// possibly being alive as someone else *may* be holding onto the object. |
93 | | MayEscape, |
94 | | |
95 | | /// All typestate tracking of the object ceases. This is usually employed |
96 | | /// when the effect of the call is completely unknown. |
97 | | StopTracking, |
98 | | |
99 | | /// All typestate tracking of the object ceases. Unlike StopTracking, |
100 | | /// this is also enforced when the method body is inlined. |
101 | | /// |
102 | | /// In some cases, we obtain a better summary for this checker |
103 | | /// by looking at the call site than by inlining the function. |
104 | | /// Signifies that we should stop tracking the symbol even if |
105 | | /// the function is inlined. |
106 | | StopTrackingHard, |
107 | | |
108 | | /// Performs the combined functionality of DecRef and StopTrackingHard. |
109 | | /// |
110 | | /// The models the effect that the called function decrements the reference |
111 | | /// count of the argument and all typestate tracking on that argument |
112 | | /// should cease. |
113 | | DecRefAndStopTrackingHard, |
114 | | }; |
115 | | |
116 | | /// An ArgEffect summarizes the retain count behavior on an argument or receiver |
117 | | /// to a function or method. |
118 | | class ArgEffect { |
119 | | ArgEffectKind K; |
120 | | ObjKind O; |
121 | | public: |
122 | | explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj) |
123 | 13.2k | : K(K), O(O) {} |
124 | | |
125 | 33.0k | ArgEffectKind getKind() const { return K; } |
126 | 25.2k | ObjKind getObjKind() const { return O; } |
127 | | |
128 | 219 | ArgEffect withKind(ArgEffectKind NewK) { |
129 | 219 | return ArgEffect(NewK, O); |
130 | 219 | } |
131 | | |
132 | 1.17k | bool operator==(const ArgEffect &Other) const { |
133 | 1.17k | return K == Other.K && O == Other.O; |
134 | 1.17k | } |
135 | | }; |
136 | | |
137 | | /// RetEffect summarizes a call's retain/release behavior with respect |
138 | | /// to its return value. |
139 | | class RetEffect { |
140 | | public: |
141 | | enum Kind { |
142 | | /// Indicates that no retain count information is tracked for |
143 | | /// the return value. |
144 | | NoRet, |
145 | | |
146 | | /// Indicates that the returned value is an owned (+1) symbol. |
147 | | OwnedSymbol, |
148 | | |
149 | | /// Indicates that the returned value is an object with retain count |
150 | | /// semantics but that it is not owned (+0). This is the default |
151 | | /// for getters, etc. |
152 | | NotOwnedSymbol, |
153 | | |
154 | | /// Indicates that the return value is an owned object when the |
155 | | /// receiver is also a tracked object. |
156 | | OwnedWhenTrackedReceiver, |
157 | | |
158 | | // Treat this function as returning a non-tracked symbol even if |
159 | | // the function has been inlined. This is used where the call |
160 | | // site summary is more precise than the summary indirectly produced |
161 | | // by inlining the function |
162 | | NoRetHard |
163 | | }; |
164 | | |
165 | | private: |
166 | | Kind K; |
167 | | ObjKind O; |
168 | | |
169 | 4.42k | RetEffect(Kind k, ObjKind o = ObjKind::AnyObj) : K(k), O(o) {} |
170 | | |
171 | | public: |
172 | 11.8k | Kind getKind() const { return K; } |
173 | | |
174 | 9.06k | ObjKind getObjKind() const { return O; } |
175 | | |
176 | 2.72k | bool isOwned() const { |
177 | 2.72k | return K == OwnedSymbol || K == OwnedWhenTrackedReceiver1.24k ; |
178 | 2.72k | } |
179 | | |
180 | 3.51k | bool notOwned() const { |
181 | 3.51k | return K == NotOwnedSymbol; |
182 | 3.51k | } |
183 | | |
184 | 9 | bool operator==(const RetEffect &Other) const { |
185 | 9 | return K == Other.K && O == Other.O3 ; |
186 | 9 | } |
187 | | |
188 | 90 | static RetEffect MakeOwnedWhenTrackedReceiver() { |
189 | 90 | return RetEffect(OwnedWhenTrackedReceiver, ObjKind::ObjC); |
190 | 90 | } |
191 | | |
192 | 474 | static RetEffect MakeOwned(ObjKind o) { |
193 | 474 | return RetEffect(OwnedSymbol, o); |
194 | 474 | } |
195 | 453 | static RetEffect MakeNotOwned(ObjKind o) { |
196 | 453 | return RetEffect(NotOwnedSymbol, o); |
197 | 453 | } |
198 | 3.31k | static RetEffect MakeNoRet() { |
199 | 3.31k | return RetEffect(NoRet); |
200 | 3.31k | } |
201 | 87 | static RetEffect MakeNoRetHard() { |
202 | 87 | return RetEffect(NoRetHard); |
203 | 87 | } |
204 | | }; |
205 | | |
206 | | /// A key identifying a summary. |
207 | | class ObjCSummaryKey { |
208 | | IdentifierInfo* II; |
209 | | Selector S; |
210 | | public: |
211 | | ObjCSummaryKey(IdentifierInfo* ii, Selector s) |
212 | 22.0k | : II(ii), S(s) {} |
213 | | |
214 | | ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s) |
215 | 5.76k | : II(d ? d->getIdentifier() : nullptr), S(s) {} |
216 | | |
217 | | ObjCSummaryKey(Selector s) |
218 | 582 | : II(nullptr), S(s) {} |
219 | | |
220 | 141k | IdentifierInfo *getIdentifier() const { return II; } |
221 | 53.5k | Selector getSelector() const { return S; } |
222 | | }; |
223 | | |
224 | | } // end namespace ento |
225 | | } // end namespace clang |
226 | | |
227 | | using namespace ento; |
228 | | |
229 | | namespace llvm { |
230 | | |
231 | | //===----------------------------------------------------------------------===// |
232 | | // Adapters for FoldingSet. |
233 | | //===----------------------------------------------------------------------===// |
234 | | template <> struct FoldingSetTrait<ArgEffect> { |
235 | 23.0k | static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) { |
236 | 23.0k | ID.AddInteger((unsigned) X.getKind()); |
237 | 23.0k | ID.AddInteger((unsigned) X.getObjKind()); |
238 | 23.0k | } |
239 | | }; |
240 | | template <> struct FoldingSetTrait<RetEffect> { |
241 | 7.05k | static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) { |
242 | 7.05k | ID.AddInteger((unsigned) X.getKind()); |
243 | 7.05k | ID.AddInteger((unsigned) X.getObjKind()); |
244 | 7.05k | } |
245 | | }; |
246 | | |
247 | | template <> struct DenseMapInfo<ObjCSummaryKey> { |
248 | 11.9k | static inline ObjCSummaryKey getEmptyKey() { |
249 | 11.9k | return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(), |
250 | 11.9k | DenseMapInfo<Selector>::getEmptyKey()); |
251 | 11.9k | } |
252 | | |
253 | 8.77k | static inline ObjCSummaryKey getTombstoneKey() { |
254 | 8.77k | return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(), |
255 | 8.77k | DenseMapInfo<Selector>::getTombstoneKey()); |
256 | 8.77k | } |
257 | | |
258 | 8.57k | static unsigned getHashValue(const ObjCSummaryKey &V) { |
259 | 8.57k | typedef std::pair<IdentifierInfo*, Selector> PairTy; |
260 | 8.57k | return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(), |
261 | 8.57k | V.getSelector())); |
262 | 8.57k | } |
263 | | |
264 | 66.2k | static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) { |
265 | 66.2k | return LHS.getIdentifier() == RHS.getIdentifier() && |
266 | 66.2k | LHS.getSelector() == RHS.getSelector()22.5k ; |
267 | 66.2k | } |
268 | | |
269 | | }; |
270 | | |
271 | | } // end llvm namespace |
272 | | |
273 | | |
274 | | namespace clang { |
275 | | namespace ento { |
276 | | |
277 | | /// ArgEffects summarizes the effects of a function/method call on all of |
278 | | /// its arguments. |
279 | | typedef llvm::ImmutableMap<unsigned, ArgEffect> ArgEffects; |
280 | | |
281 | | /// Summary for a function with respect to ownership changes. |
282 | | class RetainSummary { |
283 | | /// Args - a map of (index, ArgEffect) pairs, where index |
284 | | /// specifies the argument (starting from 0). This can be sparsely |
285 | | /// populated; arguments with no entry in Args use 'DefaultArgEffect'. |
286 | | ArgEffects Args; |
287 | | |
288 | | /// DefaultArgEffect - The default ArgEffect to apply to arguments that |
289 | | /// do not have an entry in Args. |
290 | | ArgEffect DefaultArgEffect; |
291 | | |
292 | | /// Receiver - If this summary applies to an Objective-C message expression, |
293 | | /// this is the effect applied to the state of the receiver. |
294 | | ArgEffect Receiver; |
295 | | |
296 | | /// Effect on "this" pointer - applicable only to C++ method calls. |
297 | | ArgEffect This; |
298 | | |
299 | | /// Ret - The effect on the return value. Used to indicate if the |
300 | | /// function/method call returns a new tracked symbol. |
301 | | RetEffect Ret; |
302 | | |
303 | | public: |
304 | | RetainSummary(ArgEffects A, |
305 | | RetEffect R, |
306 | | ArgEffect defaultEff, |
307 | | ArgEffect ReceiverEff, |
308 | | ArgEffect ThisEff) |
309 | | : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff), |
310 | 3.72k | This(ThisEff), Ret(R) {} |
311 | | |
312 | | /// getArg - Return the argument effect on the argument specified by |
313 | | /// idx (starting from 0). |
314 | 5.49k | ArgEffect getArg(unsigned idx) const { |
315 | 5.49k | if (const ArgEffect *AE = Args.lookup(idx)) |
316 | 2.44k | return *AE; |
317 | | |
318 | 3.04k | return DefaultArgEffect; |
319 | 5.49k | } |
320 | | |
321 | 1.31k | void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { |
322 | 1.31k | Args = af.add(Args, idx, e); |
323 | 1.31k | } |
324 | | |
325 | | /// setDefaultArgEffect - Set the default argument effect. |
326 | 0 | void setDefaultArgEffect(ArgEffect E) { |
327 | 0 | DefaultArgEffect = E; |
328 | 0 | } |
329 | | |
330 | | /// getRetEffect - Returns the effect on the return value of the call. |
331 | 4.81k | RetEffect getRetEffect() const { return Ret; } |
332 | | |
333 | | /// setRetEffect - Set the effect of the return value of the call. |
334 | 109 | void setRetEffect(RetEffect E) { Ret = E; } |
335 | | |
336 | | |
337 | | /// Sets the effect on the receiver of the message. |
338 | 14 | void setReceiverEffect(ArgEffect e) { Receiver = e; } |
339 | | |
340 | | /// getReceiverEffect - Returns the effect on the receiver of the call. |
341 | | /// This is only meaningful if the summary applies to an ObjCMessageExpr*. |
342 | 2.70k | ArgEffect getReceiverEffect() const { return Receiver; } |
343 | | |
344 | | /// \return the effect on the "this" receiver of the method call. |
345 | | /// This is only meaningful if the summary applies to CXXMethodDecl*. |
346 | 91 | ArgEffect getThisEffect() const { return This; } |
347 | | |
348 | 0 | ArgEffect getDefaultEffect() const { return DefaultArgEffect; } |
349 | | |
350 | | /// Set the effect of the method on "this". |
351 | 2 | void setThisEffect(ArgEffect e) { This = e; } |
352 | | |
353 | 0 | bool isNoop() const { |
354 | 0 | return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing |
355 | 0 | && DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing |
356 | 0 | && Args.isEmpty(); |
357 | 0 | } |
358 | | |
359 | | /// Test if two retain summaries are identical. Note that merely equivalent |
360 | | /// summaries are not necessarily identical (for example, if an explicit |
361 | | /// argument effect matches the default effect). |
362 | 0 | bool operator==(const RetainSummary &Other) const { |
363 | 0 | return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect && |
364 | 0 | Receiver == Other.Receiver && This == Other.This && Ret == Other.Ret; |
365 | 0 | } |
366 | | |
367 | | /// Profile this summary for inclusion in a FoldingSet. |
368 | 7.05k | void Profile(llvm::FoldingSetNodeID& ID) const { |
369 | 7.05k | ID.Add(Args); |
370 | 7.05k | ID.Add(DefaultArgEffect); |
371 | 7.05k | ID.Add(Receiver); |
372 | 7.05k | ID.Add(This); |
373 | 7.05k | ID.Add(Ret); |
374 | 7.05k | } |
375 | | |
376 | | /// A retain summary is simple if it has no ArgEffects other than the default. |
377 | 4.89k | bool isSimple() const { |
378 | 4.89k | return Args.isEmpty(); |
379 | 4.89k | } |
380 | | |
381 | 9.09k | ArgEffects getArgEffects() const { return Args; } |
382 | | |
383 | | private: |
384 | 1.31k | ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; } |
385 | | |
386 | | friend class RetainSummaryManager; |
387 | | }; |
388 | | |
389 | | class ObjCSummaryCache { |
390 | | typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy; |
391 | | MapTy M; |
392 | | public: |
393 | 194 | ObjCSummaryCache() {} |
394 | | |
395 | 2.98k | const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) { |
396 | | // Do a lookup with the (D,S) pair. If we find a match return |
397 | | // the iterator. |
398 | 2.98k | ObjCSummaryKey K(D, S); |
399 | 2.98k | MapTy::iterator I = M.find(K); |
400 | | |
401 | 2.98k | if (I != M.end()) |
402 | 1.83k | return I->second; |
403 | 1.15k | if (!D) |
404 | 13 | return nullptr; |
405 | | |
406 | | // Walk the super chain. If we find a hit with a parent, we'll end |
407 | | // up returning that summary. We actually allow that key (null,S), as |
408 | | // we cache summaries for the null ObjCInterfaceDecl* to allow us to |
409 | | // generate initial summaries without having to worry about NSObject |
410 | | // being declared. |
411 | | // FIXME: We may change this at some point. |
412 | 1.91k | for (ObjCInterfaceDecl *C=D->getSuperClass() ;; 1.14k C=C->getSuperClass()779 ) { |
413 | 1.91k | if ((I = M.find(ObjCSummaryKey(C, S))) != M.end()) |
414 | 295 | break; |
415 | | |
416 | 1.62k | if (!C) |
417 | 845 | return nullptr; |
418 | 1.62k | } |
419 | | |
420 | | // Cache the summary with original key to make the next lookup faster |
421 | | // and return the iterator. |
422 | 295 | const RetainSummary *Summ = I->second; |
423 | 295 | M[K] = Summ; |
424 | 295 | return Summ; |
425 | 1.14k | } |
426 | | |
427 | 0 | const RetainSummary *find(IdentifierInfo* II, Selector S) { |
428 | 0 | // FIXME: Class method lookup. Right now we don't have a good way |
429 | 0 | // of going between IdentifierInfo* and the class hierarchy. |
430 | 0 | MapTy::iterator I = M.find(ObjCSummaryKey(II, S)); |
431 | 0 |
|
432 | 0 | if (I == M.end()) |
433 | 0 | I = M.find(ObjCSummaryKey(S)); |
434 | 0 |
|
435 | 0 | return I == M.end() ? nullptr : I->second; |
436 | 0 | } |
437 | | |
438 | 2.11k | const RetainSummary *& operator[](ObjCSummaryKey K) { |
439 | 2.11k | return M[K]; |
440 | 2.11k | } |
441 | | |
442 | 582 | const RetainSummary *& operator[](Selector S) { |
443 | 582 | return M[ ObjCSummaryKey(S) ]; |
444 | 582 | } |
445 | | }; |
446 | | |
447 | | class RetainSummaryTemplate; |
448 | | |
449 | | class RetainSummaryManager { |
450 | | typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *> |
451 | | FuncSummariesTy; |
452 | | |
453 | | typedef ObjCSummaryCache ObjCMethodSummariesTy; |
454 | | |
455 | | typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode; |
456 | | |
457 | | /// Ctx - The ASTContext object for the analyzed ASTs. |
458 | | ASTContext &Ctx; |
459 | | |
460 | | /// Records whether or not the analyzed code runs in ARC mode. |
461 | | const bool ARCEnabled; |
462 | | |
463 | | /// Track Objective-C and CoreFoundation objects. |
464 | | const bool TrackObjCAndCFObjects; |
465 | | |
466 | | /// Track sublcasses of OSObject. |
467 | | const bool TrackOSObjects; |
468 | | |
469 | | /// FuncSummaries - A map from FunctionDecls to summaries. |
470 | | FuncSummariesTy FuncSummaries; |
471 | | |
472 | | /// ObjCClassMethodSummaries - A map from selectors (for instance methods) |
473 | | /// to summaries. |
474 | | ObjCMethodSummariesTy ObjCClassMethodSummaries; |
475 | | |
476 | | /// ObjCMethodSummaries - A map from selectors to summaries. |
477 | | ObjCMethodSummariesTy ObjCMethodSummaries; |
478 | | |
479 | | /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects, |
480 | | /// and all other data used by the checker. |
481 | | llvm::BumpPtrAllocator BPAlloc; |
482 | | |
483 | | /// AF - A factory for ArgEffects objects. |
484 | | ArgEffects::Factory AF; |
485 | | |
486 | | /// ObjCAllocRetE - Default return effect for methods returning Objective-C |
487 | | /// objects. |
488 | | RetEffect ObjCAllocRetE; |
489 | | |
490 | | /// ObjCInitRetE - Default return effect for init methods returning |
491 | | /// Objective-C objects. |
492 | | RetEffect ObjCInitRetE; |
493 | | |
494 | | /// SimpleSummaries - Used for uniquing summaries that don't have special |
495 | | /// effects. |
496 | | llvm::FoldingSet<CachedSummaryNode> SimpleSummaries; |
497 | | |
498 | | /// Create an OS object at +1. |
499 | | const RetainSummary *getOSSummaryCreateRule(const FunctionDecl *FD); |
500 | | |
501 | | /// Get an OS object at +0. |
502 | | const RetainSummary *getOSSummaryGetRule(const FunctionDecl *FD); |
503 | | |
504 | | /// Increment the reference count on OS object. |
505 | | const RetainSummary *getOSSummaryRetainRule(const FunctionDecl *FD); |
506 | | |
507 | | /// Decrement the reference count on OS object. |
508 | | const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD); |
509 | | |
510 | | /// Free the OS object. |
511 | | const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD); |
512 | | |
513 | | const RetainSummary *getUnarySummary(const FunctionType* FT, |
514 | | ArgEffectKind AE); |
515 | | |
516 | | const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD); |
517 | | const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD); |
518 | | const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD); |
519 | | |
520 | | const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm); |
521 | | |
522 | | const RetainSummary * |
523 | | getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs, |
524 | | ArgEffect ReceiverEff = ArgEffect(DoNothing), |
525 | | ArgEffect DefaultEff = ArgEffect(MayEscape), |
526 | 3.72k | ArgEffect ThisEff = ArgEffect(DoNothing)) { |
527 | 3.72k | RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff); |
528 | 3.72k | return getPersistentSummary(Summ); |
529 | 3.72k | } |
530 | | |
531 | 8 | const RetainSummary *getDoNothingSummary() { |
532 | 8 | return getPersistentSummary(RetEffect::MakeNoRet(), |
533 | 8 | ArgEffects(AF.getEmptyMap()), |
534 | 8 | ArgEffect(DoNothing), ArgEffect(DoNothing)); |
535 | 8 | } |
536 | | |
537 | 1.56k | const RetainSummary *getDefaultSummary() { |
538 | 1.56k | return getPersistentSummary(RetEffect::MakeNoRet(), |
539 | 1.56k | ArgEffects(AF.getEmptyMap()), |
540 | 1.56k | ArgEffect(DoNothing), ArgEffect(MayEscape)); |
541 | 1.56k | } |
542 | | |
543 | 122 | const RetainSummary *getPersistentStopSummary() { |
544 | 122 | return getPersistentSummary( |
545 | 122 | RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()), |
546 | 122 | ArgEffect(StopTracking), ArgEffect(StopTracking)); |
547 | 122 | } |
548 | | |
549 | | void InitializeClassMethodSummaries(); |
550 | | void InitializeMethodSummaries(); |
551 | | |
552 | 0 | void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) { |
553 | 0 | ObjCClassMethodSummaries[S] = Summ; |
554 | 0 | } |
555 | | |
556 | 582 | void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) { |
557 | 582 | ObjCMethodSummaries[S] = Summ; |
558 | 582 | } |
559 | | |
560 | | void addClassMethSummary(const char* Cls, const char* name, |
561 | 776 | const RetainSummary *Summ, bool isNullary = true) { |
562 | 776 | IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); |
563 | 776 | Selector S = isNullary ? GetNullarySelector(name, Ctx)679 |
564 | 776 | : GetUnarySelector(name, Ctx)97 ; |
565 | 776 | ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; |
566 | 776 | } |
567 | | |
568 | | void addInstMethSummary(const char* Cls, const char* nullaryName, |
569 | 0 | const RetainSummary *Summ) { |
570 | 0 | IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); |
571 | 0 | Selector S = GetNullarySelector(nullaryName, Ctx); |
572 | 0 | ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; |
573 | 0 | } |
574 | | |
575 | | template <typename... Keywords> |
576 | | void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries, |
577 | 485 | const RetainSummary *Summ, Keywords *... Kws) { |
578 | 485 | Selector S = getKeywordSelector(Ctx, Kws...); |
579 | 485 | Summaries[ObjCSummaryKey(ClsII, S)] = Summ; |
580 | 485 | } void clang::ento::RetainSummaryManager::addMethodSummary<char const>(clang::IdentifierInfo*, clang::ento::ObjCSummaryCache&, clang::ento::RetainSummary const*, char const*) Line | Count | Source | 577 | 194 | const RetainSummary *Summ, Keywords *... Kws) { | 578 | 194 | Selector S = getKeywordSelector(Ctx, Kws...); | 579 | 194 | Summaries[ObjCSummaryKey(ClsII, S)] = Summ; | 580 | 194 | } |
void clang::ento::RetainSummaryManager::addMethodSummary<char const, char const>(clang::IdentifierInfo*, clang::ento::ObjCSummaryCache&, clang::ento::RetainSummary const*, char const*, char const*) Line | Count | Source | 577 | 194 | const RetainSummary *Summ, Keywords *... Kws) { | 578 | 194 | Selector S = getKeywordSelector(Ctx, Kws...); | 579 | 194 | Summaries[ObjCSummaryKey(ClsII, S)] = Summ; | 580 | 194 | } |
void clang::ento::RetainSummaryManager::addMethodSummary<char const, char const, char const, char const>(clang::IdentifierInfo*, clang::ento::ObjCSummaryCache&, clang::ento::RetainSummary const*, char const*, char const*, char const*, char const*) Line | Count | Source | 577 | 97 | const RetainSummary *Summ, Keywords *... Kws) { | 578 | 97 | Selector S = getKeywordSelector(Ctx, Kws...); | 579 | 97 | Summaries[ObjCSummaryKey(ClsII, S)] = Summ; | 580 | 97 | } |
|
581 | | |
582 | | template <typename... Keywords> |
583 | | void addInstMethSummary(const char *Cls, const RetainSummary *Summ, |
584 | 485 | Keywords *... Kws) { |
585 | 485 | addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...); |
586 | 485 | } void clang::ento::RetainSummaryManager::addInstMethSummary<char const>(char const*, clang::ento::RetainSummary const*, char const*) Line | Count | Source | 584 | 194 | Keywords *... Kws) { | 585 | 194 | addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...); | 586 | 194 | } |
void clang::ento::RetainSummaryManager::addInstMethSummary<char const, char const>(char const*, clang::ento::RetainSummary const*, char const*, char const*) Line | Count | Source | 584 | 194 | Keywords *... Kws) { | 585 | 194 | addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...); | 586 | 194 | } |
void clang::ento::RetainSummaryManager::addInstMethSummary<char const, char const, char const, char const>(char const*, clang::ento::RetainSummary const*, char const*, char const*, char const*, char const*) Line | Count | Source | 584 | 97 | Keywords *... Kws) { | 585 | 97 | addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...); | 586 | 97 | } |
|
587 | | |
588 | | template <typename... Keywords> |
589 | | void addClsMethSummary(const char *Cls, const RetainSummary *Summ, |
590 | | Keywords *... Kws) { |
591 | | addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ, |
592 | | Kws...); |
593 | | } |
594 | | |
595 | | template <typename... Keywords> |
596 | | void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ, |
597 | | Keywords *... Kws) { |
598 | | addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...); |
599 | | } |
600 | | |
601 | | const RetainSummary * generateSummary(const FunctionDecl *FD, |
602 | | bool &AllowAnnotations); |
603 | | |
604 | | /// Return a summary for OSObject, or nullptr if not found. |
605 | | const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD, |
606 | | StringRef FName, QualType RetTy); |
607 | | |
608 | | /// Return a summary for Objective-C or CF object, or nullptr if not found. |
609 | | const RetainSummary *getSummaryForObjCOrCFObject( |
610 | | const FunctionDecl *FD, |
611 | | StringRef FName, |
612 | | QualType RetTy, |
613 | | const FunctionType *FT, |
614 | | bool &AllowAnnotations); |
615 | | |
616 | | /// Apply the annotation of @c pd in function @c FD |
617 | | /// to the resulting summary stored in out-parameter @c Template. |
618 | | /// \return whether an annotation was applied. |
619 | | bool applyParamAnnotationEffect(const ParmVarDecl *pd, unsigned parm_idx, |
620 | | const NamedDecl *FD, |
621 | | RetainSummaryTemplate &Template); |
622 | | |
623 | | public: |
624 | | RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects, |
625 | | bool trackOSObjects) |
626 | | : Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount), |
627 | | TrackObjCAndCFObjects(trackObjCAndCFObjects), |
628 | | TrackOSObjects(trackOSObjects), AF(BPAlloc), |
629 | | ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC) |
630 | | : RetEffect::MakeOwned(ObjKind::ObjC)), |
631 | | ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC) |
632 | 97 | : RetEffect::MakeOwnedWhenTrackedReceiver()) { |
633 | 97 | InitializeClassMethodSummaries(); |
634 | 97 | InitializeMethodSummaries(); |
635 | 97 | } |
636 | | |
637 | | enum class BehaviorSummary { |
638 | | // Function does not return. |
639 | | NoOp, |
640 | | |
641 | | // Function returns the first argument. |
642 | | Identity, |
643 | | |
644 | | // Function returns "this" argument. |
645 | | IdentityThis, |
646 | | |
647 | | // Function either returns zero, or the input parameter. |
648 | | IdentityOrZero |
649 | | }; |
650 | | |
651 | | Optional<BehaviorSummary> canEval(const CallExpr *CE, const FunctionDecl *FD, |
652 | | bool &hasTrustedImplementationAnnotation); |
653 | | |
654 | | /// \return Whether the type corresponds to a known smart pointer |
655 | | /// implementation (that is, everything about it is inlineable). |
656 | | static bool isKnownSmartPointer(QualType QT); |
657 | | |
658 | | bool isTrustedReferenceCountImplementation(const Decl *FD); |
659 | | |
660 | | const RetainSummary *getSummary(AnyCall C, |
661 | | bool HasNonZeroCallbackArg=false, |
662 | | bool IsReceiverUnconsumedSelf=false, |
663 | | QualType ReceiverType={}); |
664 | | |
665 | 401 | RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } |
666 | | |
667 | | private: |
668 | | |
669 | | /// getMethodSummary - This version of getMethodSummary is used to query |
670 | | /// the summary for the current method being analyzed. |
671 | | const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD); |
672 | | |
673 | | const RetainSummary *getFunctionSummary(const FunctionDecl *FD); |
674 | | |
675 | | const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID, |
676 | | const ObjCMethodDecl *MD, |
677 | | QualType RetTy, |
678 | | ObjCMethodSummariesTy &CachedSummaries); |
679 | | |
680 | | const RetainSummary * |
681 | | getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType); |
682 | | |
683 | | const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME); |
684 | | |
685 | | const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD, |
686 | | Selector S, QualType RetTy); |
687 | | |
688 | | /// Determine if there is a special return effect for this function or method. |
689 | | Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy, |
690 | | const Decl *D); |
691 | | |
692 | | void updateSummaryFromAnnotations(const RetainSummary *&Summ, |
693 | | const ObjCMethodDecl *MD); |
694 | | |
695 | | void updateSummaryFromAnnotations(const RetainSummary *&Summ, |
696 | | const FunctionDecl *FD); |
697 | | |
698 | | const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S, |
699 | | AnyCall &C); |
700 | | |
701 | | /// Special case '[super init];' and '[self init];' |
702 | | /// |
703 | | /// Even though calling '[super init]' without assigning the result to self |
704 | | /// and checking if the parent returns 'nil' is a bad pattern, it is common. |
705 | | /// Additionally, our Self Init checker already warns about it. To avoid |
706 | | /// overwhelming the user with messages from both checkers, we model the case |
707 | | /// of '[super init]' in cases when it is not consumed by another expression |
708 | | /// as if the call preserves the value of 'self'; essentially, assuming it can |
709 | | /// never fail and return 'nil'. |
710 | | /// Note, we don't want to just stop tracking the value since we want the |
711 | | /// RetainCount checker to report leaks and use-after-free if SelfInit checker |
712 | | /// is turned off. |
713 | | void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S); |
714 | | |
715 | | /// Set argument types for arguments which are not doing anything. |
716 | | void updateSummaryForArgumentTypes(const AnyCall &C, const RetainSummary *&RS); |
717 | | |
718 | | /// Determine whether a declaration @c D of correspondent type (return |
719 | | /// type for functions/methods) @c QT has any of the given attributes, |
720 | | /// provided they pass necessary validation checks AND tracking the given |
721 | | /// attribute is enabled. |
722 | | /// Returns the object kind corresponding to the present attribute, or None, |
723 | | /// if none of the specified attributes are present. |
724 | | /// Crashes if passed an attribute which is not explicitly handled. |
725 | | template <class T> |
726 | | Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT); |
727 | | |
728 | | template <class T1, class T2, class... Others> |
729 | | Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT); |
730 | | |
731 | | friend class RetainSummaryTemplate; |
732 | | }; |
733 | | |
734 | | |
735 | | // Used to avoid allocating long-term (BPAlloc'd) memory for default retain |
736 | | // summaries. If a function or method looks like it has a default summary, but |
737 | | // it has annotations, the annotations are added to the stack-based template |
738 | | // and then copied into managed memory. |
739 | | class RetainSummaryTemplate { |
740 | | RetainSummaryManager &Manager; |
741 | | const RetainSummary *&RealSummary; |
742 | | RetainSummary ScratchSummary; |
743 | | bool Accessed; |
744 | | public: |
745 | | RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager &mgr) |
746 | 8.71k | : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(false) {} |
747 | | |
748 | 8.71k | ~RetainSummaryTemplate() { |
749 | 8.71k | if (Accessed) |
750 | 1.17k | RealSummary = Manager.getPersistentSummary(ScratchSummary); |
751 | 8.71k | } |
752 | | |
753 | 0 | RetainSummary &operator*() { |
754 | 0 | Accessed = true; |
755 | 0 | return ScratchSummary; |
756 | 0 | } |
757 | | |
758 | 1.43k | RetainSummary *operator->() { |
759 | 1.43k | Accessed = true; |
760 | 1.43k | return &ScratchSummary; |
761 | 1.43k | } |
762 | | }; |
763 | | |
764 | | } // end namespace ento |
765 | | } // end namespace clang |
766 | | |
767 | | #endif |