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