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(I: (unsigned) X.getKind()); |
238 | ID.AddInteger(I: (unsigned) X.getObjKind()); |
239 | } |
240 | }; |
241 | template <> struct FoldingSetTrait<RetEffect> { |
242 | static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) { |
243 | ID.AddInteger(I: (unsigned) X.getKind()); |
244 | ID.AddInteger(I: (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(PairVal: 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(K: idx)) |
317 | return *AE; |
318 | |
319 | return DefaultArgEffect; |
320 | } |
321 | |
322 | void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) { |
323 | Args = af.add(Old: Args, K: idx, D: 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(x: Args); |
371 | ID.Add(x: DefaultArgEffect); |
372 | ID.Add(x: Receiver); |
373 | ID.Add(x: This); |
374 | ID.Add(x: 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(Val: 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(Val: 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(Val: ObjCSummaryKey(II, S)); |
432 | |
433 | if (I == M.end()) |
434 | I = M.find(Val: 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(OldSumm: Summ); |
530 | } |
531 | |
532 | const RetainSummary *getDoNothingSummary() { |
533 | return getPersistentSummary(RetEff: RetEffect::MakeNoRet(), |
534 | ScratchArgs: ArgEffects(AF.getEmptyMap()), |
535 | ReceiverEff: ArgEffect(DoNothing), DefaultEff: ArgEffect(DoNothing)); |
536 | } |
537 | |
538 | const RetainSummary *getDefaultSummary() { |
539 | return getPersistentSummary(RetEff: RetEffect::MakeNoRet(), |
540 | ScratchArgs: ArgEffects(AF.getEmptyMap()), |
541 | ReceiverEff: ArgEffect(DoNothing), DefaultEff: ArgEffect(MayEscape)); |
542 | } |
543 | |
544 | const RetainSummary *getPersistentStopSummary() { |
545 | return getPersistentSummary( |
546 | RetEff: RetEffect::MakeNoRet(), ScratchArgs: ArgEffects(AF.getEmptyMap()), |
547 | ReceiverEff: ArgEffect(StopTracking), DefaultEff: 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(Name: 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(Name: Cls); |
572 | Selector S = GetNullarySelector(name: 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(Name: 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(Name: 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(o: ObjKind::ObjC) |
631 | : RetEffect::MakeOwned(o: ObjKind::ObjC)), |
632 | ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(o: 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(OldSumm: 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 |
770 | |