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