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