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