clang: lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
17#include
18
19using namespace clang;
20using namespace ento;
21using namespace retaincountchecker;
22
24
26namespace ento {
27namespace retaincountchecker {
28
30 return State->get(Sym);
31}
32
33}
34}
35}
36
39 assert(Sym != nullptr);
40 return State->set(Sym, Val);
41}
42
44 return State->remove(Sym);
45}
46
49 Out << "Tracked " << T << " | ";
50
52 default: llvm_unreachable("Invalid RefVal kind");
54 Out << "Owned";
56 if (cnt) Out << " (+ " << cnt << ")";
57 break;
58 }
59
61 Out << "NotOwned";
63 if (cnt) Out << " (+ " << cnt << ")";
64 break;
65 }
66
68 Out << "ReturnedOwned";
70 if (cnt) Out << " (+ " << cnt << ")";
71 break;
72 }
73
75 Out << "ReturnedNotOwned";
77 if (cnt) Out << " (+ " << cnt << ")";
78 break;
79 }
80
82 Out << "Released";
83 break;
84
86 Out << "-dealloc (not-owned)";
87 break;
88
90 Out << "Leaked";
91 break;
92
94 Out << "Leaked (Bad naming)";
95 break;
96
98 Out << "Use-After-Release [ERROR]";
99 break;
100
102 Out << "Release of Not-Owned [ERROR]";
103 break;
104
106 Out << "Over-autoreleased";
107 break;
108
110 Out << "Non-owned object returned instead of owned";
111 break;
112 }
113
116 break;
118 Out << " [direct ivar access]";
119 break;
121 Out << " [released after direct ivar access]";
122 }
123
124 if (ACnt) {
125 Out << " [autorelease -" << ACnt << ']';
126 }
127}
128
129namespace {
130class StopTrackingCallback final : public SymbolVisitor {
132public:
135
136 bool VisitSymbol(SymbolRef sym) override {
138 return true;
139 }
140};
141}
142
143
144
145
146
149
150
151
153 return;
154
156 auto *R = cast(C.getSVal(BE).getAsRegion());
157
158 auto ReferencedVars = R->referenced_vars();
159 if (ReferencedVars.empty())
160 return;
161
162
163
164
167 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
168
169 for (auto Var : ReferencedVars) {
170 const VarRegion *VR = Var.getCapturedRegion();
173 }
174 Regions.push_back(VR);
175 }
176
177 state = state->scanReachableSymbols(Regions).getState();
178 C.addTransition(state);
179}
180
184 if (!BE)
185 return;
186
191 } else {
193 }
194
196
199
200 return;
203 break;
206 break;
207 }
208
210 SymbolRef Sym = C.getSVal(CE).getAsLocSymbol();
211 if (!Sym)
212 return;
214 if ()
215 return;
216
219
220 if (hasErr) {
221
222 return;
223 }
224
225 C.addTransition(state);
226}
227
229 const Expr *Ex) const {
239 if (hasErr) {
241 return;
242 }
243 }
244 }
245
246
247
253 }
254
255 C.addTransition(state);
256}
257
260
262}
263
266
268}
269
274
279 }
280
281 C.addTransition(State);
282}
283
286 std::optional IVarLoc = C.getSVal(IRE).getAs<Loc>();
287 if (!IVarLoc)
288 return;
289
291 SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
292 if (!Sym || !isa_and_nonnull(Sym->getOriginRegion()))
293 return;
294
295
296
297
304 else
305 return;
306
307
310 return;
311
313
314
317 return;
318 }
319
320
321 C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
322 return;
323 }
324
326
327
329 C.addTransition(setRefBinding(State, Sym, PlusZero));
330 return;
331 }
332
334 C.addTransition(State);
335}
336
338 if (const auto *MC = dyn_cast(&Call)) {
339
340
341
342 return MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper() &&
343 .getLocationContext()
344 ->getAnalysisDeclContext()
345 ->getParentMap()
346 .isConsumedExpr(Call.getOriginExpr());
347 }
348 return false;
349}
350
354 const Expr *CE = Call.getOriginExpr();
357 : AnyCall(cast(Call.getDecl()));
358 return Summaries.getSummary(C, Call.hasNonZeroCallbackArg(),
360}
361
365
366
368 if (const auto *MC = dyn_cast(&Call)) {
369 if (MC->isInstanceMessage()) {
370 SVal ReceiverV = MC->getReceiverSVal();
373 ReceiverType = T->getType();
374 }
375 }
376
378
379 if (C.wasInlined) {
381 return;
382 }
384}
385
386
387
388
389
390
391
392
395
396
397
398 if (const ObjCMessageExpr *ME = dyn_cast(RetE))
400 if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
401 PT->isObjCClassType()) {
402
403
404
405
407 return ? RetTy :
409 }
410
411 return RetTy;
412}
413
420 }
421
422 return std::nullopt;
423}
424
429 return true;
430 return false;
431}
432
433
434
436 const RefVal *TrackedValue) {
438 return false;
439 if (ArgIdx >= CE.parameters().size())
440 return false;
442}
443
444
445
446
451
452
453 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
455
456 if (SymbolRef Sym = V.getAsLocSymbol()) {
460 ShouldRemoveBinding = true;
461
462 if (ShouldRemoveBinding)
464 }
465 }
466
467
468 if (const auto *MsgInvocation = dyn_cast(&CallOrMsg)) {
469 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
472 }
473 }
474 }
475
476
478
482 }
483
484 C.addTransition(state);
485}
486
488 const auto *TR = dyn_cast(
489 cast(MR)->getSuperRegion());
491}
492
493
494
495
496
497
498
499
500
501
502
503
506 return false;
507
508 const auto *VR = dyn_cast(R);
509
511 return true;
512
513 const VarDecl *VD = VR->getDecl();
514 if (!VD->hasAttr())
515 return false;
516 return true;
517}
518
522
524
525
526
527
528
529 bool SplitNecessary = false;
533 SplitNecessary = true;
534
537
538 if (SplitNecessary) {
540
541
542 return {State};
543 }
545 AssumeNonZeroReturn = AssumeNonZeroReturn->assume(*DL, true);
546 AssumeZeroReturn = AssumeZeroReturn->assume(*DL, false);
547 }
548 }
549
550 for (unsigned idx = 0, e = CE.getNumArgs(); idx != e; ++idx) {
553
554 auto *ArgRegion = dyn_cast_or_null(ArgVal.getAsRegion());
555 if (!ArgRegion)
556 continue;
557
558 QualType PointeeTy = ArgRegion->getValueType();
559 SVal PointeeVal = State->getSVal(ArgRegion);
561 if (!Pointee)
562 continue;
563
565 continue;
566
570 };
574 };
575
578 AssumeNonZeroReturn = makeNotOwnedParameter(AssumeNonZeroReturn);
579 AssumeZeroReturn = makeNotOwnedParameter(AssumeZeroReturn);
580 break;
582 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
583 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
584 break;
586 AssumeNonZeroReturn = makeOwnedParameter(AssumeNonZeroReturn);
587 break;
589 AssumeZeroReturn = makeOwnedParameter(AssumeZeroReturn);
590 break;
591 default:
592 break;
593 }
594 }
595
596 if (SplitNecessary) {
597 return {AssumeNonZeroReturn, AssumeZeroReturn};
598 } else {
599 assert(AssumeZeroReturn == AssumeNonZeroReturn);
600 return {AssumeZeroReturn};
601 }
602}
603
608
609
613
614
615
616 bool DeallocSent = false;
617
618 for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) {
620
622 if (SymbolRef Sym = V.getAsLocSymbol()) {
624
627
628 state = updateSymbol(state, Sym, *T, Effect, hasErr, C);
629 if (hasErr) {
631 ErrorSym = Sym;
632 break;
634 DeallocSent = true;
635 }
636 }
637 }
638 }
639
640
641 bool ReceiverIsTracked = false;
642 if (!hasErr) {
643 if (const auto *MsgInvocation = dyn_cast(&CallOrMsg)) {
644 if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) {
646 ReceiverIsTracked = true;
649 if (hasErr) {
650 ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange();
651 ErrorSym = Sym;
653 DeallocSent = true;
654 }
655 }
656 }
657 } else if (const auto *MCall = dyn_cast(&CallOrMsg)) {
658 if (SymbolRef Sym = MCall->getCXXThisVal().getAsLocSymbol()) {
661 hasErr, C);
662 if (hasErr) {
663 ErrorRange = MCall->getOriginExpr()->getSourceRange();
664 ErrorSym = Sym;
665 }
666 }
667 }
668 }
669 }
670
671
672 if (hasErr) {
674 return;
675 }
676
677
679
681 if (ReceiverIsTracked)
683 else
685 }
686
691 assert(Ex);
693 }
694 if (std::optional updatedRefVal = refValFromRetEffect(RE, ResultTy))
695 state = setRefBinding(state, Sym, *updatedRefVal);
696 }
697
700
702 if (DeallocSent) {
704 } else {
705 C.addTransition(St);
706 }
707 }
708}
709
715 bool IgnoreRetainMsg = (bool)C.getASTContext().getLangOpts().ObjCAutoRefCount;
718 default:
719 break;
722 break;
725 break;
728 break;
729 }
730 }
731
732
735 hasErr = V.getKind();
737 }
738
744 llvm_unreachable("Applies to pointer-to-pointer parameters, which should "
745 "not have ref state.");
746
747 case Dealloc:
748 switch (V.getKind()) {
749 default:
750 llvm_unreachable("Invalid RefVal state for an explicit dealloc.");
752
754 V.clearCounts();
758 hasErr = V.getKind();
759 break;
760 }
761 break;
762
766 break;
767 }
768
769 [[fallthrough]];
770
772 return state;
773
775
777 break;
778
782
784 switch (V.getKind()) {
785 default:
786 llvm_unreachable("Invalid RefVal state for a retain.");
790 break;
791 }
792 break;
793
797 switch (V.getKind()) {
798 default:
799
800 llvm_unreachable("Invalid RefVal state for a release.");
801
803 assert(V.getCount() > 0);
804 if (V.getCount() == 1) {
806 V.getIvarAccessHistory() ==
809 else
813 }
814
816 break;
817
819 if (V.getCount() > 0) {
823 } else if (V.getIvarAccessHistory() ==
825
826
830 } else {
832 hasErr = V.getKind();
833 }
834 break;
835 }
836 break;
837 }
839}
840
844 switch (ErrorKind) {
853 default:
854 llvm_unreachable("Unhandled error.");
855 }
856}
857
863
864
865
866
867
868
871 return;
872
874 if (!N)
875 return;
876
877 auto report = std::make_unique(
879 C.getASTContext().getLangOpts(), N, Sym);
880 report->addRange(ErrorRange);
881 C.emitReport(std::move(report));
882}
883
884
885
886
887
891 const auto *FD = dyn_cast_or_null(Call.getDecl());
892 if (!FD)
893 return false;
894
895 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());
896 if (!CE)
897 return false;
898
901
902
903
904 bool hasTrustedImplementationAnnotation = false;
905
907
909 std::optional BSmr =
910 SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
911
912
913 if (!BSmr)
914 return false;
915
916
917 if (BSmr == BehaviorSummary::Identity ||
918 BSmr == BehaviorSummary::IdentityOrZero ||
919 BSmr == BehaviorSummary::IdentityThis) {
920
921 const Expr *BindReturnTo =
922 (BSmr == BehaviorSummary::IdentityThis)
923 ? cast(CE)->getImplicitObjectArgument()
924 : CE->getArg(0);
925 SVal RetVal = state->getSVal(BindReturnTo, LCtx);
926
927
928
929
930
932 (hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
934 RetVal =
935 SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
936 }
937
938
939 state = state->BindExpr(CE, LCtx, RetVal, false);
940
941 if (BSmr == BehaviorSummary::IdentityOrZero) {
942
944
945
946 NullOutputState = NullOutputState->BindExpr(
947 CE, LCtx, C.getSValBuilder().makeNullWithType(ResultTy),
948 false);
950
951
952
954 state = state->assume(*L, true);
955
956 }
957 }
958
959 C.addTransition(state);
960 return true;
961}
962
966
967
968
969
970
971
972 if (.inTopFrame())
973 return Pred;
974
975 if (!S)
976 return Pred;
977
978 const Expr *RetE = S->getRetValue();
979 if (!RetE)
980 return Pred;
981
983
984
985 SymbolRef Sym = state->getSValAsScalarOrLoc(RetE, C.getLocationContext())
986 .getAsLocSymbol(true);
987 if (!Sym)
988 return Pred;
989
990
992 if ()
993 return Pred;
994
995
997
998 switch (X.getKind()) {
1000 unsigned cnt = X.getCount();
1001 assert(cnt > 0);
1002 X.setCount(cnt - 1);
1004 break;
1005 }
1006
1008 unsigned cnt = X.getCount();
1009 if (cnt) {
1010 X.setCount(cnt - 1);
1012 } else {
1014 }
1015 break;
1016 }
1017
1018 default:
1019 return Pred;
1020 }
1021
1022
1024 Pred = C.addTransition(state);
1025
1026
1027
1028
1029
1030
1031 if (!Pred)
1032 return nullptr;
1033
1034
1037
1038
1039 if (!state)
1040 return nullptr;
1041
1042
1044 assert(T);
1046
1047
1051
1052
1053 if (const ObjCMethodDecl *MD = dyn_cast(CD)) {
1056 } else if (const FunctionDecl *FD = dyn_cast(CD)) {
1057 if (!isa(FD)) {
1060 }
1061 }
1062
1064}
1065
1072
1073
1074
1075
1076
1077
1079 return Pred;
1080
1081
1082 if (X.isReturnedOwned() && X.getCount() == 0) {
1085
1086
1087
1089
1090
1092
1094 ExplodedNode *N = C.addTransition(state, Pred, &ReturnOwnLeakTag);
1095 if (N) {
1096 const LangOptions &LOpts = C.getASTContext().getLangOpts();
1097 auto R =
1098 std::make_unique(*LeakAtReturn, LOpts, N, Sym, C);
1099 C.emitReport(std::move(R));
1100 }
1101 return N;
1102 }
1103 }
1104 } else if (X.isReturnedNotOwned()) {
1106 if (X.getIvarAccessHistory() ==
1108
1109
1112 } else {
1113
1114
1116
1118 ReturnNotOwnedTag(this, "ReturnNotOwnedForOwned");
1119
1120 ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
1121 if (N) {
1122 auto R = std::make_unique(
1124 C.emitReport(std::move(R));
1125 }
1126 return N;
1127 }
1128 }
1129 }
1130 return Pred;
1131}
1132
1133
1134
1135
1136
1141
1142
1143
1145 state = state->scanReachableSymbols(val).getState();
1146 C.addTransition(state);
1147 }
1148}
1149
1152 bool Assumption) const {
1153
1154
1155
1156
1157
1158
1159 RefBindingsTy B = state->get();
1160
1161 if (B.isEmpty())
1162 return state;
1163
1164 bool changed = false;
1165 RefBindingsTy::Factory &RefBFactory = state->get_context();
1167
1168 for (auto &I : B) {
1169
1172 changed = true;
1173 B = RefBFactory.remove(B, I.first);
1174 }
1175 }
1176
1177 if (changed)
1178 state = state->set(B);
1179
1180 return state;
1181}
1182
1188 if (!invalidated)
1189 return state;
1190
1192
1193 for (const MemRegion *I : ExplicitRegions)
1195 AllowedSymbols.insert(SR->getSymbol());
1196
1197 for (SymbolRef sym : *invalidated) {
1198 if (AllowedSymbols.count(sym))
1199 continue;
1200
1202 }
1203 return state;
1204}
1205
1214 unsigned ACnt = V.getAutoreleaseCount();
1215
1216
1217 if (!ACnt)
1218 return state;
1219
1220 unsigned Cnt = V.getCount();
1221
1222
1223
1225 ++Cnt;
1226
1227
1228
1229 if (ACnt > Cnt &&
1232 --ACnt;
1233 }
1234
1235 if (ACnt <= Cnt) {
1236 if (ACnt == Cnt) {
1237 V.clearCounts();
1240 } else {
1242 }
1243 } else {
1244 V.setCount(V.getCount() - ACnt);
1245 V.setAutoreleaseCount(0);
1246 }
1248 }
1249
1250
1251
1252
1253
1254
1255
1257 return state;
1258
1259
1260
1263
1264 ExplodedNode *N = Ctx.generateSink(state, Pred, Tag);
1265 if (N) {
1267 llvm::raw_svector_ostream os(sbuf);
1268 os << "Object was autoreleased ";
1269 if (V.getAutoreleaseCount() > 1)
1270 os << V.getAutoreleaseCount() << " times but the object ";
1271 else
1272 os << "but ";
1273 os << "has a +" << V.getCount() << " retain count";
1274
1276 auto R = std::make_unique(*OverAutorelease, LOpts, N, Sym,
1277 os.str());
1278 Ctx.emitReport(std::move(R));
1279 }
1280
1281 return nullptr;
1282}
1283
1288 bool hasLeak;
1289
1290
1291
1292
1293
1294
1295
1297 hasLeak = false;
1298 else if (V.isOwned())
1299 hasLeak = true;
1300 else if (V.isNotOwned() || V.isReturnedOwned())
1301 hasLeak = (V.getCount() > 0);
1302 else
1303 hasLeak = false;
1304
1305 if (!hasLeak)
1307
1308 Leaked.push_back(sid);
1310}
1311
1317
1318 ExplodedNode *N = Ctx.addTransition(state, Pred);
1320
1321 if (N) {
1324 Ctx.emitReport(std::make_unique(BT, LOpts, N, L, Ctx));
1325 }
1326 }
1327
1328 return N;
1329}
1330
1332 if (!Ctx.inTopFrame())
1333 return;
1334
1339
1341 return;
1342
1346
1347 for (unsigned idx = 0, e = C->param_size(); idx != e; ++idx) {
1348 const ParmVarDecl *Param = C->parameters()[idx];
1349 SymbolRef Sym = state->getSVal(state->getRegion(Param, LCtx)).getAsSymbol();
1350
1352 const ArgEffect *AE = CalleeSideArgEffects.lookup(idx);
1353 if (AE) {
1360 }
1361 }
1362 }
1363
1364 Ctx.addTransition(state);
1365}
1366
1369 ExplodedNode *Pred = processReturn(RS, Ctx);
1370
1371
1372 if (!Pred) {
1373 return;
1374 }
1375
1377 RefBindingsTy B = state->get();
1378
1379
1381 if (LCtx->getAnalysisDeclContext()->isBodyAutosynthesized()) {
1382 assert(!LCtx->inTopFrame());
1383 return;
1384 }
1385
1386 for (auto &I : B) {
1388 I.first, I.second);
1389 if (!state)
1390 return;
1391 }
1392
1393
1394
1395
1396
1397 if (LCtx->getParent())
1398 return;
1399
1400 B = state->get();
1402
1403 for (auto &I : B)
1405
1407}
1408
1412
1415
1416
1417 for (const auto &I: state->get()) {
1419 if (SymReaper.isDead(Sym)) {
1421 const RefVal &V = I.second;
1423 if (!state)
1424 return;
1425
1426
1427
1429 }
1430 }
1431
1432 if (Leaked.empty()) {
1433 C.addTransition(state);
1434 return;
1435 }
1436
1438
1439
1440 if (!Pred)
1441 return;
1442
1443
1444
1445 RefBindingsTy::Factory &F = state->get_context();
1446 RefBindingsTy B = state->get();
1447
1449 B = F.remove(B, L);
1450
1451 state = state->set(B);
1452 C.addTransition(state, Pred);
1453}
1454
1456 const char *NL, const char *Sep) const {
1457
1458 RefBindingsTy B = State->get();
1459
1460 if (B.isEmpty())
1461 return;
1462
1463 Out << Sep << NL;
1464
1465 for (auto &I : B) {
1466 Out << I.first << " : ";
1467 I.second.print(Out);
1468 Out << NL;
1469 }
1470}
1471
1472
1473
1474
1475
1478
1479void ento::registerRetainCountBase(CheckerManager &Mgr) {
1482 std::make_unique(Chk, "DeallocSent");
1483 Chk->CastFailTag =
1484 std::make_unique(Chk, "DynamicCastFail");
1485}
1486
1487bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) {
1488 return true;
1489}
1490void ento::registerRetainCountChecker(CheckerManager &Mgr) {
1495
1496#define INIT_BUGTYPE(KIND) \
1497 Chk->KIND = std::make_unique(Mgr.getCurrentCheckerName(), \
1498 RefCountBug::KIND);
1499
1508#undef INIT_BUGTYPE
1509}
1510
1511bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) {
1512 return true;
1513}
1514
1515void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) {
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528#define LAZY_INIT_BUGTYPE(KIND) \
1529 if (!Chk->KIND) \
1530 Chk->KIND = std::make_unique(Mgr.getCurrentCheckerName(), \
1531 RefCountBug::KIND);
1540#undef LAZY_INIT_BUGTYPE
1541}
1542
1543bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) {
1544 return true;
1545}
static CanQualType GetReturnType(QualType RetTy)
Returns the "extra-canonicalized" return type, which discards qualifiers on the return type.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define LAZY_INIT_BUGTYPE(KIND)
static const RetainSummary * getSummary(RetainSummaryManager &Summaries, const CallEvent &Call, QualType ReceiverType)
static std::optional< RefVal > refValFromRetEffect(RetEffect RE, QualType ResultTy)
static ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym, RefVal Val)
static bool isReceiverUnconsumedSelf(const CallEvent &Call)
static SmallVector< ProgramStateRef, 2 > updateOutParameters(ProgramStateRef State, const RetainSummary &Summ, const CallEvent &CE)
static ProgramStateRef removeRefBinding(ProgramStateRef State, SymbolRef Sym)
#define INIT_BUGTYPE(KIND)
static bool isPointerToObject(QualType QT)
static bool isSmartPtrField(const MemRegion *MR)
static bool shouldEscapeOSArgumentOnCall(const CallEvent &CE, unsigned ArgIdx, const RefVal *TrackedValue)
Whether the tracked value should be escaped on a given call.
static bool shouldEscapeRegion(const MemRegion *R)
A value escapes in these possible cases:
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceDecl *PrevDecl=nullptr) const
getObjCInterfaceType - Return the unique reference to the type for the specified ObjC interface decl.
const LangOptions & getLangOpts() const
QualType getObjCObjectPointerType(QualType OIT) const
Return a ObjCObjectPointerType type for the given ObjCObjectType.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
An instance of this class corresponds to a call.
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
static std::optional< AnyCall > forExpr(const Expr *E)
If E is a generic call (to ObjC method /function/block/etc), return a constructed AnyCall object.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Represents a function declaration or definition.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
ObjCArrayLiteral - used for objective-c array containers; as in: @["Hello", NSApp,...
ObjCBoxedExpr - used for generalized expression boxing.
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers,...
ObjCBridgeCastKind getBridgeKind() const
Determine which kind of bridge is being performed via this cast.
ObjCDictionaryLiteral - AST node to represent objective-c dictionary literals; as in:"name" : NSUserN...
Represents an ObjC class declaration.
ObjCIvarRefExpr - A reference to an ObjC instance variable.
An expression that sends a message to the given Objective-C object or class.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a pointer to an Objective C object.
Represents a parameter to a function.
ProgramPoints can be "tagged" as representing points specific to a given analysis entity.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isScalarType() const
const CXXRecordDecl * getPointeeCXXRecordDecl() const
If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isObjCObjectPointerType() const
const T * getAs() const
Member-template getAs'.
bool isObjCRetainableType() const
Represents a variable declaration or definition.
An ArgEffect summarizes the retain count behavior on an argument or receiver to a function or method.
ArgEffect withKind(ArgEffectKind NewK)
ObjKind getObjKind() const
ArgEffectKind getKind() const
Represents an abstract call to a function or method along a particular path.
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
virtual const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
QualType getResultType() const
Returns the result type, adjusted for references.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
SVal getReturnValue() const
Returns the return value of the call.
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call's formal parameters.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)
Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...
const ProgramStateRef & getState() const
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const LocationContext * getLocationContext() const
const Decl & getCodeDecl() const
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
MemRegion - The root abstract class for all memory regions.
bool hasStackStorage() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
const RegionTy * getAs() const
RetEffect summarizes a call's retain/release behavior with respect to its return value.
ObjKind getObjKind() const
@ OwnedWhenTrackedReceiver
Indicates that the return value is an owned object when the receiver is also a tracked object.
@ NoRet
Indicates that no retain count information is tracked for the return value.
static RetEffect MakeNoRet()
bool isTrustedReferenceCountImplementation(const Decl *FD)
std::optional< BehaviorSummary > canEval(const CallExpr *CE, const FunctionDecl *FD, bool &hasTrustedImplementationAnnotation)
static bool isKnownSmartPointer(QualType QT)
const RetainSummary * getSummary(AnyCall C, bool HasNonZeroCallbackArg=false, bool IsReceiverUnconsumedSelf=false, QualType ReceiverType={})
RetEffect getObjAllocRetEffect() const
Summary for a function with respect to ownership changes.
ArgEffect getThisEffect() const
ArgEffect getReceiverEffect() const
getReceiverEffect - Returns the effect on the receiver of the call.
RetEffect getRetEffect() const
getRetEffect - Returns the effect on the return value of the call.
ArgEffects getArgEffects() const
ArgEffect getArg(unsigned idx) const
getArg - Return the argument effect on the argument specified by idx (starting from 0).
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
const MemRegion * getAsRegion() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
SymbolicRegion - A special, "non-concrete" region.
const VarDecl * getDecl() const override=0
unsigned getCount() const
@ ReleasedAfterDirectAccess
IvarAccessHistory getIvarAccessHistory() const
Returns what the analyzer knows about direct accesses to a particular instance variable.
void print(raw_ostream &Out) const
RefVal withIvarAccess() const
static RefVal makeOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is the responsibility of the current function,...
ObjKind getObjKind() const
static RefVal makeNotOwned(ObjKind o, QualType t)
Create a state for an object whose lifetime is not the responsibility of the current function.
std::unique_ptr< RefCountBug > LeakAtReturn
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const
void checkSummary(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
ProgramStateRef handleSymbolDeath(ProgramStateRef state, SymbolRef sid, RefVal V, SmallVectorImpl< SymbolRef > &Leaked) const
static std::unique_ptr< CheckerProgramPointTag > CastFailTag
bool TrackObjCAndCFObjects
Track Objective-C and CoreFoundation objects.
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, bool Assumption) const
static std::unique_ptr< CheckerProgramPointTag > DeallocSentTag
static const CheckerProgramPointTag & getCastFailTag()
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, RefVal::Kind ErrorKind, SymbolRef Sym, CheckerContext &C) const
const RefCountBug & errorKindToBugKind(RefVal::Kind ErrorKind, SymbolRef Sym) const
std::unique_ptr< RefCountBug > ReleaseNotOwned
std::unique_ptr< RefCountBug > DeallocNotOwned
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const
ExplodedNode * checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, ExplodedNode *Pred, RetEffect RE, RefVal X, SymbolRef Sym, ProgramStateRef state) const
ProgramStateRef handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, const ProgramPointTag *Tag, CheckerContext &Ctx, SymbolRef Sym, RefVal V, const ReturnStmt *S=nullptr) const
std::unique_ptr< RefCountBug > OverAutorelease
ExplodedNode * processLeaks(ProgramStateRef state, SmallVectorImpl< SymbolRef > &Leaked, CheckerContext &Ctx, ExplodedNode *Pred=nullptr) const
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, RefVal V, ArgEffect E, RefVal::Kind &hasErr, CheckerContext &C) const
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const
static const CheckerProgramPointTag & getDeallocSentTag()
std::unique_ptr< RetainSummaryManager > Summaries
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override
See CheckerManager::runCheckersForPrintState.
bool evalCall(const CallEvent &Call, CheckerContext &C) const
void checkBeginFunction(CheckerContext &C) const
bool TrackOSObjects
Track sublcasses of OSObject.
void checkPostCall(const CallEvent &Call, CheckerContext &C) const
std::unique_ptr< RefCountBug > FreeNotOwned
std::unique_ptr< RefCountBug > LeakWithinFunction
ProgramStateRef checkRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef< const MemRegion * > ExplicitRegions, ArrayRef< const MemRegion * > Regions, const LocationContext *LCtx, const CallEvent *Call) const
void processObjCLiterals(CheckerContext &C, const Expr *Ex) const
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const
void processSummaryOfInlined(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const
std::unique_ptr< RefCountBug > ReturnNotOwnedForOwned
RetainSummaryManager & getSummaryManager(ASTContext &Ctx) const
bool TrackNSCFStartParam
Track initial parameters (for the entry point) for NS/CF objects.
std::unique_ptr< RefCountBug > UseAfterRelease
bool isCFObjectRef(QualType T)
const RefVal * getRefBinding(ProgramStateRef State, SymbolRef Sym)
bool isSynthesizedAccessor(const StackFrameContext *SFC)
Returns true if this stack frame is for an Objective-C method that is a property getter or setter who...
llvm::ImmutableMap< unsigned, ArgEffect > ArgEffects
ArgEffects summarizes the effects of a function/method call on all of its arguments.
ObjKind
Determines the object kind of a tracked object.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
@ Generalized
Indicates that the tracked object is a generalized object.
@ CF
Indicates that the tracked object is a CF object.
@ ObjC
Indicates that the tracked object is an Objective-C object.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
@ IncRef
The argument has its reference count increased by 1.
@ UnretainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +0 v...
@ DoNothing
There is no effect.
@ RetainedOutParameter
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ RetainedOutParameterOnZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ MayEscape
The argument is treated as potentially escaping, meaning that even when its reference count hits 0 it...
@ StopTracking
All typestate tracking of the object ceases.
@ Dealloc
The argument is treated as if the referenced object was deallocated.
@ Autorelease
The argument is treated as if an -autorelease message had been sent to the referenced object.
@ RetainedOutParameterOnNonZero
The argument is a pointer to a retain-counted object; on exit, the new value of the pointer is a +1 v...
@ DecRef
The argument has its reference count decreased by 1.
@ StopTrackingHard
All typestate tracking of the object ceases.
@ DecRefAndStopTrackingHard
Performs the combined functionality of DecRef and StopTrackingHard.
@ DecRefBridgedTransferred
The argument has its reference count decreased by 1 to model a transferred bridge cast under ARC.
The JSON file list parser is used to communicate input to InstallAPI.
@ OBC_Bridge
Bridging via __bridge, which does nothing but reinterpret the bits.
@ OBC_BridgeTransfer
Bridging via __bridge_transfer, which transfers ownership of an Objective-C pointer into ARC.
@ OBC_BridgeRetained
Bridging via __bridge_retain, which makes an ARC object available as a +1 C pointer.
const FunctionProtoType * T