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 (T)

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 Call.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 D ? 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

776 V = V.autorelease();

777 break;

778

782

784 switch (V.getKind()) {

785 default:

786 llvm_unreachable("Invalid RefVal state for a retain.");

789 V = V + 1;

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

815 V = V - 1;

816 break;

817

819 if (V.getCount() > 0) {

822 V = V - 1;

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 (C.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 (T)

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);

1045 X = *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 &&

1231 V = V.releaseViaIvar();

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