clang  10.0.0svn
RetainCountDiagnostics.cpp
Go to the documentation of this file.
1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- C++ -*--//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines diagnostics for RetainCountChecker, which implements
10 // a reference count checker for Core Foundation and Cocoa on (Mac OS X).
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "RetainCountDiagnostics.h"
15 #include "RetainCountChecker.h"
16 
17 using namespace clang;
18 using namespace ento;
19 using namespace retaincountchecker;
20 
21 StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugType BT) {
22  switch (BT) {
23  case UseAfterRelease:
24  return "Use-after-release";
25  case ReleaseNotOwned:
26  return "Bad release";
27  case DeallocNotOwned:
28  return "-dealloc sent to non-exclusively owned object";
29  case FreeNotOwned:
30  return "freeing non-exclusively owned object";
31  case OverAutorelease:
32  return "Object autoreleased too many times";
34  return "Method should return an owned object";
35  case LeakWithinFunction:
36  return "Leak";
37  case LeakAtReturn:
38  return "Leak of returned object";
39  }
40  llvm_unreachable("Unknown RefCountBugType");
41 }
42 
43 StringRef RefCountBug::getDescription() const {
44  switch (BT) {
45  case UseAfterRelease:
46  return "Reference-counted object is used after it is released";
47  case ReleaseNotOwned:
48  return "Incorrect decrement of the reference count of an object that is "
49  "not owned at this point by the caller";
50  case DeallocNotOwned:
51  return "-dealloc sent to object that may be referenced elsewhere";
52  case FreeNotOwned:
53  return "'free' called on an object that may be referenced elsewhere";
54  case OverAutorelease:
55  return "Object autoreleased too many times";
57  return "Object with a +0 retain count returned to caller where a +1 "
58  "(owning) retain count is expected";
59  case LeakWithinFunction:
60  case LeakAtReturn:
61  return "";
62  }
63  llvm_unreachable("Unknown RefCountBugType");
64 }
65 
67  : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount,
68  /*SuppressOnSink=*/BT == LeakWithinFunction || BT == LeakAtReturn),
69  BT(BT), Checker(Checker) {}
70 
71 static bool isNumericLiteralExpression(const Expr *E) {
72  // FIXME: This set of cases was copied from SemaExprObjC.
73  return isa<IntegerLiteral>(E) ||
74  isa<CharacterLiteral>(E) ||
75  isa<FloatingLiteral>(E) ||
76  isa<ObjCBoolLiteralExpr>(E) ||
77  isa<CXXBoolLiteralExpr>(E);
78 }
79 
80 /// If type represents a pointer to CXXRecordDecl,
81 /// and is not a typedef, return the decl name.
82 /// Otherwise, return the serialization of type.
83 static std::string getPrettyTypeName(QualType QT) {
84  QualType PT = QT->getPointeeType();
85  if (!PT.isNull() && !QT->getAs<TypedefType>())
86  if (const auto *RD = PT->getAsCXXRecordDecl())
87  return RD->getName();
88  return QT.getAsString();
89 }
90 
91 /// Write information about the type state change to {@code os},
92 /// return whether the note should be generated.
93 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
94  const RefVal *PrevT,
95  const RefVal &CurrV,
96  bool DeallocSent) {
97  // Get the previous type state.
98  RefVal PrevV = *PrevT;
99 
100  // Specially handle -dealloc.
101  if (DeallocSent) {
102  // Determine if the object's reference count was pushed to zero.
103  assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
104  // We may not have transitioned to 'release' if we hit an error.
105  // This case is handled elsewhere.
106  if (CurrV.getKind() == RefVal::Released) {
107  assert(CurrV.getCombinedCounts() == 0);
108  os << "Object released by directly sending the '-dealloc' message";
109  return true;
110  }
111  }
112 
113  // Determine if the typestate has changed.
114  if (!PrevV.hasSameState(CurrV))
115  switch (CurrV.getKind()) {
116  case RefVal::Owned:
117  case RefVal::NotOwned:
118  if (PrevV.getCount() == CurrV.getCount()) {
119  // Did an autorelease message get sent?
120  if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
121  return false;
122 
123  assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
124  os << "Object autoreleased";
125  return true;
126  }
127 
128  if (PrevV.getCount() > CurrV.getCount())
129  os << "Reference count decremented.";
130  else
131  os << "Reference count incremented.";
132 
133  if (unsigned Count = CurrV.getCount())
134  os << " The object now has a +" << Count << " retain count.";
135 
136  return true;
137 
138  case RefVal::Released:
139  if (CurrV.getIvarAccessHistory() ==
141  CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
142  os << "Strong instance variable relinquished. ";
143  }
144  os << "Object released.";
145  return true;
146 
148  // Autoreleases can be applied after marking a node ReturnedOwned.
149  if (CurrV.getAutoreleaseCount())
150  return false;
151 
152  os << "Object returned to caller as an owning reference (single "
153  "retain count transferred to caller)";
154  return true;
155 
157  os << "Object returned to caller with a +0 retain count";
158  return true;
159 
160  default:
161  return false;
162  }
163  return true;
164 }
165 
166 /// Finds argument index of the out paramter in the call {@code S}
167 /// corresponding to the symbol {@code Sym}.
168 /// If none found, returns None.
169 static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
170  const LocationContext *LCtx,
171  SymbolRef &Sym,
172  Optional<CallEventRef<>> CE) {
173  if (!CE)
174  return None;
175 
176  for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
177  if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
178  if (const auto *TR = dyn_cast<TypedValueRegion>(MR))
179  if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym)
180  return Idx;
181 
182  return None;
183 }
184 
185 static Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
186  if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
187  if (ME->getMemberDecl()->getNameAsString() != "alloc")
188  return None;
189  const Expr *This = ME->getBase()->IgnoreParenImpCasts();
190  if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
191  const ValueDecl *VD = DRE->getDecl();
192  if (VD->getNameAsString() != "metaClass")
193  return None;
194 
195  if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
196  return RD->getNameAsString();
197 
198  }
199  }
200  return None;
201 }
202 
203 static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
204  if (const auto *CE = dyn_cast<CallExpr>(S))
205  if (auto Out = findMetaClassAlloc(CE->getCallee()))
206  return *Out;
207  return getPrettyTypeName(QT);
208 }
209 
210 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
211  const LocationContext *LCtx,
212  const RefVal &CurrV, SymbolRef &Sym,
213  const Stmt *S,
214  llvm::raw_string_ostream &os) {
215  CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
216  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
217  // Get the name of the callee (if it is available)
218  // from the tracked SVal.
219  SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
220  const FunctionDecl *FD = X.getAsFunctionDecl();
221 
222  // If failed, try to get it from AST.
223  if (!FD)
224  FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
225 
226  if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
227  os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
228  } else if (FD) {
229  os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
230  } else {
231  os << "function call";
232  }
233  } else if (isa<CXXNewExpr>(S)) {
234  os << "Operator 'new'";
235  } else {
236  assert(isa<ObjCMessageExpr>(S));
238  Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
239 
240  switch (Call->getMessageKind()) {
241  case OCM_Message:
242  os << "Method";
243  break;
244  case OCM_PropertyAccess:
245  os << "Property";
246  break;
247  case OCM_Subscript:
248  os << "Subscript";
249  break;
250  }
251  }
252 
253  Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
254  auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
255 
256  // If index is not found, we assume that the symbol was returned.
257  if (!Idx) {
258  os << " returns ";
259  } else {
260  os << " writes ";
261  }
262 
263  if (CurrV.getObjKind() == ObjKind::CF) {
264  os << "a Core Foundation object of type '"
265  << Sym->getType().getAsString() << "' with a ";
266  } else if (CurrV.getObjKind() == ObjKind::OS) {
267  os << "an OSObject of type '" << findAllocatedObjectName(S, Sym->getType())
268  << "' with a ";
269  } else if (CurrV.getObjKind() == ObjKind::Generalized) {
270  os << "an object of type '" << Sym->getType().getAsString()
271  << "' with a ";
272  } else {
273  assert(CurrV.getObjKind() == ObjKind::ObjC);
274  QualType T = Sym->getType();
275  if (!isa<ObjCObjectPointerType>(T)) {
276  os << "an Objective-C object with a ";
277  } else {
278  const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
279  os << "an instance of " << PT->getPointeeType().getAsString()
280  << " with a ";
281  }
282  }
283 
284  if (CurrV.isOwned()) {
285  os << "+1 retain count";
286  } else {
287  assert(CurrV.isNotOwned());
288  os << "+0 retain count";
289  }
290 
291  if (Idx) {
292  os << " into an out parameter '";
293  const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
295  /*Qualified=*/false);
296  os << "'";
297 
298  QualType RT = (*CE)->getResultType();
299  if (!RT.isNull() && !RT->isVoidType()) {
300  SVal RV = (*CE)->getReturnValue();
301  if (CurrSt->isNull(RV).isConstrainedTrue()) {
302  os << " (assuming the call returns zero)";
303  } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
304  os << " (assuming the call returns non-zero)";
305  }
306 
307  }
308  }
309 }
310 
311 namespace clang {
312 namespace ento {
313 namespace retaincountchecker {
314 
315 class RefCountReportVisitor : public BugReporterVisitor {
316 protected:
317  SymbolRef Sym;
318 
319 public:
320  RefCountReportVisitor(SymbolRef sym) : Sym(sym) {}
321 
322  void Profile(llvm::FoldingSetNodeID &ID) const override {
323  static int x = 0;
324  ID.AddPointer(&x);
325  ID.AddPointer(Sym);
326  }
327 
328  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
329  BugReporterContext &BRC,
330  PathSensitiveBugReport &BR) override;
331 
333  const ExplodedNode *N,
334  PathSensitiveBugReport &BR) override;
335 };
336 
337 class RefLeakReportVisitor : public RefCountReportVisitor {
338 public:
339  RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
340 
342  const ExplodedNode *N,
343  PathSensitiveBugReport &BR) override;
344 };
345 
346 } // end namespace retaincountchecker
347 } // end namespace ento
348 } // end namespace clang
349 
350 
351 /// Find the first node with the parent stack frame.
352 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
353  const StackFrameContext *SC = Pred->getStackFrame();
354  if (SC->inTopFrame())
355  return nullptr;
356  const StackFrameContext *PC = SC->getParent()->getStackFrame();
357  if (!PC)
358  return nullptr;
359 
360  const ExplodedNode *N = Pred;
361  while (N && N->getStackFrame() != PC) {
362  N = N->getFirstPred();
363  }
364  return N;
365 }
366 
367 
368 /// Insert a diagnostic piece at function exit
369 /// if a function parameter is annotated as "os_consumed",
370 /// but it does not actually consume the reference.
371 static std::shared_ptr<PathDiagnosticEventPiece>
372 annotateConsumedSummaryMismatch(const ExplodedNode *N,
373  CallExitBegin &CallExitLoc,
374  const SourceManager &SM,
375  CallEventManager &CEMgr) {
376 
377  const ExplodedNode *CN = getCalleeNode(N);
378  if (!CN)
379  return nullptr;
380 
381  CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());
382 
383  std::string sbuf;
384  llvm::raw_string_ostream os(sbuf);
385  ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
386  for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
387  const ParmVarDecl *PVD = Parameters[I];
388 
389  if (!PVD->hasAttr<OSConsumedAttr>())
390  continue;
391 
392  if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
393  const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
394  const RefVal *CountAtExit = getRefBinding(N->getState(), SR);
395 
396  if (!CountBeforeCall || !CountAtExit)
397  continue;
398 
399  unsigned CountBefore = CountBeforeCall->getCount();
400  unsigned CountAfter = CountAtExit->getCount();
401 
402  bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
403  if (!AsExpected) {
404  os << "Parameter '";
406  /*Qualified=*/false);
407  os << "' is marked as consuming, but the function did not consume "
408  << "the reference\n";
409  }
410  }
411  }
412 
413  if (os.str().empty())
414  return nullptr;
415 
417  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
418 }
419 
420 /// Annotate the parameter at the analysis entry point.
421 static std::shared_ptr<PathDiagnosticEventPiece>
422 annotateStartParameter(const ExplodedNode *N, SymbolRef Sym,
423  const SourceManager &SM) {
424  auto PP = N->getLocationAs<BlockEdge>();
425  if (!PP)
426  return nullptr;
427 
428  const CFGBlock *Src = PP->getSrc();
429  const RefVal *CurrT = getRefBinding(N->getState(), Sym);
430 
431  if (&Src->getParent()->getEntry() != Src || !CurrT ||
432  getRefBinding(N->getFirstPred()->getState(), Sym))
433  return nullptr;
434 
435  const auto *VR = cast<VarRegion>(cast<SymbolRegionValue>(Sym)->getRegion());
436  const auto *PVD = cast<ParmVarDecl>(VR->getDecl());
438 
439  std::string s;
440  llvm::raw_string_ostream os(s);
441  os << "Parameter '" << PVD->getNameAsString() << "' starts at +";
442  if (CurrT->getCount() == 1) {
443  os << "1, as it is marked as consuming";
444  } else {
445  assert(CurrT->getCount() == 0);
446  os << "0";
447  }
448  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
449 }
450 
452 RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
454 
455  const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
456  const auto *Checker =
457  static_cast<const RetainCountChecker *>(BT.getChecker());
458 
459  bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned ||
460  BT.getBugType() == RefCountBug::DeallocNotOwned;
461 
462  const SourceManager &SM = BRC.getSourceManager();
464  if (auto CE = N->getLocationAs<CallExitBegin>())
465  if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
466  return PD;
467 
468  if (auto PD = annotateStartParameter(N, Sym, SM))
469  return PD;
470 
471  // FIXME: We will eventually need to handle non-statement-based events
472  // (__attribute__((cleanup))).
473  if (!N->getLocation().getAs<StmtPoint>())
474  return nullptr;
475 
476  // Check if the type state has changed.
477  const ExplodedNode *PrevNode = N->getFirstPred();
478  ProgramStateRef PrevSt = PrevNode->getState();
479  ProgramStateRef CurrSt = N->getState();
480  const LocationContext *LCtx = N->getLocationContext();
481 
482  const RefVal* CurrT = getRefBinding(CurrSt, Sym);
483  if (!CurrT)
484  return nullptr;
485 
486  const RefVal &CurrV = *CurrT;
487  const RefVal *PrevT = getRefBinding(PrevSt, Sym);
488 
489  // Create a string buffer to constain all the useful things we want
490  // to tell the user.
491  std::string sbuf;
492  llvm::raw_string_ostream os(sbuf);
493 
494  if (PrevT && IsFreeUnowned && CurrV.isNotOwned() && PrevT->isOwned()) {
495  os << "Object is now not exclusively owned";
497  return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
498  }
499 
500  // This is the allocation site since the previous node had no bindings
501  // for this symbol.
502  if (!PrevT) {
503  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
504 
505  if (isa<ObjCIvarRefExpr>(S) &&
507  S = LCtx->getStackFrame()->getCallSite();
508  }
509 
510  if (isa<ObjCArrayLiteral>(S)) {
511  os << "NSArray literal is an object with a +0 retain count";
512  } else if (isa<ObjCDictionaryLiteral>(S)) {
513  os << "NSDictionary literal is an object with a +0 retain count";
514  } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
515  if (isNumericLiteralExpression(BL->getSubExpr()))
516  os << "NSNumber literal is an object with a +0 retain count";
517  else {
518  const ObjCInterfaceDecl *BoxClass = nullptr;
519  if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
520  BoxClass = Method->getClassInterface();
521 
522  // We should always be able to find the boxing class interface,
523  // but consider this future-proofing.
524  if (BoxClass) {
525  os << *BoxClass << " b";
526  } else {
527  os << "B";
528  }
529 
530  os << "oxed expression produces an object with a +0 retain count";
531  }
532  } else if (isa<ObjCIvarRefExpr>(S)) {
533  os << "Object loaded from instance variable";
534  } else {
535  generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
536  }
537 
539  return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
540  }
541 
542  // Gather up the effects that were performed on the object at this
543  // program point
544  bool DeallocSent = false;
545 
546  const ProgramPointTag *Tag = N->getLocation().getTag();
547 
548  if (Tag == &Checker->getCastFailTag()) {
549  os << "Assuming dynamic cast returns null due to type mismatch";
550  }
551 
552  if (Tag == &Checker->getDeallocSentTag()) {
553  // We only have summaries attached to nodes after evaluating CallExpr and
554  // ObjCMessageExprs.
555  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
556 
557  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
558  // Iterate through the parameter expressions and see if the symbol
559  // was ever passed as an argument.
560  unsigned i = 0;
561 
562  for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
563 
564  // Retrieve the value of the argument. Is it the symbol
565  // we are interested in?
566  if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
567  continue;
568 
569  // We have an argument. Get the effect!
570  DeallocSent = true;
571  }
572  } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
573  if (const Expr *receiver = ME->getInstanceReceiver()) {
574  if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
575  .getAsLocSymbol() == Sym) {
576  // The symbol we are tracking is the receiver.
577  DeallocSent = true;
578  }
579  }
580  }
581  }
582 
583  if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent))
584  return nullptr;
585 
586  if (os.str().empty())
587  return nullptr; // We have nothing to say!
588 
589  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
591  N->getLocationContext());
592  auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
593 
594  // Add the range by scanning the children of the statement for any bindings
595  // to Sym.
596  for (const Stmt *Child : S->children())
597  if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
598  if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
599  P->addRange(Exp->getSourceRange());
600  break;
601  }
602 
603  return std::move(P);
604 }
605 
606 static Optional<std::string> describeRegion(const MemRegion *MR) {
607  if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
608  return std::string(VR->getDecl()->getName());
609  // Once we support more storage locations for bindings,
610  // this would need to be improved.
611  return None;
612 }
613 
614 namespace {
615 // Find the first node in the current function context that referred to the
616 // tracked symbol and the memory location that value was stored to. Note, the
617 // value is only reported if the allocation occurred in the same function as
618 // the leak. The function can also return a location context, which should be
619 // treated as interesting.
620 struct AllocationInfo {
621  const ExplodedNode* N;
622  const MemRegion *R;
623  const LocationContext *InterestingMethodContext;
624  AllocationInfo(const ExplodedNode *InN,
625  const MemRegion *InR,
626  const LocationContext *InInterestingMethodContext) :
627  N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
628 };
629 } // end anonymous namespace
630 
631 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
632  const ExplodedNode *N, SymbolRef Sym) {
633  const ExplodedNode *AllocationNode = N;
634  const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
635  const MemRegion *FirstBinding = nullptr;
636  const LocationContext *LeakContext = N->getLocationContext();
637 
638  // The location context of the init method called on the leaked object, if
639  // available.
640  const LocationContext *InitMethodContext = nullptr;
641 
642  while (N) {
643  ProgramStateRef St = N->getState();
644  const LocationContext *NContext = N->getLocationContext();
645 
646  if (!getRefBinding(St, Sym))
647  break;
648 
650  StateMgr.iterBindings(St, FB);
651 
652  if (FB) {
653  const MemRegion *R = FB.getRegion();
654  // Do not show local variables belonging to a function other than
655  // where the error is reported.
656  if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
657  if (MR->getStackFrame() == LeakContext->getStackFrame())
658  FirstBinding = R;
659  }
660 
661  // AllocationNode is the last node in which the symbol was tracked.
662  AllocationNode = N;
663 
664  // AllocationNodeInCurrentContext, is the last node in the current or
665  // parent context in which the symbol was tracked.
666  //
667  // Note that the allocation site might be in the parent context. For example,
668  // the case where an allocation happens in a block that captures a reference
669  // to it and that reference is overwritten/dropped by another call to
670  // the block.
671  if (NContext == LeakContext || NContext->isParentOf(LeakContext))
672  AllocationNodeInCurrentOrParentContext = N;
673 
674  // Find the last init that was called on the given symbol and store the
675  // init method's location context.
676  if (!InitMethodContext)
677  if (auto CEP = N->getLocation().getAs<CallEnter>()) {
678  const Stmt *CE = CEP->getCallExpr();
679  if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
680  const Stmt *RecExpr = ME->getInstanceReceiver();
681  if (RecExpr) {
682  SVal RecV = St->getSVal(RecExpr, NContext);
683  if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
684  InitMethodContext = CEP->getCalleeContext();
685  }
686  }
687  }
688 
689  N = N->getFirstPred();
690  }
691 
692  // If we are reporting a leak of the object that was allocated with alloc,
693  // mark its init method as interesting.
694  const LocationContext *InterestingMethodContext = nullptr;
695  if (InitMethodContext) {
696  const ProgramPoint AllocPP = AllocationNode->getLocation();
697  if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
698  if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
699  if (ME->getMethodFamily() == OMF_alloc)
700  InterestingMethodContext = InitMethodContext;
701  }
702 
703  // If allocation happened in a function different from the leak node context,
704  // do not report the binding.
705  assert(N && "Could not find allocation node");
706 
707  if (AllocationNodeInCurrentOrParentContext &&
708  AllocationNodeInCurrentOrParentContext->getLocationContext() !=
709  LeakContext)
710  FirstBinding = nullptr;
711 
712  return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding,
713  InterestingMethodContext);
714 }
715 
717 RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
718  const ExplodedNode *EndN,
720  BR.markInteresting(Sym);
721  return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
722 }
723 
725 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
726  const ExplodedNode *EndN,
728 
729  // Tell the BugReporterContext to report cases when the tracked symbol is
730  // assigned to different variables, etc.
731  BR.markInteresting(Sym);
732 
733  // We are reporting a leak. Walk up the graph to get to the first node where
734  // the symbol appeared, and also get the first VarDecl that tracked object
735  // is stored to.
736  AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
737 
738  const MemRegion* FirstBinding = AllocI.R;
739  BR.markInteresting(AllocI.InterestingMethodContext);
740 
741  PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath();
742 
743  std::string sbuf;
744  llvm::raw_string_ostream os(sbuf);
745 
746  os << "Object leaked: ";
747 
748  Optional<std::string> RegionDescription = describeRegion(FirstBinding);
749  if (RegionDescription) {
750  os << "object allocated and stored into '" << *RegionDescription << '\'';
751  } else {
752  os << "allocated object of type '" << getPrettyTypeName(Sym->getType())
753  << "'";
754  }
755 
756  // Get the retain count.
757  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
758  assert(RV);
759 
760  if (RV->getKind() == RefVal::ErrorLeakReturned) {
761  // FIXME: Per comments in rdar://6320065, "create" only applies to CF
762  // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
763  // to the caller for NS objects.
764  const Decl *D = &EndN->getCodeDecl();
765 
766  os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
767  : " is returned from a function ");
768 
769  if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
770  os << "that is annotated as CF_RETURNS_NOT_RETAINED";
771  } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
772  os << "that is annotated as NS_RETURNS_NOT_RETAINED";
773  } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
774  os << "that is annotated as OS_RETURNS_NOT_RETAINED";
775  } else {
776  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
777  if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
778  os << "managed by Automatic Reference Counting";
779  } else {
780  os << "whose name ('" << MD->getSelector().getAsString()
781  << "') does not start with "
782  "'copy', 'mutableCopy', 'alloc' or 'new'."
783  " This violates the naming convention rules"
784  " given in the Memory Management Guide for Cocoa";
785  }
786  } else {
787  const FunctionDecl *FD = cast<FunctionDecl>(D);
788  ObjKind K = RV->getObjKind();
789  if (K == ObjKind::ObjC || K == ObjKind::CF) {
790  os << "whose name ('" << *FD
791  << "') does not contain 'Copy' or 'Create'. This violates the "
792  "naming"
793  " convention rules given in the Memory Management Guide for "
794  "Core"
795  " Foundation";
796  } else if (RV->getObjKind() == ObjKind::OS) {
797  std::string FuncName = FD->getNameAsString();
798  os << "whose name ('" << FuncName
799  << "') starts with '" << StringRef(FuncName).substr(0, 3) << "'";
800  }
801  }
802  }
803  } else {
804  os << " is not referenced later in this execution path and has a retain "
805  "count of +" << RV->getCount();
806  }
807 
808  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
809 }
810 
812  ExplodedNode *n, SymbolRef sym, bool isLeak)
813  : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym),
814  isLeak(isLeak) {
815  if (!isLeak)
816  addVisitor(std::make_unique<RefCountReportVisitor>(sym));
817 }
818 
820  ExplodedNode *n, SymbolRef sym,
821  StringRef endText)
822  : PathSensitiveBugReport(D, D.getDescription(), endText, n) {
823 
824  addVisitor(std::make_unique<RefCountReportVisitor>(sym));
825 }
826 
827 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
828  const SourceManager& SMgr = Ctx.getSourceManager();
829 
830  if (!sym->getOriginRegion())
831  return;
832 
833  auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
834  if (Region) {
835  const Decl *PDecl = Region->getDecl();
836  if (PDecl && isa<ParmVarDecl>(PDecl)) {
837  PathDiagnosticLocation ParamLocation =
838  PathDiagnosticLocation::create(PDecl, SMgr);
839  Location = ParamLocation;
840  UniqueingLocation = ParamLocation;
841  UniqueingDecl = Ctx.getLocationContext()->getDecl();
842  }
843  }
844 }
845 
846 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
847  SymbolRef sym) {
848  // Most bug reports are cached at the location where they occurred.
849  // With leaks, we want to unique them by the location where they were
850  // allocated, and only report a single path. To do this, we need to find
851  // the allocation site of a piece of tracked memory, which we do via a
852  // call to GetAllocationSite. This will walk the ExplodedGraph backwards.
853  // Note that this is *not* the trimmed graph; we are guaranteed, however,
854  // that all ancestor nodes that represent the allocation site have the
855  // same SourceLocation.
856  const ExplodedNode *AllocNode = nullptr;
857 
858  const SourceManager& SMgr = Ctx.getSourceManager();
859 
860  AllocationInfo AllocI =
861  GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
862 
863  AllocNode = AllocI.N;
864  AllocBinding = AllocI.R;
865  markInteresting(AllocI.InterestingMethodContext);
866 
867  // Get the SourceLocation for the allocation site.
868  // FIXME: This will crash the analyzer if an allocation comes from an
869  // implicit call (ex: a destructor call).
870  // (Currently there are no such allocations in Cocoa, though.)
871  AllocStmt = AllocNode->getStmtForDiagnostics();
872 
873  if (!AllocStmt) {
874  AllocBinding = nullptr;
875  return;
876  }
877 
878  PathDiagnosticLocation AllocLocation =
879  PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
880  AllocNode->getLocationContext());
881  Location = AllocLocation;
882 
883  // Set uniqieing info, which will be used for unique the bug reports. The
884  // leaks should be uniqued on the allocation site.
885  UniqueingLocation = AllocLocation;
886  UniqueingDecl = AllocNode->getLocationContext()->getDecl();
887 }
888 
889 void RefLeakReport::createDescription(CheckerContext &Ctx) {
890  assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
891  Description.clear();
892  llvm::raw_string_ostream os(Description);
893  os << "Potential leak of an object";
894 
895  Optional<std::string> RegionDescription = describeRegion(AllocBinding);
896  if (RegionDescription) {
897  os << " stored into '" << *RegionDescription << '\'';
898  } else {
899 
900  // If we can't figure out the name, just supply the type information.
901  os << " of type '" << getPrettyTypeName(Sym->getType()) << "'";
902  }
903 }
904 
906  ExplodedNode *n, SymbolRef sym,
907  CheckerContext &Ctx)
908  : RefCountReport(D, LOpts, n, sym, /*isLeak=*/true) {
909 
910  deriveAllocLocation(Ctx, sym);
911  if (!AllocBinding)
912  deriveParamLocation(Ctx, sym);
913 
914  createDescription(Ctx);
915 
916  addVisitor(std::make_unique<RefLeakReportVisitor>(sym));
917 }
Indicates that the tracked object is a generalized object.
Indicates that the tracked object is a CF object.
Represents a function declaration or definition.
Definition: Decl.h:1784
ObjKind
Determines the object kind of a tracked object.
A (possibly-)qualified type.
Definition: Type.h:643
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:94
Stmt - This represents one statement.
Definition: Stmt.h:66
CFGBlock & getEntry()
Definition: CFG.h:1317
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
ASTContext & getASTContext() const
Definition: BugReporter.h:706
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:630
Manages the lifetime of CallEvent objects.
Definition: CallEvent.h:1148
StringRef P
const ProgramStateRef & getState() const
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6858
bool This(InterpState &S, CodePtr OpPC)
Definition: Interp.h:830
const Decl & getCodeDecl() const
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:138
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
Definition: SymExpr.h:101
Represents a parameter to a function.
Definition: Decl.h:1600
Symbolic value.
Definition: SymExpr.h:29
bool isParentOf(const LocationContext *LC) const
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
Represents a point when we start the call exit sequence (for inlined call).
Definition: ProgramPoint.h:668
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
const BugType & getBugType() const
Definition: BugReporter.h:149
const char *const MemoryRefCount
ProgramStateManager & getStateManager()
child_range children()
Definition: Stmt.cpp:223
const LocationContext * getLocationContext() const
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:670
const LocationContext * getParent() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
ExplodedNode * getFirstPred()
Represents an ObjC class declaration.
Definition: DeclObjC.h:1171
const MemSpaceRegion * getMemorySpace() const
Definition: MemRegion.cpp:1128
static std::string getPrettyTypeName(QualType QT)
If type represents a pointer to CXXRecordDecl, and is not a typedef, return the decl name...
virtual QualType getType() const =0
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition: SVals.cpp:127
CFG * getParent() const
Definition: CFG.h:1077
bool hasAttr() const
Definition: DeclBase.h:542
const SourceManager & getSourceManager()
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1692
const Stmt * getCallSite() const
bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
Represents a single basic block in a source-level CFG.
Definition: CFG.h:576
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:644
This represents one expression.
Definition: Expr.h:108
CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)
Gets an outside caller given a callee context.
Definition: CallEvent.cpp:1380
DeclContext * getDeclContext()
Definition: DeclBase.h:438
bool inTopFrame() const override
Return true if the current LocationContext has no caller context.
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:950
RefCountReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, bool isLeak=false)
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
Definition: CallEvent.h:1217
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:708
const SourceManager & SM
Definition: Format.cpp:1667
RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, CheckerContext &Ctx)
const SourceManager & getSourceManager() const
Definition: BugReporter.h:710
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
Definition: ProgramPoint.h:140
ProgramPoints can be "tagged" as representing points specific to a given analysis entity...
Definition: ProgramPoint.h:39
Indicates that the tracked object is an Objective-C object.
std::string getNameAsString() const
Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...
Definition: Decl.h:291
CallEventManager & getCallEventManager()
Definition: ProgramState.h:530
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:377
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:75
ObjCBoxedExpr - used for generalized expression boxing.
Definition: ExprObjC.h:124
CallEventRef getCall(const Stmt *S, ProgramStateRef State, const LocationContext *LC)
Gets a call event for a function call, Objective-C method call, or a &#39;new&#39; call.
Definition: CallEvent.cpp:1430
Dataflow Directional Tag Classes.
virtual void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const
Appends a human-readable name for this declaration into the given stream.
Definition: Decl.cpp:1667
ProgramStateManager & getStateManager() const
Definition: BugReporter.h:702
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:979
const ProgramPointTag * getTag() const
Definition: ProgramPoint.h:177
const Decl * getDecl() const
Represents a pointer to an Objective C object.
Definition: Type.h:5870
const FunctionDecl * getAsFunctionDecl() const
getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a CodeTextRegion wrapping a FunctionDecl...
Definition: SVals.cpp:63
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
const StackFrameContext * getStackFrame() const
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Definition: SemaDecl.cpp:14652
bool isVoidType() const
Definition: Type.h:6650
RefCountBug(const CheckerBase *checker, RefCountBugType BT)
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2521
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1550
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
Definition: ProgramState.h:552
const StackFrameContext * getStackFrame() const
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
Definition: ProgramPoint.h:151
const LocationContext * getLocationContext() const
const LangOptions & getLangOpts() const
Definition: ASTContext.h:723
This class handles loading and caching of source files into memory.
static bool isNumericLiteralExpression(const Expr *E)
QualType getPointeeType() const
Gets the type pointed to by this ObjC pointer.
Definition: Type.h:5886