xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp (revision 0bd37a1a367dffdf4513a3068c2f51290366e3f3)
1 //==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This checker analyzes Objective-C -dealloc methods and their callees
11 //  to warn about improper releasing of instance variables that back synthesized
12 // properties. It warns about missing releases in the following cases:
13 //  - When a class has a synthesized instance variable for a 'retain' or 'copy'
14 //    property and lacks a -dealloc method in its implementation.
15 //  - When a class has a synthesized instance variable for a 'retain'/'copy'
16 //   property but the ivar is not released in -dealloc by either -release
17 //   or by nilling out the property.
18 //
19 //  It warns about extra releases in -dealloc (but not in callees) when a
20 //  synthesized instance variable is released in the following cases:
21 //  - When the property is 'assign' and is not 'readonly'.
22 //  - When the property is 'weak'.
23 //
24 //  This checker only warns for instance variables synthesized to back
25 //  properties. Handling the more general case would require inferring whether
26 //  an instance variable is stored retained or not. For synthesized properties,
27 //  this is specified in the property declaration itself.
28 //
29 //===----------------------------------------------------------------------===//
30 
31 #include "ClangSACheckers.h"
32 #include "clang/AST/Attr.h"
33 #include "clang/AST/DeclObjC.h"
34 #include "clang/AST/Expr.h"
35 #include "clang/AST/ExprObjC.h"
36 #include "clang/Basic/LangOptions.h"
37 #include "clang/Basic/TargetInfo.h"
38 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
39 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
40 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
41 #include "clang/StaticAnalyzer/Core/Checker.h"
42 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
43 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
44 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
45 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
46 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
47 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
48 #include "llvm/Support/raw_ostream.h"
49 
50 using namespace clang;
51 using namespace ento;
52 
53 /// Indicates whether an instance variable is required to be released in
54 /// -dealloc.
55 enum class ReleaseRequirement {
56   /// The instance variable must be released, either by calling
57   /// -release on it directly or by nilling it out with a property setter.
58   MustRelease,
59 
60   /// The instance variable must not be directly released with -release.
61   MustNotReleaseDirectly,
62 
63   /// The requirement for the instance variable could not be determined.
64   Unknown
65 };
66 
67 /// Returns true if the property implementation is synthesized and the
68 /// type of the property is retainable.
69 static bool isSynthesizedRetainableProperty(const ObjCPropertyImplDecl *I,
70                                             const ObjCIvarDecl **ID,
71                                             const ObjCPropertyDecl **PD) {
72 
73   if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
74     return false;
75 
76   (*ID) = I->getPropertyIvarDecl();
77   if (!(*ID))
78     return false;
79 
80   QualType T = (*ID)->getType();
81   if (!T->isObjCRetainableType())
82     return false;
83 
84   (*PD) = I->getPropertyDecl();
85   // Shouldn't be able to synthesize a property that doesn't exist.
86   assert(*PD);
87 
88   return true;
89 }
90 
91 namespace {
92 
93 class ObjCDeallocChecker
94     : public Checker<check::ASTDecl<ObjCImplementationDecl>,
95                      check::PreObjCMessage, check::PostObjCMessage,
96                      check::PreCall,
97                      check::BeginFunction, check::EndFunction,
98                      eval::Assume,
99                      check::PointerEscape,
100                      check::PreStmt<ReturnStmt>> {
101 
102   mutable IdentifierInfo *NSObjectII, *SenTestCaseII, *XCTestCaseII,
103       *Block_releaseII, *CIFilterII;
104 
105   mutable Selector DeallocSel, ReleaseSel;
106 
107   std::unique_ptr<BugType> MissingReleaseBugType;
108   std::unique_ptr<BugType> ExtraReleaseBugType;
109   std::unique_ptr<BugType> MistakenDeallocBugType;
110 
111   // FIXME: constexpr initialization isn't supported by MSVC2013.
112   static const char *const MsgDeclared;
113   static const char *const MsgSynthesized;
114 
115 public:
116   ObjCDeallocChecker();
117 
118   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
119                     BugReporter &BR) const;
120   void checkBeginFunction(CheckerContext &Ctx) const;
121   void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
122   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
123   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
124 
125   ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
126                              bool Assumption) const;
127 
128   ProgramStateRef checkPointerEscape(ProgramStateRef State,
129                                      const InvalidatedSymbols &Escaped,
130                                      const CallEvent *Call,
131                                      PointerEscapeKind Kind) const;
132   void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
133   void checkEndFunction(CheckerContext &Ctx) const;
134 
135 private:
136   void addNoteForDecl(std::unique_ptr<BugReport> &BR, StringRef Msg,
137                            const Decl *D) const;
138 
139   void diagnoseMissingReleases(CheckerContext &C) const;
140 
141   bool diagnoseExtraRelease(SymbolRef ReleasedValue, const ObjCMethodCall &M,
142                             CheckerContext &C) const;
143 
144   bool diagnoseMistakenDealloc(SymbolRef DeallocedValue,
145                                const ObjCMethodCall &M,
146                                CheckerContext &C) const;
147 
148   SymbolRef getValueReleasedByNillingOut(const ObjCMethodCall &M,
149                                          CheckerContext &C) const;
150 
151   const ObjCIvarRegion *getIvarRegionForIvarSymbol(SymbolRef IvarSym) const;
152   SymbolRef getInstanceSymbolFromIvarSymbol(SymbolRef IvarSym) const;
153 
154   const ObjCPropertyImplDecl*
155   findPropertyOnDeallocatingInstance(SymbolRef IvarSym,
156                                      CheckerContext &C) const;
157 
158   ReleaseRequirement
159   getDeallocReleaseRequirement(const ObjCPropertyImplDecl *PropImpl) const;
160 
161   bool isInInstanceDealloc(const CheckerContext &C, SVal &SelfValOut) const;
162   bool isInInstanceDealloc(const CheckerContext &C, const LocationContext *LCtx,
163                            SVal &SelfValOut) const;
164   bool instanceDeallocIsOnStack(const CheckerContext &C,
165                                 SVal &InstanceValOut) const;
166 
167   bool isSuperDeallocMessage(const ObjCMethodCall &M) const;
168 
169   const ObjCImplDecl *getContainingObjCImpl(const LocationContext *LCtx) const;
170 
171   const ObjCPropertyDecl *
172   findShadowedPropertyDecl(const ObjCPropertyImplDecl *PropImpl) const;
173 
174   void transitionToReleaseValue(CheckerContext &C, SymbolRef Value) const;
175   ProgramStateRef removeValueRequiringRelease(ProgramStateRef State,
176                                               SymbolRef InstanceSym,
177                                               SymbolRef ValueSym) const;
178 
179   void initIdentifierInfoAndSelectors(ASTContext &Ctx) const;
180 
181   bool classHasSeparateTeardown(const ObjCInterfaceDecl *ID) const;
182 
183   bool isReleasedByCIFilterDealloc(const ObjCPropertyImplDecl *PropImpl) const;
184   bool isNibLoadedIvarWithoutRetain(const ObjCPropertyImplDecl *PropImpl) const;
185 };
186 } // End anonymous namespace.
187 
188 typedef llvm::ImmutableSet<SymbolRef> SymbolSet;
189 
190 const char *const ObjCDeallocChecker::MsgDeclared =
191     "Property is declared here";
192 const char *const ObjCDeallocChecker::MsgSynthesized =
193     "Property is synthesized here";
194 
195 /// Maps from the symbol for a class instance to the set of
196 /// symbols remaining that must be released in -dealloc.
197 REGISTER_MAP_WITH_PROGRAMSTATE(UnreleasedIvarMap, SymbolRef, SymbolSet)
198 
199 namespace clang {
200 namespace ento {
201 template<> struct ProgramStateTrait<SymbolSet>
202 :  public ProgramStatePartialTrait<SymbolSet> {
203   static void *GDMIndex() { static int index = 0; return &index; }
204 };
205 }
206 }
207 
208 /// An AST check that diagnose when the class requires a -dealloc method and
209 /// is missing one.
210 void ObjCDeallocChecker::checkASTDecl(const ObjCImplementationDecl *D,
211                                       AnalysisManager &Mgr,
212                                       BugReporter &BR) const {
213   assert(Mgr.getLangOpts().getGC() != LangOptions::GCOnly);
214   assert(!Mgr.getLangOpts().ObjCAutoRefCount);
215   initIdentifierInfoAndSelectors(Mgr.getASTContext());
216 
217   const ObjCInterfaceDecl *ID = D->getClassInterface();
218   // If the class is known to have a lifecycle with a separate teardown method
219   // then it may not require a -dealloc method.
220   if (classHasSeparateTeardown(ID))
221     return;
222 
223   // Does the class contain any synthesized properties that are retainable?
224   // If not, skip the check entirely.
225   const ObjCPropertyImplDecl *PropImplRequiringRelease = nullptr;
226   bool HasOthers = false;
227   for (const auto *I : D->property_impls()) {
228     if (getDeallocReleaseRequirement(I) == ReleaseRequirement::MustRelease) {
229       if (!PropImplRequiringRelease)
230         PropImplRequiringRelease = I;
231       else {
232         HasOthers = true;
233         break;
234       }
235     }
236   }
237 
238   if (!PropImplRequiringRelease)
239     return;
240 
241   const ObjCMethodDecl *MD = nullptr;
242 
243   // Scan the instance methods for "dealloc".
244   for (const auto *I : D->instance_methods()) {
245     if (I->getSelector() == DeallocSel) {
246       MD = I;
247       break;
248     }
249   }
250 
251   if (!MD) { // No dealloc found.
252     const char* Name = "Missing -dealloc";
253 
254     std::string Buf;
255     llvm::raw_string_ostream OS(Buf);
256     OS << "'" << *D << "' lacks a 'dealloc' instance method but "
257        << "must release '" << *PropImplRequiringRelease->getPropertyIvarDecl()
258        << "'";
259 
260     if (HasOthers)
261       OS << " and others";
262     PathDiagnosticLocation DLoc =
263         PathDiagnosticLocation::createBegin(D, BR.getSourceManager());
264 
265     BR.EmitBasicReport(D, this, Name, categories::CoreFoundationObjectiveC,
266                        OS.str(), DLoc);
267     return;
268   }
269 }
270 
271 /// If this is the beginning of -dealloc, mark the values initially stored in
272 /// instance variables that must be released by the end of -dealloc
273 /// as unreleased in the state.
274 void ObjCDeallocChecker::checkBeginFunction(
275     CheckerContext &C) const {
276   initIdentifierInfoAndSelectors(C.getASTContext());
277 
278   // Only do this if the current method is -dealloc.
279   SVal SelfVal;
280   if (!isInInstanceDealloc(C, SelfVal))
281     return;
282 
283   SymbolRef SelfSymbol = SelfVal.getAsSymbol();
284 
285   const LocationContext *LCtx = C.getLocationContext();
286   ProgramStateRef InitialState = C.getState();
287 
288   ProgramStateRef State = InitialState;
289 
290   SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();
291 
292   // Symbols that must be released by the end of the -dealloc;
293   SymbolSet RequiredReleases = F.getEmptySet();
294 
295   // If we're an inlined -dealloc, we should add our symbols to the existing
296   // set from our subclass.
297   if (const SymbolSet *CurrSet = State->get<UnreleasedIvarMap>(SelfSymbol))
298     RequiredReleases = *CurrSet;
299 
300   for (auto *PropImpl : getContainingObjCImpl(LCtx)->property_impls()) {
301     ReleaseRequirement Requirement = getDeallocReleaseRequirement(PropImpl);
302     if (Requirement != ReleaseRequirement::MustRelease)
303       continue;
304 
305     SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal);
306     Optional<Loc> LValLoc = LVal.getAs<Loc>();
307     if (!LValLoc)
308       continue;
309 
310     SVal InitialVal = State->getSVal(LValLoc.getValue());
311     SymbolRef Symbol = InitialVal.getAsSymbol();
312     if (!Symbol || !isa<SymbolRegionValue>(Symbol))
313       continue;
314 
315     // Mark the value as requiring a release.
316     RequiredReleases = F.add(RequiredReleases, Symbol);
317   }
318 
319   if (!RequiredReleases.isEmpty()) {
320     State = State->set<UnreleasedIvarMap>(SelfSymbol, RequiredReleases);
321   }
322 
323   if (State != InitialState) {
324     C.addTransition(State);
325   }
326 }
327 
328 /// Given a symbol for an ivar, return the ivar region it was loaded from.
329 /// Returns nullptr if the instance symbol cannot be found.
330 const ObjCIvarRegion *
331 ObjCDeallocChecker::getIvarRegionForIvarSymbol(SymbolRef IvarSym) const {
332   return dyn_cast_or_null<ObjCIvarRegion>(IvarSym->getOriginRegion());
333 }
334 
335 /// Given a symbol for an ivar, return a symbol for the instance containing
336 /// the ivar. Returns nullptr if the instance symbol cannot be found.
337 SymbolRef
338 ObjCDeallocChecker::getInstanceSymbolFromIvarSymbol(SymbolRef IvarSym) const {
339 
340   const ObjCIvarRegion *IvarRegion = getIvarRegionForIvarSymbol(IvarSym);
341   if (!IvarRegion)
342     return nullptr;
343 
344   return IvarRegion->getSymbolicBase()->getSymbol();
345 }
346 
347 /// If we are in -dealloc or -dealloc is on the stack, handle the call if it is
348 /// a release or a nilling-out property setter.
349 void ObjCDeallocChecker::checkPreObjCMessage(
350     const ObjCMethodCall &M, CheckerContext &C) const {
351   // Only run if -dealloc is on the stack.
352   SVal DeallocedInstance;
353   if (!instanceDeallocIsOnStack(C, DeallocedInstance))
354     return;
355 
356   SymbolRef ReleasedValue = nullptr;
357 
358   if (M.getSelector() == ReleaseSel) {
359     ReleasedValue = M.getReceiverSVal().getAsSymbol();
360   } else if (M.getSelector() == DeallocSel && !M.isReceiverSelfOrSuper()) {
361     if (diagnoseMistakenDealloc(M.getReceiverSVal().getAsSymbol(), M, C))
362       return;
363   }
364 
365   if (ReleasedValue) {
366     // An instance variable symbol was released with -release:
367     //    [_property release];
368     if (diagnoseExtraRelease(ReleasedValue,M, C))
369       return;
370   } else {
371     // An instance variable symbol was released nilling out its property:
372     //    self.property = nil;
373     ReleasedValue = getValueReleasedByNillingOut(M, C);
374   }
375 
376   if (!ReleasedValue)
377     return;
378 
379   transitionToReleaseValue(C, ReleasedValue);
380 }
381 
382 /// If we are in -dealloc or -dealloc is on the stack, handle the call if it is
383 /// call to Block_release().
384 void ObjCDeallocChecker::checkPreCall(const CallEvent &Call,
385                                       CheckerContext &C) const {
386   const IdentifierInfo *II = Call.getCalleeIdentifier();
387   if (II != Block_releaseII)
388     return;
389 
390   if (Call.getNumArgs() != 1)
391     return;
392 
393   SymbolRef ReleasedValue = Call.getArgSVal(0).getAsSymbol();
394   if (!ReleasedValue)
395     return;
396 
397   transitionToReleaseValue(C, ReleasedValue);
398 }
399 /// If the message was a call to '[super dealloc]', diagnose any missing
400 /// releases.
401 void ObjCDeallocChecker::checkPostObjCMessage(
402     const ObjCMethodCall &M, CheckerContext &C) const {
403   // We perform this check post-message so that if the super -dealloc
404   // calls a helper method and that this class overrides, any ivars released in
405   // the helper method will be recorded before checking.
406   if (isSuperDeallocMessage(M))
407     diagnoseMissingReleases(C);
408 }
409 
410 /// Check for missing releases even when -dealloc does not call
411 /// '[super dealloc]'.
412 void ObjCDeallocChecker::checkEndFunction(
413     CheckerContext &C) const {
414   diagnoseMissingReleases(C);
415 }
416 
417 /// Check for missing releases on early return.
418 void ObjCDeallocChecker::checkPreStmt(
419     const ReturnStmt *RS, CheckerContext &C) const {
420   diagnoseMissingReleases(C);
421 }
422 
423 /// When a symbol is assumed to be nil, remove it from the set of symbols
424 /// require to be nil.
425 ProgramStateRef ObjCDeallocChecker::evalAssume(ProgramStateRef State, SVal Cond,
426                                                bool Assumption) const {
427   if (State->get<UnreleasedIvarMap>().isEmpty())
428     return State;
429 
430   auto *CondBSE = dyn_cast_or_null<BinarySymExpr>(Cond.getAsSymExpr());
431   if (!CondBSE)
432     return State;
433 
434   BinaryOperator::Opcode OpCode = CondBSE->getOpcode();
435   if (Assumption) {
436     if (OpCode != BO_EQ)
437       return State;
438   } else {
439     if (OpCode != BO_NE)
440       return State;
441   }
442 
443   SymbolRef NullSymbol = nullptr;
444   if (auto *SIE = dyn_cast<SymIntExpr>(CondBSE)) {
445     const llvm::APInt &RHS = SIE->getRHS();
446     if (RHS != 0)
447       return State;
448     NullSymbol = SIE->getLHS();
449   } else if (auto *SIE = dyn_cast<IntSymExpr>(CondBSE)) {
450     const llvm::APInt &LHS = SIE->getLHS();
451     if (LHS != 0)
452       return State;
453     NullSymbol = SIE->getRHS();
454   } else {
455     return State;
456   }
457 
458   SymbolRef InstanceSymbol = getInstanceSymbolFromIvarSymbol(NullSymbol);
459   if (!InstanceSymbol)
460     return State;
461 
462   State = removeValueRequiringRelease(State, InstanceSymbol, NullSymbol);
463 
464   return State;
465 }
466 
467 /// If a symbol escapes conservatively assume unseen code released it.
468 ProgramStateRef ObjCDeallocChecker::checkPointerEscape(
469     ProgramStateRef State, const InvalidatedSymbols &Escaped,
470     const CallEvent *Call, PointerEscapeKind Kind) const {
471 
472   if (State->get<UnreleasedIvarMap>().isEmpty())
473     return State;
474 
475   // Don't treat calls to '[super dealloc]' as escaping for the purposes
476   // of this checker. Because the checker diagnoses missing releases in the
477   // post-message handler for '[super dealloc], escaping here would cause
478   // the checker to never warn.
479   auto *OMC = dyn_cast_or_null<ObjCMethodCall>(Call);
480   if (OMC && isSuperDeallocMessage(*OMC))
481     return State;
482 
483   for (const auto &Sym : Escaped) {
484     if (!Call || (Call && !Call->isInSystemHeader())) {
485       // If Sym is a symbol for an object with instance variables that
486       // must be released, remove these obligations when the object escapes
487       // unless via a call to a system function. System functions are
488       // very unlikely to release instance variables on objects passed to them,
489       // and are frequently called on 'self' in -dealloc (e.g., to remove
490       // observers) -- we want to avoid false negatives from escaping on
491       // them.
492       State = State->remove<UnreleasedIvarMap>(Sym);
493     }
494 
495 
496     SymbolRef InstanceSymbol = getInstanceSymbolFromIvarSymbol(Sym);
497     if (!InstanceSymbol)
498       continue;
499 
500     State = removeValueRequiringRelease(State, InstanceSymbol, Sym);
501   }
502 
503   return State;
504 }
505 
506 /// Add an extra note piece describing a declaration that is important
507 /// for understanding the bug report.
508 void ObjCDeallocChecker::addNoteForDecl(std::unique_ptr<BugReport> &BR,
509                                              StringRef Msg,
510                                              const Decl *D) const {
511   ASTContext &ACtx = D->getASTContext();
512   SourceManager &SM = ACtx.getSourceManager();
513   PathDiagnosticLocation Pos = PathDiagnosticLocation::createBegin(D, SM);
514   if (Pos.isValid() && Pos.asLocation().isValid())
515     BR->addNote(Msg, Pos, D->getSourceRange());
516 }
517 
518 /// Report any unreleased instance variables for the current instance being
519 /// dealloced.
520 void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
521   ProgramStateRef State = C.getState();
522 
523   SVal SelfVal;
524   if (!isInInstanceDealloc(C, SelfVal))
525     return;
526 
527   const MemRegion *SelfRegion = SelfVal.castAs<loc::MemRegionVal>().getRegion();
528   const LocationContext *LCtx = C.getLocationContext();
529 
530   ExplodedNode *ErrNode = nullptr;
531 
532   SymbolRef SelfSym = SelfVal.getAsSymbol();
533   if (!SelfSym)
534     return;
535 
536   const SymbolSet *OldUnreleased = State->get<UnreleasedIvarMap>(SelfSym);
537   if (!OldUnreleased)
538     return;
539 
540   SymbolSet NewUnreleased = *OldUnreleased;
541   SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();
542 
543   ProgramStateRef InitialState = State;
544 
545   for (auto *IvarSymbol : *OldUnreleased) {
546     const TypedValueRegion *TVR =
547         cast<SymbolRegionValue>(IvarSymbol)->getRegion();
548     const ObjCIvarRegion *IvarRegion = cast<ObjCIvarRegion>(TVR);
549 
550     // Don't warn if the ivar is not for this instance.
551     if (SelfRegion != IvarRegion->getSuperRegion())
552       continue;
553 
554     const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl();
555     // Prevent an inlined call to -dealloc in a super class from warning
556     // about the values the subclass's -dealloc should release.
557     if (IvarDecl->getContainingInterface() !=
558         cast<ObjCMethodDecl>(LCtx->getDecl())->getClassInterface())
559       continue;
560 
561     // Prevents diagnosing multiple times for the same instance variable
562     // at, for example, both a return and at the end of of the function.
563     NewUnreleased = F.remove(NewUnreleased, IvarSymbol);
564 
565     if (State->getStateManager()
566             .getConstraintManager()
567             .isNull(State, IvarSymbol)
568             .isConstrainedTrue()) {
569       continue;
570     }
571 
572     // A missing release manifests as a leak, so treat as a non-fatal error.
573     if (!ErrNode)
574       ErrNode = C.generateNonFatalErrorNode();
575     // If we've already reached this node on another path, return without
576     // diagnosing.
577     if (!ErrNode)
578       return;
579 
580     std::string Buf;
581     llvm::raw_string_ostream OS(Buf);
582 
583     const ObjCInterfaceDecl *Interface = IvarDecl->getContainingInterface();
584     // If the class is known to have a lifecycle with teardown that is
585     // separate from -dealloc, do not warn about missing releases. We
586     // suppress here (rather than not tracking for instance variables in
587     // such classes) because these classes are rare.
588     if (classHasSeparateTeardown(Interface))
589       return;
590 
591     ObjCImplDecl *ImplDecl = Interface->getImplementation();
592 
593     const ObjCPropertyImplDecl *PropImpl =
594         ImplDecl->FindPropertyImplIvarDecl(IvarDecl->getIdentifier());
595 
596     const ObjCPropertyDecl *PropDecl = PropImpl->getPropertyDecl();
597 
598     assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Copy ||
599            PropDecl->getSetterKind() == ObjCPropertyDecl::Retain);
600 
601     OS << "The '" << *IvarDecl << "' ivar in '" << *ImplDecl
602        << "' was ";
603 
604     if (PropDecl->getSetterKind() == ObjCPropertyDecl::Retain)
605       OS << "retained";
606     else
607       OS << "copied";
608 
609     OS << " by a synthesized property but not released"
610           " before '[super dealloc]'";
611 
612     std::unique_ptr<BugReport> BR(
613         new BugReport(*MissingReleaseBugType, OS.str(), ErrNode));
614 
615     addNoteForDecl(BR, MsgDeclared, PropDecl);
616     addNoteForDecl(BR, MsgSynthesized, PropImpl);
617 
618     C.emitReport(std::move(BR));
619   }
620 
621   if (NewUnreleased.isEmpty()) {
622     State = State->remove<UnreleasedIvarMap>(SelfSym);
623   } else {
624     State = State->set<UnreleasedIvarMap>(SelfSym, NewUnreleased);
625   }
626 
627   if (ErrNode) {
628     C.addTransition(State, ErrNode);
629   } else if (State != InitialState) {
630     C.addTransition(State);
631   }
632 
633   // Make sure that after checking in the top-most frame the list of
634   // tracked ivars is empty. This is intended to detect accidental leaks in
635   // the UnreleasedIvarMap program state.
636   assert(!LCtx->inTopFrame() || State->get<UnreleasedIvarMap>().isEmpty());
637 }
638 
639 /// Given a symbol, determine whether the symbol refers to an ivar on
640 /// the top-most deallocating instance. If so, find the property for that
641 /// ivar, if one exists. Otherwise return null.
642 const ObjCPropertyImplDecl *
643 ObjCDeallocChecker::findPropertyOnDeallocatingInstance(
644     SymbolRef IvarSym, CheckerContext &C) const {
645   SVal DeallocedInstance;
646   if (!isInInstanceDealloc(C, DeallocedInstance))
647     return nullptr;
648 
649   // Try to get the region from which the ivar value was loaded.
650   auto *IvarRegion = getIvarRegionForIvarSymbol(IvarSym);
651   if (!IvarRegion)
652     return nullptr;
653 
654   // Don't try to find the property if the ivar was not loaded from the
655   // given instance.
656   if (DeallocedInstance.castAs<loc::MemRegionVal>().getRegion() !=
657       IvarRegion->getSuperRegion())
658     return nullptr;
659 
660   const LocationContext *LCtx = C.getLocationContext();
661   const ObjCIvarDecl *IvarDecl = IvarRegion->getDecl();
662 
663   const ObjCImplDecl *Container = getContainingObjCImpl(LCtx);
664   const ObjCPropertyImplDecl *PropImpl =
665       Container->FindPropertyImplIvarDecl(IvarDecl->getIdentifier());
666   return PropImpl;
667 }
668 
669 /// Emits a warning if the current context is -dealloc and ReleasedValue
670 /// must not be directly released in a -dealloc. Returns true if a diagnostic
671 /// was emitted.
672 bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue,
673                                               const ObjCMethodCall &M,
674                                               CheckerContext &C) const {
675   // Try to get the region from which the the released value was loaded.
676   // Note that, unlike diagnosing for missing releases, here we don't track
677   // values that must not be released in the state. This is because even if
678   // these values escape, it is still an error under the rules of MRR to
679   // release them in -dealloc.
680   const ObjCPropertyImplDecl *PropImpl =
681       findPropertyOnDeallocatingInstance(ReleasedValue, C);
682 
683   if (!PropImpl)
684     return false;
685 
686   // If the ivar belongs to a property that must not be released directly
687   // in dealloc, emit a warning.
688   if (getDeallocReleaseRequirement(PropImpl) !=
689       ReleaseRequirement::MustNotReleaseDirectly) {
690     return false;
691   }
692 
693   // If the property is readwrite but it shadows a read-only property in its
694   // external interface, treat the property a read-only. If the outside
695   // world cannot write to a property then the internal implementation is free
696   // to make its own convention about whether the value is stored retained
697   // or not. We look up the shadow here rather than in
698   // getDeallocReleaseRequirement() because doing so can be expensive.
699   const ObjCPropertyDecl *PropDecl = findShadowedPropertyDecl(PropImpl);
700   if (PropDecl) {
701     if (PropDecl->isReadOnly())
702       return false;
703   } else {
704     PropDecl = PropImpl->getPropertyDecl();
705   }
706 
707   ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
708   if (!ErrNode)
709     return false;
710 
711   std::string Buf;
712   llvm::raw_string_ostream OS(Buf);
713 
714   assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Weak ||
715          (PropDecl->getSetterKind() == ObjCPropertyDecl::Assign &&
716           !PropDecl->isReadOnly()) ||
717          isReleasedByCIFilterDealloc(PropImpl)
718          );
719 
720   const ObjCImplDecl *Container = getContainingObjCImpl(C.getLocationContext());
721   const ObjCIvarDecl *IvarDecl = PropImpl->getPropertyIvarDecl();
722   OS << "The '" << *IvarDecl << "' ivar in '" << *Container;
723 
724   bool ReleasedByCIFilterDealloc = isReleasedByCIFilterDealloc(PropImpl);
725 
726   if (ReleasedByCIFilterDealloc) {
727     OS << "' will be released by '-[CIFilter dealloc]' but also released here";
728   } else {
729     OS << "' was synthesized for ";
730 
731     if (PropDecl->getSetterKind() == ObjCPropertyDecl::Weak)
732       OS << "a weak";
733     else
734       OS << "an assign, readwrite";
735 
736     OS <<  " property but was released in 'dealloc'";
737   }
738 
739   std::unique_ptr<BugReport> BR(
740       new BugReport(*ExtraReleaseBugType, OS.str(), ErrNode));
741   BR->addRange(M.getOriginExpr()->getSourceRange());
742 
743   addNoteForDecl(BR, MsgDeclared, PropDecl);
744   if (!ReleasedByCIFilterDealloc)
745     addNoteForDecl(BR, MsgSynthesized, PropImpl);
746 
747   C.emitReport(std::move(BR));
748 
749   return true;
750 }
751 
752 /// Emits a warning if the current context is -dealloc and DeallocedValue
753 /// must not be directly dealloced in a -dealloc. Returns true if a diagnostic
754 /// was emitted.
755 bool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue,
756                                                  const ObjCMethodCall &M,
757                                                  CheckerContext &C) const {
758 
759   // Find the property backing the instance variable that M
760   // is dealloc'ing.
761   const ObjCPropertyImplDecl *PropImpl =
762       findPropertyOnDeallocatingInstance(DeallocedValue, C);
763   if (!PropImpl)
764     return false;
765 
766   if (getDeallocReleaseRequirement(PropImpl) !=
767       ReleaseRequirement::MustRelease) {
768     return false;
769   }
770 
771   ExplodedNode *ErrNode = C.generateErrorNode();
772   if (!ErrNode)
773     return false;
774 
775   std::string Buf;
776   llvm::raw_string_ostream OS(Buf);
777 
778   OS << "'" << *PropImpl->getPropertyIvarDecl()
779      << "' should be released rather than deallocated";
780 
781   std::unique_ptr<BugReport> BR(
782       new BugReport(*MistakenDeallocBugType, OS.str(), ErrNode));
783   BR->addRange(M.getOriginExpr()->getSourceRange());
784 
785   C.emitReport(std::move(BR));
786 
787   return true;
788 }
789 
790 ObjCDeallocChecker::ObjCDeallocChecker()
791     : NSObjectII(nullptr), SenTestCaseII(nullptr), XCTestCaseII(nullptr),
792       CIFilterII(nullptr) {
793 
794   MissingReleaseBugType.reset(
795       new BugType(this, "Missing ivar release (leak)",
796                   categories::MemoryCoreFoundationObjectiveC));
797 
798   ExtraReleaseBugType.reset(
799       new BugType(this, "Extra ivar release",
800                   categories::MemoryCoreFoundationObjectiveC));
801 
802   MistakenDeallocBugType.reset(
803       new BugType(this, "Mistaken dealloc",
804                   categories::MemoryCoreFoundationObjectiveC));
805 }
806 
807 void ObjCDeallocChecker::initIdentifierInfoAndSelectors(
808     ASTContext &Ctx) const {
809   if (NSObjectII)
810     return;
811 
812   NSObjectII = &Ctx.Idents.get("NSObject");
813   SenTestCaseII = &Ctx.Idents.get("SenTestCase");
814   XCTestCaseII = &Ctx.Idents.get("XCTestCase");
815   Block_releaseII = &Ctx.Idents.get("_Block_release");
816   CIFilterII = &Ctx.Idents.get("CIFilter");
817 
818   IdentifierInfo *DeallocII = &Ctx.Idents.get("dealloc");
819   IdentifierInfo *ReleaseII = &Ctx.Idents.get("release");
820   DeallocSel = Ctx.Selectors.getSelector(0, &DeallocII);
821   ReleaseSel = Ctx.Selectors.getSelector(0, &ReleaseII);
822 }
823 
824 /// Returns true if M is a call to '[super dealloc]'.
825 bool ObjCDeallocChecker::isSuperDeallocMessage(
826     const ObjCMethodCall &M) const {
827   if (M.getOriginExpr()->getReceiverKind() != ObjCMessageExpr::SuperInstance)
828     return false;
829 
830   return M.getSelector() == DeallocSel;
831 }
832 
833 /// Returns the ObjCImplDecl containing the method declaration in LCtx.
834 const ObjCImplDecl *
835 ObjCDeallocChecker::getContainingObjCImpl(const LocationContext *LCtx) const {
836   auto *MD = cast<ObjCMethodDecl>(LCtx->getDecl());
837   return cast<ObjCImplDecl>(MD->getDeclContext());
838 }
839 
840 /// Returns the property that shadowed by PropImpl if one exists and
841 /// nullptr otherwise.
842 const ObjCPropertyDecl *ObjCDeallocChecker::findShadowedPropertyDecl(
843     const ObjCPropertyImplDecl *PropImpl) const {
844   const ObjCPropertyDecl *PropDecl = PropImpl->getPropertyDecl();
845 
846   // Only readwrite properties can shadow.
847   if (PropDecl->isReadOnly())
848     return nullptr;
849 
850   auto *CatDecl = dyn_cast<ObjCCategoryDecl>(PropDecl->getDeclContext());
851 
852   // Only class extensions can contain shadowing properties.
853   if (!CatDecl || !CatDecl->IsClassExtension())
854     return nullptr;
855 
856   IdentifierInfo *ID = PropDecl->getIdentifier();
857   DeclContext::lookup_result R = CatDecl->getClassInterface()->lookup(ID);
858   for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
859     auto *ShadowedPropDecl = dyn_cast<ObjCPropertyDecl>(*I);
860     if (!ShadowedPropDecl)
861       continue;
862 
863     if (ShadowedPropDecl->isInstanceProperty()) {
864       assert(ShadowedPropDecl->isReadOnly());
865       return ShadowedPropDecl;
866     }
867   }
868 
869   return nullptr;
870 }
871 
872 /// Add a transition noting the release of the given value.
873 void ObjCDeallocChecker::transitionToReleaseValue(CheckerContext &C,
874                                                   SymbolRef Value) const {
875   assert(Value);
876   SymbolRef InstanceSym = getInstanceSymbolFromIvarSymbol(Value);
877   if (!InstanceSym)
878     return;
879   ProgramStateRef InitialState = C.getState();
880 
881   ProgramStateRef ReleasedState =
882       removeValueRequiringRelease(InitialState, InstanceSym, Value);
883 
884   if (ReleasedState != InitialState) {
885     C.addTransition(ReleasedState);
886   }
887 }
888 
889 /// Remove the Value requiring a release from the tracked set for
890 /// Instance and return the resultant state.
891 ProgramStateRef ObjCDeallocChecker::removeValueRequiringRelease(
892     ProgramStateRef State, SymbolRef Instance, SymbolRef Value) const {
893   assert(Instance);
894   assert(Value);
895   const ObjCIvarRegion *RemovedRegion = getIvarRegionForIvarSymbol(Value);
896   if (!RemovedRegion)
897     return State;
898 
899   const SymbolSet *Unreleased = State->get<UnreleasedIvarMap>(Instance);
900   if (!Unreleased)
901     return State;
902 
903   // Mark the value as no longer requiring a release.
904   SymbolSet::Factory &F = State->getStateManager().get_context<SymbolSet>();
905   SymbolSet NewUnreleased = *Unreleased;
906   for (auto &Sym : *Unreleased) {
907     const ObjCIvarRegion *UnreleasedRegion = getIvarRegionForIvarSymbol(Sym);
908     assert(UnreleasedRegion);
909     if (RemovedRegion->getDecl() == UnreleasedRegion->getDecl()) {
910       NewUnreleased = F.remove(NewUnreleased, Sym);
911     }
912   }
913 
914   if (NewUnreleased.isEmpty()) {
915     return State->remove<UnreleasedIvarMap>(Instance);
916   }
917 
918   return State->set<UnreleasedIvarMap>(Instance, NewUnreleased);
919 }
920 
921 /// Determines whether the instance variable for \p PropImpl must or must not be
922 /// released in -dealloc or whether it cannot be determined.
923 ReleaseRequirement ObjCDeallocChecker::getDeallocReleaseRequirement(
924     const ObjCPropertyImplDecl *PropImpl) const {
925   const ObjCIvarDecl *IvarDecl;
926   const ObjCPropertyDecl *PropDecl;
927   if (!isSynthesizedRetainableProperty(PropImpl, &IvarDecl, &PropDecl))
928     return ReleaseRequirement::Unknown;
929 
930   ObjCPropertyDecl::SetterKind SK = PropDecl->getSetterKind();
931 
932   switch (SK) {
933   // Retain and copy setters retain/copy their values before storing and so
934   // the value in their instance variables must be released in -dealloc.
935   case ObjCPropertyDecl::Retain:
936   case ObjCPropertyDecl::Copy:
937     if (isReleasedByCIFilterDealloc(PropImpl))
938       return ReleaseRequirement::MustNotReleaseDirectly;
939 
940     if (isNibLoadedIvarWithoutRetain(PropImpl))
941       return ReleaseRequirement::Unknown;
942 
943     return ReleaseRequirement::MustRelease;
944 
945   case ObjCPropertyDecl::Weak:
946     return ReleaseRequirement::MustNotReleaseDirectly;
947 
948   case ObjCPropertyDecl::Assign:
949     // It is common for the ivars for read-only assign properties to
950     // always be stored retained, so their release requirement cannot be
951     // be determined.
952     if (PropDecl->isReadOnly())
953       return ReleaseRequirement::Unknown;
954 
955     return ReleaseRequirement::MustNotReleaseDirectly;
956   }
957   llvm_unreachable("Unrecognized setter kind");
958 }
959 
960 /// Returns the released value if M is a call a setter that releases
961 /// and nils out its underlying instance variable.
962 SymbolRef
963 ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M,
964                                                  CheckerContext &C) const {
965   SVal ReceiverVal = M.getReceiverSVal();
966   if (!ReceiverVal.isValid())
967     return nullptr;
968 
969   if (M.getNumArgs() == 0)
970     return nullptr;
971 
972   if (!M.getArgExpr(0)->getType()->isObjCRetainableType())
973     return nullptr;
974 
975   // Is the first argument nil?
976   SVal Arg = M.getArgSVal(0);
977   ProgramStateRef notNilState, nilState;
978   std::tie(notNilState, nilState) =
979       M.getState()->assume(Arg.castAs<DefinedOrUnknownSVal>());
980   if (!(nilState && !notNilState))
981     return nullptr;
982 
983   const ObjCPropertyDecl *Prop = M.getAccessedProperty();
984   if (!Prop)
985     return nullptr;
986 
987   ObjCIvarDecl *PropIvarDecl = Prop->getPropertyIvarDecl();
988   if (!PropIvarDecl)
989     return nullptr;
990 
991   ProgramStateRef State = C.getState();
992 
993   SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal);
994   Optional<Loc> LValLoc = LVal.getAs<Loc>();
995   if (!LValLoc)
996     return nullptr;
997 
998   SVal CurrentValInIvar = State->getSVal(LValLoc.getValue());
999   return CurrentValInIvar.getAsSymbol();
1000 }
1001 
1002 /// Returns true if the current context is a call to -dealloc and false
1003 /// otherwise. If true, it also sets SelfValOut to the value of
1004 /// 'self'.
1005 bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
1006                                              SVal &SelfValOut) const {
1007   return isInInstanceDealloc(C, C.getLocationContext(), SelfValOut);
1008 }
1009 
1010 /// Returns true if LCtx is a call to -dealloc and false
1011 /// otherwise. If true, it also sets SelfValOut to the value of
1012 /// 'self'.
1013 bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C,
1014                                              const LocationContext *LCtx,
1015                                              SVal &SelfValOut) const {
1016   auto *MD = dyn_cast<ObjCMethodDecl>(LCtx->getDecl());
1017   if (!MD || !MD->isInstanceMethod() || MD->getSelector() != DeallocSel)
1018     return false;
1019 
1020   const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
1021   assert(SelfDecl && "No self in -dealloc?");
1022 
1023   ProgramStateRef State = C.getState();
1024   SelfValOut = State->getSVal(State->getRegion(SelfDecl, LCtx));
1025   return true;
1026 }
1027 
1028 /// Returns true if there is a call to -dealloc anywhere on the stack and false
1029 /// otherwise. If true, it also sets InstanceValOut to the value of
1030 /// 'self' in the frame for -dealloc.
1031 bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C,
1032                                                   SVal &InstanceValOut) const {
1033   const LocationContext *LCtx = C.getLocationContext();
1034 
1035   while (LCtx) {
1036     if (isInInstanceDealloc(C, LCtx, InstanceValOut))
1037       return true;
1038 
1039     LCtx = LCtx->getParent();
1040   }
1041 
1042   return false;
1043 }
1044 
1045 /// Returns true if the ID is a class in which which is known to have
1046 /// a separate teardown lifecycle. In this case, -dealloc warnings
1047 /// about missing releases should be suppressed.
1048 bool ObjCDeallocChecker::classHasSeparateTeardown(
1049     const ObjCInterfaceDecl *ID) const {
1050   // Suppress if the class is not a subclass of NSObject.
1051   for ( ; ID ; ID = ID->getSuperClass()) {
1052     IdentifierInfo *II = ID->getIdentifier();
1053 
1054     if (II == NSObjectII)
1055       return false;
1056 
1057     // FIXME: For now, ignore classes that subclass SenTestCase and XCTestCase,
1058     // as these don't need to implement -dealloc.  They implement tear down in
1059     // another way, which we should try and catch later.
1060     //  http://llvm.org/bugs/show_bug.cgi?id=3187
1061     if (II == XCTestCaseII || II == SenTestCaseII)
1062       return true;
1063   }
1064 
1065   return true;
1066 }
1067 
1068 /// The -dealloc method in CIFilter highly unusual in that is will release
1069 /// instance variables belonging to its *subclasses* if the variable name
1070 /// starts with "input" or backs a property whose name starts with "input".
1071 /// Subclasses should not release these ivars in their own -dealloc method --
1072 /// doing so could result in an over release.
1073 ///
1074 /// This method returns true if the property will be released by
1075 /// -[CIFilter dealloc].
1076 bool ObjCDeallocChecker::isReleasedByCIFilterDealloc(
1077     const ObjCPropertyImplDecl *PropImpl) const {
1078   assert(PropImpl->getPropertyIvarDecl());
1079   StringRef PropName = PropImpl->getPropertyDecl()->getName();
1080   StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName();
1081 
1082   const char *ReleasePrefix = "input";
1083   if (!(PropName.startswith(ReleasePrefix) ||
1084         IvarName.startswith(ReleasePrefix))) {
1085     return false;
1086   }
1087 
1088   const ObjCInterfaceDecl *ID =
1089       PropImpl->getPropertyIvarDecl()->getContainingInterface();
1090   for ( ; ID ; ID = ID->getSuperClass()) {
1091     IdentifierInfo *II = ID->getIdentifier();
1092     if (II == CIFilterII)
1093       return true;
1094   }
1095 
1096   return false;
1097 }
1098 
1099 /// Returns whether the ivar backing the property is an IBOutlet that
1100 /// has its value set by nib loading code without retaining the value.
1101 ///
1102 /// On macOS, if there is no setter, the nib-loading code sets the ivar
1103 /// directly, without retaining the value,
1104 ///
1105 /// On iOS and its derivatives, the nib-loading code will call
1106 /// -setValue:forKey:, which retains the value before directly setting the ivar.
1107 bool ObjCDeallocChecker::isNibLoadedIvarWithoutRetain(
1108     const ObjCPropertyImplDecl *PropImpl) const {
1109   const ObjCIvarDecl *IvarDecl = PropImpl->getPropertyIvarDecl();
1110   if (!IvarDecl->hasAttr<IBOutletAttr>())
1111     return false;
1112 
1113   const llvm::Triple &Target =
1114       IvarDecl->getASTContext().getTargetInfo().getTriple();
1115 
1116   if (!Target.isMacOSX())
1117     return false;
1118 
1119   if (PropImpl->getPropertyDecl()->getSetterMethodDecl())
1120     return false;
1121 
1122   return true;
1123 }
1124 
1125 void ento::registerObjCDeallocChecker(CheckerManager &Mgr) {
1126   const LangOptions &LangOpts = Mgr.getLangOpts();
1127   // These checker only makes sense under MRR.
1128   if (LangOpts.getGC() == LangOptions::GCOnly || LangOpts.ObjCAutoRefCount)
1129     return;
1130 
1131   Mgr.registerChecker<ObjCDeallocChecker>();
1132 }
1133