clang 22.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 {
26namespace retaincountchecker {
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 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,
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,
252 }
253
254 C.addTransition(state);
255}
256
258 CheckerContext &C) const {
259 // Apply the 'MayEscape' to all values.
261}
262
264 CheckerContext &C) const {
265 // Apply the 'MayEscape' to all keys and values.
267}
268
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,
278 }
279
280 C.addTransition(State);
281}
282
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;
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
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
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
362 CheckerContext &C) const {
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) {
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.
392static 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 :
408 }
409
410 return RetTy;
411}
412
413static 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
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.
434static 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.
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()) {
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
486static 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.
503static 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
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()) {
577 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
578 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
579 break;
581 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
582 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
583 break;
585 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
586 break;
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
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))
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
680 if (ReceiverIsTracked)
682 else
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
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
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;
726 AE = AE.withKind(StopTracking);
727 break;
728 }
729 }
730
731 // Handle all use-after-releases.
732 if (V.getKind() == RefVal::Released) {
734 hasErr = V.getKind();
735 return setRefBinding(state, sym, V);
736 }
737
738 switch (AE.getKind()) {
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:
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:
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() ==
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) {
820 return removeRefBinding(state, sym);
821 V = V - 1;
822 } else if (V.getIvarAccessHistory() ==
824 // Assume that the instance variable was holding on the object at
825 // +1, and we just didn't know.
827 return removeRefBinding(state, sym);
828 V = V.releaseViaIvar() ^ RefVal::Released;
829 } else {
831 hasErr = V.getKind();
832 }
833 break;
834 }
835 break;
836 }
837 return setRefBinding(state, sym, V);
838}
839
840const RefCountBug &
842 SymbolRef Sym) const {
844
845 switch (ErrorKind) {
847 return FE.UseAfterRelease;
849 return FE.ReleaseNotOwned;
851 if (Sym->getType()->getPointeeCXXRecordDecl())
852 return FE.FreeNotOwned;
853 return FE.DeallocNotOwned;
854 default:
855 llvm_unreachable("Unhandled error.");
856 }
857}
858
860 return ErrorKind == RefVal::ErrorReleaseNotOwned ||
861 ErrorKind == RefVal::ErrorDeallocNotOwned;
862}
863
865 SourceRange ErrorRange,
866 RefVal::Kind ErrorKind,
867 SymbolRef Sym,
868 CheckerContext &C) const {
869 // HACK: Ignore retain-count issues on values accessed through ivars,
870 // because of cases like this:
871 // [_contentView retain];
872 // [_contentView removeFromSuperview];
873 // [self addSubview:_contentView]; // invalidates 'self'
874 // [_contentView release];
875 if (const RefVal *RV = getRefBinding(St, Sym))
876 if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
877 return;
878
879 ExplodedNode *N = C.generateErrorNode(St);
880 if (!N)
881 return;
882
883 auto report = std::make_unique<RefCountReport>(
884 errorKindToBugKind(ErrorKind, Sym), C.getASTContext().getLangOpts(), N,
885 Sym, /*isLeak=*/false, isReleaseUnownedError(ErrorKind));
886 report->addRange(ErrorRange);
887 C.emitReport(std::move(report));
888}
889
890//===----------------------------------------------------------------------===//
891// Handle the return values of retain-count-related functions.
892//===----------------------------------------------------------------------===//
893
895 CheckerContext &C) const {
896 ProgramStateRef state = C.getState();
897 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
898 if (!FD)
899 return false;
900
901 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
902 if (!CE)
903 return false;
904
906 QualType ResultTy = Call.getResultType();
907
908 // See if the function has 'rc_ownership_trusted_implementation'
909 // annotate attribute. If it does, we will not inline it.
910 bool hasTrustedImplementationAnnotation = false;
911
912 const LocationContext *LCtx = C.getLocationContext();
913
914 using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
915 std::optional<BehaviorSummary> BSmr =
916 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
917
918 // See if it's one of the specific functions we know how to eval.
919 if (!BSmr)
920 return false;
921
922 // Bind the return value.
923 if (BSmr == BehaviorSummary::Identity ||
924 BSmr == BehaviorSummary::IdentityOrZero ||
925 BSmr == BehaviorSummary::IdentityThis) {
926
927 const Expr *BindReturnTo =
928 (BSmr == BehaviorSummary::IdentityThis)
929 ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument()
930 : CE->getArg(0);
931 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
932
933 // If the receiver is unknown or the function has
934 // 'rc_ownership_trusted_implementation' annotate attribute, conjure a
935 // return value.
936 // FIXME: this branch is very strange.
937 if (RetVal.isUnknown() ||
938 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
939 SValBuilder &SVB = C.getSValBuilder();
940 RetVal = SVB.conjureSymbolVal(Call, C.blockCount());
941 }
942
943 // Bind the value.
944 state = state->BindExpr(CE, LCtx, RetVal, /*Invalidate=*/false);
945
946 if (BSmr == BehaviorSummary::IdentityOrZero) {
947 // Add a branch where the output is zero.
948 ProgramStateRef NullOutputState = C.getState();
949
950 // Assume that output is zero on the other branch.
951 NullOutputState = NullOutputState->BindExpr(
952 CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
953 /*Invalidate=*/false);
954 C.addTransition(NullOutputState, &getCastFailTag());
955
956 // And on the original branch assume that both input and
957 // output are non-zero.
958 if (auto L = RetVal.getAs<DefinedOrUnknownSVal>())
959 state = state->assume(*L, /*assumption=*/true);
960
961 }
962 }
963
964 C.addTransition(state);
965 return true;
966}
967
968ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S,
969 CheckerContext &C) const {
970 ExplodedNode *Pred = C.getPredecessor();
971
972 // Only adjust the reference count if this is the top-level call frame,
973 // and not the result of inlining. In the future, we should do
974 // better checking even for inlined calls, and see if they match
975 // with their expected semantics (e.g., the method should return a retained
976 // object, etc.).
977 if (!C.inTopFrame())
978 return Pred;
979
980 if (!S)
981 return Pred;
982
983 const Expr *RetE = S->getRetValue();
984 if (!RetE)
985 return Pred;
986
987 ProgramStateRef state = C.getState();
988 // We need to dig down to the symbolic base here because various
989 // custom allocators do sometimes return the symbol with an offset.
990 SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
991 .getAsLocSymbol(/*IncludeBaseRegions=*/true);
992 if (!Sym)
993 return Pred;
994
995 // Get the reference count binding (if any).
996 const RefVal *T = getRefBinding(state, Sym);
997 if (!T)
998 return Pred;
999
1000 // Change the reference count.
1001 RefVal X = *T;
1002
1003 switch (X.getKind()) {
1004 case RefVal::Owned: {
1005 unsigned cnt = X.getCount();
1006 assert(cnt > 0);
1007 X.setCount(cnt - 1);
1009 break;
1010 }
1011
1012 case RefVal::NotOwned: {
1013 unsigned cnt = X.getCount();
1014 if (cnt) {
1015 X.setCount(cnt - 1);
1017 } else {
1019 }
1020 break;
1021 }
1022
1023 default:
1024 return Pred;
1025 }
1026
1027 // Update the binding.
1028 state = setRefBinding(state, Sym, X);
1029 Pred = C.addTransition(state);
1030
1031 // At this point we have updated the state properly.
1032 // Everything after this is merely checking to see if the return value has
1033 // been over- or under-retained.
1034
1035 // Did we cache out?
1036 if (!Pred)
1037 return nullptr;
1038
1039 // Update the autorelease counts.
1040 state = handleAutoreleaseCounts(state, Pred, C, Sym, X, S);
1041
1042 // Have we generated a sink node?
1043 if (!state)
1044 return nullptr;
1045
1046 // Get the updated binding.
1047 T = getRefBinding(state, Sym);
1048 assert(T);
1049 X = *T;
1050
1051 // Consult the summary of the enclosing method.
1053 const Decl *CD = &Pred->getCodeDecl();
1055
1056 // FIXME: What is the convention for blocks? Is there one?
1057 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) {
1058 const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD));
1059 RE = Summ->getRetEffect();
1060 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
1061 if (!isa<CXXMethodDecl>(FD)) {
1062 const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD));
1063 RE = Summ->getRetEffect();
1064 }
1065 }
1066
1067 return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state);
1068}
1069
1072 ExplodedNode *Pred,
1073 RetEffect RE, RefVal X,
1074 SymbolRef Sym,
1075 ProgramStateRef state) const {
1076 // HACK: Ignore retain-count issues on values accessed through ivars,
1077 // because of cases like this:
1078 // [_contentView retain];
1079 // [_contentView removeFromSuperview];
1080 // [self addSubview:_contentView]; // invalidates 'self'
1081 // [_contentView release];
1082 if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1083 return Pred;
1084
1085 // Any leaks or other errors?
1086 if (X.isReturnedOwned() && X.getCount() == 0) {
1087 if (RE.getKind() != RetEffect::NoRet) {
1088 if (!RE.isOwned()) {
1089
1090 // The returning type is a CF, we expect the enclosing method should
1091 // return ownership.
1093
1094 // Generate an error node.
1095 state = setRefBinding(state, Sym, X);
1096
1097 ExplodedNode *N = C.addTransition(state, Pred);
1098 if (N) {
1099 const LangOptions &LOpts = C.getASTContext().getLangOpts();
1100 auto R = std::make_unique<RefLeakReport>(
1101 getPreferredFrontend().LeakAtReturn, LOpts, N, Sym, C);
1102 C.emitReport(std::move(R));
1103 }
1104 return N;
1105 }
1106 }
1107 } else if (X.isReturnedNotOwned()) {
1108 if (RE.isOwned()) {
1109 if (X.getIvarAccessHistory() ==
1111 // Assume the method was trying to transfer a +1 reference from a
1112 // strong ivar to the caller.
1113 state = setRefBinding(state, Sym,
1114 X.releaseViaIvar() ^ RefVal::ReturnedOwned);
1115 } else {
1116 // Trying to return a not owned object to a caller expecting an
1117 // owned object.
1118 state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned);
1119
1120 ExplodedNode *N = C.addTransition(state, Pred);
1121 if (N) {
1122 auto R = std::make_unique<RefCountReport>(
1123 getPreferredFrontend().ReturnNotOwnedForOwned,
1124 C.getASTContext().getLangOpts(), N, Sym);
1125 C.emitReport(std::move(R));
1126 }
1127 return N;
1128 }
1129 }
1130 }
1131 return Pred;
1132}
1133
1134//===----------------------------------------------------------------------===//
1135// Check various ways a symbol can be invalidated.
1136//===----------------------------------------------------------------------===//
1137
1139 bool AtDeclInit, CheckerContext &C) const {
1140 ProgramStateRef state = C.getState();
1141 const MemRegion *MR = loc.getAsRegion();
1142
1143 // Find all symbols referenced by 'val' that we are tracking
1144 // and stop tracking them.
1145 if (MR && shouldEscapeRegion(state, MR)) {
1146 state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
1147 C.addTransition(state);
1148 }
1149}
1150
1152 SVal Cond,
1153 bool Assumption) const {
1154 // FIXME: We may add to the interface of evalAssume the list of symbols
1155 // whose assumptions have changed. For now we just iterate through the
1156 // bindings and check if any of the tracked symbols are NULL. This isn't
1157 // too bad since the number of symbols we will track in practice are
1158 // probably small and evalAssume is only called at branches and a few
1159 // other places.
1160 RefBindingsTy B = state->get<RefBindings>();
1161
1162 if (B.isEmpty())
1163 return state;
1164
1165 bool changed = false;
1166 RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>();
1167 ConstraintManager &CMgr = state->getConstraintManager();
1168
1169 for (auto &I : B) {
1170 // Check if the symbol is null stop tracking the symbol.
1171 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first);
1172 if (AllocFailed.isConstrainedTrue()) {
1173 changed = true;
1174 B = RefBFactory.remove(B, I.first);
1175 }
1176 }
1177
1178 if (changed)
1179 state = state->set<RefBindings>(B);
1180
1181 return state;
1182}
1183
1185 ProgramStateRef state, const InvalidatedSymbols *invalidated,
1186 ArrayRef<const MemRegion *> ExplicitRegions,
1187 ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
1188 const CallEvent *Call) const {
1189 if (!invalidated)
1190 return state;
1191
1192 llvm::SmallPtrSet<SymbolRef, 8> AllowedSymbols;
1193
1194 for (const MemRegion *I : ExplicitRegions)
1195 if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
1196 AllowedSymbols.insert(SR->getSymbol());
1197
1198 for (SymbolRef sym : *invalidated) {
1199 if (AllowedSymbols.count(sym))
1200 continue;
1201 // Remove any existing reference-count binding.
1202 state = removeRefBinding(state, sym);
1203 }
1204 return state;
1205}
1206
1208 ProgramStateRef state, ExplodedNode *Pred, CheckerContext &Ctx,
1209 SymbolRef Sym, RefVal V, const ReturnStmt *S) const {
1210 unsigned ACnt = V.getAutoreleaseCount();
1211
1212 // No autorelease counts? Nothing to be done.
1213 if (!ACnt)
1214 return state;
1215
1216 unsigned Cnt = V.getCount();
1217
1218 // FIXME: Handle sending 'autorelease' to already released object.
1219
1220 if (V.getKind() == RefVal::ReturnedOwned)
1221 ++Cnt;
1222
1223 // If we would over-release here, but we know the value came from an ivar,
1224 // assume it was a strong ivar that's just been relinquished.
1225 if (ACnt > Cnt &&
1226 V.getIvarAccessHistory() == RefVal::IvarAccessHistory::AccessedDirectly) {
1227 V = V.releaseViaIvar();
1228 --ACnt;
1229 }
1230
1231 if (ACnt <= Cnt) {
1232 if (ACnt == Cnt) {
1233 V.clearCounts();
1234 if (V.getKind() == RefVal::ReturnedOwned) {
1236 } else {
1237 V = V ^ RefVal::NotOwned;
1238 }
1239 } else {
1240 V.setCount(V.getCount() - ACnt);
1241 V.setAutoreleaseCount(0);
1242 }
1243 return setRefBinding(state, Sym, V);
1244 }
1245
1246 // HACK: Ignore retain-count issues on values accessed through ivars,
1247 // because of cases like this:
1248 // [_contentView retain];
1249 // [_contentView removeFromSuperview];
1250 // [self addSubview:_contentView]; // invalidates 'self'
1251 // [_contentView release];
1252 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1253 return state;
1254
1255 // Woah! More autorelease counts then retain counts left.
1256 // Emit hard error.
1258 state = setRefBinding(state, Sym, V);
1259
1260 ExplodedNode *N = Ctx.generateSink(state, Pred);
1261 if (N) {
1262 SmallString<128> sbuf;
1263 llvm::raw_svector_ostream os(sbuf);
1264 os << "Object was autoreleased ";
1265 if (V.getAutoreleaseCount() > 1)
1266 os << V.getAutoreleaseCount() << " times but the object ";
1267 else
1268 os << "but ";
1269 os << "has a +" << V.getCount() << " retain count";
1270
1271 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1272 auto R = std::make_unique<RefCountReport>(
1273 getPreferredFrontend().OverAutorelease, LOpts, N, Sym, os.str());
1274 Ctx.emitReport(std::move(R));
1275 }
1276
1277 return nullptr;
1278}
1279
1282 SymbolRef sid, RefVal V,
1283 SmallVectorImpl<SymbolRef> &Leaked) const {
1284 bool hasLeak;
1285
1286 // HACK: Ignore retain-count issues on values accessed through ivars,
1287 // because of cases like this:
1288 // [_contentView retain];
1289 // [_contentView removeFromSuperview];
1290 // [self addSubview:_contentView]; // invalidates 'self'
1291 // [_contentView release];
1292 if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None)
1293 hasLeak = false;
1294 else if (V.isOwned())
1295 hasLeak = true;
1296 else if (V.isNotOwned() || V.isReturnedOwned())
1297 hasLeak = (V.getCount() > 0);
1298 else
1299 hasLeak = false;
1300
1301 if (!hasLeak)
1302 return removeRefBinding(state, sid);
1303
1304 Leaked.push_back(sid);
1305 return setRefBinding(state, sid, V ^ RefVal::ErrorLeak);
1306}
1307
1311 CheckerContext &Ctx,
1312 ExplodedNode *Pred) const {
1313 // Generate an intermediate node representing the leak point.
1314 ExplodedNode *N = Ctx.addTransition(state, Pred);
1315 const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
1316
1317 if (N) {
1319 const RefCountBug &BT = Pred ? FE.LeakWithinFunction : FE.LeakAtReturn;
1320
1321 for (SymbolRef L : Leaked) {
1322 Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
1323 }
1324 }
1325
1326 return N;
1327}
1328
1330 if (!Ctx.inTopFrame())
1331 return;
1332
1334 const LocationContext *LCtx = Ctx.getLocationContext();
1335 const Decl *D = LCtx->getDecl();
1336 std::optional<AnyCall> C = AnyCall::forDecl(D);
1337
1339 return;
1340
1341 ProgramStateRef state = Ctx.getState();
1342 const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C);
1343 ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects();
1344
1345 for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
1346 const ParmVarDecl *Param = C->parameters()[idx];
1347 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1348
1349 QualType Ty = Param->getType();
1350 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
1351 if (AE) {
1352 ObjKind K = AE->getObjKind();
1353 if (K == ObjKind::Generalized || K == ObjKind::OS ||
1354 (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) {
1355 RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty)
1356 : RefVal::makeNotOwned(K, Ty);
1357 state = setRefBinding(state, Sym, NewVal);
1358 }
1359 }
1360 }
1361
1362 Ctx.addTransition(state);
1363}
1364
1366 CheckerContext &Ctx) const {
1367 ExplodedNode *Pred = processReturn(RS, Ctx);
1368
1369 // Created state cached out.
1370 if (!Pred) {
1371 return;
1372 }
1373
1374 ProgramStateRef state = Pred->getState();
1375 RefBindingsTy B = state->get<RefBindings>();
1376
1377 // Don't process anything within synthesized bodies.
1378 const LocationContext *LCtx = Pred->getLocationContext();
1379 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1380 assert(!LCtx->inTopFrame());
1381 return;
1382 }
1383
1384 for (auto &I : B) {
1385 state = handleAutoreleaseCounts(state, Pred, Ctx, I.first, I.second);
1386 if (!state)
1387 return;
1388 }
1389
1390 // If the current LocationContext has a parent, don't check for leaks.
1391 // We will do that later.
1392 // FIXME: we should instead check for imbalances of the retain/releases,
1393 // and suggest annotations.
1394 if (LCtx->getParent())
1395 return;
1396
1397 B = state->get<RefBindings>();
1399
1400 for (auto &I : B)
1401 state = handleSymbolDeath(state, I.first, I.second, Leaked);
1402
1403 processLeaks(state, Leaked, Ctx, Pred);
1404}
1405
1407 CheckerContext &C) const {
1408 ExplodedNode *Pred = C.getPredecessor();
1409
1410 ProgramStateRef state = C.getState();
1412
1413 // Update counts from autorelease pools
1414 for (const auto &I: state->get<RefBindings>()) {
1415 SymbolRef Sym = I.first;
1416 if (SymReaper.isDead(Sym)) {
1417 const RefVal &V = I.second;
1418 state = handleAutoreleaseCounts(state, Pred, C, Sym, V);
1419 if (!state)
1420 return;
1421
1422 // Fetch the new reference count from the state, and use it to handle
1423 // this symbol.
1424 state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked);
1425 }
1426 }
1427
1428 if (Leaked.empty()) {
1429 C.addTransition(state);
1430 return;
1431 }
1432
1433 Pred = processLeaks(state, Leaked, C, Pred);
1434
1435 // Did we cache out?
1436 if (!Pred)
1437 return;
1438
1439 // Now generate a new node that nukes the old bindings.
1440 // The only bindings left at this point are the leaked symbols.
1441 RefBindingsTy::Factory &F = state->get_context<RefBindings>();
1442 RefBindingsTy B = state->get<RefBindings>();
1443
1444 for (SymbolRef L : Leaked)
1445 B = F.remove(B, L);
1446
1447 state = state->set<RefBindings>(B);
1448 C.addTransition(state, Pred);
1449}
1450
1452 const char *NL, const char *Sep) const {
1453
1454 RefBindingsTy B = State->get<RefBindings>();
1455
1456 if (B.isEmpty())
1457 return;
1458
1459 Out << Sep << NL;
1460
1461 for (auto &I : B) {
1462 Out << I.first << " : ";
1463 I.second.print(Out);
1464 Out << NL;
1465 }
1466}
1467
1468//===----------------------------------------------------------------------===//
1469// Checker registration.
1470//===----------------------------------------------------------------------===//
1471
1472std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::DeallocSentTag;
1473std::unique_ptr<SimpleProgramPointTag> RetainCountChecker::CastFailTag;
1474
1475void ento::registerRetainCountBase(CheckerManager &Mgr) {
1476 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1477 Chk->DeallocSentTag = std::make_unique<SimpleProgramPointTag>(
1478 "RetainCountChecker", "DeallocSent");
1479 Chk->CastFailTag = std::make_unique<SimpleProgramPointTag>(
1480 "RetainCountChecker", "DynamicCastFail");
1481}
1482
1483bool ento::shouldRegisterRetainCountBase(const CheckerManager &) {
1484 return true;
1485}
1486
1487void ento::registerRetainCountChecker(CheckerManager &Mgr) {
1488 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1489 Chk->RetainCount.enable(Mgr);
1490 Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
1491 Mgr.getCurrentCheckerName(), "TrackNSCFStartParam");
1492}
1493
1494bool ento::shouldRegisterRetainCountChecker(const CheckerManager &) {
1495 return true;
1496}
1497
1498void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1499 auto *Chk = Mgr.getChecker<RetainCountChecker>();
1500 Chk->OSObjectRetainCount.enable(Mgr);
1501
1502 // FIXME: We want bug reports to always have the same checker name associated
1503 // with them, yet here, if RetainCountChecker is disabled but
1504 // OSObjectRetainCountChecker is enabled, the checker names will be different.
1505 // This hack will make it so that the checker name depends on which checker is
1506 // enabled rather than on the registration order.
1507 // For the most part, we want **non-hidden checkers** to be associated with
1508 // diagnostics, and **hidden checker options** with the fine-tuning of
1509 // modeling. Following this logic, OSObjectRetainCountChecker should be the
1510 // latter, but we can't just remove it for backward compatibility reasons.
1511}
1512
1513bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &) {
1514 return true;
1515}
#define V(N, I)
Definition: ASTContext.h:3597
StringRef P
static CanQualType GetReturnType(QualType RetTy)
Returns the "extra-canonicalized" return type, which discards qualifiers on the return type.
Definition: CGCall.cpp:151
const Decl * D
#define X(type, name)
Definition: Value.h:145
#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:188
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:894
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
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:4753
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
Definition: Expr.h:6560
const BlockDecl * getBlockDecl() const
Definition: Expr.h:6572
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3612
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
bool hasAttr() const
Definition: DeclBase.h:577
This represents one expression.
Definition: Expr.h:112
QualType getType() const
Definition: Expr.h:144
Represents a function declaration or definition.
Definition: Decl.h:1999
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:434
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
Definition: ExprObjC.h:192
ObjCBoxedExpr - used for generalized expression boxing.
Definition: ExprObjC.h:128
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers,...
Definition: ExprObjC.h:1643
ObjCBridgeCastKind getBridgeKind() const
Determine which kind of bridge is being performed via this cast.
Definition: ExprObjC.h:1669
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Definition: ExprObjC.h:308
Represents an ObjC class declaration.
Definition: DeclObjC.h:1154
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:548
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:940
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:140
Represents a pointer to an Objective C object.
Definition: TypeBase.h:7961
Represents a parameter to a function.
Definition: Decl.h:1789
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:3160
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition: Stmt.h:85
child_range children()
Definition: Stmt.cpp:295
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:9038
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:1909
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:752
bool isObjCObjectPointerType() const
Definition: TypeBase.h:8749
const T * getAs() const
Member-template getAs<specific type>'.
Definition: TypeBase.h:9159
bool isObjCRetainableType() const
Definition: Type.cpp:5336
QualType getType() const
Definition: Decl.h:722
Represents a variable declaration or definition.
Definition: Decl.h:925
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.
Definition: CallEvent.cpp:314
virtual const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
Definition: CallEvent.h:250
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.
Definition: CallEvent.cpp:307
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
Definition: CallEvent.cpp:321
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call's formal parameters.
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 Stmt *S) 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...
Definition: MemRegion.cpp:1041
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:98
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
Definition: MemRegion.cpp:1457
bool hasMemorySpace(ProgramStateRef State) const
Definition: MemRegion.h:148
const RegionTy * getAs() const
Definition: MemRegion.h:1416
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.
static RetEffect MakeNoRet()
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
Symbolic value.
Definition: SymExpr.h:32
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
const RefCountFrontend & getPreferredFrontend() 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.
#define bool
Definition: gpuintrin.h:32
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
llvm::ImmutableMap< unsigned, ArgEffect > ArgEffects
ArgEffects summarizes the effects of a function/method call on all of its arguments.
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.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
@ 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.
The JSON file list parser is used to communicate input to InstallAPI.
@ 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.
const FunctionProtoType * T