1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "RetainCountChecker.h" |
15 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
16 | |
17 | using namespace clang; |
18 | using namespace ento; |
19 | using namespace retaincountchecker; |
20 | using llvm::StrInStrNoCase; |
21 | |
22 | REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) |
23 | |
24 | namespace clang { |
25 | namespace ento { |
26 | namespace retaincountchecker { |
27 | |
28 | const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) { |
29 | return State->get<RefBindings>(Sym); |
30 | } |
31 | |
32 | } |
33 | } |
34 | } |
35 | |
36 | static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym, |
37 | RefVal Val) { |
38 | assert(Sym != nullptr); |
39 | return State->set<RefBindings>(Sym, Val); |
40 | } |
41 | |
42 | static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym) { |
43 | return State->remove<RefBindings>(Sym); |
44 | } |
45 | |
46 | void RefVal::print(raw_ostream &Out) const { |
47 | if (!T.isNull()) |
48 | Out << "Tracked " << T.getAsString() << " | "; |
49 | |
50 | switch (getKind()) { |
51 | default: llvm_unreachable("Invalid RefVal kind"); |
52 | case Owned: { |
53 | Out << "Owned"; |
54 | unsigned cnt = getCount(); |
55 | if (cnt) Out << " (+ " << cnt << ")"; |
56 | break; |
57 | } |
58 | |
59 | case NotOwned: { |
60 | Out << "NotOwned"; |
61 | unsigned cnt = getCount(); |
62 | if (cnt) Out << " (+ " << cnt << ")"; |
63 | break; |
64 | } |
65 | |
66 | case ReturnedOwned: { |
67 | Out << "ReturnedOwned"; |
68 | unsigned cnt = getCount(); |
69 | if (cnt) Out << " (+ " << cnt << ")"; |
70 | break; |
71 | } |
72 | |
73 | case ReturnedNotOwned: { |
74 | Out << "ReturnedNotOwned"; |
75 | unsigned cnt = getCount(); |
76 | if (cnt) Out << " (+ " << cnt << ")"; |
77 | break; |
78 | } |
79 | |
80 | case Released: |
81 | Out << "Released"; |
82 | break; |
83 | |
84 | case ErrorDeallocNotOwned: |
85 | Out << "-dealloc (not-owned)"; |
86 | break; |
87 | |
88 | case ErrorLeak: |
89 | Out << "Leaked"; |
90 | break; |
91 | |
92 | case ErrorLeakReturned: |
93 | Out << "Leaked (Bad naming)"; |
94 | break; |
95 | |
96 | case ErrorUseAfterRelease: |
97 | Out << "Use-After-Release [ERROR]"; |
98 | break; |
99 | |
100 | case ErrorReleaseNotOwned: |
101 | Out << "Release of Not-Owned [ERROR]"; |
102 | break; |
103 | |
104 | case RefVal::ErrorOverAutorelease: |
105 | Out << "Over-autoreleased"; |
106 | break; |
107 | |
108 | case RefVal::ErrorReturnedNotOwned: |
109 | Out << "Non-owned object returned instead of owned"; |
110 | break; |
111 | } |
112 | |
113 | switch (getIvarAccessHistory()) { |
114 | case IvarAccessHistory::None: |
115 | break; |
116 | case IvarAccessHistory::AccessedDirectly: |
117 | Out << " [direct ivar access]"; |
118 | break; |
119 | case IvarAccessHistory::ReleasedAfterDirectAccess: |
120 | Out << " [released after direct ivar access]"; |
121 | } |
122 | |
123 | if (ACnt) { |
124 | Out << " [autorelease -" << ACnt << ']'; |
125 | } |
126 | } |
127 | |
128 | namespace { |
129 | class StopTrackingCallback final : public SymbolVisitor { |
130 | ProgramStateRef state; |
131 | public: |
132 | StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {} |
133 | ProgramStateRef getState() const { return state; } |
134 | |
135 | bool VisitSymbol(SymbolRef sym) override { |
136 | state = removeRefBinding(state, sym); |
137 | return true; |
138 | } |
139 | }; |
140 | } |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | void RetainCountChecker::checkPostStmt(const BlockExpr *BE, |
147 | CheckerContext &C) const { |
148 | |
149 | |
150 | |
151 | if (!BE->getBlockDecl()->hasCaptures()) |
152 | return; |
153 | |
154 | ProgramStateRef state = C.getState(); |
155 | auto *R = cast<BlockDataRegion>(C.getSVal(BE).getAsRegion()); |
156 | |
157 | BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), |
158 | E = R->referenced_vars_end(); |
159 | |
160 | if (I == E) |
161 | return; |
162 | |
163 | |
164 | |
165 | |
166 | SmallVector<const MemRegion*, 10> Regions; |
167 | const LocationContext *LC = C.getLocationContext(); |
168 | MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); |
169 | |
170 | for ( ; I != E; ++I) { |
171 | const VarRegion *VR = I.getCapturedRegion(); |
172 | if (VR->getSuperRegion() == R) { |
173 | VR = MemMgr.getVarRegion(VR->getDecl(), LC); |
174 | } |
175 | Regions.push_back(VR); |
176 | } |
177 | |
178 | state = state->scanReachableSymbols<StopTrackingCallback>(Regions).getState(); |
179 | C.addTransition(state); |
180 | } |
181 | |
182 | void RetainCountChecker::checkPostStmt(const CastExpr *CE, |
183 | CheckerContext &C) const { |
184 | const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); |
185 | if (!BE) |
186 | return; |
187 | |
188 | QualType QT = CE->getType(); |
189 | ObjKind K; |
190 | if (QT->isObjCObjectPointerType()) { |
191 | K = ObjKind::ObjC; |
192 | } else { |
193 | K = ObjKind::CF; |
194 | } |
195 | |
196 | ArgEffect AE = ArgEffect(IncRef, K); |
197 | |
198 | switch (BE->getBridgeKind()) { |
199 | case OBC_Bridge: |
200 | |
201 | return; |
202 | case OBC_BridgeRetained: |
203 | AE = AE.withKind(IncRef); |
204 | break; |
205 | case OBC_BridgeTransfer: |
206 | AE = AE.withKind(DecRefBridgedTransferred); |
207 | break; |
208 | } |
209 | |
210 | ProgramStateRef state = C.getState(); |
211 | SymbolRef Sym = C.getSVal(CE).getAsLocSymbol(); |
212 | if (!Sym) |
213 | return; |
214 | const RefVal* T = getRefBinding(state, Sym); |
215 | if (!T) |
216 | return; |
217 | |
218 | RefVal::Kind hasErr = (RefVal::Kind) 0; |
219 | state = updateSymbol(state, Sym, *T, AE, hasErr, C); |
220 | |
221 | if (hasErr) { |
222 | |
223 | return; |
224 | } |
225 | |
226 | C.addTransition(state); |
227 | } |
228 | |
229 | void RetainCountChecker::processObjCLiterals(CheckerContext &C, |
230 | const Expr *Ex) const { |
231 | ProgramStateRef state = C.getState(); |
232 | const ExplodedNode *pred = C.getPredecessor(); |
233 | for (const Stmt *Child : Ex->children()) { |
234 | SVal V = pred->getSVal(Child); |
235 | if (SymbolRef sym = V.getAsSymbol()) |
236 | if (const RefVal* T = getRefBinding(state, sym)) { |
237 | RefVal::Kind hasErr = (RefVal::Kind) 0; |
238 | state = updateSymbol(state, sym, *T, |
239 | ArgEffect(MayEscape, ObjKind::ObjC), hasErr, C); |
240 | if (hasErr) { |
241 | processNonLeakError(state, Child->getSourceRange(), hasErr, sym, C); |
242 | return; |
243 | } |
244 | } |
245 | } |
246 | |
247 | |
248 | |
249 | if (SymbolRef sym = |
250 | state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) { |
251 | QualType ResultTy = Ex->getType(); |
252 | state = setRefBinding(state, sym, |
253 | RefVal::makeNotOwned(ObjKind::ObjC, ResultTy)); |
254 | } |
255 | |
256 | C.addTransition(state); |
257 | } |
258 | |
259 | void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL, |
260 | CheckerContext &C) const { |
261 | |
262 | processObjCLiterals(C, AL); |
263 | } |
264 | |
265 | void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, |
266 | CheckerContext &C) const { |
267 | |
268 | processObjCLiterals(C, DL); |
269 | } |
270 | |
271 | void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, |
272 | CheckerContext &C) const { |
273 | const ExplodedNode *Pred = C.getPredecessor(); |
274 | ProgramStateRef State = Pred->getState(); |
275 | |
276 | if (SymbolRef Sym = Pred->getSVal(Ex).getAsSymbol()) { |
277 | QualType ResultTy = Ex->getType(); |
278 | State = setRefBinding(State, Sym, |
279 | RefVal::makeNotOwned(ObjKind::ObjC, ResultTy)); |
280 | } |
281 | |
282 | C.addTransition(State); |
283 | } |
284 | |
285 | void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, |
286 | CheckerContext &C) const { |
287 | Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>(); |
288 | if (!IVarLoc) |
289 | return; |
290 | |
291 | ProgramStateRef State = C.getState(); |
292 | SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol(); |
293 | if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion())) |
294 | return; |
295 | |
296 | |
297 | |
298 | |
299 | QualType Ty = Sym->getType(); |
300 | ObjKind Kind; |
301 | if (Ty->isObjCRetainableType()) |
302 | Kind = ObjKind::ObjC; |
303 | else if (coreFoundation::isCFObjectRef(Ty)) |
304 | Kind = ObjKind::CF; |
305 | else |
306 | return; |
307 | |
308 | |
309 | ConstraintManager &CMgr = State->getConstraintManager(); |
310 | if (CMgr.isNull(State, Sym).isConstrainedTrue()) |
311 | return; |
312 | |
313 | if (const RefVal *RV = getRefBinding(State, Sym)) { |
314 | |
315 | |
316 | if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None || |
317 | isSynthesizedAccessor(C.getStackFrame())) { |
318 | return; |
319 | } |
320 | |
321 | |
322 | C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess())); |
323 | return; |
324 | } |
325 | |
326 | RefVal PlusZero = RefVal::makeNotOwned(Kind, Ty); |
327 | |
328 | |
329 | if (isSynthesizedAccessor(C.getStackFrame())) { |
330 | C.addTransition(setRefBinding(State, Sym, PlusZero)); |
331 | return; |
332 | } |
333 | |
334 | State = setRefBinding(State, Sym, PlusZero.withIvarAccess()); |
335 | C.addTransition(State); |
336 | } |
337 | |
338 | static bool isReceiverUnconsumedSelf(const CallEvent &Call) { |
339 | if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) { |
340 | |
341 | |
342 | |
343 | return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() && |
344 | !Call.getLocationContext() |
345 | ->getAnalysisDeclContext() |
346 | ->getParentMap() |
347 | .isConsumedExpr(Call.getOriginExpr()); |
348 | } |
349 | return false; |
350 | } |
351 | |
352 | const static RetainSummary *getSummary(RetainSummaryManager &Summaries, |
353 | const CallEvent &Call, |
354 | QualType ReceiverType) { |
355 | const Expr *CE = Call.getOriginExpr(); |
356 | AnyCall C = |
357 | CE ? *AnyCall::forExpr(CE) |
358 | : AnyCall(cast<CXXDestructorDecl>(Call.getDecl())); |
359 | return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(), |
360 | isReceiverUnconsumedSelf(Call), ReceiverType); |
361 | } |
362 | |
363 | void RetainCountChecker::checkPostCall(const CallEvent &Call, |
364 | CheckerContext &C) const { |
365 | RetainSummaryManager &Summaries = getSummaryManager(C); |
366 | |
367 | |
368 | QualType ReceiverType; |
369 | if (const auto *MC = dyn_cast<ObjCMethodCall>(&Call)) { |
370 | if (MC->isInstanceMessage()) { |
371 | SVal ReceiverV = MC->getReceiverSVal(); |
372 | if (SymbolRef Sym = ReceiverV.getAsLocSymbol()) |
373 | if (const RefVal *T = getRefBinding(C.getState(), Sym)) |
374 | ReceiverType = T->getType(); |
375 | } |
376 | } |
377 | |
378 | const RetainSummary *Summ = getSummary(Summaries, Call, ReceiverType); |
379 | |
380 | if (C.wasInlined) { |
381 | processSummaryOfInlined(*Summ, Call, C); |
382 | return; |
383 | } |
384 | checkSummary(*Summ, Call, C); |
385 | } |
386 | |
387 | |
388 | |
389 | |
390 | |
391 | |
392 | |
393 | |
394 | static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { |
395 | QualType RetTy = RetE->getType(); |
396 | |
397 | |
398 | |
399 | if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE)) |
400 | if (const ObjCObjectPointerType *PT = RetTy->getAs<ObjCObjectPointerType>()) |
401 | if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || |
402 | PT->isObjCClassType()) { |
403 | |
404 | |
405 | |
406 | |
407 | const ObjCInterfaceDecl *D = ME->getReceiverInterface(); |
408 | return !D ? RetTy : |
409 | Ctx.getObjCObjectPointerType(Ctx.getObjCInterfaceType(D)); |
410 | } |
411 | |
412 | return RetTy; |
413 | } |
414 | |
415 | static Optional<RefVal> refValFromRetEffect(RetEffect RE, |
416 | QualType ResultTy) { |
417 | if (RE.isOwned()) { |
418 | return RefVal::makeOwned(RE.getObjKind(), ResultTy); |
419 | } else if (RE.notOwned()) { |
420 | return RefVal::makeNotOwned(RE.getObjKind(), ResultTy); |
421 | } |
422 | |
423 | return None; |
424 | } |
425 | |
426 | static bool isPointerToObject(QualType QT) { |
427 | QualType PT = QT->getPointeeType(); |
428 | if (!PT.isNull()) |
429 | if (PT->getAsCXXRecordDecl()) |
430 | return true; |
431 | return false; |
432 | } |
433 | |
434 | |
435 | |
436 | static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx, |
437 | const RefVal *TrackedValue) { |
438 | if (TrackedValue->getObjKind() != ObjKind::OS) |
439 | return false; |
440 | if (ArgIdx >= CE.parameters().size()) |
441 | return false; |
442 | return !isPointerToObject(CE.parameters()[ArgIdx]->getType()); |
443 | } |
444 | |
445 | |
446 | |
447 | |
448 | void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, |
449 | const CallEvent &CallOrMsg, |
450 | CheckerContext &C) const { |
451 | ProgramStateRef state = C.getState(); |
452 | |
453 | |
454 | for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { |
455 | SVal V = CallOrMsg.getArgSVal(idx); |
456 | |
457 | if (SymbolRef Sym = V.getAsLocSymbol()) { |
458 | bool ShouldRemoveBinding = Summ.getArg(idx).getKind() == StopTrackingHard; |
459 | if (const RefVal *T = getRefBinding(state, Sym)) |
460 | if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T)) |
461 | ShouldRemoveBinding = true; |
462 | |
463 | if (ShouldRemoveBinding) |
464 | state = removeRefBinding(state, Sym); |
465 | } |
466 | } |
467 | |
468 | |
469 | if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) { |
470 | if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { |
471 | if (Summ.getReceiverEffect().getKind() == StopTrackingHard) { |
472 | state = removeRefBinding(state, Sym); |
473 | } |
474 | } |
475 | } |
476 | |
477 | |
478 | RetEffect RE = Summ.getRetEffect(); |
479 | |
480 | if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) { |
481 | if (RE.getKind() == RetEffect::NoRetHard) |
482 | state = removeRefBinding(state, Sym); |
483 | } |
484 | |
485 | C.addTransition(state); |
486 | } |
487 | |
488 | static bool isSmartPtrField(const MemRegion *MR) { |
489 | const auto *TR = dyn_cast<TypedValueRegion>( |
490 | cast<SubRegion>(MR)->getSuperRegion()); |
491 | return TR && RetainSummaryManager::isKnownSmartPointer(TR->getValueType()); |
492 | } |
493 | |
494 | |
495 | |
496 | |
497 | |
498 | |
499 | |
500 | |
501 | |
502 | |
503 | |
504 | |
505 | static bool shouldEscapeRegion(const MemRegion *R) { |
506 | if (isSmartPtrField(R)) |
507 | return false; |
508 | |
509 | const auto *VR = dyn_cast<VarRegion>(R); |
510 | |
511 | if (!R->hasStackStorage() || !VR) |
512 | return true; |
513 | |
514 | const VarDecl *VD = VR->getDecl(); |
515 | if (!VD->hasAttr<CleanupAttr>()) |
516 | return false; |
517 | return true; |
518 | } |
519 | |
520 | static SmallVector<ProgramStateRef, 2> |
521 | updateOutParameters(ProgramStateRef State, const RetainSummary &Summ, |
522 | const CallEvent &CE) { |
523 | |
524 | SVal L = CE.getReturnValue(); |
525 | |
526 | |
527 | |
528 | |
529 | |
530 | bool SplitNecessary = false; |
531 | for (auto &P : Summ.getArgEffects()) |
532 | if (P.second.getKind() == RetainedOutParameterOnNonZero || |
533 | P.second.getKind() == RetainedOutParameterOnZero) |
534 | SplitNecessary = true; |
535 | |
536 | ProgramStateRef AssumeNonZeroReturn = State; |
537 | ProgramStateRef AssumeZeroReturn = State; |
538 | |
539 | if (SplitNecessary) { |
540 | if (auto DL = L.getAs<DefinedOrUnknownSVal>()) { |
541 | AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true); |
542 | AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false); |
543 | } |
544 | } |
545 | |
546 | for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) { |
547 | SVal ArgVal = CE.getArgSVal(idx); |
548 | ArgEffect AE = Summ.getArg(idx); |
549 | |
550 | auto *ArgRegion = dyn_cast_or_null<TypedValueRegion>(ArgVal.getAsRegion()); |
551 | if (!ArgRegion) |
552 | continue; |
553 | |
554 | QualType PointeeTy = ArgRegion->getValueType(); |
555 | SVal PointeeVal = State->getSVal(ArgRegion); |
556 | SymbolRef Pointee = PointeeVal.getAsLocSymbol(); |
557 | if (!Pointee) |
558 | continue; |
559 | |
560 | if (shouldEscapeRegion(ArgRegion)) |
561 | continue; |
562 | |
563 | auto makeNotOwnedParameter = [&](ProgramStateRef St) { |
564 | return setRefBinding(St, Pointee, |
565 | RefVal::makeNotOwned(AE.getObjKind(), PointeeTy)); |
566 | }; |
567 | auto makeOwnedParameter = [&](ProgramStateRef St) { |
568 | return setRefBinding(St, Pointee, |
569 | RefVal::makeOwned(ObjKind::OS, PointeeTy)); |
570 | }; |
571 | |
572 | switch (AE.getKind()) { |
573 | case UnretainedOutParameter: |
574 | AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn); |
575 | AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn); |
576 | break; |
577 | case RetainedOutParameter: |
578 | AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn); |
579 | AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn); |
580 | break; |
581 | case RetainedOutParameterOnNonZero: |
582 | AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn); |
583 | break; |
584 | case RetainedOutParameterOnZero: |
585 | AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn); |
586 | break; |
587 | default: |
588 | break; |
589 | } |
590 | } |
591 | |
592 | if (SplitNecessary) { |
593 | return {AssumeNonZeroReturn, AssumeZeroReturn}; |
594 | } else { |
595 | assert(AssumeZeroReturn == AssumeNonZeroReturn); |
596 | return {AssumeZeroReturn}; |
597 | } |
598 | } |
599 | |
600 | void RetainCountChecker::checkSummary(const RetainSummary &Summ, |
601 | const CallEvent &CallOrMsg, |
602 | CheckerContext &C) const { |
603 | ProgramStateRef state = C.getState(); |
604 | |
605 | |
606 | RefVal::Kind hasErr = (RefVal::Kind) 0; |
607 | SourceRange ErrorRange; |
608 | SymbolRef ErrorSym = nullptr; |
609 | |
610 | |
611 | |
612 | bool DeallocSent = false; |
613 | |
614 | for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { |
615 | SVal V = CallOrMsg.getArgSVal(idx); |
616 | |
617 | ArgEffect Effect = Summ.getArg(idx); |
618 | if (SymbolRef Sym = V.getAsLocSymbol()) { |
619 | if (const RefVal *T = getRefBinding(state, Sym)) { |
620 | |
621 | if (shouldEscapeOSArgumentOnCall(CallOrMsg, idx, T)) |
622 | Effect = ArgEffect(StopTrackingHard, ObjKind::OS); |
623 | |
624 | state = updateSymbol(state, Sym, *T, Effect, hasErr, C); |
625 | if (hasErr) { |
626 | ErrorRange = CallOrMsg.getArgSourceRange(idx); |
627 | ErrorSym = Sym; |
628 | break; |
629 | } else if (Effect.getKind() == Dealloc) { |
630 | DeallocSent = true; |
631 | } |
632 | } |
633 | } |
634 | } |
635 | |
636 | |
637 | bool ReceiverIsTracked = false; |
638 | if (!hasErr) { |
639 | if (const auto *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg)) { |
640 | if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { |
641 | if (const RefVal *T = getRefBinding(state, Sym)) { |
642 | ReceiverIsTracked = true; |
643 | state = updateSymbol(state, Sym, *T, |
644 | Summ.getReceiverEffect(), hasErr, C); |
645 | if (hasErr) { |
646 | ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange(); |
647 | ErrorSym = Sym; |
648 | } else if (Summ.getReceiverEffect().getKind() == Dealloc) { |
649 | DeallocSent = true; |
650 | } |
651 | } |
652 | } |
653 | } else if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) { |
654 | if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) { |
655 | if (const RefVal *T = getRefBinding(state, Sym)) { |
656 | state = updateSymbol(state, Sym, *T, Summ.getThisEffect(), |
657 | hasErr, C); |
658 | if (hasErr) { |
659 | ErrorRange = MCall->getOriginExpr()->getSourceRange(); |
660 | ErrorSym = Sym; |
661 | } |
662 | } |
663 | } |
664 | } |
665 | } |
666 | |
667 | |
668 | if (hasErr) { |
669 | processNonLeakError(state, ErrorRange, hasErr, ErrorSym, C); |
670 | return; |
671 | } |
672 | |
673 | |
674 | RetEffect RE = Summ.getRetEffect(); |
675 | |
676 | if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { |
677 | if (ReceiverIsTracked) |
678 | RE = getSummaryManager(C).getObjAllocRetEffect(); |
679 | else |
680 | RE = RetEffect::MakeNoRet(); |
681 | } |
682 | |
683 | if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) { |
684 | QualType ResultTy = CallOrMsg.getResultType(); |
685 | if (RE.notOwned()) { |
686 | const Expr *Ex = CallOrMsg.getOriginExpr(); |
687 | assert(Ex); |
688 | ResultTy = GetReturnType(Ex, C.getASTContext()); |
689 | } |
690 | if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy)) |
691 | state = setRefBinding(state, Sym, *updatedRefVal); |
692 | } |
693 | |
694 | SmallVector<ProgramStateRef, 2> Out = |
695 | updateOutParameters(state, Summ, CallOrMsg); |
696 | |
697 | for (ProgramStateRef St : Out) { |
698 | if (DeallocSent) { |
699 | C.addTransition(St, C.getPredecessor(), &DeallocSentTag); |
700 | } else { |
701 | C.addTransition(St); |
702 | } |
703 | } |
704 | } |
705 | |
706 | ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state, |
707 | SymbolRef sym, RefVal V, |
708 | ArgEffect AE, |
709 | RefVal::Kind &hasErr, |
710 | CheckerContext &C) const { |
711 | bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount; |
712 | if (AE.getObjKind() == ObjKind::ObjC && IgnoreRetainMsg) { |
713 | switch (AE.getKind()) { |
714 | default: |
715 | break; |
716 | case IncRef: |
717 | AE = AE.withKind(DoNothing); |
718 | break; |
719 | case DecRef: |
720 | AE = AE.withKind(DoNothing); |
721 | break; |
722 | case DecRefAndStopTrackingHard: |
723 | AE = AE.withKind(StopTracking); |
724 | break; |
725 | } |
726 | } |
727 | |
728 | |
729 | if (V.getKind() == RefVal::Released) { |
730 | V = V ^ RefVal::ErrorUseAfterRelease; |
731 | hasErr = V.getKind(); |
732 | return setRefBinding(state, sym, V); |
733 | } |
734 | |
735 | switch (AE.getKind()) { |
736 | case UnretainedOutParameter: |
737 | case RetainedOutParameter: |
738 | case RetainedOutParameterOnZero: |
739 | case RetainedOutParameterOnNonZero: |
740 | llvm_unreachable("Applies to pointer-to-pointer parameters, which should " |
741 | "not have ref state."); |
742 | |
743 | case Dealloc: |
744 | switch (V.getKind()) { |
745 | default: |
746 | llvm_unreachable("Invalid RefVal state for an explicit dealloc."); |
747 | case RefVal::Owned: |
748 | |
749 | V = V ^ RefVal::Released; |
750 | V.clearCounts(); |
751 | return setRefBinding(state, sym, V); |
752 | case RefVal::NotOwned: |
753 | V = V ^ RefVal::ErrorDeallocNotOwned; |
754 | hasErr = V.getKind(); |
755 | break; |
756 | } |
757 | break; |
758 | |
759 | case MayEscape: |
760 | if (V.getKind() == RefVal::Owned) { |
761 | V = V ^ RefVal::NotOwned; |
762 | break; |
763 | } |
764 | |
765 | LLVM_FALLTHROUGH; |
766 | |
767 | case DoNothing: |
768 | return state; |
769 | |
770 | case Autorelease: |
771 | |
772 | V = V.autorelease(); |
773 | break; |
774 | |
775 | case StopTracking: |
776 | case StopTrackingHard: |
777 | return removeRefBinding(state, sym); |
778 | |
779 | case IncRef: |
780 | switch (V.getKind()) { |
781 | default: |
782 | llvm_unreachable("Invalid RefVal state for a retain."); |
783 | case RefVal::Owned: |
784 | case RefVal::NotOwned: |
785 | V = V + 1; |
786 | break; |
787 | } |
788 | break; |
789 | |
790 | case DecRef: |
791 | case DecRefBridgedTransferred: |
792 | case DecRefAndStopTrackingHard: |
793 | switch (V.getKind()) { |
794 | default: |
795 | |
796 | llvm_unreachable("Invalid RefVal state for a release."); |
797 | |
798 | case RefVal::Owned: |
799 | 0", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp", 799, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(V.getCount() > 0); |
800 | if (V.getCount() == 1) { |
801 | if (AE.getKind() == DecRefBridgedTransferred || |
802 | V.getIvarAccessHistory() == |
803 | RefVal::IvarAccessHistory::AccessedDirectly) |
804 | V = V ^ RefVal::NotOwned; |
805 | else |
806 | V = V ^ RefVal::Released; |
807 | } else if (AE.getKind() == DecRefAndStopTrackingHard) { |
808 | return removeRefBinding(state, sym); |
809 | } |
810 | |
811 | V = V - 1; |
812 | break; |
813 | |
814 | case RefVal::NotOwned: |
815 | if (V.getCount() > 0) { |
816 | if (AE.getKind() == DecRefAndStopTrackingHard) |
817 | return removeRefBinding(state, sym); |
818 | V = V - 1; |
819 | } else if (V.getIvarAccessHistory() == |
820 | RefVal::IvarAccessHistory::AccessedDirectly) { |
821 | |
822 | |
823 | if (AE.getKind() == DecRefAndStopTrackingHard) |
824 | return removeRefBinding(state, sym); |
825 | V = V.releaseViaIvar() ^ RefVal::Released; |
826 | } else { |
827 | V = V ^ RefVal::ErrorReleaseNotOwned; |
828 | hasErr = V.getKind(); |
829 | } |
830 | break; |
831 | } |
832 | break; |
833 | } |
834 | return setRefBinding(state, sym, V); |
835 | } |
836 | |
837 | const RefCountBug & |
838 | RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind, |
839 | SymbolRef Sym) const { |
840 | switch (ErrorKind) { |
841 | case RefVal::ErrorUseAfterRelease: |
842 | return useAfterRelease; |
843 | case RefVal::ErrorReleaseNotOwned: |
844 | return releaseNotOwned; |
845 | case RefVal::ErrorDeallocNotOwned: |
846 | if (Sym->getType()->getPointeeCXXRecordDecl()) |
847 | return freeNotOwned; |
848 | return deallocNotOwned; |
849 | default: |
850 | llvm_unreachable("Unhandled error."); |
851 | } |
852 | } |
853 | |
854 | void RetainCountChecker::processNonLeakError(ProgramStateRef St, |
855 | SourceRange ErrorRange, |
856 | RefVal::Kind ErrorKind, |
857 | SymbolRef Sym, |
858 | CheckerContext &C) const { |
859 | |
860 | |
861 | |
862 | |
863 | |
864 | |
865 | if (const RefVal *RV = getRefBinding(St, Sym)) |
866 | if (RV->getIvarAccessHistory() != RefVal::IvarAccessHistory::None) |
867 | return; |
868 | |
869 | ExplodedNode *N = C.generateErrorNode(St); |
870 | if (!N) |
871 | return; |
872 | |
873 | auto report = llvm::make_unique<RefCountReport>( |
874 | errorKindToBugKind(ErrorKind, Sym), |
875 | C.getASTContext().getLangOpts(), N, Sym); |
876 | report->addRange(ErrorRange); |
877 | C.emitReport(std::move(report)); |
878 | } |
879 | |
880 | |
881 | |
882 | |
883 | |
884 | bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { |
885 | ProgramStateRef state = C.getState(); |
886 | const FunctionDecl *FD = C.getCalleeDecl(CE); |
887 | if (!FD) |
888 | return false; |
889 | |
890 | RetainSummaryManager &SmrMgr = getSummaryManager(C); |
891 | QualType ResultTy = CE->getCallReturnType(C.getASTContext()); |
892 | |
893 | |
894 | |
895 | bool hasTrustedImplementationAnnotation = false; |
896 | |
897 | const LocationContext *LCtx = C.getLocationContext(); |
898 | |
899 | using BehaviorSummary = RetainSummaryManager::BehaviorSummary; |
900 | Optional<BehaviorSummary> BSmr = |
901 | SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation); |
902 | |
903 | |
904 | if (!BSmr) |
905 | return false; |
906 | |
907 | |
908 | if (BSmr == BehaviorSummary::Identity || |
909 | BSmr == BehaviorSummary::IdentityOrZero || |
910 | BSmr == BehaviorSummary::IdentityThis) { |
911 | |
912 | const Expr *BindReturnTo = |
913 | (BSmr == BehaviorSummary::IdentityThis) |
914 | ? cast<CXXMemberCallExpr>(CE)->getImplicitObjectArgument() |
915 | : CE->getArg(0); |
916 | SVal RetVal = state->getSVal(BindReturnTo, LCtx); |
917 | |
918 | |
919 | |
920 | |
921 | |
922 | if (RetVal.isUnknown() || |
923 | (hasTrustedImplementationAnnotation && !ResultTy.isNull())) { |
924 | SValBuilder &SVB = C.getSValBuilder(); |
925 | RetVal = |
926 | SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount()); |
927 | } |
928 | |
929 | |
930 | state = state->BindExpr(CE, LCtx, RetVal, ); |
931 | |
932 | if (BSmr == BehaviorSummary::IdentityOrZero) { |
933 | |
934 | ProgramStateRef NullOutputState = C.getState(); |
935 | |
936 | |
937 | NullOutputState = NullOutputState->BindExpr( |
938 | CE, LCtx, C.getSValBuilder().makeNull(), ); |
939 | C.addTransition(NullOutputState, &CastFailTag); |
940 | |
941 | |
942 | |
943 | if (auto L = RetVal.getAs<DefinedOrUnknownSVal>()) |
944 | state = state->assume(*L, ); |
945 | |
946 | } |
947 | } |
948 | |
949 | C.addTransition(state); |
950 | return true; |
951 | } |
952 | |
953 | ExplodedNode * RetainCountChecker::processReturn(const ReturnStmt *S, |
954 | CheckerContext &C) const { |
955 | ExplodedNode *Pred = C.getPredecessor(); |
956 | |
957 | |
958 | |
959 | |
960 | |
961 | |
962 | if (!C.inTopFrame()) |
963 | return Pred; |
964 | |
965 | if (!S) |
966 | return Pred; |
967 | |
968 | const Expr *RetE = S->getRetValue(); |
969 | if (!RetE) |
970 | return Pred; |
971 | |
972 | ProgramStateRef state = C.getState(); |
973 | SymbolRef Sym = |
974 | state->getSValAsScalarOrLoc(RetE, C.getLocationContext()).getAsLocSymbol(); |
975 | if (!Sym) |
976 | return Pred; |
977 | |
978 | |
979 | const RefVal *T = getRefBinding(state, Sym); |
980 | if (!T) |
981 | return Pred; |
982 | |
983 | |
984 | RefVal X = *T; |
985 | |
986 | switch (X.getKind()) { |
987 | case RefVal::Owned: { |
988 | unsigned cnt = X.getCount(); |
989 | 0", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp", 989, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(cnt > 0); |
990 | X.setCount(cnt - 1); |
991 | X = X ^ RefVal::ReturnedOwned; |
992 | break; |
993 | } |
994 | |
995 | case RefVal::NotOwned: { |
996 | unsigned cnt = X.getCount(); |
997 | if (cnt) { |
998 | X.setCount(cnt - 1); |
999 | X = X ^ RefVal::ReturnedOwned; |
1000 | } else { |
1001 | X = X ^ RefVal::ReturnedNotOwned; |
1002 | } |
1003 | break; |
1004 | } |
1005 | |
1006 | default: |
1007 | return Pred; |
1008 | } |
1009 | |
1010 | |
1011 | state = setRefBinding(state, Sym, X); |
1012 | Pred = C.addTransition(state); |
1013 | |
1014 | |
1015 | |
1016 | |
1017 | |
1018 | |
1019 | if (!Pred) |
1020 | return nullptr; |
1021 | |
1022 | |
1023 | static CheckerProgramPointTag AutoreleaseTag(this, "Autorelease"); |
1024 | state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X, S); |
1025 | |
1026 | |
1027 | if (!state) |
1028 | return nullptr; |
1029 | |
1030 | |
1031 | T = getRefBinding(state, Sym); |
1032 | assert(T); |
1033 | X = *T; |
1034 | |
1035 | |
1036 | RetainSummaryManager &Summaries = getSummaryManager(C); |
1037 | const Decl *CD = &Pred->getCodeDecl(); |
1038 | RetEffect RE = RetEffect::MakeNoRet(); |
1039 | |
1040 | |
1041 | if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CD)) { |
1042 | const RetainSummary *Summ = Summaries.getSummary(AnyCall(MD)); |
1043 | RE = Summ->getRetEffect(); |
1044 | } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) { |
1045 | if (!isa<CXXMethodDecl>(FD)) { |
1046 | const RetainSummary *Summ = Summaries.getSummary(AnyCall(FD)); |
1047 | RE = Summ->getRetEffect(); |
1048 | } |
1049 | } |
1050 | |
1051 | return checkReturnWithRetEffect(S, C, Pred, RE, X, Sym, state); |
1052 | } |
1053 | |
1054 | ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, |
1055 | CheckerContext &C, |
1056 | ExplodedNode *Pred, |
1057 | RetEffect RE, RefVal X, |
1058 | SymbolRef Sym, |
1059 | ProgramStateRef state) const { |
1060 | |
1061 | |
1062 | |
1063 | |
1064 | |
1065 | |
1066 | if (X.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) |
1067 | return Pred; |
1068 | |
1069 | |
1070 | if (X.isReturnedOwned() && X.getCount() == 0) { |
1071 | if (RE.getKind() != RetEffect::NoRet) { |
1072 | if (!RE.isOwned()) { |
1073 | |
1074 | |
1075 | |
1076 | X = X ^ RefVal::ErrorLeakReturned; |
1077 | |
1078 | |
1079 | state = setRefBinding(state, Sym, X); |
1080 | |
1081 | static CheckerProgramPointTag ReturnOwnLeakTag(this, "ReturnsOwnLeak"); |
1082 | ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag); |
1083 | if (N) { |
1084 | const LangOptions &LOpts = C.getASTContext().getLangOpts(); |
1085 | auto R = |
1086 | llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C); |
1087 | C.emitReport(std::move(R)); |
1088 | } |
1089 | return N; |
1090 | } |
1091 | } |
1092 | } else if (X.isReturnedNotOwned()) { |
1093 | if (RE.isOwned()) { |
1094 | if (X.getIvarAccessHistory() == |
1095 | RefVal::IvarAccessHistory::AccessedDirectly) { |
1096 | |
1097 | |
1098 | state = setRefBinding(state, Sym, |
1099 | X.releaseViaIvar() ^ RefVal::ReturnedOwned); |
1100 | } else { |
1101 | |
1102 | |
1103 | state = setRefBinding(state, Sym, X ^ RefVal::ErrorReturnedNotOwned); |
1104 | |
1105 | static CheckerProgramPointTag |
1106 | ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned"); |
1107 | |
1108 | ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); |
1109 | if (N) { |
1110 | auto R = llvm::make_unique<RefCountReport>( |
1111 | returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); |
1112 | C.emitReport(std::move(R)); |
1113 | } |
1114 | return N; |
1115 | } |
1116 | } |
1117 | } |
1118 | return Pred; |
1119 | } |
1120 | |
1121 | |
1122 | |
1123 | |
1124 | |
1125 | void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, |
1126 | CheckerContext &C) const { |
1127 | ProgramStateRef state = C.getState(); |
1128 | const MemRegion *MR = loc.getAsRegion(); |
1129 | |
1130 | |
1131 | |
1132 | if (MR && shouldEscapeRegion(MR)) { |
1133 | state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); |
1134 | C.addTransition(state); |
1135 | } |
1136 | } |
1137 | |
1138 | ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, |
1139 | SVal Cond, |
1140 | bool Assumption) const { |
1141 | |
1142 | |
1143 | |
1144 | |
1145 | |
1146 | |
1147 | RefBindingsTy B = state->get<RefBindings>(); |
1148 | |
1149 | if (B.isEmpty()) |
1150 | return state; |
1151 | |
1152 | bool changed = false; |
1153 | RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>(); |
1154 | ConstraintManager &CMgr = state->getConstraintManager(); |
1155 | |
1156 | for (auto &I : B) { |
1157 | |
1158 | ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first); |
1159 | if (AllocFailed.isConstrainedTrue()) { |
1160 | changed = true; |
1161 | B = RefBFactory.remove(B, I.first); |
1162 | } |
1163 | } |
1164 | |
1165 | if (changed) |
1166 | state = state->set<RefBindings>(B); |
1167 | |
1168 | return state; |
1169 | } |
1170 | |
1171 | ProgramStateRef RetainCountChecker::checkRegionChanges( |
1172 | ProgramStateRef state, const InvalidatedSymbols *invalidated, |
1173 | ArrayRef<const MemRegion *> ExplicitRegions, |
1174 | ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, |
1175 | const CallEvent *Call) const { |
1176 | if (!invalidated) |
1177 | return state; |
1178 | |
1179 | llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; |
1180 | |
1181 | for (const MemRegion *I : ExplicitRegions) |
1182 | if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>()) |
1183 | WhitelistedSymbols.insert(SR->getSymbol()); |
1184 | |
1185 | for (SymbolRef sym : *invalidated) { |
1186 | if (WhitelistedSymbols.count(sym)) |
1187 | continue; |
1188 | |
1189 | state = removeRefBinding(state, sym); |
1190 | } |
1191 | return state; |
1192 | } |
1193 | |
1194 | ProgramStateRef |
1195 | RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, |
1196 | ExplodedNode *Pred, |
1197 | const ProgramPointTag *Tag, |
1198 | CheckerContext &Ctx, |
1199 | SymbolRef Sym, |
1200 | RefVal V, |
1201 | const ReturnStmt *S) const { |
1202 | unsigned ACnt = V.getAutoreleaseCount(); |
1203 | |
1204 | |
1205 | if (!ACnt) |
1206 | return state; |
1207 | |
1208 | unsigned Cnt = V.getCount(); |
1209 | |
1210 | |
1211 | |
1212 | if (V.getKind() == RefVal::ReturnedOwned) |
1213 | ++Cnt; |
1214 | |
1215 | |
1216 | |
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 | |
1239 | |
1240 | |
1241 | |
1242 | |
1243 | |
1244 | if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) |
1245 | return state; |
1246 | |
1247 | |
1248 | |
1249 | V = V ^ RefVal::ErrorOverAutorelease; |
1250 | state = setRefBinding(state, Sym, V); |
1251 | |
1252 | ExplodedNode *N = Ctx.generateSink(state, Pred, Tag); |
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 = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym, |
1265 | os.str()); |
1266 | Ctx.emitReport(std::move(R)); |
1267 | } |
1268 | |
1269 | return nullptr; |
1270 | } |
1271 | |
1272 | ProgramStateRef |
1273 | RetainCountChecker::handleSymbolDeath(ProgramStateRef state, |
1274 | SymbolRef sid, RefVal V, |
1275 | SmallVectorImpl<SymbolRef> &Leaked) const { |
1276 | bool hasLeak; |
1277 | |
1278 | |
1279 | |
1280 | |
1281 | |
1282 | |
1283 | |
1284 | if (V.getIvarAccessHistory() != RefVal::IvarAccessHistory::None) |
1285 | hasLeak = false; |
1286 | else if (V.isOwned()) |
1287 | hasLeak = true; |
1288 | else if (V.isNotOwned() || V.isReturnedOwned()) |
1289 | hasLeak = (V.getCount() > 0); |
1290 | else |
1291 | hasLeak = false; |
1292 | |
1293 | if (!hasLeak) |
1294 | return removeRefBinding(state, sid); |
1295 | |
1296 | Leaked.push_back(sid); |
1297 | return setRefBinding(state, sid, V ^ RefVal::ErrorLeak); |
1298 | } |
1299 | |
1300 | ExplodedNode * |
1301 | RetainCountChecker::processLeaks(ProgramStateRef state, |
1302 | SmallVectorImpl<SymbolRef> &Leaked, |
1303 | CheckerContext &Ctx, |
1304 | ExplodedNode *Pred) const { |
1305 | |
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(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx)); |
1313 | } |
1314 | } |
1315 | |
1316 | return N; |
1317 | } |
1318 | |
1319 | void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const { |
1320 | if (!Ctx.inTopFrame()) |
1321 | return; |
1322 | |
1323 | RetainSummaryManager &SmrMgr = getSummaryManager(Ctx); |
1324 | const LocationContext *LCtx = Ctx.getLocationContext(); |
1325 | const Decl *D = LCtx->getDecl(); |
1326 | Optional<AnyCall> C = AnyCall::forDecl(D); |
1327 | |
1328 | if (!C || SmrMgr.isTrustedReferenceCountImplementation(D)) |
1329 | return; |
1330 | |
1331 | ProgramStateRef state = Ctx.getState(); |
1332 | const RetainSummary *FunctionSummary = SmrMgr.getSummary(*C); |
1333 | ArgEffects CalleeSideArgEffects = FunctionSummary->getArgEffects(); |
1334 | |
1335 | for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) { |
1336 | const ParmVarDecl *Param = C->parameters()[idx]; |
1337 | SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol(); |
1338 | |
1339 | QualType Ty = Param->getType(); |
1340 | const ArgEffect *AE = CalleeSideArgEffects.lookup(idx); |
1341 | if (AE) { |
1342 | ObjKind K = AE->getObjKind(); |
1343 | if (K == ObjKind::Generalized || K == ObjKind::OS || |
1344 | (TrackNSCFStartParam && (K == ObjKind::ObjC || K == ObjKind::CF))) { |
1345 | RefVal NewVal = AE->getKind() == DecRef ? RefVal::makeOwned(K, Ty) |
1346 | : RefVal::makeNotOwned(K, Ty); |
1347 | state = setRefBinding(state, Sym, NewVal); |
1348 | } |
1349 | } |
1350 | } |
1351 | |
1352 | Ctx.addTransition(state); |
1353 | } |
1354 | |
1355 | void RetainCountChecker::checkEndFunction(const ReturnStmt *RS, |
1356 | CheckerContext &Ctx) const { |
1357 | ExplodedNode *Pred = processReturn(RS, Ctx); |
1358 | |
1359 | |
1360 | if (!Pred) { |
1361 | return; |
1362 | } |
1363 | |
1364 | ProgramStateRef state = Pred->getState(); |
1365 | RefBindingsTy B = state->get<RefBindings>(); |
1366 | |
1367 | |
1368 | const LocationContext *LCtx = Pred->getLocationContext(); |
1369 | if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) { |
1370 | inTopFrame()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp", 1370, __PRETTY_FUNCTION__))" file_link="../../../../../include/assert.h.html#88" macro="true">assert(!LCtx->inTopFrame()); |
1371 | return; |
1372 | } |
1373 | |
1374 | for (auto &I : B) { |
1375 | state = handleAutoreleaseCounts(state, Pred, , Ctx, |
1376 | I.first, I.second); |
1377 | if (!state) |
1378 | return; |
1379 | } |
1380 | |
1381 | |
1382 | |
1383 | |
1384 | |
1385 | if (LCtx->getParent()) |
1386 | return; |
1387 | |
1388 | B = state->get<RefBindings>(); |
1389 | SmallVector<SymbolRef, 10> Leaked; |
1390 | |
1391 | for (auto &I : B) |
1392 | state = handleSymbolDeath(state, I.first, I.second, Leaked); |
1393 | |
1394 | processLeaks(state, Leaked, Ctx, Pred); |
1395 | } |
1396 | |
1397 | void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, |
1398 | CheckerContext &C) const { |
1399 | ExplodedNode *Pred = C.getPredecessor(); |
1400 | |
1401 | ProgramStateRef state = C.getState(); |
1402 | SmallVector<SymbolRef, 10> Leaked; |
1403 | |
1404 | |
1405 | for (const auto &I: state->get<RefBindings>()) { |
1406 | SymbolRef Sym = I.first; |
1407 | if (SymReaper.isDead(Sym)) { |
1408 | static CheckerProgramPointTag Tag(this, "DeadSymbolAutorelease"); |
1409 | const RefVal &V = I.second; |
1410 | state = handleAutoreleaseCounts(state, Pred, &Tag, C, Sym, V); |
1411 | if (!state) |
1412 | return; |
1413 | |
1414 | |
1415 | |
1416 | state = handleSymbolDeath(state, Sym, *getRefBinding(state, Sym), Leaked); |
1417 | } |
1418 | } |
1419 | |
1420 | if (Leaked.empty()) { |
1421 | C.addTransition(state); |
1422 | return; |
1423 | } |
1424 | |
1425 | Pred = processLeaks(state, Leaked, C, Pred); |
1426 | |
1427 | |
1428 | if (!Pred) |
1429 | return; |
1430 | |
1431 | |
1432 | |
1433 | RefBindingsTy::Factory &F = state->get_context<RefBindings>(); |
1434 | RefBindingsTy B = state->get<RefBindings>(); |
1435 | |
1436 | for (SymbolRef L : Leaked) |
1437 | B = F.remove(B, L); |
1438 | |
1439 | state = state->set<RefBindings>(B); |
1440 | C.addTransition(state, Pred); |
1441 | } |
1442 | |
1443 | void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, |
1444 | const char *NL, const char *Sep) const { |
1445 | |
1446 | RefBindingsTy B = State->get<RefBindings>(); |
1447 | |
1448 | if (B.isEmpty()) |
1449 | return; |
1450 | |
1451 | Out << Sep << NL; |
1452 | |
1453 | for (auto &I : B) { |
1454 | Out << I.first << " : "; |
1455 | I.second.print(Out); |
1456 | Out << NL; |
1457 | } |
1458 | } |
1459 | |
1460 | |
1461 | |
1462 | |
1463 | |
1464 | void ento::registerRetainCountBase(CheckerManager &Mgr) { |
1465 | Mgr.registerChecker<RetainCountChecker>(); |
1466 | } |
1467 | |
1468 | bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) { |
1469 | return true; |
1470 | } |
1471 | |
1472 | |
1473 | |
1474 | |
1475 | |
1476 | static bool getOption(AnalyzerOptions &Options, |
1477 | StringRef Postfix, |
1478 | StringRef Value) { |
1479 | auto I = Options.Config.find( |
1480 | (StringRef("osx.cocoa.RetainCount:") + Postfix).str()); |
1481 | if (I != Options.Config.end()) |
1482 | return I->getValue() == Value; |
1483 | return false; |
1484 | } |
1485 | |
1486 | void ento::registerRetainCountChecker(CheckerManager &Mgr) { |
1487 | auto *Chk = Mgr.getChecker<RetainCountChecker>(); |
1488 | Chk->TrackObjCAndCFObjects = true; |
1489 | Chk->TrackNSCFStartParam = getOption(Mgr.getAnalyzerOptions(), |
1490 | "TrackNSCFStartParam", |
1491 | "true"); |
1492 | } |
1493 | |
1494 | bool ento::shouldRegisterRetainCountChecker(const LangOptions &LO) { |
1495 | return true; |
1496 | } |
1497 | |
1498 | void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) { |
1499 | auto *Chk = Mgr.getChecker<RetainCountChecker>(); |
1500 | if (!getOption(Mgr.getAnalyzerOptions(), |
1501 | "CheckOSObject", |
1502 | "false")) |
1503 | Chk->TrackOSObjects = true; |
1504 | } |
1505 | |
1506 | bool ento::shouldRegisterOSObjectRetainCountChecker(const LangOptions &LO) { |
1507 | return true; |
1508 | } |
1509 | |