clang  8.0.0
RetainCountDiagnostics.cpp
Go to the documentation of this file.
1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- 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 file defines diagnostics for RetainCountChecker, which implements
11 // a reference count checker for Core Foundation and Cocoa on (Mac OS X).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "RetainCountDiagnostics.h"
16 #include "RetainCountChecker.h"
17 
18 using namespace clang;
19 using namespace ento;
20 using namespace retaincountchecker;
21 
22 static bool isNumericLiteralExpression(const Expr *E) {
23  // FIXME: This set of cases was copied from SemaExprObjC.
24  return isa<IntegerLiteral>(E) ||
25  isa<CharacterLiteral>(E) ||
26  isa<FloatingLiteral>(E) ||
27  isa<ObjCBoolLiteralExpr>(E) ||
28  isa<CXXBoolLiteralExpr>(E);
29 }
30 
31 /// If type represents a pointer to CXXRecordDecl,
32 /// and is not a typedef, return the decl name.
33 /// Otherwise, return the serialization of type.
34 static std::string getPrettyTypeName(QualType QT) {
35  QualType PT = QT->getPointeeType();
36  if (!PT.isNull() && !QT->getAs<TypedefType>())
37  if (const auto *RD = PT->getAsCXXRecordDecl())
38  return RD->getName();
39  return QT.getAsString();
40 }
41 
42 /// Write information about the type state change to {@code os},
43 /// return whether the note should be generated.
44 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
45  const RefVal *PrevT, const RefVal &CurrV,
46  bool DeallocSent) {
47  // Get the previous type state.
48  RefVal PrevV = *PrevT;
49 
50  // Specially handle -dealloc.
51  if (DeallocSent) {
52  // Determine if the object's reference count was pushed to zero.
53  assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
54  // We may not have transitioned to 'release' if we hit an error.
55  // This case is handled elsewhere.
56  if (CurrV.getKind() == RefVal::Released) {
57  assert(CurrV.getCombinedCounts() == 0);
58  os << "Object released by directly sending the '-dealloc' message";
59  return true;
60  }
61  }
62 
63  // Determine if the typestate has changed.
64  if (!PrevV.hasSameState(CurrV))
65  switch (CurrV.getKind()) {
66  case RefVal::Owned:
67  case RefVal::NotOwned:
68  if (PrevV.getCount() == CurrV.getCount()) {
69  // Did an autorelease message get sent?
70  if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
71  return false;
72 
73  assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
74  os << "Object autoreleased";
75  return true;
76  }
77 
78  if (PrevV.getCount() > CurrV.getCount())
79  os << "Reference count decremented.";
80  else
81  os << "Reference count incremented.";
82 
83  if (unsigned Count = CurrV.getCount())
84  os << " The object now has a +" << Count << " retain count.";
85 
86  return true;
87 
88  case RefVal::Released:
89  if (CurrV.getIvarAccessHistory() ==
91  CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
92  os << "Strong instance variable relinquished. ";
93  }
94  os << "Object released.";
95  return true;
96 
98  // Autoreleases can be applied after marking a node ReturnedOwned.
99  if (CurrV.getAutoreleaseCount())
100  return false;
101 
102  os << "Object returned to caller as an owning reference (single "
103  "retain count transferred to caller)";
104  return true;
105 
107  os << "Object returned to caller with a +0 retain count";
108  return true;
109 
110  default:
111  return false;
112  }
113  return true;
114 }
115 
116 /// Finds argument index of the out paramter in the call {@code S}
117 /// corresponding to the symbol {@code Sym}.
118 /// If none found, returns None.
119 static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
120  const LocationContext *LCtx,
121  SymbolRef &Sym,
122  Optional<CallEventRef<>> CE) {
123  if (!CE)
124  return None;
125 
126  for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
127  if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
128  if (const auto *TR = dyn_cast<TypedValueRegion>(MR))
129  if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym)
130  return Idx;
131 
132  return None;
133 }
134 
135 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
136  const LocationContext *LCtx,
137  const RefVal &CurrV, SymbolRef &Sym,
138  const Stmt *S,
139  llvm::raw_string_ostream &os) {
140  CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
141  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
142  // Get the name of the callee (if it is available)
143  // from the tracked SVal.
144  SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
145  const FunctionDecl *FD = X.getAsFunctionDecl();
146 
147  // If failed, try to get it from AST.
148  if (!FD)
149  FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
150 
151  if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
152  os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
153  } else if (FD) {
154  os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
155  } else {
156  os << "function call";
157  }
158  } else if (isa<CXXNewExpr>(S)) {
159  os << "Operator 'new'";
160  } else {
161  assert(isa<ObjCMessageExpr>(S));
163  Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
164 
165  switch (Call->getMessageKind()) {
166  case OCM_Message:
167  os << "Method";
168  break;
169  case OCM_PropertyAccess:
170  os << "Property";
171  break;
172  case OCM_Subscript:
173  os << "Subscript";
174  break;
175  }
176  }
177 
178  Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
179  auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
180 
181  // If index is not found, we assume that the symbol was returned.
182  if (!Idx) {
183  os << " returns ";
184  } else {
185  os << " writes ";
186  }
187 
188  if (CurrV.getObjKind() == ObjKind::CF) {
189  os << "a Core Foundation object of type '"
190  << Sym->getType().getAsString() << "' with a ";
191  } else if (CurrV.getObjKind() == ObjKind::OS) {
192  os << "an OSObject of type '" << getPrettyTypeName(Sym->getType())
193  << "' with a ";
194  } else if (CurrV.getObjKind() == ObjKind::Generalized) {
195  os << "an object of type '" << Sym->getType().getAsString()
196  << "' with a ";
197  } else {
198  assert(CurrV.getObjKind() == ObjKind::ObjC);
199  QualType T = Sym->getType();
200  if (!isa<ObjCObjectPointerType>(T)) {
201  os << "an Objective-C object with a ";
202  } else {
203  const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
204  os << "an instance of " << PT->getPointeeType().getAsString()
205  << " with a ";
206  }
207  }
208 
209  if (CurrV.isOwned()) {
210  os << "+1 retain count";
211  } else {
212  assert(CurrV.isNotOwned());
213  os << "+0 retain count";
214  }
215 
216  if (Idx) {
217  os << " into an out parameter '";
218  const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
220  /*Qualified=*/false);
221  os << "'";
222 
223  QualType RT = (*CE)->getResultType();
224  if (!RT.isNull() && !RT->isVoidType()) {
225  SVal RV = (*CE)->getReturnValue();
226  if (CurrSt->isNull(RV).isConstrainedTrue()) {
227  os << " (assuming the call returns zero)";
228  } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
229  os << " (assuming the call returns non-zero)";
230  }
231 
232  }
233  }
234 }
235 
236 namespace clang {
237 namespace ento {
238 namespace retaincountchecker {
239 
240 class RefCountReportVisitor : public BugReporterVisitor {
241 protected:
242  SymbolRef Sym;
243 
244 public:
245  RefCountReportVisitor(SymbolRef sym) : Sym(sym) {}
246 
247  void Profile(llvm::FoldingSetNodeID &ID) const override {
248  static int x = 0;
249  ID.AddPointer(&x);
250  ID.AddPointer(Sym);
251  }
252 
253  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
254  BugReporterContext &BRC,
255  BugReport &BR) override;
256 
257  std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
258  const ExplodedNode *N,
259  BugReport &BR) override;
260 };
261 
262 class RefLeakReportVisitor : public RefCountReportVisitor {
263 public:
264  RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
265 
266  std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
267  const ExplodedNode *N,
268  BugReport &BR) override;
269 };
270 
271 } // end namespace retaincountchecker
272 } // end namespace ento
273 } // end namespace clang
274 
275 
276 /// Find the first node with the parent stack frame.
277 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
278  const StackFrameContext *SC = Pred->getStackFrame();
279  if (SC->inTopFrame())
280  return nullptr;
281  const StackFrameContext *PC = SC->getParent()->getStackFrame();
282  if (!PC)
283  return nullptr;
284 
285  const ExplodedNode *N = Pred;
286  while (N && N->getStackFrame() != PC) {
287  N = N->getFirstPred();
288  }
289  return N;
290 }
291 
292 
293 /// Insert a diagnostic piece at function exit
294 /// if a function parameter is annotated as "os_consumed",
295 /// but it does not actually consume the reference.
296 static std::shared_ptr<PathDiagnosticEventPiece>
297 annotateConsumedSummaryMismatch(const ExplodedNode *N,
298  CallExitBegin &CallExitLoc,
299  const SourceManager &SM,
300  CallEventManager &CEMgr) {
301 
302  const ExplodedNode *CN = getCalleeNode(N);
303  if (!CN)
304  return nullptr;
305 
306  CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());
307 
308  std::string sbuf;
309  llvm::raw_string_ostream os(sbuf);
310  ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
311  for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
312  const ParmVarDecl *PVD = Parameters[I];
313 
314  if (!PVD->hasAttr<OSConsumedAttr>())
315  continue;
316 
317  if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
318  const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
319  const RefVal *CountAtExit = getRefBinding(N->getState(), SR);
320 
321  if (!CountBeforeCall || !CountAtExit)
322  continue;
323 
324  unsigned CountBefore = CountBeforeCall->getCount();
325  unsigned CountAfter = CountAtExit->getCount();
326 
327  bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
328  if (!AsExpected) {
329  os << "Parameter '";
331  /*Qualified=*/false);
332  os << "' is marked as consuming, but the function did not consume "
333  << "the reference\n";
334  }
335  }
336  }
337 
338  if (os.str().empty())
339  return nullptr;
340 
341  // FIXME: remove the code duplication with NoStoreFuncVisitor.
343  if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) {
345  } else {
347  Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM);
348  }
349 
350  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
351 }
352 
353 std::shared_ptr<PathDiagnosticPiece>
354 RefCountReportVisitor::VisitNode(const ExplodedNode *N,
355  BugReporterContext &BRC, BugReport &BR) {
356 
357  const SourceManager &SM = BRC.getSourceManager();
359  if (auto CE = N->getLocationAs<CallExitBegin>())
360  if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
361  return PD;
362 
363  // FIXME: We will eventually need to handle non-statement-based events
364  // (__attribute__((cleanup))).
365  if (!N->getLocation().getAs<StmtPoint>())
366  return nullptr;
367 
368  // Check if the type state has changed.
369  const ExplodedNode *PrevNode = N->getFirstPred();
370  ProgramStateRef PrevSt = PrevNode->getState();
371  ProgramStateRef CurrSt = N->getState();
372  const LocationContext *LCtx = N->getLocationContext();
373 
374  const RefVal* CurrT = getRefBinding(CurrSt, Sym);
375  if (!CurrT) return nullptr;
376 
377  const RefVal &CurrV = *CurrT;
378  const RefVal *PrevT = getRefBinding(PrevSt, Sym);
379 
380  // Create a string buffer to constain all the useful things we want
381  // to tell the user.
382  std::string sbuf;
383  llvm::raw_string_ostream os(sbuf);
384 
385  // This is the allocation site since the previous node had no bindings
386  // for this symbol.
387  if (!PrevT) {
388  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
389 
390  if (isa<ObjCIvarRefExpr>(S) &&
392  S = LCtx->getStackFrame()->getCallSite();
393  }
394 
395  if (isa<ObjCArrayLiteral>(S)) {
396  os << "NSArray literal is an object with a +0 retain count";
397  } else if (isa<ObjCDictionaryLiteral>(S)) {
398  os << "NSDictionary literal is an object with a +0 retain count";
399  } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
400  if (isNumericLiteralExpression(BL->getSubExpr()))
401  os << "NSNumber literal is an object with a +0 retain count";
402  else {
403  const ObjCInterfaceDecl *BoxClass = nullptr;
404  if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
405  BoxClass = Method->getClassInterface();
406 
407  // We should always be able to find the boxing class interface,
408  // but consider this future-proofing.
409  if (BoxClass) {
410  os << *BoxClass << " b";
411  } else {
412  os << "B";
413  }
414 
415  os << "oxed expression produces an object with a +0 retain count";
416  }
417  } else if (isa<ObjCIvarRefExpr>(S)) {
418  os << "Object loaded from instance variable";
419  } else {
420  generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
421  }
422 
424  return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
425  }
426 
427  // Gather up the effects that were performed on the object at this
428  // program point
429  bool DeallocSent = false;
430 
431  if (N->getLocation().getTag() &&
432  N->getLocation().getTag()->getTagDescription().contains(
434  // We only have summaries attached to nodes after evaluating CallExpr and
435  // ObjCMessageExprs.
436  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
437 
438  if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
439  // Iterate through the parameter expressions and see if the symbol
440  // was ever passed as an argument.
441  unsigned i = 0;
442 
443  for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
444 
445  // Retrieve the value of the argument. Is it the symbol
446  // we are interested in?
447  if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
448  continue;
449 
450  // We have an argument. Get the effect!
451  DeallocSent = true;
452  }
453  } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
454  if (const Expr *receiver = ME->getInstanceReceiver()) {
455  if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
456  .getAsLocSymbol() == Sym) {
457  // The symbol we are tracking is the receiver.
458  DeallocSent = true;
459  }
460  }
461  }
462  }
463 
464  if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent))
465  return nullptr;
466 
467  if (os.str().empty())
468  return nullptr; // We have nothing to say!
469 
470  const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
472  N->getLocationContext());
473  auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
474 
475  // Add the range by scanning the children of the statement for any bindings
476  // to Sym.
477  for (const Stmt *Child : S->children())
478  if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
479  if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
480  P->addRange(Exp->getSourceRange());
481  break;
482  }
483 
484  return std::move(P);
485 }
486 
487 static Optional<std::string> describeRegion(const MemRegion *MR) {
488  if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
489  return std::string(VR->getDecl()->getName());
490  // Once we support more storage locations for bindings,
491  // this would need to be improved.
492  return None;
493 }
494 
495 namespace {
496 // Find the first node in the current function context that referred to the
497 // tracked symbol and the memory location that value was stored to. Note, the
498 // value is only reported if the allocation occurred in the same function as
499 // the leak. The function can also return a location context, which should be
500 // treated as interesting.
501 struct AllocationInfo {
502  const ExplodedNode* N;
503  const MemRegion *R;
504  const LocationContext *InterestingMethodContext;
505  AllocationInfo(const ExplodedNode *InN,
506  const MemRegion *InR,
507  const LocationContext *InInterestingMethodContext) :
508  N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
509 };
510 } // end anonymous namespace
511 
512 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
513  const ExplodedNode *N, SymbolRef Sym) {
514  const ExplodedNode *AllocationNode = N;
515  const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
516  const MemRegion *FirstBinding = nullptr;
517  const LocationContext *LeakContext = N->getLocationContext();
518 
519  // The location context of the init method called on the leaked object, if
520  // available.
521  const LocationContext *InitMethodContext = nullptr;
522 
523  while (N) {
524  ProgramStateRef St = N->getState();
525  const LocationContext *NContext = N->getLocationContext();
526 
527  if (!getRefBinding(St, Sym))
528  break;
529 
531  StateMgr.iterBindings(St, FB);
532 
533  if (FB) {
534  const MemRegion *R = FB.getRegion();
535  // Do not show local variables belonging to a function other than
536  // where the error is reported.
537  if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
538  if (MR->getStackFrame() == LeakContext->getStackFrame())
539  FirstBinding = R;
540  }
541 
542  // AllocationNode is the last node in which the symbol was tracked.
543  AllocationNode = N;
544 
545  // AllocationNodeInCurrentContext, is the last node in the current or
546  // parent context in which the symbol was tracked.
547  //
548  // Note that the allocation site might be in the parent context. For example,
549  // the case where an allocation happens in a block that captures a reference
550  // to it and that reference is overwritten/dropped by another call to
551  // the block.
552  if (NContext == LeakContext || NContext->isParentOf(LeakContext))
553  AllocationNodeInCurrentOrParentContext = N;
554 
555  // Find the last init that was called on the given symbol and store the
556  // init method's location context.
557  if (!InitMethodContext)
558  if (auto CEP = N->getLocation().getAs<CallEnter>()) {
559  const Stmt *CE = CEP->getCallExpr();
560  if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
561  const Stmt *RecExpr = ME->getInstanceReceiver();
562  if (RecExpr) {
563  SVal RecV = St->getSVal(RecExpr, NContext);
564  if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
565  InitMethodContext = CEP->getCalleeContext();
566  }
567  }
568  }
569 
570  N = N->getFirstPred();
571  }
572 
573  // If we are reporting a leak of the object that was allocated with alloc,
574  // mark its init method as interesting.
575  const LocationContext *InterestingMethodContext = nullptr;
576  if (InitMethodContext) {
577  const ProgramPoint AllocPP = AllocationNode->getLocation();
578  if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
579  if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
580  if (ME->getMethodFamily() == OMF_alloc)
581  InterestingMethodContext = InitMethodContext;
582  }
583 
584  // If allocation happened in a function different from the leak node context,
585  // do not report the binding.
586  assert(N && "Could not find allocation node");
587 
588  if (AllocationNodeInCurrentOrParentContext &&
589  AllocationNodeInCurrentOrParentContext->getLocationContext() !=
590  LeakContext)
591  FirstBinding = nullptr;
592 
593  return AllocationInfo(AllocationNodeInCurrentOrParentContext,
594  FirstBinding,
595  InterestingMethodContext);
596 }
597 
598 std::shared_ptr<PathDiagnosticPiece>
599 RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
600  const ExplodedNode *EndN, BugReport &BR) {
601  BR.markInteresting(Sym);
602  return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
603 }
604 
605 std::shared_ptr<PathDiagnosticPiece>
606 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
607  const ExplodedNode *EndN, BugReport &BR) {
608 
609  // Tell the BugReporterContext to report cases when the tracked symbol is
610  // assigned to different variables, etc.
611  BR.markInteresting(Sym);
612 
613  // We are reporting a leak. Walk up the graph to get to the first node where
614  // the symbol appeared, and also get the first VarDecl that tracked object
615  // is stored to.
616  AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
617 
618  const MemRegion* FirstBinding = AllocI.R;
619  BR.markInteresting(AllocI.InterestingMethodContext);
620 
621  SourceManager& SM = BRC.getSourceManager();
622 
623  // Compute an actual location for the leak. Sometimes a leak doesn't
624  // occur at an actual statement (e.g., transition between blocks; end
625  // of function) so we need to walk the graph and compute a real location.
626  const ExplodedNode *LeakN = EndN;
628 
629  std::string sbuf;
630  llvm::raw_string_ostream os(sbuf);
631 
632  os << "Object leaked: ";
633 
634  Optional<std::string> RegionDescription = describeRegion(FirstBinding);
635  if (RegionDescription) {
636  os << "object allocated and stored into '" << *RegionDescription << '\'';
637  } else {
638  os << "allocated object of type '" << getPrettyTypeName(Sym->getType())
639  << "'";
640  }
641 
642  // Get the retain count.
643  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
644  assert(RV);
645 
646  if (RV->getKind() == RefVal::ErrorLeakReturned) {
647  // FIXME: Per comments in rdar://6320065, "create" only applies to CF
648  // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
649  // to the caller for NS objects.
650  const Decl *D = &EndN->getCodeDecl();
651 
652  os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
653  : " is returned from a function ");
654 
655  if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
656  os << "that is annotated as CF_RETURNS_NOT_RETAINED";
657  } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
658  os << "that is annotated as NS_RETURNS_NOT_RETAINED";
659  } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
660  os << "that is annotated as OS_RETURNS_NOT_RETAINED";
661  } else {
662  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
663  if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
664  os << "managed by Automatic Reference Counting";
665  } else {
666  os << "whose name ('" << MD->getSelector().getAsString()
667  << "') does not start with "
668  "'copy', 'mutableCopy', 'alloc' or 'new'."
669  " This violates the naming convention rules"
670  " given in the Memory Management Guide for Cocoa";
671  }
672  } else {
673  const FunctionDecl *FD = cast<FunctionDecl>(D);
674  os << "whose name ('" << *FD
675  << "') does not contain 'Copy' or 'Create'. This violates the naming"
676  " convention rules given in the Memory Management Guide for Core"
677  " Foundation";
678  }
679  }
680  } else {
681  os << " is not referenced later in this execution path and has a retain "
682  "count of +" << RV->getCount();
683  }
684 
685  return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
686 }
687 
688 RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts,
689  ExplodedNode *n, SymbolRef sym,
690  bool registerVisitor)
691  : BugReport(D, D.getDescription(), n), Sym(sym) {
692  if (registerVisitor)
693  addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
694 }
695 
696 RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts,
697  ExplodedNode *n, SymbolRef sym,
698  StringRef endText)
699  : BugReport(D, D.getDescription(), endText, n) {
700 
701  addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
702 }
703 
704 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
705  const SourceManager& SMgr = Ctx.getSourceManager();
706 
707  if (!sym->getOriginRegion())
708  return;
709 
710  auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
711  if (Region) {
712  const Decl *PDecl = Region->getDecl();
713  if (PDecl && isa<ParmVarDecl>(PDecl)) {
714  PathDiagnosticLocation ParamLocation =
715  PathDiagnosticLocation::create(PDecl, SMgr);
716  Location = ParamLocation;
717  UniqueingLocation = ParamLocation;
718  UniqueingDecl = Ctx.getLocationContext()->getDecl();
719  }
720  }
721 }
722 
723 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
724  SymbolRef sym) {
725  // Most bug reports are cached at the location where they occurred.
726  // With leaks, we want to unique them by the location where they were
727  // allocated, and only report a single path. To do this, we need to find
728  // the allocation site of a piece of tracked memory, which we do via a
729  // call to GetAllocationSite. This will walk the ExplodedGraph backwards.
730  // Note that this is *not* the trimmed graph; we are guaranteed, however,
731  // that all ancestor nodes that represent the allocation site have the
732  // same SourceLocation.
733  const ExplodedNode *AllocNode = nullptr;
734 
735  const SourceManager& SMgr = Ctx.getSourceManager();
736 
737  AllocationInfo AllocI =
738  GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
739 
740  AllocNode = AllocI.N;
741  AllocBinding = AllocI.R;
742  markInteresting(AllocI.InterestingMethodContext);
743 
744  // Get the SourceLocation for the allocation site.
745  // FIXME: This will crash the analyzer if an allocation comes from an
746  // implicit call (ex: a destructor call).
747  // (Currently there are no such allocations in Cocoa, though.)
748  AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
749 
750  if (!AllocStmt) {
751  AllocBinding = nullptr;
752  return;
753  }
754 
755  PathDiagnosticLocation AllocLocation =
756  PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
757  AllocNode->getLocationContext());
758  Location = AllocLocation;
759 
760  // Set uniqieing info, which will be used for unique the bug reports. The
761  // leaks should be uniqued on the allocation site.
762  UniqueingLocation = AllocLocation;
763  UniqueingDecl = AllocNode->getLocationContext()->getDecl();
764 }
765 
766 void RefLeakReport::createDescription(CheckerContext &Ctx) {
767  assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
768  Description.clear();
769  llvm::raw_string_ostream os(Description);
770  os << "Potential leak of an object";
771 
772  Optional<std::string> RegionDescription = describeRegion(AllocBinding);
773  if (RegionDescription) {
774  os << " stored into '" << *RegionDescription << '\'';
775  } else {
776 
777  // If we can't figure out the name, just supply the type information.
778  os << " of type '" << getPrettyTypeName(Sym->getType()) << "'";
779  }
780 }
781 
782 RefLeakReport::RefLeakReport(RefCountBug &D, const LangOptions &LOpts,
783  ExplodedNode *n, SymbolRef sym,
784  CheckerContext &Ctx)
785  : RefCountReport(D, LOpts, n, sym, false) {
786 
787  deriveAllocLocation(Ctx, sym);
788  if (!AllocBinding)
789  deriveParamLocation(Ctx, sym);
790 
791  createDescription(Ctx);
792 
793  addVisitor(llvm::make_unique<RefLeakReportVisitor>(sym));
794 }
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:1738
A (possibly-)qualified type.
Definition: Type.h:638
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:95
RefLeakReport(RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, CheckerContext &Ctx)
Stmt - This represents one statement.
Definition: Stmt.h:66
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:505
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:87
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:632
Manages the lifetime of CallEvent objects.
Definition: CallEvent.h:1087
StringRef P
const ProgramStateRef & getState() const
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6748
const Decl & getCodeDecl() const
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
Definition: SymExpr.h:102
Represents a parameter to a function.
Definition: Decl.h:1550
Symbolic value.
Definition: SymExpr.h:30
bool isParentOf(const LocationContext *LC) const
RefCountReport(RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n, SymbolRef sym, bool registerVisitor=true)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:50
Optional< T > getLocationAs() const LLVM_LVALUE_FUNCTION
Represents a point when we start the call exit sequence (for inlined call).
Definition: ProgramPoint.h:670
ProgramStateManager & getStateManager()
child_range children()
Definition: Stmt.cpp:237
const LocationContext * getLocationContext() const
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:654
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:1172
const MemSpaceRegion * getMemorySpace() const
Definition: MemRegion.cpp:1126
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
bool hasAttr() const
Definition: DeclBase.h:531
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1613
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...
This represents one expression.
Definition: Expr.h:106
CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)
Gets an outside caller given a callee context.
Definition: CallEvent.cpp:1363
virtual StringRef getTagDescription() const =0
bool inTopFrame() const override
Return true if the current LocationContext has no caller context.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Definition: Stmt.h:2443
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:904
void markInteresting(SymbolRef sym)
CallEventRef< ObjCMethodCall > getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State, const LocationContext *LCtx)
Definition: CallEvent.h:1156
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:703
const SourceManager & SM
Definition: Format.cpp:1490
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
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:142
Indicates that the tracked object is an Objective-C object.
CallEventManager & getCallEventManager()
Definition: ProgramState.h:562
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:376
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:76
ObjCBoxedExpr - used for generalized expression boxing.
Definition: ExprObjC.h:117
const ReturnStmt * getReturnStmt() const
Definition: ProgramPoint.h:676
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:1413
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:1620
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:971
const ProgramPointTag * getTag() const
Definition: ProgramPoint.h:179
const Decl * getDecl() const
Represents a pointer to an Objective C object.
Definition: Type.h:5794
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.
ProgramStateManager & getStateManager()
Definition: BugReporter.h:573
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:13954
bool isVoidType() const
Definition: Type.h:6544
SourceManager & getSourceManager()
static PathDiagnosticLocation createEndOfPath(const ExplodedNode *N, const SourceManager &SM)
Create a location corresponding to the next valid ExplodedNode as end of path location.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2396
std::string getQualifiedNameAsString() const
Definition: Decl.cpp:1520
void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler &F)
Definition: ProgramState.h:584
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:153
This class provides an interface through which checkers can create individual bug reports...
Definition: BugReporter.h:76
const LocationContext * getLocationContext() const
const LangOptions & getLangOpts() const
Definition: ASTContext.h:707
This class handles loading and caching of source files into memory.
SourceManager & getSourceManager()
Definition: BugReporter.h:585
static bool isNumericLiteralExpression(const Expr *E)
QualType getPointeeType() const
Gets the type pointed to by this ObjC pointer.
Definition: Type.h:5810