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