1 //==-- RetainCountChecker.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 the methods for RetainCountChecker, which implements 10 // a reference count checker for Core Foundation and Cocoa on (Mac OS X). 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "RetainCountChecker.h" 15 16 using namespace clang; 17 using namespace ento; 18 using namespace retaincountchecker; 19 using llvm::StrInStrNoCase; 20 21 REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) 22 23 namespace clang { 24 namespace ento { 25 namespace retaincountchecker { 26 27 const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) { 28 return State->get<RefBindings>(Sym); 29 } 30 31 } // end namespace retaincountchecker 32 } // end namespace ento 33 } // end namespace clang 34 35 static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym, 36 RefVal Val) { 37 assert(Sym != nullptr); 38 return State->set<RefBindings>(Sym, Val); 39 } 40 41 static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) { 42 return State->remove<RefBindings>(Sym); 43 } 44 45 void RefVal::print(raw_ostream &Out) const { 46 if (!T.isNull()) 47 Out << "Tracked " << T.getAsString() << " | "; 48 49 switch (getKind()) { 50 default: llvm_unreachable("Invalid RefVal kind"); 51 case Owned: { 52 Out << "Owned"; 53 unsigned cnt = getCount(); 54 if (cnt) Out << " (+ " << cnt << ")"; 55 break; 56 } 57 58 case NotOwned: { 59 Out << "NotOwned"; 60 unsigned cnt = getCount(); 61 if (cnt) Out << " (+ " << cnt << ")"; 62 break; 63 } 64 65 case ReturnedOwned: { 66 Out << "ReturnedOwned"; 67 unsigned cnt = getCount(); 68 if (cnt) Out << " (+ " << cnt << ")"; 69 break; 70 } 71 72 case ReturnedNotOwned: { 73 Out << "ReturnedNotOwned"; 74 unsigned cnt = getCount(); 75 if (cnt) Out << " (+ " << cnt << ")"; 76 break; 77 } 78 79 case Released: 80 Out << "Released"; 81 break; 82 83 case ErrorDeallocNotOwned: 84 Out << "-dealloc (not-owned)"; 85 break; 86 87 case ErrorLeak: 88 Out << "Leaked"; 89 break; 90 91 case ErrorLeakReturned: 92 Out << "Leaked (Bad naming)"; 93 break; 94 95 case ErrorUseAfterRelease: 96 Out << "Use-After-Release [ERROR]"; 97 break; 98 99 case ErrorReleaseNotOwned: 100 Out << "Release of Not-Owned [ERROR]"; 101 break; 102 103 case RefVal::ErrorOverAutorelease: 104 Out << "Over-autoreleased"; 105 break; 106 107 case RefVal::ErrorReturnedNotOwned: 108 Out << "Non-owned object returned instead of owned"; 109 break; 110 } 111 112 switch (getIvarAccessHistory()) { 113 case IvarAccessHistory::None: 114 break; 115 case IvarAccessHistory::AccessedDirectly: 116 Out << " [direct ivar access]"; 117 break; 118 case IvarAccessHistory::ReleasedAfterDirectAccess: 119 Out << " [released after direct ivar access]"; 120 } 121 122 if (ACnt) { 123 Out << " [autorelease -" << ACnt << ']'; 124 } 125 } 126 127 namespace { 128 class StopTrackingCallback final : public SymbolVisitor { 129 ProgramStateRef state; 130 public: 131 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {} 132 ProgramStateRef getState() const { return state; } 133 134 bool VisitSymbol(SymbolRef sym) override { 135 state = removeRefBinding(state, sym); 136 return true; 137 } 138 }; 139 } // end anonymous namespace 140 141 //===----------------------------------------------------------------------===// 142 // Handle statements that may have an effect on refcounts. 143 //===----------------------------------------------------------------------===// 144 145 void RetainCountChecker::checkPostStmt(const BlockExpr *BE, 146 CheckerContext &C) const { 147 148 // Scan the BlockDecRefExprs for any object the retain count checker 149 // may be tracking. 150 if (!BE->getBlockDecl()->hasCaptures()) 151 return; 152 153 ProgramStateRef state = C.getState(); 154 auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion()); 155 156 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), 157 E = R->referenced_vars_end(); 158 159 if (I == E) 160 return; 161 162 // FIXME: For now we invalidate the tracking of all symbols passed to blocks 163 // via captured variables, even though captured variables result in a copy 164 // and in implicit increment/decrement of a retain count. 165 SmallVector<const MemRegion*, 10> Regions; 166 const LocationContext *LC = C.getLocationContext(); 167 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); 168 169 for ( ; I != E; ++I) { 170 const VarRegion *VR = I.getCapturedRegion(); 171 if (VR->getSuperRegion() == R) { 172 VR = MemMgr.getVarRegion(VR->getDecl(), LC); 173 } 174 Regions.push_back(VR); 175 } 176 177 state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState(); 178 C.addTransition(state); 179 } 180 181 void RetainCountChecker::checkPostStmt(const CastExpr *CE, 182 CheckerContext &C) const { 183 const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); 184 if (!BE) 185 return; 186 187 ArgEffect AE = ArgEffect(IncRef, ObjKind::ObjC); 188 189 switch (BE->getBridgeKind()) { 190 case OBC_Bridge: 191 // Do nothing. 192 return; 193 case OBC_BridgeRetained: 194 AE = AE.withKind(IncRef); 195 break; 196 case OBC_BridgeTransfer: 197 AE = AE.withKind(DecRefBridgedTransferred); 198 break; 199 } 200 201 ProgramStateRef state = C.getState(); 202 SymbolRef Sym = C.getSVal(CE).getAsLocSymbol(); 203 if (!Sym) 204 return; 205 const RefVal* T = getRefBinding(state, Sym); 206 if (!T) 207 return; 208 209 RefVal::Kind hasErr = (RefVal::Kind) 0; 210 state = updateSymbol(state, Sym, *T, AE, hasErr, C); 211 212 if (hasErr) { 213 // FIXME: If we get an error during a bridge cast, should we report it? 214 return; 215 } 216 217 C.addTransition(state); 218 } 219 220 void RetainCountChecker::processObjCLiterals(CheckerContext &C, 221 const Expr *Ex) const { 222 ProgramStateRef state = C.getState(); 223 const ExplodedNode *pred = C.getPredecessor(); 224 for (const Stmt *Child : Ex->children()) { 225 SVal V = pred->getSVal(Child); 226 if (SymbolRef sym = V.getAsSymbol()) 227 if (const RefVal* T = getRefBinding(state, sym)) { 228 RefVal::Kind hasErr = (RefVal::Kind) 0; 229 state = updateSymbol(state, sym, *T, 230 ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C); 231 if (hasErr) { 232 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C); 233 return; 234 } 235 } 236 } 237 238 // Return the object as autoreleased. 239 // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC); 240 if (SymbolRef sym = 241 state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) { 242 QualType ResultTy = Ex->getType(); 243 state = setRefBinding(state, sym, 244 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy)); 245 } 246 247 C.addTransition(state); 248 } 249 250 void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL, 251 CheckerContext &C) const { 252 // Apply the 'MayEscape' to all values. 253 processObjCLiterals(C, AL); 254 } 255 256 void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, 257 CheckerContext &C) const { 258 // Apply the 'MayEscape' to all keys and values. 259 processObjCLiterals(C, DL); 260 } 261 262 void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, 263 CheckerContext &C) const { 264 const ExplodedNode *Pred = C.getPredecessor(); 265 ProgramStateRef State = Pred->getState(); 266 267 if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) { 268 QualType ResultTy = Ex->getType(); 269 State = setRefBinding(State, Sym, 270 RefVal::makeNotOwned(ObjKind::ObjC, ResultTy)); 271 } 272 273 C.addTransition(State); 274 } 275 276 void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, 277 CheckerContext &C) const { 278 Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>(); 279 if (!IVarLoc) 280 return; 281 282 ProgramStateRef State = C.getState(); 283 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol(); 284 if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion())) 285 return; 286 287 // Accessing an ivar directly is unusual. If we've done that, be more 288 // forgiving about what the surrounding code is allowed to do. 289 290 QualType Ty = Sym->getType(); 291 ObjKind Kind; 292 if (Ty->isObjCRetainableType()) 293 Kind = ObjKind::ObjC; 294 else if (coreFoundation::isCFObjectRef(Ty)) 295 Kind = ObjKind::CF; 296 else 297 return; 298 299 // If the value is already known to be nil, don't bother tracking it. 300 ConstraintManager &CMgr = State->getConstraintManager(); 301 if (CMgr.isNull(State, Sym).isConstrainedTrue()) 302 return; 303 304 if (const RefVal *RV = getRefBinding(State, Sym)) { 305 // If we've seen this symbol before, or we're only seeing it now because 306 // of something the analyzer has synthesized, don't do anything. 307 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None || 308 isSynthesizedAccessor(C.getStackFrame())) { 309 return; 310 } 311 312 // Note that this value has been loaded from an ivar. 313 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess())); 314 return; 315 } 316 317 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty); 318 319 // In a synthesized accessor, the effective retain count is +0. 320 if (isSynthesizedAccessor(C.getStackFrame())) { 321 C.addTransition(setRefBinding(State, Sym, PlusZero)); 322 return; 323 } 324 325 State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); 326 C.addTransition(State); 327 } 328 329 void RetainCountChecker::checkPostCall(const CallEvent &Call, 330 CheckerContext &C) const { 331 RetainSummaryManager &Summaries = getSummaryManager(C); 332 333 // Leave null if no receiver. 334 QualType ReceiverType; 335 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) { 336 if (MC->isInstanceMessage()) { 337 SVal ReceiverV = MC->getReceiverSVal(); 338 if (SymbolRef Sym = ReceiverV.getAsLocSymbol()) 339 if (const RefVal *T = getRefBinding(C.getState(), Sym)) 340 ReceiverType = T->getType(); 341 } 342 } 343 344 const RetainSummary *Summ = Summaries.getSummary(Call, ReceiverType); 345 346 if (C.wasInlined) { 347 processSummaryOfInlined(*Summ, Call, C); 348 return; 349 } 350 checkSummary(*Summ, Call, C); 351 } 352 353 /// GetReturnType - Used to get the return type of a message expression or 354 /// function call with the intention of affixing that type to a tracked symbol. 355 /// While the return type can be queried directly from RetEx, when 356 /// invoking class methods we augment to the return type to be that of 357 /// a pointer to the class (as opposed it just being id). 358 // FIXME: We may be able to do this with related result types instead. 359 // This function is probably overestimating. 360 static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { 361 QualType RetTy = RetE->getType(); 362 // If RetE is not a message expression just return its type. 363 // If RetE is a message expression, return its types if it is something 364 /// more specific than id. 365 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) 366 if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>()) 367 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || 368 PT->isObjCClassType()) { 369 // At this point we know the return type of the message expression is 370 // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this 371 // is a call to a class method whose type we can resolve. In such 372 // cases, promote the return type to XXX* (where XXX is the class). 373 const ObjCInterfaceDecl *D = ME->getReceiverInterface(); 374 return !D ? RetTy : 375 Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D)); 376 } 377 378 return RetTy; 379 } 380 381 static Optional<RefVal> refValFromRetEffect(RetEffect RE, 382 QualType ResultTy) { 383 if (RE.isOwned()) { 384 return RefVal::makeOwned(RE.getObjKind(), ResultTy); 385 } else if (RE.notOwned()) { 386 return RefVal::makeNotOwned(RE.getObjKind(), ResultTy); 387 } 388 389 return None; 390 } 391 392 static bool isPointerToObject(QualType QT) { 393 QualType PT = QT->getPointeeType(); 394 if (!PT.isNull()) 395 if (PT->getAsCXXRecordDecl()) 396 return true; 397 return false; 398 } 399 400 /// Whether the tracked value should be escaped on a given call. 401 /// OSObjects are escaped when passed to void * / etc. 402 static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx, 403 const RefVal *TrackedValue) { 404 if (TrackedValue->getObjKind() != ObjKind::OS) 405 return false; 406 if (ArgIdx >= CE.parameters().size()) 407 return false; 408 return !isPointerToObject(CE.parameters()[ArgIdx]->getType()); 409 } 410 411 // We don't always get the exact modeling of the function with regards to the 412 // retain count checker even when the function is inlined. For example, we need 413 // to stop tracking the symbols which were marked with StopTrackingHard. 414 void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, 415 const CallEvent &CallOrMsg, 416 CheckerContext &C) const { 417 ProgramStateRef state = C.getState(); 418 419 // Evaluate the effect of the arguments. 420 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { 421 SVal V = CallOrMsg.getArgSVal(idx); 422 423 if (SymbolRef Sym = V.getAsLocSymbol()) { 424 bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard; 425 if (const RefVal *T = getRefBinding(state, Sym)) 426 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T)) 427 ShouldRemoveBinding = true; 428 429 if (ShouldRemoveBinding) 430 state = removeRefBinding(state, Sym); 431 } 432 } 433 434 // Evaluate the effect on the message receiver. 435 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) { 436 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { 437 if (Summ.getReceiverEffect().getKind() == StopTrackingHard) { 438 state = removeRefBinding(state, Sym); 439 } 440 } 441 } 442 443 // Consult the summary for the return value. 444 RetEffect RE = Summ.getRetEffect(); 445 446 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) { 447 if (RE.getKind() == RetEffect::NoRetHard) 448 state = removeRefBinding(state, Sym); 449 } 450 451 C.addTransition(state); 452 } 453 454 static bool isSmartPtrField(const MemRegion *MR) { 455 const auto *TR = dyn_cast<TypedValueRegion>( 456 cast<SubRegion>(MR)->getSuperRegion()); 457 return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType()); 458 } 459 460 461 /// A value escapes in these possible cases: 462 /// 463 /// - binding to something that is not a memory region. 464 /// - binding to a memregion that does not have stack storage 465 /// - binding to a variable that has a destructor attached using CleanupAttr 466 /// 467 /// We do not currently model what happens when a symbol is 468 /// assigned to a struct field, unless it is a known smart pointer 469 /// implementation, about which we know that it is inlined. 470 /// FIXME: This could definitely be improved upon. 471 static bool shouldEscapeRegion(const MemRegion *R) { 472 if (isSmartPtrField(R)) 473 return false; 474 475 const auto *VR = dyn_cast<VarRegion>(R); 476 477 if (!R->hasStackStorage() || !VR) 478 return true; 479 480 const VarDecl *VD = VR->getDecl(); 481 if (!VD->hasAttr<CleanupAttr>()) 482 return false; // CleanupAttr attaches destructors, which cause escaping. 483 return true; 484 } 485 486 static SmallVector<ProgramStateRef, 2> 487 updateOutParameters(ProgramStateRef State, const RetainSummary &Summ, 488 const CallEvent &CE) { 489 490 SVal L = CE.getReturnValue(); 491 492 // Splitting is required to support out parameters, 493 // as out parameters might be created only on the "success" branch. 494 // We want to avoid eagerly splitting unless out parameters are actually 495 // needed. 496 bool SplitNecessary = false; 497 for (auto &P : Summ.getArgEffects()) 498 if (P.second.getKind() == RetainedOutParameterOnNonZero || 499 P.second.getKind() == RetainedOutParameterOnZero) 500 SplitNecessary = true; 501 502 ProgramStateRef AssumeNonZeroReturn = State; 503 ProgramStateRef AssumeZeroReturn = State; 504 505 if (SplitNecessary) { 506 if (auto DL = L.getAs<DefinedOrUnknownSVal>()) { 507 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true); 508 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false); 509 } 510 } 511 512 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) { 513 SVal ArgVal = CE.getArgSVal(idx); 514 ArgEffect AE = Summ.getArg(idx); 515 516 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion()); 517 if (!ArgRegion) 518 continue; 519 520 QualType PointeeTy = ArgRegion->getValueType(); 521 SVal PointeeVal = State->getSVal(ArgRegion); 522 SymbolRef Pointee = PointeeVal.getAsLocSymbol(); 523 if (!Pointee) 524 continue; 525 526 if (shouldEscapeRegion(ArgRegion)) 527 continue; 528 529 auto makeNotOwnedParameter = [&](ProgramStateRef St) { 530 return setRefBinding(St, Pointee, 531 RefVal::makeNotOwned(AE.getObjKind(), PointeeTy)); 532 }; 533 auto makeOwnedParameter = [&](ProgramStateRef St) { 534 return setRefBinding(St, Pointee, 535 RefVal::makeOwned(ObjKind::OS, PointeeTy)); 536 }; 537 538 switch (AE.getKind()) { 539 case UnretainedOutParameter: 540 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn); 541 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn); 542 break; 543 case RetainedOutParameter: 544 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn); 545 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn); 546 break; 547 case RetainedOutParameterOnNonZero: 548 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn); 549 break; 550 case RetainedOutParameterOnZero: 551 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn); 552 break; 553 default: 554 break; 555 } 556 } 557 558 if (SplitNecessary) { 559 return {AssumeNonZeroReturn, AssumeZeroReturn}; 560 } else { 561 assert(AssumeZeroReturn == AssumeNonZeroReturn); 562 return {AssumeZeroReturn}; 563 } 564 } 565 566 void RetainCountChecker::checkSummary(const RetainSummary &Summ, 567 const CallEvent &CallOrMsg, 568 CheckerContext &C) const { 569 ProgramStateRef state = C.getState(); 570 571 // Evaluate the effect of the arguments. 572 RefVal::Kind hasErr = (RefVal::Kind) 0; 573 SourceRange ErrorRange; 574 SymbolRef ErrorSym = nullptr; 575 576 // Helper tag for providing diagnostics: indicate whether dealloc was sent 577 // at this location. 578 bool DeallocSent = false; 579 580 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { 581 SVal V = CallOrMsg.getArgSVal(idx); 582 583 ArgEffect Effect = Summ.getArg(idx); 584 if (SymbolRef Sym = V.getAsLocSymbol()) { 585 if (const RefVal *T = getRefBinding(state, Sym)) { 586 587 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T)) 588 Effect = ArgEffect(StopTrackingHard, ObjKind::OS); 589 590 state = updateSymbol(state, Sym, *T, Effect, hasErr, C); 591 if (hasErr) { 592 ErrorRange = CallOrMsg.getArgSourceRange(idx); 593 ErrorSym = Sym; 594 break; 595 } else if (Effect.getKind() == Dealloc) { 596 DeallocSent = true; 597 } 598 } 599 } 600 } 601 602 // Evaluate the effect on the message receiver / `this` argument. 603 bool ReceiverIsTracked = false; 604 if (!hasErr) { 605 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) { 606 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { 607 if (const RefVal *T = getRefBinding(state, Sym)) { 608 ReceiverIsTracked = true; 609 state = updateSymbol(state, Sym, *T, 610 Summ.getReceiverEffect(), hasErr, C); 611 if (hasErr) { 612 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange(); 613 ErrorSym = Sym; 614 } else if (Summ.getReceiverEffect().getKind() == Dealloc) { 615 DeallocSent = true; 616 } 617 } 618 } 619 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) { 620 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) { 621 if (const RefVal *T = getRefBinding(state, Sym)) { 622 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(), 623 hasErr, C); 624 if (hasErr) { 625 ErrorRange = MCall->getOriginExpr()->getSourceRange(); 626 ErrorSym = Sym; 627 } 628 } 629 } 630 } 631 } 632 633 // Process any errors. 634 if (hasErr) { 635 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C); 636 return; 637 } 638 639 // Consult the summary for the return value. 640 RetEffect RE = Summ.getRetEffect(); 641 642 if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { 643 if (ReceiverIsTracked) 644 RE = getSummaryManager(C).getObjAllocRetEffect(); 645 else 646 RE = RetEffect::MakeNoRet(); 647 } 648 649 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) { 650 QualType ResultTy = CallOrMsg.getResultType(); 651 if (RE.notOwned()) { 652 const Expr *Ex = CallOrMsg.getOriginExpr(); 653 assert(Ex); 654 ResultTy = GetReturnType(Ex, C.getASTContext()); 655 } 656 if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy)) 657 state = setRefBinding(state, Sym, *updatedRefVal); 658 } 659 660 SmallVector<ProgramStateRef, 2> Out = 661 updateOutParameters(state, Summ, CallOrMsg); 662 663 for (ProgramStateRef St : Out) { 664 if (DeallocSent) { 665 C.addTransition(St, C.getPredecessor(), &DeallocSentTag); 666 } else { 667 C.addTransition(St); 668 } 669 } 670 } 671 672 ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state, 673 SymbolRef sym, RefVal V, 674 ArgEffect AE, 675 RefVal::Kind &hasErr, 676 CheckerContext &C) const { 677 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount; 678 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) { 679 switch (AE.getKind()) { 680 default: 681 break; 682 case IncRef: 683 AE = AE.withKind(DoNothing); 684 break; 685 case DecRef: 686 AE = AE.withKind(DoNothing); 687 break; 688 case DecRefAndStopTrackingHard: 689 AE = AE.withKind(StopTracking); 690 break; 691 } 692 } 693 694 // Handle all use-after-releases. 695 if (V.getKind() == RefVal::Released) { 696 V = V ^ RefVal::ErrorUseAfterRelease; 697 hasErr = V.getKind(); 698 return setRefBinding(state, sym, V); 699 } 700 701 switch (AE.getKind()) { 702 case UnretainedOutParameter: 703 case RetainedOutParameter: 704 case RetainedOutParameterOnZero: 705 case RetainedOutParameterOnNonZero: 706 llvm_unreachable("Applies to pointer-to-pointer parameters, which should " 707 "not have ref state."); 708 709 case Dealloc: // NB. we only need to add a note in a non-error case. 710 switch (V.getKind()) { 711 default: 712 llvm_unreachable("Invalid RefVal state for an explicit dealloc."); 713 case RefVal::Owned: 714 // The object immediately transitions to the released state. 715 V = V ^ RefVal::Released; 716 V.clearCounts(); 717 return setRefBinding(state, sym, V); 718 case RefVal::NotOwned: 719 V = V ^ RefVal::ErrorDeallocNotOwned; 720 hasErr = V.getKind(); 721 break; 722 } 723 break; 724 725 case MayEscape: 726 if (V.getKind() == RefVal::Owned) { 727 V = V ^ RefVal::NotOwned; 728 break; 729 } 730 731 LLVM_FALLTHROUGH; 732 733 case DoNothing: 734 return state; 735 736 case Autorelease: 737 // Update the autorelease counts. 738 V = V.autorelease(); 739 break; 740 741 case StopTracking: 742 case StopTrackingHard: 743 return removeRefBinding(state, sym); 744 745 case IncRef: 746 switch (V.getKind()) { 747 default: 748 llvm_unreachable("Invalid RefVal state for a retain."); 749 case RefVal::Owned: 750 case RefVal::NotOwned: 751 V = V + 1; 752 break; 753 } 754 break; 755 756 case DecRef: 757 case DecRefBridgedTransferred: 758 case DecRefAndStopTrackingHard: 759 switch (V.getKind()) { 760 default: 761 // case 'RefVal::Released' handled above. 762 llvm_unreachable("Invalid RefVal state for a release."); 763 764 case RefVal::Owned: 765 assert(V.getCount() > 0); 766 if (V.getCount() == 1) { 767 if (AE.getKind() == DecRefBridgedTransferred || 768 V.getIvarAccessHistory() == 769 RefVal::IvarAccessHistory::AccessedDirectly) 770 V = V ^ RefVal::NotOwned; 771 else 772 V = V ^ RefVal::Released; 773 } else if (AE.getKind() == DecRefAndStopTrackingHard) { 774 return removeRefBinding(state, sym); 775 } 776 777 V = V - 1; 778 break; 779 780 case RefVal::NotOwned: 781 if (V.getCount() > 0) { 782 if (AE.getKind() == DecRefAndStopTrackingHard) 783 return removeRefBinding(state, sym); 784 V = V - 1; 785 } else if (V.getIvarAccessHistory() == 786 RefVal::IvarAccessHistory::AccessedDirectly) { 787 // Assume that the instance variable was holding on the object at 788 // +1, and we just didn't know. 789 if (AE.getKind() == DecRefAndStopTrackingHard) 790 return removeRefBinding(state, sym); 791 V = V.releaseViaIvar() ^ RefVal::Released; 792 } else { 793 V = V ^ RefVal::ErrorReleaseNotOwned; 794 hasErr = V.getKind(); 795 } 796 break; 797 } 798 break; 799 } 800 return setRefBinding(state, sym, V); 801 } 802 803 const RefCountBug & 804 RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind, 805 SymbolRef Sym) const { 806 switch (ErrorKind) { 807 case RefVal::ErrorUseAfterRelease: 808 return useAfterRelease; 809 case RefVal::ErrorReleaseNotOwned: 810 return releaseNotOwned; 811 case RefVal::ErrorDeallocNotOwned: 812 if (Sym->getType()->getPointeeCXXRecordDecl()) 813 return freeNotOwned; 814 return deallocNotOwned; 815 default: 816 llvm_unreachable("Unhandled error."); 817 } 818 } 819 820 void RetainCountChecker::processNonLeakError(ProgramStateRef St, 821 SourceRange ErrorRange, 822 RefVal::Kind ErrorKind, 823 SymbolRef Sym, 824 CheckerContext &C) const { 825 // HACK: Ignore retain-count issues on values accessed through ivars, 826 // because of cases like this: 827 // [_contentView retain]; 828 // [_contentView removeFromSuperview]; 829 // [self addSubview:_contentView]; // invalidates 'self' 830 // [_contentView release]; 831 if (const RefVal *RV = getRefBinding(St, Sym)) 832 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None) 833 return; 834 835 ExplodedNode *N = C.generateErrorNode(St); 836 if (!N) 837 return; 838 839 auto report = llvm::make_unique<RefCountReport>( 840 errorKindToBugKind(ErrorKind, Sym), 841 C.getASTContext().getLangOpts(), N, Sym); 842 report->addRange(ErrorRange); 843 C.emitReport(std::move(report)); 844 } 845 846 //===----------------------------------------------------------------------===// 847 // Handle the return values of retain-count-related functions. 848 //===----------------------------------------------------------------------===// 849 850 bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { 851 ProgramStateRef state = C.getState(); 852 const FunctionDecl *FD = C.getCalleeDecl(CE); 853 if (!FD) 854 return false; 855 856 RetainSummaryManager &SmrMgr = getSummaryManager(C); 857 QualType ResultTy = CE->getCallReturnType(C.getASTContext()); 858 859 // See if the function has 'rc_ownership_trusted_implementation' 860 // annotate attribute. If it does, we will not inline it. 861 bool hasTrustedImplementationAnnotation = false; 862 863 const LocationContext *LCtx = C.getLocationContext(); 864 865 using BehaviorSummary = RetainSummaryManager::BehaviorSummary; 866 Optional<BehaviorSummary> BSmr = 867 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation); 868 869 // See if it's one of the specific functions we know how to eval. 870 if (!BSmr) 871 return false; 872 873 // Bind the return value. 874 if (BSmr == BehaviorSummary::Identity || 875 BSmr == BehaviorSummary::IdentityOrZero || 876 BSmr == BehaviorSummary::IdentityThis) { 877 878 const Expr *BindReturnTo = 879 (BSmr == BehaviorSummary::IdentityThis) 880 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument() 881 : CE->getArg(0); 882 SVal RetVal = state->getSVal(BindReturnTo, LCtx); 883 884 // If the receiver is unknown or the function has 885 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a 886 // return value. 887 // FIXME: this branch is very strange. 888 if (RetVal.isUnknown() || 889 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { 890 SValBuilder &SVB = C.getSValBuilder(); 891 RetVal = 892 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); 893 } 894 895 // Bind the value. 896 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false); 897 898 if (BSmr == BehaviorSummary::IdentityOrZero) { 899 // Add a branch where the output is zero. 900 ProgramStateRef NullOutputState = C.getState(); 901 902 // Assume that output is zero on the other branch. 903 NullOutputState = NullOutputState->BindExpr( 904 CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false); 905 C.addTransition(NullOutputState, &CastFailTag); 906 907 // And on the original branch assume that both input and 908 // output are non-zero. 909 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>()) 910 state = state->assume(*L, /*Assumption=*/true); 911 912 } 913 } 914 915 C.addTransition(state); 916 return true; 917 } 918 919 ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S, 920 CheckerContext &C) const { 921 ExplodedNode *Pred = C.getPredecessor(); 922 923 // Only adjust the reference count if this is the top-level call frame, 924 // and not the result of inlining. In the future, we should do 925 // better checking even for inlined calls, and see if they match 926 // with their expected semantics (e.g., the method should return a retained 927 // object, etc.). 928 if (!C.inTopFrame()) 929 return Pred; 930 931 if (!S) 932 return Pred; 933 934 const Expr *RetE = S->getRetValue(); 935 if (!RetE) 936 return Pred; 937 938 ProgramStateRef state = C.getState(); 939 SymbolRef Sym = 940 state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol(); 941 if (!Sym) 942 return Pred; 943 944 // Get the reference count binding (if any). 945 const RefVal *T = getRefBinding(state, Sym); 946 if (!T) 947 return Pred; 948 949 // Change the reference count. 950 RefVal X = *T; 951 952 switch (X.getKind()) { 953 case RefVal::Owned: { 954 unsigned cnt = X.getCount(); 955 assert(cnt > 0); 956 X.setCount(cnt - 1); 957 X = X ^ RefVal::ReturnedOwned; 958 break; 959 } 960 961 case RefVal::NotOwned: { 962 unsigned cnt = X.getCount(); 963 if (cnt) { 964 X.setCount(cnt - 1); 965 X = X ^ RefVal::ReturnedOwned; 966 } else { 967 X = X ^ RefVal::ReturnedNotOwned; 968 } 969 break; 970 } 971 972 default: 973 return Pred; 974 } 975 976 // Update the binding. 977 state = setRefBinding(state, Sym, X); 978 Pred = C.addTransition(state); 979 980 // At this point we have updated the state properly. 981 // Everything after this is merely checking to see if the return value has 982 // been over- or under-retained. 983 984 // Did we cache out? 985 if (!Pred) 986 return nullptr; 987 988 // Update the autorelease counts. 989 static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease"); 990 state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S); 991 992 // Have we generated a sink node? 993 if (!state) 994 return nullptr; 995 996 // Get the updated binding. 997 T = getRefBinding(state, Sym); 998 assert(T); 999 X = *T; 1000 1001 // Consult the summary of the enclosing method. 1002 RetainSummaryManager &Summaries = getSummaryManager(C); 1003 const Decl *CD = &Pred->getCodeDecl(); 1004 RetEffect RE = RetEffect::MakeNoRet(); 1005 1006 // FIXME: What is the convention for blocks? Is there one? 1007 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) { 1008 const RetainSummary *Summ = Summaries.getMethodSummary(MD); 1009 RE = Summ->getRetEffect(); 1010 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { 1011 if (!isa<CXXMethodDecl>(FD)) { 1012 const RetainSummary *Summ = Summaries.getFunctionSummary(FD); 1013 RE = Summ->getRetEffect(); 1014 } 1015 } 1016 1017 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); 1018 } 1019 1020 ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, 1021 CheckerContext &C, 1022 ExplodedNode *Pred, 1023 RetEffect RE, RefVal X, 1024 SymbolRef Sym, 1025 ProgramStateRef state) const { 1026 // HACK: Ignore retain-count issues on values accessed through ivars, 1027 // because of cases like this: 1028 // [_contentView retain]; 1029 // [_contentView removeFromSuperview]; 1030 // [self addSubview:_contentView]; // invalidates 'self' 1031 // [_contentView release]; 1032 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) 1033 return Pred; 1034 1035 // Any leaks or other errors? 1036 if (X.isReturnedOwned() && X.getCount() == 0) { 1037 if (RE.getKind() != RetEffect::NoRet) { 1038 if (!RE.isOwned()) { 1039 1040 // The returning type is a CF, we expect the enclosing method should 1041 // return ownership. 1042 X = X ^ RefVal::ErrorLeakReturned; 1043 1044 // Generate an error node. 1045 state = setRefBinding(state, Sym, X); 1046 1047 static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak"); 1048 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag); 1049 if (N) { 1050 const LangOptions &LOpts = C.getASTContext().getLangOpts(); 1051 auto R = 1052 llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C); 1053 C.emitReport(std::move(R)); 1054 } 1055 return N; 1056 } 1057 } 1058 } else if (X.isReturnedNotOwned()) { 1059 if (RE.isOwned()) { 1060 if (X.getIvarAccessHistory() == 1061 RefVal::IvarAccessHistory::AccessedDirectly) { 1062 // Assume the method was trying to transfer a +1 reference from a 1063 // strong ivar to the caller. 1064 state = setRefBinding(state, Sym, 1065 X.releaseViaIvar() ^ RefVal::ReturnedOwned); 1066 } else { 1067 // Trying to return a not owned object to a caller expecting an 1068 // owned object. 1069 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned); 1070 1071 static CheckerProgramPointTag 1072 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned"); 1073 1074 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); 1075 if (N) { 1076 auto R = llvm::make_unique<RefCountReport>( 1077 returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); 1078 C.emitReport(std::move(R)); 1079 } 1080 return N; 1081 } 1082 } 1083 } 1084 return Pred; 1085 } 1086 1087 //===----------------------------------------------------------------------===// 1088 // Check various ways a symbol can be invalidated. 1089 //===----------------------------------------------------------------------===// 1090 1091 void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, 1092 CheckerContext &C) const { 1093 ProgramStateRef state = C.getState(); 1094 const MemRegion *MR = loc.getAsRegion(); 1095 1096 // Find all symbols referenced by 'val' that we are tracking 1097 // and stop tracking them. 1098 if (MR && shouldEscapeRegion(MR)) { 1099 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); 1100 C.addTransition(state); 1101 } 1102 } 1103 1104 ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, 1105 SVal Cond, 1106 bool Assumption) const { 1107 // FIXME: We may add to the interface of evalAssume the list of symbols 1108 // whose assumptions have changed. For now we just iterate through the 1109 // bindings and check if any of the tracked symbols are NULL. This isn't 1110 // too bad since the number of symbols we will track in practice are 1111 // probably small and evalAssume is only called at branches and a few 1112 // other places. 1113 RefBindingsTy B = state->get<RefBindings>(); 1114 1115 if (B.isEmpty()) 1116 return state; 1117 1118 bool changed = false; 1119 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>(); 1120 ConstraintManager &CMgr = state->getConstraintManager(); 1121 1122 for (auto &I : B) { 1123 // Check if the symbol is null stop tracking the symbol. 1124 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first); 1125 if (AllocFailed.isConstrainedTrue()) { 1126 changed = true; 1127 B = RefBFactory.remove(B, I.first); 1128 } 1129 } 1130 1131 if (changed) 1132 state = state->set<RefBindings>(B); 1133 1134 return state; 1135 } 1136 1137 ProgramStateRef RetainCountChecker::checkRegionChanges( 1138 ProgramStateRef state, const InvalidatedSymbols *invalidated, 1139 ArrayRef<const MemRegion *> ExplicitRegions, 1140 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, 1141 const CallEvent *Call) const { 1142 if (!invalidated) 1143 return state; 1144 1145 llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; 1146 1147 for (const MemRegion *I : ExplicitRegions) 1148 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>()) 1149 WhitelistedSymbols.insert(SR->getSymbol()); 1150 1151 for (SymbolRef sym : *invalidated) { 1152 if (WhitelistedSymbols.count(sym)) 1153 continue; 1154 // Remove any existing reference-count binding. 1155 state = removeRefBinding(state, sym); 1156 } 1157 return state; 1158 } 1159 1160 ProgramStateRef 1161 RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, 1162 ExplodedNode *Pred, 1163 const ProgramPointTag *Tag, 1164 CheckerContext &Ctx, 1165 SymbolRef Sym, 1166 RefVal V, 1167 const ReturnStmt *S) const { 1168 unsigned ACnt = V.getAutoreleaseCount(); 1169 1170 // No autorelease counts? Nothing to be done. 1171 if (!ACnt) 1172 return state; 1173 1174 unsigned Cnt = V.getCount(); 1175 1176 // FIXME: Handle sending 'autorelease' to already released object. 1177 1178 if (V.getKind() == RefVal::ReturnedOwned) 1179 ++Cnt; 1180 1181 // If we would over-release here, but we know the value came from an ivar, 1182 // assume it was a strong ivar that's just been relinquished. 1183 if (ACnt > Cnt && 1184 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) { 1185 V = V.releaseViaIvar(); 1186 --ACnt; 1187 } 1188 1189 if (ACnt <= Cnt) { 1190 if (ACnt == Cnt) { 1191 V.clearCounts(); 1192 if (V.getKind() == RefVal::ReturnedOwned) { 1193 V = V ^ RefVal::ReturnedNotOwned; 1194 } else { 1195 V = V ^ RefVal::NotOwned; 1196 } 1197 } else { 1198 V.setCount(V.getCount() - ACnt); 1199 V.setAutoreleaseCount(0); 1200 } 1201 return setRefBinding(state, Sym, V); 1202 } 1203 1204 // HACK: Ignore retain-count issues on values accessed through ivars, 1205 // because of cases like this: 1206 // [_contentView retain]; 1207 // [_contentView removeFromSuperview]; 1208 // [self addSubview:_contentView]; // invalidates 'self' 1209 // [_contentView release]; 1210 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) 1211 return state; 1212 1213 // Woah! More autorelease counts then retain counts left. 1214 // Emit hard error. 1215 V = V ^ RefVal::ErrorOverAutorelease; 1216 state = setRefBinding(state, Sym, V); 1217 1218 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag); 1219 if (N) { 1220 SmallString<128> sbuf; 1221 llvm::raw_svector_ostream os(sbuf); 1222 os << "Object was autoreleased "; 1223 if (V.getAutoreleaseCount() > 1) 1224 os << V.getAutoreleaseCount() << " times but the object "; 1225 else 1226 os << "but "; 1227 os << "has a +" << V.getCount() << " retain count"; 1228 1229 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); 1230 auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym, 1231 os.str()); 1232 Ctx.emitReport(std::move(R)); 1233 } 1234 1235 return nullptr; 1236 } 1237 1238 ProgramStateRef 1239 RetainCountChecker::handleSymbolDeath(ProgramStateRef state, 1240 SymbolRef sid, RefVal V, 1241 SmallVectorImpl<SymbolRef> &Leaked) const { 1242 bool hasLeak; 1243 1244 // HACK: Ignore retain-count issues on values accessed through ivars, 1245 // because of cases like this: 1246 // [_contentView retain]; 1247 // [_contentView removeFromSuperview]; 1248 // [self addSubview:_contentView]; // invalidates 'self' 1249 // [_contentView release]; 1250 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) 1251 hasLeak = false; 1252 else if (V.isOwned()) 1253 hasLeak = true; 1254 else if (V.isNotOwned() || V.isReturnedOwned()) 1255 hasLeak = (V.getCount() > 0); 1256 else 1257 hasLeak = false; 1258 1259 if (!hasLeak) 1260 return removeRefBinding(state, sid); 1261 1262 Leaked.push_back(sid); 1263 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak); 1264 } 1265 1266 ExplodedNode * 1267 RetainCountChecker::processLeaks(ProgramStateRef state, 1268 SmallVectorImpl<SymbolRef> &Leaked, 1269 CheckerContext &Ctx, 1270 ExplodedNode *Pred) const { 1271 // Generate an intermediate node representing the leak point. 1272 ExplodedNode *N = Ctx.addTransition(state, Pred); 1273 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); 1274 1275 if (N) { 1276 for (SymbolRef L : Leaked) { 1277 const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn; 1278 Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx)); 1279 } 1280 } 1281 1282 return N; 1283 } 1284 1285 static bool isISLObjectRef(QualType Ty) { 1286 return StringRef(Ty.getAsString()).startswith("isl_"); 1287 } 1288 1289 void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { 1290 if (!Ctx.inTopFrame()) 1291 return; 1292 1293 RetainSummaryManager &SmrMgr = getSummaryManager(Ctx); 1294 const LocationContext *LCtx = Ctx.getLocationContext(); 1295 const FunctionDecl *FD = dyn_cast<FunctionDecl>(LCtx->getDecl()); 1296 1297 if (!FD || SmrMgr.isTrustedReferenceCountImplementation(FD)) 1298 return; 1299 1300 ProgramStateRef state = Ctx.getState(); 1301 const RetainSummary *FunctionSummary = SmrMgr.getFunctionSummary(FD); 1302 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects(); 1303 1304 for (unsigned idx = 0, e = FD->getNumParams(); idx != e; ++idx) { 1305 const ParmVarDecl *Param = FD->getParamDecl(idx); 1306 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol(); 1307 1308 QualType Ty = Param->getType(); 1309 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx); 1310 if (AE && AE->getKind() == DecRef && isISLObjectRef(Ty)) { 1311 state = setRefBinding( 1312 state, Sym, RefVal::makeOwned(ObjKind::Generalized, Ty)); 1313 } else if (isISLObjectRef(Ty)) { 1314 state = setRefBinding( 1315 state, Sym, 1316 RefVal::makeNotOwned(ObjKind::Generalized, Ty)); 1317 } 1318 } 1319 1320 Ctx.addTransition(state); 1321 } 1322 1323 void RetainCountChecker::checkEndFunction(const ReturnStmt *RS, 1324 CheckerContext &Ctx) const { 1325 ExplodedNode *Pred = processReturn(RS, Ctx); 1326 1327 // Created state cached out. 1328 if (!Pred) { 1329 return; 1330 } 1331 1332 ProgramStateRef state = Pred->getState(); 1333 RefBindingsTy B = state->get<RefBindings>(); 1334 1335 // Don't process anything within synthesized bodies. 1336 const LocationContext *LCtx = Pred->getLocationContext(); 1337 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) { 1338 assert(!LCtx->inTopFrame()); 1339 return; 1340 } 1341 1342 for (auto &I : B) { 1343 state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx, 1344 I.first, I.second); 1345 if (!state) 1346 return; 1347 } 1348 1349 // If the current LocationContext has a parent, don't check for leaks. 1350 // We will do that later. 1351 // FIXME: we should instead check for imbalances of the retain/releases, 1352 // and suggest annotations. 1353 if (LCtx->getParent()) 1354 return; 1355 1356 B = state->get<RefBindings>(); 1357 SmallVector<SymbolRef, 10> Leaked; 1358 1359 for (auto &I : B) 1360 state = handleSymbolDeath(state, I.first, I.second, Leaked); 1361 1362 processLeaks(state, Leaked, Ctx, Pred); 1363 } 1364 1365 void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, 1366 CheckerContext &C) const { 1367 ExplodedNode *Pred = C.getPredecessor(); 1368 1369 ProgramStateRef state = C.getState(); 1370 SmallVector<SymbolRef, 10> Leaked; 1371 1372 // Update counts from autorelease pools 1373 for (const auto &I: state->get<RefBindings>()) { 1374 SymbolRef Sym = I.first; 1375 if (SymReaper.isDead(Sym)) { 1376 static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease"); 1377 const RefVal &V = I.second; 1378 state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V); 1379 if (!state) 1380 return; 1381 1382 // Fetch the new reference count from the state, and use it to handle 1383 // this symbol. 1384 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked); 1385 } 1386 } 1387 1388 if (Leaked.empty()) { 1389 C.addTransition(state); 1390 return; 1391 } 1392 1393 Pred = processLeaks(state, Leaked, C, Pred); 1394 1395 // Did we cache out? 1396 if (!Pred) 1397 return; 1398 1399 // Now generate a new node that nukes the old bindings. 1400 // The only bindings left at this point are the leaked symbols. 1401 RefBindingsTy::Factory &F = state->get_context<RefBindings>(); 1402 RefBindingsTy B = state->get<RefBindings>(); 1403 1404 for (SymbolRef L : Leaked) 1405 B = F.remove(B, L); 1406 1407 state = state->set<RefBindings>(B); 1408 C.addTransition(state, Pred); 1409 } 1410 1411 void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, 1412 const char *NL, const char *Sep) const { 1413 1414 RefBindingsTy B = State->get<RefBindings>(); 1415 1416 if (B.isEmpty()) 1417 return; 1418 1419 Out << Sep << NL; 1420 1421 for (auto &I : B) { 1422 Out << I.first << " : "; 1423 I.second.print(Out); 1424 Out << NL; 1425 } 1426 } 1427 1428 //===----------------------------------------------------------------------===// 1429 // Checker registration. 1430 //===----------------------------------------------------------------------===// 1431 1432 void ento::registerRetainCountChecker(CheckerManager &Mgr) { 1433 auto *Chk = Mgr.registerChecker<RetainCountChecker>(); 1434 Chk->TrackObjCAndCFObjects = true; 1435 } 1436 1437 // FIXME: remove this, hack for backwards compatibility: 1438 // it should be possible to enable the NS/CF retain count checker as 1439 // osx.cocoa.RetainCount, and it should be possible to disable 1440 // osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false. 1441 static bool hasPrevCheckOSObjectOptionDisabled(AnalyzerOptions &Options) { 1442 auto I = Options.Config.find("osx.cocoa.RetainCount:CheckOSObject"); 1443 if (I != Options.Config.end()) 1444 return I->getValue() == "false"; 1445 return false; 1446 } 1447 1448 void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) { 1449 auto *Chk = Mgr.registerChecker<RetainCountChecker>(); 1450 if (!hasPrevCheckOSObjectOptionDisabled(Mgr.getAnalyzerOptions())) 1451 Chk->TrackOSObjects = true; 1452 } 1453