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