clang 23.0.0git
RetainCountChecker.cpp
Go to the documentation of this file.
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"
16#include <optional>
17
18using namespace clang;
19using namespace ento;
20using namespace retaincountchecker;
21
23
24namespace clang {
25namespace ento {
27
29 return State->get<RefBindings>(Sym);
30}
31
32} // end namespace retaincountchecker
33} // end namespace ento
34} // end namespace clang
35
37 RefVal Val) {
38 assert(Sym != nullptr);
39 return State->set<RefBindings>(Sym, Val);
40}
41
43 return State->remove<RefBindings>(Sym);
44}
45
46void 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
85 Out << "-dealloc (not-owned)";
86 break;
87
88 case ErrorLeak:
89 Out << "Leaked";
90 break;
91
93 Out << "Leaked (Bad naming)";
94 break;
95
97 Out << "Use-After-Release [ERROR]";
98 break;
99
101 Out << "Release of Not-Owned [ERROR]";
102 break;
103
105 Out << "Over-autoreleased";
106 break;
107
109 Out << "Non-owned object returned instead of owned";
110 break;
111 }
112
113 switch (getIvarAccessHistory()) {
115 break;
117 Out << " [direct ivar access]";
118 break;
120 Out << " [released after direct ivar access]";
121 }
122
123 if (ACnt) {
124 Out << " [autorelease -" << ACnt << ']';
125 }
126}
127
128namespace {
129class StopTrackingCallback final : public SymbolVisitor {
130 ProgramStateRef state;
131public:
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
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.
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
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;
201 AE = AE.withKind(IncRef);
202 break;
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
228 const Expr *Ex) const {
229 ProgramStateRef state = C.getState();
230 const ExplodedNode *pred = C.getPredecessor();
231 for (const Stmt *Child : Ex->children()) {
232 const auto *ChildAsExpr = dyn_cast<Expr>(Child);
233 SVal V = ChildAsExpr ? pred->getSVal(ChildAsExpr) : UnknownVal();
234 if (SymbolRef sym = V.getAsSymbol())
235 if (const RefVal* T = getRefBinding(state, sym)) {
236 RefVal::Kind hasErr = (RefVal::Kind) 0;
237 state = updateSymbol(state, sym, *T,
239 if (hasErr) {
240 processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C);
241 return;
242 }
243 }
244 }
245
246 // Return the object as autoreleased.
247 // RetEffect RE = RetEffect::MakeNotOwned(ObjKind::ObjC);
248 if (SymbolRef sym =
249 state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
250 QualType ResultTy = Ex->getType();
251 state = setRefBinding(state, sym,
253 }
254
255 C.addTransition(state);
256}
257
259 CheckerContext &C) const {
260 // Apply the 'MayEscape' to all values.
262}
263
265 CheckerContext &C) const {
266 // Apply the 'MayEscape' to all keys and values.
268}
269
271 CheckerContext &C) const {
272 const ExplodedNode *Pred = C.getPredecessor();
273 ProgramStateRef State = Pred->getState();
274
275 if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) {
276 QualType ResultTy = Ex->getType();
277 State = setRefBinding(State, Sym,
279 }
280
281 C.addTransition(State);
282}
283
285 CheckerContext &C) const {
286 std::optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
287 if (!IVarLoc)
288 return;
289
290 ProgramStateRef State = C.getState();
291 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
292 if (!Sym || !isa_and_nonnull<ObjCIvarRegion>(Sym->getOriginRegion()))
293 return;
294
295 // Accessing an ivar directly is unusual. If we've done that, be more
296 // forgiving about what the surrounding code is allowed to do.
297
298 QualType Ty = Sym->getType();
299 ObjKind Kind;
300 if (Ty->isObjCRetainableType())
301 Kind = ObjKind::ObjC;
303 Kind = ObjKind::CF;
304 else
305 return;
306
307 // If the value is already known to be nil, don't bother tracking it.
308 ConstraintManager &CMgr = State->getConstraintManager();
309 if (CMgr.isNull(State, Sym).isConstrainedTrue())
310 return;
311
312 if (const RefVal *RV = getRefBinding(State, Sym)) {
313 // If we've seen this symbol before, or we're only seeing it now because
314 // of something the analyzer has synthesized, don't do anything.
315 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None ||
316 isSynthesizedAccessor(C.getStackFrame())) {
317 return;
318 }
319
320 // Note that this value has been loaded from an ivar.
321 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
322 return;
323 }
324
325 RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty);
326
327 // In a synthesized accessor, the effective retain count is +0.
328 if (isSynthesizedAccessor(C.getStackFrame())) {
329 C.addTransition(setRefBinding(State, Sym, PlusZero));
330 return;
331 }
332
333 State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
334 C.addTransition(State);
335}
336
338 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
339
340 // Check if the message is not consumed, we know it will not be used in
341 // an assignment, ex: "self = [super init]".
342 return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
343 !Call.getLocationContext()
344 ->getAnalysisDeclContext()
345 ->getParentMap()
346 .isConsumedExpr(Call.getOriginExpr());
347 }
348 return false;
349}
350
352 const CallEvent &Call,
353 QualType ReceiverType) {
354 const Expr *CE = Call.getOriginExpr();
355 AnyCall C =
356 CE ? *AnyCall::forExpr(CE)
358 return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
359 isReceiverUnconsumedSelf(Call), ReceiverType);
360}
361
363 CheckerContext &C) const {
365
366 // Leave null if no receiver.
367 QualType ReceiverType;
368 if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) {
369 if (MC->isInstanceMessage()) {
370 SVal ReceiverV = MC->getReceiverSVal();
371 if (SymbolRef Sym = ReceiverV.getAsLocSymbol())
372 if (const RefVal *T = getRefBinding(C.getState(), Sym))
373 ReceiverType = T->getType();
374 }
375 }
376
377 const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType);
378
379 if (C.wasInlined) {
381 return;
382 }
383 checkSummary(*Summ, Call, C);
384}
385
386/// GetReturnType - Used to get the return type of a message expression or
387/// function call with the intention of affixing that type to a tracked symbol.
388/// While the return type can be queried directly from RetEx, when
389/// invoking class methods we augment to the return type to be that of
390/// a pointer to the class (as opposed it just being id).
391// FIXME: We may be able to do this with related result types instead.
392// This function is probably overestimating.
393static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
394 QualType RetTy = RetE->getType();
395 // If RetE is not a message expression just return its type.
396 // If RetE is a message expression, return its types if it is something
397 /// more specific than id.
398 if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
399 if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>())
400 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
401 PT->isObjCClassType()) {
402 // At this point we know the return type of the message expression is
403 // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
404 // is a call to a class method whose type we can resolve. In such
405 // cases, promote the return type to XXX* (where XXX is the class).
406 const ObjCInterfaceDecl *D = ME->getReceiverInterface();
407 return !D ? RetTy :
409 }
410
411 return RetTy;
412}
413
414static std::optional<RefVal> refValFromRetEffect(RetEffect RE,
415 QualType ResultTy) {
416 if (RE.isOwned()) {
417 return RefVal::makeOwned(RE.getObjKind(), ResultTy);
418 } else if (RE.notOwned()) {
419 return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
420 }
421
422 return std::nullopt;
423}
424
426 QualType PT = QT->getPointeeType();
427 if (!PT.isNull())
428 if (PT->getAsCXXRecordDecl())
429 return true;
430 return false;
431}
432
433/// Whether the tracked value should be escaped on a given call.
434/// OSObjects are escaped when passed to void * / etc.
435static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx,
436 const RefVal *TrackedValue) {
437 if (TrackedValue->getObjKind() != ObjKind::OS)
438 return false;
439 if (ArgIdx >= CE.parameters().size())
440 return false;
441 return !isPointerToObject(CE.parameters()[ArgIdx]->getType());
442}
443
444// We don't always get the exact modeling of the function with regards to the
445// retain count checker even when the function is inlined. For example, we need
446// to stop tracking the symbols which were marked with StopTrackingHard.
448 const CallEvent &CallOrMsg,
449 CheckerContext &C) const {
450 ProgramStateRef state = C.getState();
451
452 // Evaluate the effect of the arguments.
453 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
454 SVal V = CallOrMsg.getArgSVal(idx);
455
456 if (SymbolRef Sym = V.getAsLocSymbol()) {
457 bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard;
458 if (const RefVal *T = getRefBinding(state, Sym))
459 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
460 ShouldRemoveBinding = true;
461
462 if (ShouldRemoveBinding)
463 state = removeRefBinding(state, Sym);
464 }
465 }
466
467 // Evaluate the effect on the message receiver.
468 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
469 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
471 state = removeRefBinding(state, Sym);
472 }
473 }
474 }
475
476 // Consult the summary for the return value.
477 RetEffect RE = Summ.getRetEffect();
478
479 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
480 if (RE.getKind() == RetEffect::NoRetHard)
481 state = removeRefBinding(state, Sym);
482 }
483
484 C.addTransition(state);
485}
486
487static bool isSmartPtrField(const MemRegion *MR) {
488 const auto *TR = dyn_cast<TypedValueRegion>(
489 cast<SubRegion>(MR)->getSuperRegion());
490 return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType());
491}
492
493
494/// A value escapes in these possible cases:
495///
496/// - binding to something that is not a memory region.
497/// - binding to a memregion that does not have stack storage
498/// - binding to a variable that has a destructor attached using CleanupAttr
499///
500/// We do not currently model what happens when a symbol is
501/// assigned to a struct field, unless it is a known smart pointer
502/// implementation, about which we know that it is inlined.
503/// FIXME: This could definitely be improved upon.
504static bool shouldEscapeRegion(ProgramStateRef State, const MemRegion *R) {
505 if (isSmartPtrField(R))
506 return false;
507
508 const auto *VR = dyn_cast<VarRegion>(R);
509
510 if (!R->hasMemorySpace<StackSpaceRegion>(State) || !VR)
511 return true;
512
513 const VarDecl *VD = VR->getDecl();
514 if (!VD->hasAttr<CleanupAttr>())
515 return false; // CleanupAttr attaches destructors, which cause escaping.
516 return true;
517}
518
519static SmallVector<ProgramStateRef, 2>
521 const CallEvent &CE) {
522
523 SVal L = CE.getReturnValue();
524
525 // Splitting is required to support out parameters,
526 // as out parameters might be created only on the "success" branch.
527 // We want to avoid eagerly splitting unless out parameters are actually
528 // needed.
529 bool SplitNecessary = false;
530 for (auto &P : Summ.getArgEffects())
531 if (P.second.getKind() == RetainedOutParameterOnNonZero ||
532 P.second.getKind() == RetainedOutParameterOnZero)
533 SplitNecessary = true;
534
535 ProgramStateRef AssumeNonZeroReturn = State;
536 ProgramStateRef AssumeZeroReturn = State;
537
538 if (SplitNecessary) {
539 if (!CE.getResultType()->isScalarType()) {
540 // Structures cannot be assumed. This probably deserves
541 // a compiler warning for invalid annotations.
542 return {State};
543 }
544 if (auto DL = L.getAs<DefinedOrUnknownSVal>()) {
545 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
546 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
547 }
548 }
549
550 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
551 SVal ArgVal = CE.getArgSVal(idx);
552 ArgEffect AE = Summ.getArg(idx);
553
554 auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion());
555 if (!ArgRegion)
556 continue;
557
558 QualType PointeeTy = ArgRegion->getValueType();
559 SVal PointeeVal = State->getSVal(ArgRegion);
560 SymbolRef Pointee = PointeeVal.getAsLocSymbol();
561 if (!Pointee)
562 continue;
563
564 if (shouldEscapeRegion(State, ArgRegion))
565 continue;
566
567 auto makeNotOwnedParameter = [&](ProgramStateRef St) {
568 return setRefBinding(St, Pointee,
569 RefVal::makeNotOwned(AE.getObjKind(), PointeeTy));
570 };
571 auto makeOwnedParameter = [&](ProgramStateRef St) {
572 return setRefBinding(St, Pointee,
573 RefVal::makeOwned(ObjKind::OS, PointeeTy));
574 };
575
576 switch (AE.getKind()) {
578 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
579 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
580 break;
582 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
583 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
584 break;
586 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
587 break;
589 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
590 break;
591 default:
592 break;
593 }
594 }
595
596 if (SplitNecessary) {
597 return {AssumeNonZeroReturn, AssumeZeroReturn};
598 } else {
599 assert(AssumeZeroReturn == AssumeNonZeroReturn);
600 return {AssumeZeroReturn};
601 }
602}
603
605 const CallEvent &CallOrMsg,
606 CheckerContext &C) const {
607 ProgramStateRef state = C.getState();
608
609 // Evaluate the effect of the arguments.
610 RefVal::Kind hasErr = (RefVal::Kind) 0;
611 SourceRange ErrorRange;
612 SymbolRef ErrorSym = nullptr;
613
614 // Helper tag for providing diagnostics: indicate whether dealloc was sent
615 // at this location.
616 bool DeallocSent = false;
617
618 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
619 SVal V = CallOrMsg.getArgSVal(idx);
620
621 ArgEffect Effect = Summ.getArg(idx);
622 if (SymbolRef Sym = V.getAsLocSymbol()) {
623 if (const RefVal *T = getRefBinding(state, Sym)) {
624
625 if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T))
627
628 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
629 if (hasErr) {
630 ErrorRange = CallOrMsg.getArgSourceRange(idx);
631 ErrorSym = Sym;
632 break;
633 } else if (Effect.getKind() == Dealloc) {
634 DeallocSent = true;
635 }
636 }
637 }
638 }
639
640 // Evaluate the effect on the message receiver / `this` argument.
641 bool ReceiverIsTracked = false;
642 if (!hasErr) {
643 if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) {
644 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
645 if (const RefVal *T = getRefBinding(state, Sym)) {
646 ReceiverIsTracked = true;
647 state = updateSymbol(state, Sym, *T,
648 Summ.getReceiverEffect(), hasErr, C);
649 if (hasErr) {
650 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
651 ErrorSym = Sym;
652 } else if (Summ.getReceiverEffect().getKind() == Dealloc) {
653 DeallocSent = true;
654 }
655 }
656 }
657 } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
658 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
659 if (const RefVal *T = getRefBinding(state, Sym)) {
660 state = updateSymbol(state, Sym, *T, Summ.getThisEffect(),
661 hasErr, C);
662 if (hasErr) {
663 ErrorRange = MCall->getOriginExpr()->getSourceRange();
664 ErrorSym = Sym;
665 }
666 }
667 }
668 }
669 }
670
671 // Process any errors.
672 if (hasErr) {
673 processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C);
674 return;
675 }
676
677 // Consult the summary for the return value.
678 RetEffect RE = Summ.getRetEffect();
679
681 if (ReceiverIsTracked)
683 else
685 }
686
687 if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
688 QualType ResultTy = CallOrMsg.getResultType();
689 if (RE.notOwned()) {
690 const Expr *Ex = CallOrMsg.getOriginExpr();
691 assert(Ex);
692 ResultTy = GetReturnType(Ex, C.getASTContext());
693 }
694 if (std::optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
695 state = setRefBinding(state, Sym, *updatedRefVal);
696 }
697
699 updateOutParameters(state, Summ, CallOrMsg);
700
701 for (ProgramStateRef St : Out) {
702 if (DeallocSent) {
703 C.addTransition(St, C.getPredecessor(), &getDeallocSentTag());
704 } else {
705 C.addTransition(St);
706 }
707 }
708}
709
711 SymbolRef sym, RefVal V,
712 ArgEffect AE,
713 RefVal::Kind &hasErr,
714 CheckerContext &C) const {
715 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
716 if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) {
717 switch (AE.getKind()) {
718 default:
719 break;
720 case IncRef:
721 AE = AE.withKind(DoNothing);
722 break;
723 case DecRef:
724 AE = AE.withKind(DoNothing);
725 break;
727 AE = AE.withKind(StopTracking);
728 break;
729 }
730 }
731
732 // Handle all use-after-releases.
733 if (V.getKind() == RefVal::Released) {
735 hasErr = V.getKind();
736 return setRefBinding(state, sym, V);
737 }
738
739 switch (AE.getKind()) {
744 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
745 "not have ref state.");
746
747 case Dealloc: // NB. we only need to add a note in a non-error case.
748 switch (V.getKind()) {
749 default:
750 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
751 case RefVal::Owned:
752 // The object immediately transitions to the released state.
753 V = V ^ RefVal::Released;
754 V.clearCounts();
755 return setRefBinding(state, sym, V);
756 case RefVal::NotOwned:
758 hasErr = V.getKind();
759 break;
760 }
761 break;
762
763 case MayEscape:
764 if (V.getKind() == RefVal::Owned) {
765 V = V ^ RefVal::NotOwned;
766 break;
767 }
768
769 [[fallthrough]];
770
771 case DoNothing:
772 return state;
773
774 case Autorelease:
775 // Update the autorelease counts.
776 V = V.autorelease();
777 break;
778
779 case StopTracking:
780 case StopTrackingHard:
781 return removeRefBinding(state, sym);
782
783 case IncRef:
784 switch (V.getKind()) {
785 default:
786 llvm_unreachable("Invalid RefVal state for a retain.");
787 case RefVal::Owned:
788 case RefVal::NotOwned:
789 V = V + 1;
790 break;
791 }
792 break;
793
794 case DecRef:
797 switch (V.getKind()) {
798 default:
799 // case 'RefVal::Released' handled above.
800 llvm_unreachable("Invalid RefVal state for a release.");
801
802 case RefVal::Owned:
803 assert(V.getCount() > 0);
804 if (V.getCount() == 1) {
805 if (AE.getKind() == DecRefBridgedTransferred ||
806 V.getIvarAccessHistory() ==
808 V = V ^ RefVal::NotOwned;
809 else
810 V = V ^ RefVal::Released;
811 } else if (AE.getKind() == DecRefAndStopTrackingHard) {
812 return removeRefBinding(state, sym);
813 }
814
815 V = V - 1;
816 break;
817
818 case RefVal::NotOwned:
819 if (V.getCount() > 0) {
821 return removeRefBinding(state, sym);
822 V = V - 1;
823 } else if (V.getIvarAccessHistory() ==
825 // Assume that the instance variable was holding on the object at
826 // +1, and we just didn't know.
828 return removeRefBinding(state, sym);
829 V = V.releaseViaIvar() ^ RefVal::Released;
830 } else {
832 hasErr = V.getKind();
833 }
834 break;
835 }
836 break;
837 }
838 return setRefBinding(state, sym, V);
839}
840
841const RefCountBug &
843 SymbolRef Sym) const {
845
846 switch (ErrorKind) {
848 return FE.UseAfterRelease;
850 return FE.ReleaseNotOwned;
852 if (Sym->getType()->getPointeeCXXRecordDecl())
853 return FE.FreeNotOwned;
854 return FE.DeallocNotOwned;
855 default:
856 llvm_unreachable("Unhandled error.");
857 }
858}
859
861 return ErrorKind == RefVal::ErrorReleaseNotOwned ||
862 ErrorKind == RefVal::ErrorDeallocNotOwned;
863}
864
866 SourceRange ErrorRange,
867 RefVal::Kind ErrorKind,
868 SymbolRef Sym,
869 CheckerContext &C) const {
870 // HACK: Ignore retain-count issues on values accessed through ivars,
871 // because of cases like this:
872 // [_contentView retain];
873 // [_contentView removeFromSuperview];
874 // [self addSubview:_contentView]; // invalidates 'self'
875 // [_contentView release];
876 if (const RefVal *RV = getRefBinding(St, Sym))
877 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
878 return;
879
880 ExplodedNode *N = C.generateErrorNode(St);
881 if (!N)
882 return;
883
884 auto report = std::make_unique<RefCountReport>(
885 errorKindToBugKind(ErrorKind, Sym), C.getASTContext().getLangOpts(), N,
886 Sym, /*isLeak=*/false, isReleaseUnownedError(ErrorKind));
887 report->addRange(ErrorRange);
888 C.emitReport(std::move(report));
889}
890
891//===----------------------------------------------------------------------===//
892// Handle the return values of retain-count-related functions.
893//===----------------------------------------------------------------------===//
894
896 CheckerContext &C) const {
897 ProgramStateRef state = C.getState();
898 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
899 if (!FD)
900 return false;
901
902 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
903 if (!CE)
904 return false;
905
907 QualType ResultTy = Call.getResultType();
908
909 // See if the function has 'rc_ownership_trusted_implementation'
910 // annotate attribute. If it does, we will not inline it.
911 bool hasTrustedImplementationAnnotation = false;
912
913 const LocationContext *LCtx = C.getLocationContext();
914
915 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
916 std::optional<BehaviorSummary> BSmr =
917 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
918
919 // See if it's one of the specific functions we know how to eval.
920 if (!BSmr)
921 return false;
922
923 // Bind the return value.
924 if (BSmr == BehaviorSummary::Identity ||
925 BSmr == BehaviorSummary::IdentityOrZero ||
926 BSmr == BehaviorSummary::IdentityThis) {
927
928 const Expr *BindReturnTo =
929 (BSmr == BehaviorSummary::IdentityThis)
930 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
931 : CE->getArg(0);
932 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
933
934 // If the receiver is unknown or the function has
935 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
936 // return value.
937 // FIXME: this branch is very strange.
938 if (RetVal.isUnknown() ||
939 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
940 SValBuilder &SVB = C.getSValBuilder();
941 RetVal = SVB.conjureSymbolVal(Call, C.blockCount());
942 }
943
944 // Bind the value.
945 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
946
947 if (BSmr == BehaviorSummary::IdentityOrZero) {
948 // Add a branch where the output is zero.
949 ProgramStateRef NullOutputState = C.getState();
950
951 // Assume that output is zero on the other branch.
952 NullOutputState = NullOutputState->BindExpr(
953 CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
954 /*Invalidate=*/false);
955 C.addTransition(NullOutputState, &getCastFailTag());
956
957 // And on the original branch assume that both input and
958 // output are non-zero.
959 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
960 state = state->assume(*L, /*assumption=*/true);
961
962 }
963 }
964
965 C.addTransition(state);
966 return true;
967}
968
969ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
970 CheckerContext &C) const {
971 ExplodedNode *Pred = C.getPredecessor();
972
973 // Only adjust the reference count if this is the top-level call frame,
974 // and not the result of inlining. In the future, we should do
975 // better checking even for inlined calls, and see if they match
976 // with their expected semantics (e.g., the method should return a retained
977 // object, etc.).
978 if (!C.inTopFrame())
979 return Pred;
980
981 if (!S)
982 return Pred;
983
984 const Expr *RetE = S->getRetValue();
985 if (!RetE)
986 return Pred;
987
988 ProgramStateRef state = C.getState();
989 // We need to dig down to the symbolic base here because various
990 // custom allocators do sometimes return the symbol with an offset.
991 SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
992 .getAsLocSymbol(/*IncludeBaseRegions=*/true);
993 if (!Sym)
994 return Pred;
995
996 // Get the reference count binding (if any).
997 const RefVal *T = getRefBinding(state, Sym);
998 if (!T)
999 return Pred;
1000
1001 // Change the reference count.
1002 RefVal X = *T;
1003
1004 switch (X.getKind()) {
1005 case RefVal::Owned: {
1006 unsigned cnt = X.getCount();
1007 assert(cnt > 0);
1008 X.setCount(cnt - 1);
1010 break;
1011 }
1012
1013 case RefVal::NotOwned: {
1014 unsigned cnt = X.getCount();
1015 if (cnt) {
1016 X.setCount(cnt - 1);
1018 } else {
1020 }
1021 break;
1022 }
1023
1024 default:
1025 return Pred;
1026 }
1027
1028 // Update the binding.
1029 state = setRefBinding(state, Sym, X);
1030 Pred = C.addTransition(state);
1031
1032 // At this point we have updated the state properly.
1033 // Everything after this is merely checking to see if the return value has
1034 // been over- or under-retained.
1035
1036 // Did we cache out?
1037 if (!Pred)
1038 return nullptr;
1039
1040 // Update the autorelease counts.
1041 state = handleAutoreleaseCounts(state, Pred, C, Sym, X, S);
1042
1043 // Have we generated a sink node?
1044 if (!state)
1045 return nullptr;
1046
1047 // Get the updated binding.
1048 T = getRefBinding(state, Sym);
1049 assert(T);
1050 X = *T;
1051
1052 // Consult the summary of the enclosing method.
1053 RetainSummaryManager &Summaries = getSummaryManager(C);
1054 const Decl *CD = &Pred->getCodeDecl();
1055 RetEffect RE = RetEffect::MakeNoRet();
1056
1057 // FIXME: What is the convention for blocks? Is there one?
1058 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1059 const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
1060 RE = Summ->getRetEffect();
1061 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1062 if (!isa<CXXMethodDecl>(FD)) {
1063 const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
1064 RE = Summ->getRetEffect();
1065 }
1066 }
1067
1068 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
1069}
1070
1073 ExplodedNode *Pred,
1074 RetEffect RE, RefVal X,
1075 SymbolRef Sym,
1076 ProgramStateRef state) const {
1077 // HACK: Ignore retain-count issues on values accessed through ivars,
1078 // because of cases like this:
1079 // [_contentView retain];
1080 // [_contentView removeFromSuperview];
1081 // [self addSubview:_contentView]; // invalidates 'self'
1082 // [_contentView release];
1083 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1084 return Pred;
1085
1086 // Any leaks or other errors?
1087 if (X.isReturnedOwned() && X.getCount() == 0) {
1088 if (RE.getKind() != RetEffect::NoRet) {
1089 if (!RE.isOwned()) {
1090
1091 // The returning type is a CF, we expect the enclosing method should
1092 // return ownership.
1094
1095 // Generate an error node.
1096 state = setRefBinding(state, Sym, X);
1097
1098 ExplodedNode *N = C.addTransition(state, Pred);
1099 if (N) {
1100 const LangOptions &LOpts = C.getASTContext().getLangOpts();
1101 auto R = std::make_unique<RefLeakReport>(
1102 getPreferredFrontend().LeakAtReturn, LOpts, N, Sym, C);
1103 C.emitReport(std::move(R));
1104 }
1105 return N;
1106 }
1107 }
1108 } else if (X.isReturnedNotOwned()) {
1109 if (RE.isOwned()) {
1110 if (X.getIvarAccessHistory() ==
1112 // Assume the method was trying to transfer a +1 reference from a
1113 // strong ivar to the caller.
1114 state = setRefBinding(state, Sym,
1115 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1116 } else {
1117 // Trying to return a not owned object to a caller expecting an
1118 // owned object.
1119 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1120
1121 ExplodedNode *N = C.addTransition(state, Pred);
1122 if (N) {
1123 auto R = std::make_unique<RefCountReport>(
1124 getPreferredFrontend().ReturnNotOwnedForOwned,
1125 C.getASTContext().getLangOpts(), N, Sym);
1126 C.emitReport(std::move(R));
1127 }
1128 return N;
1129 }
1130 }
1131 }
1132 return Pred;
1133}
1134
1135//===----------------------------------------------------------------------===//
1136// Check various ways a symbol can be invalidated.
1137//===----------------------------------------------------------------------===//
1138
1140 bool AtDeclInit, CheckerContext &C) const {
1141 ProgramStateRef state = C.getState();
1142 const MemRegion *MR = loc.getAsRegion();
1143
1144 // Find all symbols referenced by 'val' that we are tracking
1145 // and stop tracking them.
1146 if (MR && shouldEscapeRegion(state, MR)) {
1147 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1148 C.addTransition(state);
1149 }
1150}
1151
1153 SVal Cond,
1154 bool Assumption) const {
1155 // FIXME: We may add to the interface of evalAssume the list of symbols
1156 // whose assumptions have changed. For now we just iterate through the
1157 // bindings and check if any of the tracked symbols are NULL. This isn't
1158 // too bad since the number of symbols we will track in practice are
1159 // probably small and evalAssume is only called at branches and a few
1160 // other places.
1161 RefBindingsTy B = state->get<RefBindings>();
1162
1163 if (B.isEmpty())
1164 return state;
1165
1166 bool changed = false;
1167 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
1168 ConstraintManager &CMgr = state->getConstraintManager();
1169
1170 for (auto &I : B) {
1171 // Check if the symbol is null stop tracking the symbol.
1172 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
1173 if (AllocFailed.isConstrainedTrue()) {
1174 changed = true;
1175 B = RefBFactory.remove(B, I.first);
1176 }
1177 }
1178
1179 if (changed)
1180 state = state->set<RefBindings>(B);
1181
1182 return state;
1183}
1184
1186 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1187 ArrayRef<const MemRegion *> ExplicitRegions,
1188 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1189 const CallEvent *Call) const {
1190 if (!invalidated)
1191 return state;
1192
1193 llvm::SmallPtrSet<SymbolRef, 8> AllowedSymbols;
1194
1195 for (const MemRegion *I : ExplicitRegions)
1196 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1197 AllowedSymbols.insert(SR->getSymbol());
1198
1199 for (SymbolRef sym : *invalidated) {
1200 if (AllowedSymbols.count(sym))
1201 continue;
1202 // Remove any existing reference-count binding.
1203 state = removeRefBinding(state, sym);
1204 }
1205 return state;
1206}
1207
1209 ProgramStateRef state, ExplodedNode *Pred, CheckerContext &Ctx,
1210 SymbolRef Sym, RefVal V, const ReturnStmt *S) const {
1211 unsigned ACnt = V.getAutoreleaseCount();
1212
1213 // No autorelease counts? Nothing to be done.
1214 if (!ACnt)
1215 return state;
1216
1217 unsigned Cnt = V.getCount();
1218
1219 // FIXME: Handle sending 'autorelease' to already released object.
1220
1221 if (V.getKind() == RefVal::ReturnedOwned)
1222 ++Cnt;
1223
1224 // If we would over-release here, but we know the value came from an ivar,
1225 // assume it was a strong ivar that's just been relinquished.
1226 if (ACnt > Cnt &&
1227 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1228 V = V.releaseViaIvar();
1229 --ACnt;
1230 }
1231
1232 if (ACnt <= Cnt) {
1233 if (ACnt == Cnt) {
1234 V.clearCounts();
1235 if (V.getKind() == RefVal::ReturnedOwned) {
1237 } else {
1238 V = V ^ RefVal::NotOwned;
1239 }
1240 } else {
1241 V.setCount(V.getCount() - ACnt);
1242 V.setAutoreleaseCount(0);
1243 }
1244 return setRefBinding(state, Sym, V);
1245 }
1246
1247 // HACK: Ignore retain-count issues on values accessed through ivars,
1248 // because of cases like this:
1249 // [_contentView retain];
1250 // [_contentView removeFromSuperview];
1251 // [self addSubview:_contentView]; // invalidates 'self'
1252 // [_contentView release];
1253 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1254 return state;
1255
1256 // Woah! More autorelease counts then retain counts left.
1257 // Emit hard error.
1259 state = setRefBinding(state, Sym, V);
1260
1261 ExplodedNode *N = Ctx.generateSink(state, Pred);
1262 if (N) {
1263 SmallString<128> sbuf;
1264 llvm::raw_svector_ostream os(sbuf);
1265 os << "Object was autoreleased ";
1266 if (V.getAutoreleaseCount() > 1)
1267 os << V.getAutoreleaseCount() << " times but the object ";
1268 else
1269 os << "but ";
1270 os << "has a +" << V.getCount() << " retain count";
1271
1272 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1273 auto R = std::make_unique<RefCountReport>(
1274 getPreferredFrontend().OverAutorelease, LOpts, N, Sym, os.str());
1275 Ctx.emitReport(std::move(R));
1276 }
1277
1278 return nullptr;
1279}
1280
1283 SymbolRef sid, RefVal V,
1284 SmallVectorImpl<SymbolRef> &Leaked) const {
1285 bool hasLeak;
1286
1287 // HACK: Ignore retain-count issues on values accessed through ivars,
1288 // because of cases like this:
1289 // [_contentView retain];
1290 // [_contentView removeFromSuperview];
1291 // [self addSubview:_contentView]; // invalidates 'self'
1292 // [_contentView release];
1293 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1294 hasLeak = false;
1295 else if (V.isOwned())
1296 hasLeak = true;
1297 else if (V.isNotOwned() || V.isReturnedOwned())
1298 hasLeak = (V.getCount() > 0);
1299 else
1300 hasLeak = false;
1301
1302 if (!hasLeak)
1303 return removeRefBinding(state, sid);
1304
1305 Leaked.push_back(sid);
1306 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1307}
1308
1312 CheckerContext &Ctx,
1313 ExplodedNode *Pred) const {
1314 // Generate an intermediate node representing the leak point.
1315 ExplodedNode *N = Ctx.addTransition(state, Pred);
1316 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1317
1318 if (N) {
1320 const RefCountBug &BT = Pred ? FE.LeakWithinFunction : FE.LeakAtReturn;
1321
1322 for (SymbolRef L : Leaked) {
1323 Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
1324 }
1325 }
1326
1327 return N;
1328}
1329
1331 if (!Ctx.inTopFrame())
1332 return;
1333
1335 const LocationContext *LCtx = Ctx.getLocationContext();
1336 const Decl *D = LCtx->getDecl();
1337 std::optional<AnyCall> C = AnyCall::forDecl(D);
1338
1339 if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
1340 return;
1341
1342 ProgramStateRef state = Ctx.getState();
1343 const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C);
1344 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1345
1346 for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
1347 const ParmVarDecl *Param = C->parameters()[idx];
1348 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1349
1350 QualType Ty = Param->getType();
1351 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
1352 if (AE) {
1353 ObjKind K = AE->getObjKind();
1354 if (K == ObjKind::Generalized || K == ObjKind::OS ||
1355 (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) {
1356 RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty)
1357 : RefVal::makeNotOwned(K, Ty);
1358 state = setRefBinding(state, Sym, NewVal);
1359 }
1360 }
1361 }
1362
1363 Ctx.addTransition(state);
1364}
1365
1367 CheckerContext &Ctx) const {
1368 ExplodedNode *Pred = processReturn(RS, Ctx);
1369
1370 // Created state cached out.
1371 if (!Pred) {
1372 return;
1373 }
1374
1375 ProgramStateRef state = Pred->getState();
1376 RefBindingsTy B = state->get<RefBindings>();
1377
1378 // Don't process anything within synthesized bodies.
1379 const LocationContext *LCtx = Pred->getLocationContext();
1380 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1381 assert(!LCtx->inTopFrame());
1382 return;
1383 }
1384
1385 for (auto &I : B) {
1386 state = handleAutoreleaseCounts(state, Pred, Ctx, I.first, I.second);
1387 if (!state)
1388 return;
1389 }
1390
1391 // If the current LocationContext has a parent, don't check for leaks.
1392 // We will do that later.
1393 // FIXME: we should instead check for imbalances of the retain/releases,
1394 // and suggest annotations.
1395 if (LCtx->getParent())
1396 return;
1397
1398 B = state->get<RefBindings>();
1400
1401 for (auto &I : B)
1402 state = handleSymbolDeath(state, I.first, I.second, Leaked);
1403
1404 processLeaks(state, Leaked, Ctx, Pred);
1405}
1406
1408 CheckerContext &C) const {
1409 ExplodedNode *Pred = C.getPredecessor();
1410
1411 ProgramStateRef state = C.getState();
1413
1414 // Update counts from autorelease pools
1415 for (const auto &I: state->get<RefBindings>()) {
1416 SymbolRef Sym = I.first;
1417 if (SymReaper.isDead(Sym)) {
1418 const RefVal &V = I.second;
1419 state = handleAutoreleaseCounts(state, Pred, C, Sym, V);
1420 if (!state)
1421 return;
1422
1423 // Fetch the new reference count from the state, and use it to handle
1424 // this symbol.
1425 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
1426 }
1427 }
1428
1429 if (Leaked.empty()) {
1430 C.addTransition(state);
1431 return;
1432 }
1433
1434 Pred = processLeaks(state, Leaked, C, Pred);
1435
1436 // Did we cache out?
1437 if (!Pred)
1438 return;
1439
1440 // Now generate a new node that nukes the old bindings.
1441 // The only bindings left at this point are the leaked symbols.
1442 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
1443 RefBindingsTy B = state->get<RefBindings>();
1444
1445 for (SymbolRef L : Leaked)
1446 B = F.remove(B, L);
1447
1448 state = state->set<RefBindings>(B);
1449 C.addTransition(state, Pred);
1450}
1451
1453 const char *NL, const char *Sep) const {
1454
1455 RefBindingsTy B = State->get<RefBindings>();
1456
1457 if (B.isEmpty())
1458 return;
1459
1460 Out << Sep << NL;
1461
1462 for (auto &I : B) {
1463 Out << I.first << " : ";
1464 I.second.print(Out);
1465 Out << NL;
1466 }
1467}
1468
1469//===----------------------------------------------------------------------===//
1470// Checker registration.
1471//===----------------------------------------------------------------------===//
1472
1473std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::DeallocSentTag;
1474std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::CastFailTag;
1475
1476void ento::registerRetainCountBase(CheckerManager &Mgr) {
1477 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1478 Chk->DeallocSentTag = std::make_unique<SimpleProgramPointTag>(
1479 "RetainCountChecker", "DeallocSent");
1480 Chk->CastFailTag = std::make_unique<SimpleProgramPointTag>(
1481 "RetainCountChecker", "DynamicCastFail");
1482}
1483
1484bool ento::shouldRegisterRetainCountBase(const CheckerManager &) {
1485 return true;
1486}
1487
1488void ento::registerRetainCountChecker(CheckerManager &Mgr) {
1489 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1490 Chk->RetainCount.enable(Mgr);
1491 Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
1492 Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
1493}
1494
1495bool ento::shouldRegisterRetainCountChecker(const CheckerManager &) {
1496 return true;
1497}
1498
1499void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1500 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1501 Chk->OSObjectRetainCount.enable(Mgr);
1502
1503 // FIXME: We want bug reports to always have the same checker name associated
1504 // with them, yet here, if RetainCountChecker is disabled but
1505 // OSObjectRetainCountChecker is enabled, the checker names will be different.
1506 // This hack will make it so that the checker name depends on which checker is
1507 // enabled rather than on the registration order.
1508 // For the most part, we want **non-hidden checkers** to be associated with
1509 // diagnostics, and **hidden checker options** with the fine-tuning of
1510 // modeling. Following this logic, OSObjectRetainCountChecker should be the
1511 // latter, but we can't just remove it for backward compatibility reasons.
1512}
1513
1514bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &) {
1515 return true;
1516}
#define V(N, I)
static CanQualType GetReturnType(QualType RetTy)
Returns the "extra-canonicalized" return type, which discards qualifiers on the return type.
Definition CGCall.cpp:159
#define X(type, name)
Definition Value.h:97
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static const RetainSummary * getSummary(RetainSummaryManager &Summaries, const CallEvent &Call, QualType ReceiverType)
static std::optional< RefVal > refValFromRetEffect(RetEffect RE, QualType ResultTy)
static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym, RefVal Val)
static bool shouldEscapeRegion(ProgramStateRef State, const MemRegion *R)
A value escapes in these possible cases:
static bool isReceiverUnconsumedSelf(const CallEvent &Call)
static SmallVector< ProgramStateRef, 2 > updateOutParameters(ProgramStateRef State, const RetainSummary &Summ, const CallEvent &CE)
static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym)
static bool isPointerToObject(QualType QT)
static bool isSmartPtrField(const MemRegion *MR)
static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx, const RefVal *TrackedValue)
Whether the tracked value should be escaped on a given call.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceDecl *PrevDecl=nullptr) const
getObjCInterfaceType - Return the unique reference to the type for the specified ObjC interface decl.
const LangOptions & getLangOpts() const
Definition ASTContext.h:959
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
An instance of this class corresponds to a call.
Definition AnyCall.h:26
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
Definition AnyCall.h:134
static std::optional< AnyCall > forExpr(const Expr *E)
If E is a generic call (to ObjC method /function/block/etc), return a constructed AnyCall object.
Definition AnyCall.h:113
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
Definition Decl.h:4809
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition Expr.h:6673
const BlockDecl * getBlockDecl() const
Definition Expr.h:6685
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition Expr.h:3679
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
bool hasAttr() const
Definition DeclBase.h:585
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const Decl * getDecl() const
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition ExprObjC.h:220
ObjCBoxedExpr - used for generalized expression boxing.
Definition ExprObjC.h:159
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers,...
Definition ExprObjC.h:1674
ObjCBridgeCastKind getBridgeKind() const
Determine which kind of bridge is being performed via this cast.
Definition ExprObjC.h:1700
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition ExprObjC.h:342
Represents an ObjC class declaration.
Definition DeclObjC.h:1154
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition ExprObjC.h:580
An expression that sends a message to the given Objective-C object or class.
Definition ExprObjC.h:971
Represents a pointer to an Objective C object.
Definition TypeBase.h:8054
Represents a parameter to a function.
Definition Decl.h:1808
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3166
Expr * getRetValue()
Definition Stmt.h:3193
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition Stmt.h:86
child_range children()
Definition Stmt.cpp:304
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
bool isScalarType() const
Definition TypeBase.h:9145
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
Definition Type.cpp:1958
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isObjCObjectPointerType() const
Definition TypeBase.h:8852
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9266
bool isObjCRetainableType() const
Definition Type.cpp:5416
Represents a variable declaration or definition.
Definition Decl.h:924
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
ArgEffect withKind(ArgEffectKind NewK)
ArgEffectKind getKind() const
Represents an abstract call to a function or method along a particular path.
Definition CallEvent.h:153
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
virtual const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
Definition CallEvent.h:263
QualType getResultType() const
Returns the result type, adjusted for references.
Definition CallEvent.cpp:70
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call's formal parameters.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
const ProgramStateRef & getState() const
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
bool inTopFrame() const
Return true if the current LocationContext has no caller context.
const LocationContext * getLocationContext() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
void enable(CheckerManager &Mgr)
Definition Checker.h:519
const AnalyzerOptions & getAnalyzerOptions() const
CheckerNameRef getCurrentCheckerName() const
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
SVal getSVal(const Expr *E) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
const Decl & getCodeDecl() const
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
const RegionTy * getAs() const
Definition MemRegion.h:1421
RetEffect summarizes a call's retain/release behavior with respect to its return value.
@ OwnedWhenTrackedReceiver
Indicates that the return value is an owned object when the receiver is also a tracked object.
@ NoRet
Indicates that no retain count information is tracked for the return value.
bool isTrustedReferenceCountImplementation(const Decl *FD)
std::optional< BehaviorSummary > canEval(const CallExpr *CE, const FunctionDecl *FD, bool &hasTrustedImplementationAnnotation)
static bool isKnownSmartPointer(QualType QT)
const RetainSummary * getSummary(AnyCall C, bool HasNonZeroCallbackArg=false, bool IsReceiverUnconsumedSelf=false, QualType ReceiverType={})
Summary for a function with respect to ownership changes.
ArgEffect getReceiverEffect() const
getReceiverEffect - Returns the effect on the receiver of the call.
RetEffect getRetEffect() const
getRetEffect - Returns the effect on the return value of the call.
ArgEffect getArg(unsigned idx) const
getArg - Return the argument effect on the argument specified by idx (starting from 0).
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
Definition SVals.cpp:103
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition SVals.cpp:67
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
bool isUnknown() const
Definition SVals.h:105
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
Definition MemRegion.h:487
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
Definition SymExpr.h:124
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolicRegion - A special, "non-concrete" region.
Definition MemRegion.h:808
const VarDecl * getDecl() const override=0
IvarAccessHistory getIvarAccessHistory() const
Returns what the analyzer knows about direct accesses to a particular instance variable.
static RefVal makeOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is the responsibility of the current function,...
static RefVal makeNotOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is not the responsibility of the current function.
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const
void checkSummary(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
ProgramStateRef handleSymbolDeath(ProgramStateRef state, SymbolRef sid, RefVal V, SmallVectorImpl< SymbolRef > &Leaked) const
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, bool Assumption) const
static const SimpleProgramPointTag & getCastFailTag()
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, RefVal::Kind ErrorKind, SymbolRef Sym, CheckerContext &C) const
const RefCountBug & errorKindToBugKind(RefVal::Kind ErrorKind, SymbolRef Sym) const
static std::unique_ptr< SimpleProgramPointTag > DeallocSentTag
ExplodedNode * checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, SymbolRef Sym, ProgramStateRef state) const
ProgramStateRef handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, CheckerContext &Ctx, SymbolRef Sym, RefVal V, const ReturnStmt *S=nullptr) const
bool isReleaseUnownedError(RefVal::Kind ErrorKind) const
ExplodedNode * processLeaks(ProgramStateRef state, SmallVectorImpl< SymbolRef > &Leaked, CheckerContext &Ctx, ExplodedNode *Pred=nullptr) const
void checkBind(SVal loc, SVal val, const Stmt *S, bool AtDeclInit, CheckerContext &C) const
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind &hasErr, CheckerContext &C) const
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const
std::unique_ptr< RetainSummaryManager > Summaries
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override
Debug state dump callback, see CheckerManager::runCheckersForPrintState.
bool evalCall(const CallEvent &Call, CheckerContext &C) const
void checkPostCall(const CallEvent &Call, CheckerContext &C) const
static std::unique_ptr< SimpleProgramPointTag > CastFailTag
ProgramStateRef checkRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const LocationContext *LCtx, const CallEvent *Call) const
static const SimpleProgramPointTag & getDeallocSentTag()
void processObjCLiterals(CheckerContext &C, const Expr *Ex) const
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const
void processSummaryOfInlined(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
RetainSummaryManager & getSummaryManager(ASTContext &Ctx) const
bool TrackNSCFStartParam
Track initial parameters (for the entry point) for NS/CF objects.
bool isSynthesizedAccessor(const StackFrame *SF)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
llvm::ImmutableMap< unsigned, ArgEffect > ArgEffects
ArgEffects summarizes the effects of a function/method call on all of its arguments.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition Store.h:51
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
ObjKind
Determines the object kind of a tracked object.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Generalized
Indicates that the tracked object is a generalized object.
@ CF
Indicates that the tracked object is a CF object.
@ ObjC
Indicates that the tracked object is an Objective-C object.
@ IncRef
The argument has its reference count increased by 1.
@ UnretainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +0 v...
@ DoNothing
There is no effect.
@ RetainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ RetainedOutParameterOnZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ MayEscape
The argument is treated as potentially escaping, meaning that even when its reference count hits 0 it...
@ StopTracking
All typestate tracking of the object ceases.
@ Dealloc
The argument is treated as if the referenced object was deallocated.
@ Autorelease
The argument is treated as if an -autorelease message had been sent to the referenced object.
@ RetainedOutParameterOnNonZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ DecRef
The argument has its reference count decreased by 1.
@ StopTrackingHard
All typestate tracking of the object ceases.
@ DecRefAndStopTrackingHard
Performs the combined functionality of DecRef and StopTrackingHard.
@ DecRefBridgedTransferred
The argument has its reference count decreased by 1 to model a transferred bridge cast under ARC.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
Expr * Cond
};
@ OBC_Bridge
Bridging via __bridge, which does nothing but reinterpret the bits.
@ OBC_BridgeTransfer
Bridging via __bridge_transfer, which transfers ownership of an Objective-C pointer into ARC.
@ OBC_BridgeRetained
Bridging via __bridge_retain, which makes an ARC object available as a +1 C pointer.
U cast(CodeGen::Address addr)
Definition Address.h:327