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 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/SmallVector.h" 18 19 using namespace clang; 20 using namespace ento; 21 using namespace retaincountchecker; 22 23 StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugKind BT) { 24 switch (BT) { 25 case UseAfterRelease: 26 return "Use-after-release"; 27 case ReleaseNotOwned: 28 return "Bad release"; 29 case DeallocNotOwned: 30 return "-dealloc sent to non-exclusively owned object"; 31 case FreeNotOwned: 32 return "freeing non-exclusively owned object"; 33 case OverAutorelease: 34 return "Object autoreleased too many times"; 35 case ReturnNotOwnedForOwned: 36 return "Method should return an owned object"; 37 case LeakWithinFunction: 38 return "Leak"; 39 case LeakAtReturn: 40 return "Leak of returned object"; 41 } 42 llvm_unreachable("Unknown RefCountBugKind"); 43 } 44 45 StringRef RefCountBug::getDescription() const { 46 switch (BT) { 47 case UseAfterRelease: 48 return "Reference-counted object is used after it is released"; 49 case ReleaseNotOwned: 50 return "Incorrect decrement of the reference count of an object that is " 51 "not owned at this point by the caller"; 52 case DeallocNotOwned: 53 return "-dealloc sent to object that may be referenced elsewhere"; 54 case FreeNotOwned: 55 return "'free' called on an object that may be referenced elsewhere"; 56 case OverAutorelease: 57 return "Object autoreleased too many times"; 58 case ReturnNotOwnedForOwned: 59 return "Object with a +0 retain count returned to caller where a +1 " 60 "(owning) retain count is expected"; 61 case LeakWithinFunction: 62 case LeakAtReturn: 63 return ""; 64 } 65 llvm_unreachable("Unknown RefCountBugKind"); 66 } 67 68 RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT) 69 : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount, 70 /*SuppressOnSink=*/BT == LeakWithinFunction || 71 BT == LeakAtReturn), 72 BT(BT) {} 73 74 static bool isNumericLiteralExpression(const Expr *E) { 75 // FIXME: This set of cases was copied from SemaExprObjC. 76 return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral, 77 ObjCBoolLiteralExpr, 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 std::string(RD->getName()); 88 return QT.getAsString(); 89 } 90 91 /// Write information about the type state change to @c 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() == 140 RefVal::IvarAccessHistory::ReleasedAfterDirectAccess && 141 CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) { 142 os << "Strong instance variable relinquished. "; 143 } 144 os << "Object released."; 145 return true; 146 147 case RefVal::ReturnedOwned: 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 156 case RefVal::ReturnedNotOwned: 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 @c S 167 /// corresponding to the symbol @c 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()).getAsSymbol() == 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)); 237 CallEventRef<ObjCMethodCall> Call = 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]; 294 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 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 332 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 333 const ExplodedNode *N, 334 PathSensitiveBugReport &BR) override; 335 }; 336 337 class RefLeakReportVisitor : public RefCountReportVisitor { 338 public: 339 RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding) 340 : RefCountReportVisitor(Sym), LastBinding(LastBinding) {} 341 342 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 343 const ExplodedNode *N, 344 PathSensitiveBugReport &BR) override; 345 346 private: 347 const MemRegion *LastBinding; 348 }; 349 350 } // end namespace retaincountchecker 351 } // end namespace ento 352 } // end namespace clang 353 354 355 /// Find the first node with the parent stack frame. 356 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) { 357 const StackFrameContext *SC = Pred->getStackFrame(); 358 if (SC->inTopFrame()) 359 return nullptr; 360 const StackFrameContext *PC = SC->getParent()->getStackFrame(); 361 if (!PC) 362 return nullptr; 363 364 const ExplodedNode *N = Pred; 365 while (N && N->getStackFrame() != PC) { 366 N = N->getFirstPred(); 367 } 368 return N; 369 } 370 371 372 /// Insert a diagnostic piece at function exit 373 /// if a function parameter is annotated as "os_consumed", 374 /// but it does not actually consume the reference. 375 static std::shared_ptr<PathDiagnosticEventPiece> 376 annotateConsumedSummaryMismatch(const ExplodedNode *N, 377 CallExitBegin &CallExitLoc, 378 const SourceManager &SM, 379 CallEventManager &CEMgr) { 380 381 const ExplodedNode *CN = getCalleeNode(N); 382 if (!CN) 383 return nullptr; 384 385 CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState()); 386 387 std::string sbuf; 388 llvm::raw_string_ostream os(sbuf); 389 ArrayRef<const ParmVarDecl *> Parameters = Call->parameters(); 390 for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) { 391 const ParmVarDecl *PVD = Parameters[I]; 392 393 if (!PVD->hasAttr<OSConsumedAttr>()) 394 continue; 395 396 if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) { 397 const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR); 398 const RefVal *CountAtExit = getRefBinding(N->getState(), SR); 399 400 if (!CountBeforeCall || !CountAtExit) 401 continue; 402 403 unsigned CountBefore = CountBeforeCall->getCount(); 404 unsigned CountAfter = CountAtExit->getCount(); 405 406 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1; 407 if (!AsExpected) { 408 os << "Parameter '"; 409 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 410 /*Qualified=*/false); 411 os << "' is marked as consuming, but the function did not consume " 412 << "the reference\n"; 413 } 414 } 415 } 416 417 if (os.str().empty()) 418 return nullptr; 419 420 PathDiagnosticLocation L = PathDiagnosticLocation::create(CallExitLoc, SM); 421 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 422 } 423 424 /// Annotate the parameter at the analysis entry point. 425 static std::shared_ptr<PathDiagnosticEventPiece> 426 annotateStartParameter(const ExplodedNode *N, SymbolRef Sym, 427 const SourceManager &SM) { 428 auto PP = N->getLocationAs<BlockEdge>(); 429 if (!PP) 430 return nullptr; 431 432 const CFGBlock *Src = PP->getSrc(); 433 const RefVal *CurrT = getRefBinding(N->getState(), Sym); 434 435 if (&Src->getParent()->getEntry() != Src || !CurrT || 436 getRefBinding(N->getFirstPred()->getState(), Sym)) 437 return nullptr; 438 439 const auto *VR = cast<VarRegion>(cast<SymbolRegionValue>(Sym)->getRegion()); 440 const auto *PVD = cast<ParmVarDecl>(VR->getDecl()); 441 PathDiagnosticLocation L = PathDiagnosticLocation(PVD, SM); 442 443 std::string s; 444 llvm::raw_string_ostream os(s); 445 os << "Parameter '" << PVD->getDeclName() << "' starts at +"; 446 if (CurrT->getCount() == 1) { 447 os << "1, as it is marked as consuming"; 448 } else { 449 assert(CurrT->getCount() == 0); 450 os << "0"; 451 } 452 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 453 } 454 455 PathDiagnosticPieceRef 456 RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, 457 PathSensitiveBugReport &BR) { 458 459 const auto &BT = static_cast<const RefCountBug&>(BR.getBugType()); 460 461 bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned || 462 BT.getBugType() == RefCountBug::DeallocNotOwned; 463 464 const SourceManager &SM = BRC.getSourceManager(); 465 CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); 466 if (auto CE = N->getLocationAs<CallExitBegin>()) 467 if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr)) 468 return PD; 469 470 if (auto PD = annotateStartParameter(N, Sym, SM)) 471 return PD; 472 473 // FIXME: We will eventually need to handle non-statement-based events 474 // (__attribute__((cleanup))). 475 if (!N->getLocation().getAs<StmtPoint>()) 476 return nullptr; 477 478 // Check if the type state has changed. 479 const ExplodedNode *PrevNode = N->getFirstPred(); 480 ProgramStateRef PrevSt = PrevNode->getState(); 481 ProgramStateRef CurrSt = N->getState(); 482 const LocationContext *LCtx = N->getLocationContext(); 483 484 const RefVal* CurrT = getRefBinding(CurrSt, Sym); 485 if (!CurrT) 486 return nullptr; 487 488 const RefVal &CurrV = *CurrT; 489 const RefVal *PrevT = getRefBinding(PrevSt, Sym); 490 491 // Create a string buffer to constain all the useful things we want 492 // to tell the user. 493 std::string sbuf; 494 llvm::raw_string_ostream os(sbuf); 495 496 if (PrevT && IsFreeUnowned && CurrV.isNotOwned() && PrevT->isOwned()) { 497 os << "Object is now not exclusively owned"; 498 auto Pos = PathDiagnosticLocation::create(N->getLocation(), SM); 499 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 500 } 501 502 // This is the allocation site since the previous node had no bindings 503 // for this symbol. 504 if (!PrevT) { 505 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 506 507 if (isa<ObjCIvarRefExpr>(S) && 508 isSynthesizedAccessor(LCtx->getStackFrame())) { 509 S = LCtx->getStackFrame()->getCallSite(); 510 } 511 512 if (isa<ObjCArrayLiteral>(S)) { 513 os << "NSArray literal is an object with a +0 retain count"; 514 } else if (isa<ObjCDictionaryLiteral>(S)) { 515 os << "NSDictionary literal is an object with a +0 retain count"; 516 } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) { 517 if (isNumericLiteralExpression(BL->getSubExpr())) 518 os << "NSNumber literal is an object with a +0 retain count"; 519 else { 520 const ObjCInterfaceDecl *BoxClass = nullptr; 521 if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) 522 BoxClass = Method->getClassInterface(); 523 524 // We should always be able to find the boxing class interface, 525 // but consider this future-proofing. 526 if (BoxClass) { 527 os << *BoxClass << " b"; 528 } else { 529 os << "B"; 530 } 531 532 os << "oxed expression produces an object with a +0 retain count"; 533 } 534 } else if (isa<ObjCIvarRefExpr>(S)) { 535 os << "Object loaded from instance variable"; 536 } else { 537 generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os); 538 } 539 540 PathDiagnosticLocation Pos(S, SM, N->getLocationContext()); 541 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 542 } 543 544 // Gather up the effects that were performed on the object at this 545 // program point 546 bool DeallocSent = false; 547 548 const ProgramPointTag *Tag = N->getLocation().getTag(); 549 550 if (Tag == &RetainCountChecker::getCastFailTag()) { 551 os << "Assuming dynamic cast returns null due to type mismatch"; 552 } 553 554 if (Tag == &RetainCountChecker::getDeallocSentTag()) { 555 // We only have summaries attached to nodes after evaluating CallExpr and 556 // ObjCMessageExprs. 557 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 558 559 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 560 // Iterate through the parameter expressions and see if the symbol 561 // was ever passed as an argument. 562 unsigned i = 0; 563 564 for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) { 565 566 // Retrieve the value of the argument. Is it the symbol 567 // we are interested in? 568 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym) 569 continue; 570 571 // We have an argument. Get the effect! 572 DeallocSent = true; 573 } 574 } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { 575 if (const Expr *receiver = ME->getInstanceReceiver()) { 576 if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx) 577 .getAsLocSymbol() == Sym) { 578 // The symbol we are tracking is the receiver. 579 DeallocSent = true; 580 } 581 } 582 } 583 } 584 585 if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent)) 586 return nullptr; 587 588 if (os.str().empty()) 589 return nullptr; // We have nothing to say! 590 591 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 592 PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 593 N->getLocationContext()); 594 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 595 596 // Add the range by scanning the children of the statement for any bindings 597 // to Sym. 598 for (const Stmt *Child : S->children()) 599 if (const Expr *Exp = dyn_cast_or_null<Expr>(Child)) 600 if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) { 601 P->addRange(Exp->getSourceRange()); 602 break; 603 } 604 605 return std::move(P); 606 } 607 608 static Optional<std::string> describeRegion(const MemRegion *MR) { 609 if (const auto *VR = dyn_cast_or_null<VarRegion>(MR)) 610 return std::string(VR->getDecl()->getName()); 611 // Once we support more storage locations for bindings, 612 // this would need to be improved. 613 return None; 614 } 615 616 using Bindings = llvm::SmallVector<std::pair<const MemRegion *, SVal>, 4>; 617 618 class VarBindingsCollector : public StoreManager::BindingsHandler { 619 SymbolRef Sym; 620 Bindings &Result; 621 622 public: 623 VarBindingsCollector(SymbolRef Sym, Bindings &ToFill) 624 : Sym(Sym), Result(ToFill) {} 625 626 bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *R, 627 SVal Val) override { 628 SymbolRef SymV = Val.getAsLocSymbol(); 629 if (!SymV || SymV != Sym) 630 return true; 631 632 if (isa<NonParamVarRegion>(R)) 633 Result.emplace_back(R, Val); 634 635 return true; 636 } 637 }; 638 639 Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager, 640 const ExplodedNode *Node, SymbolRef Sym) { 641 Bindings Result; 642 VarBindingsCollector Collector{Sym, Result}; 643 while (Result.empty() && Node) { 644 Manager.iterBindings(Node->getState(), Collector); 645 Node = Node->getFirstPred(); 646 } 647 648 return Result; 649 } 650 651 namespace { 652 // Find the first node in the current function context that referred to the 653 // tracked symbol and the memory location that value was stored to. Note, the 654 // value is only reported if the allocation occurred in the same function as 655 // the leak. The function can also return a location context, which should be 656 // treated as interesting. 657 struct AllocationInfo { 658 const ExplodedNode* N; 659 const MemRegion *R; 660 const LocationContext *InterestingMethodContext; 661 AllocationInfo(const ExplodedNode *InN, 662 const MemRegion *InR, 663 const LocationContext *InInterestingMethodContext) : 664 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} 665 }; 666 } // end anonymous namespace 667 668 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr, 669 const ExplodedNode *N, SymbolRef Sym) { 670 const ExplodedNode *AllocationNode = N; 671 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N; 672 const MemRegion *FirstBinding = nullptr; 673 const LocationContext *LeakContext = N->getLocationContext(); 674 675 // The location context of the init method called on the leaked object, if 676 // available. 677 const LocationContext *InitMethodContext = nullptr; 678 679 while (N) { 680 ProgramStateRef St = N->getState(); 681 const LocationContext *NContext = N->getLocationContext(); 682 683 if (!getRefBinding(St, Sym)) 684 break; 685 686 StoreManager::FindUniqueBinding FB(Sym); 687 StateMgr.iterBindings(St, FB); 688 689 if (FB) { 690 const MemRegion *R = FB.getRegion(); 691 // Do not show local variables belonging to a function other than 692 // where the error is reported. 693 if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace())) 694 if (MR->getStackFrame() == LeakContext->getStackFrame()) 695 FirstBinding = R; 696 } 697 698 // AllocationNode is the last node in which the symbol was tracked. 699 AllocationNode = N; 700 701 // AllocationNodeInCurrentContext, is the last node in the current or 702 // parent context in which the symbol was tracked. 703 // 704 // Note that the allocation site might be in the parent context. For example, 705 // the case where an allocation happens in a block that captures a reference 706 // to it and that reference is overwritten/dropped by another call to 707 // the block. 708 if (NContext == LeakContext || NContext->isParentOf(LeakContext)) 709 AllocationNodeInCurrentOrParentContext = N; 710 711 // Find the last init that was called on the given symbol and store the 712 // init method's location context. 713 if (!InitMethodContext) 714 if (auto CEP = N->getLocation().getAs<CallEnter>()) { 715 const Stmt *CE = CEP->getCallExpr(); 716 if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { 717 const Stmt *RecExpr = ME->getInstanceReceiver(); 718 if (RecExpr) { 719 SVal RecV = St->getSVal(RecExpr, NContext); 720 if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) 721 InitMethodContext = CEP->getCalleeContext(); 722 } 723 } 724 } 725 726 N = N->getFirstPred(); 727 } 728 729 // If we are reporting a leak of the object that was allocated with alloc, 730 // mark its init method as interesting. 731 const LocationContext *InterestingMethodContext = nullptr; 732 if (InitMethodContext) { 733 const ProgramPoint AllocPP = AllocationNode->getLocation(); 734 if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) 735 if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) 736 if (ME->getMethodFamily() == OMF_alloc) 737 InterestingMethodContext = InitMethodContext; 738 } 739 740 // If allocation happened in a function different from the leak node context, 741 // do not report the binding. 742 assert(N && "Could not find allocation node"); 743 744 if (AllocationNodeInCurrentOrParentContext && 745 AllocationNodeInCurrentOrParentContext->getLocationContext() != 746 LeakContext) 747 FirstBinding = nullptr; 748 749 return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding, 750 InterestingMethodContext); 751 } 752 753 PathDiagnosticPieceRef 754 RefCountReportVisitor::getEndPath(BugReporterContext &BRC, 755 const ExplodedNode *EndN, 756 PathSensitiveBugReport &BR) { 757 BR.markInteresting(Sym); 758 return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); 759 } 760 761 PathDiagnosticPieceRef 762 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC, 763 const ExplodedNode *EndN, 764 PathSensitiveBugReport &BR) { 765 766 // Tell the BugReporterContext to report cases when the tracked symbol is 767 // assigned to different variables, etc. 768 BR.markInteresting(Sym); 769 770 PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath(); 771 772 std::string sbuf; 773 llvm::raw_string_ostream os(sbuf); 774 775 os << "Object leaked: "; 776 777 Optional<std::string> RegionDescription = describeRegion(LastBinding); 778 if (RegionDescription) { 779 os << "object allocated and stored into '" << *RegionDescription << '\''; 780 } else { 781 os << "allocated object of type '" << getPrettyTypeName(Sym->getType()) 782 << "'"; 783 } 784 785 // Get the retain count. 786 const RefVal *RV = getRefBinding(EndN->getState(), Sym); 787 assert(RV); 788 789 if (RV->getKind() == RefVal::ErrorLeakReturned) { 790 // FIXME: Per comments in rdar://6320065, "create" only applies to CF 791 // objects. Only "copy", "alloc", "retain" and "new" transfer ownership 792 // to the caller for NS objects. 793 const Decl *D = &EndN->getCodeDecl(); 794 795 os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " 796 : " is returned from a function "); 797 798 if (D->hasAttr<CFReturnsNotRetainedAttr>()) { 799 os << "that is annotated as CF_RETURNS_NOT_RETAINED"; 800 } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) { 801 os << "that is annotated as NS_RETURNS_NOT_RETAINED"; 802 } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) { 803 os << "that is annotated as OS_RETURNS_NOT_RETAINED"; 804 } else { 805 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 806 if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) { 807 os << "managed by Automatic Reference Counting"; 808 } else { 809 os << "whose name ('" << MD->getSelector().getAsString() 810 << "') does not start with " 811 "'copy', 'mutableCopy', 'alloc' or 'new'." 812 " This violates the naming convention rules" 813 " given in the Memory Management Guide for Cocoa"; 814 } 815 } else { 816 const FunctionDecl *FD = cast<FunctionDecl>(D); 817 ObjKind K = RV->getObjKind(); 818 if (K == ObjKind::ObjC || K == ObjKind::CF) { 819 os << "whose name ('" << *FD 820 << "') does not contain 'Copy' or 'Create'. This violates the " 821 "naming" 822 " convention rules given in the Memory Management Guide for " 823 "Core" 824 " Foundation"; 825 } else if (RV->getObjKind() == ObjKind::OS) { 826 std::string FuncName = FD->getNameAsString(); 827 os << "whose name ('" << FuncName << "') starts with '" 828 << StringRef(FuncName).substr(0, 3) << "'"; 829 } 830 } 831 } 832 } else { 833 os << " is not referenced later in this execution path and has a retain " 834 "count of +" 835 << RV->getCount(); 836 } 837 838 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 839 } 840 841 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts, 842 ExplodedNode *n, SymbolRef sym, bool isLeak) 843 : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym), 844 isLeak(isLeak) { 845 if (!isLeak) 846 addVisitor<RefCountReportVisitor>(sym); 847 } 848 849 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts, 850 ExplodedNode *n, SymbolRef sym, 851 StringRef endText) 852 : PathSensitiveBugReport(D, D.getDescription(), endText, n) { 853 854 addVisitor<RefCountReportVisitor>(sym); 855 } 856 857 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx) { 858 const SourceManager &SMgr = Ctx.getSourceManager(); 859 860 if (!Sym->getOriginRegion()) 861 return; 862 863 auto *Region = dyn_cast<DeclRegion>(Sym->getOriginRegion()); 864 if (Region) { 865 const Decl *PDecl = Region->getDecl(); 866 if (isa_and_nonnull<ParmVarDecl>(PDecl)) { 867 PathDiagnosticLocation ParamLocation = 868 PathDiagnosticLocation::create(PDecl, SMgr); 869 Location = ParamLocation; 870 UniqueingLocation = ParamLocation; 871 UniqueingDecl = Ctx.getLocationContext()->getDecl(); 872 } 873 } 874 } 875 876 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx) { 877 // Most bug reports are cached at the location where they occurred. 878 // With leaks, we want to unique them by the location where they were 879 // allocated, and only report a single path. To do this, we need to find 880 // the allocation site of a piece of tracked memory, which we do via a 881 // call to GetAllocationSite. This will walk the ExplodedGraph backwards. 882 // Note that this is *not* the trimmed graph; we are guaranteed, however, 883 // that all ancestor nodes that represent the allocation site have the 884 // same SourceLocation. 885 const ExplodedNode *AllocNode = nullptr; 886 887 const SourceManager &SMgr = Ctx.getSourceManager(); 888 889 AllocationInfo AllocI = 890 GetAllocationSite(Ctx.getStateManager(), getErrorNode(), Sym); 891 892 AllocNode = AllocI.N; 893 AllocFirstBinding = AllocI.R; 894 markInteresting(AllocI.InterestingMethodContext); 895 896 // Get the SourceLocation for the allocation site. 897 // FIXME: This will crash the analyzer if an allocation comes from an 898 // implicit call (ex: a destructor call). 899 // (Currently there are no such allocations in Cocoa, though.) 900 AllocStmt = AllocNode->getStmtForDiagnostics(); 901 902 if (!AllocStmt) { 903 AllocFirstBinding = nullptr; 904 return; 905 } 906 907 PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin( 908 AllocStmt, SMgr, AllocNode->getLocationContext()); 909 Location = AllocLocation; 910 911 // Set uniqieing info, which will be used for unique the bug reports. The 912 // leaks should be uniqued on the allocation site. 913 UniqueingLocation = AllocLocation; 914 UniqueingDecl = AllocNode->getLocationContext()->getDecl(); 915 } 916 917 void RefLeakReport::createDescription(CheckerContext &Ctx) { 918 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid()); 919 Description.clear(); 920 llvm::raw_string_ostream os(Description); 921 os << "Potential leak of an object"; 922 923 Optional<std::string> RegionDescription = 924 describeRegion(AllocBindingToReport); 925 if (RegionDescription) { 926 os << " stored into '" << *RegionDescription << '\''; 927 } else { 928 929 // If we can't figure out the name, just supply the type information. 930 os << " of type '" << getPrettyTypeName(Sym->getType()) << "'"; 931 } 932 } 933 934 void RefLeakReport::findBindingToReport(CheckerContext &Ctx, 935 ExplodedNode *Node) { 936 if (!AllocFirstBinding) 937 // If we don't have any bindings, we won't be able to find any 938 // better binding to report. 939 return; 940 941 // If the original region still contains the leaking symbol... 942 if (Node->getState()->getSVal(AllocFirstBinding).getAsSymbol() == Sym) { 943 // ...it is the best binding to report. 944 AllocBindingToReport = AllocFirstBinding; 945 return; 946 } 947 948 // At this point, we know that the original region doesn't contain the leaking 949 // when the actual leak happens. It means that it can be confusing for the 950 // user to see such description in the message. 951 // 952 // Let's consider the following example: 953 // Object *Original = allocate(...); 954 // Object *New = Original; 955 // Original = allocate(...); 956 // Original->release(); 957 // 958 // Complaining about a leaking object "stored into Original" might cause a 959 // rightful confusion because 'Original' is actually released. 960 // We should complain about 'New' instead. 961 Bindings AllVarBindings = 962 getAllVarBindingsForSymbol(Ctx.getStateManager(), Node, Sym); 963 964 // While looking for the last var bindings, we can still find 965 // `AllocFirstBinding` to be one of them. In situations like this, 966 // it would still be the easiest case to explain to our users. 967 if (!AllVarBindings.empty() && 968 llvm::count_if(AllVarBindings, 969 [this](const std::pair<const MemRegion *, SVal> Binding) { 970 return Binding.first == AllocFirstBinding; 971 }) == 0) { 972 // Let's pick one of them at random (if there is something to pick from). 973 AllocBindingToReport = AllVarBindings[0].first; 974 975 // Because 'AllocBindingToReport' is not the the same as 976 // 'AllocFirstBinding', we need to explain how the leaking object 977 // got from one to another. 978 // 979 // NOTE: We use the actual SVal stored in AllocBindingToReport here because 980 // trackStoredValue compares SVal's and it can get trickier for 981 // something like derived regions if we want to construct SVal from 982 // Sym. Instead, we take the value that is definitely stored in that 983 // region, thus guaranteeing that trackStoredValue will work. 984 bugreporter::trackStoredValue(AllVarBindings[0].second.castAs<KnownSVal>(), 985 AllocBindingToReport, *this); 986 } else { 987 AllocBindingToReport = AllocFirstBinding; 988 } 989 } 990 991 RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, 992 ExplodedNode *N, SymbolRef Sym, 993 CheckerContext &Ctx) 994 : RefCountReport(D, LOpts, N, Sym, /*isLeak=*/true) { 995 996 deriveAllocLocation(Ctx); 997 findBindingToReport(Ctx, N); 998 999 if (!AllocFirstBinding) 1000 deriveParamLocation(Ctx); 1001 1002 createDescription(Ctx); 1003 1004 addVisitor<RefLeakReportVisitor>(Sym, AllocBindingToReport); 1005 } 1006