clang: lib/StaticAnalyzer/Checkers/MallocChecker.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

81#include "llvm/ADT/STLExtras.h"

82#include "llvm/ADT/SetOperations.h"

83#include "llvm/ADT/StringExtras.h"

84#include "llvm/Support/Casting.h"

85#include "llvm/Support/Compiler.h"

86#include "llvm/Support/ErrorHandling.h"

87#include "llvm/Support/raw_ostream.h"

88#include

89#include

90#include

91

92using namespace clang;

93using namespace ento;

94using namespace std::placeholders;

95

96

97

98

99

100

101

102

103namespace {

104

105

106enum AllocationFamilyKind {

107 AF_None,

108 AF_Malloc,

109 AF_CXXNew,

110 AF_CXXNewArray,

111 AF_IfNameIndex,

112 AF_Alloca,

113 AF_InnerBuffer,

114 AF_Custom,

115};

116

117struct AllocationFamily {

118 AllocationFamilyKind Kind;

119 std::optional CustomName;

120

121 explicit AllocationFamily(AllocationFamilyKind AKind,

122 std::optional Name = std::nullopt)

123 : Kind(AKind), CustomName(Name) {

124 assert((Kind != AF_Custom || CustomName.has_value()) &&

125 "Custom family must specify also the name");

126

127

128 if (Kind == AF_Custom && CustomName.value() == "malloc") {

129 Kind = AF_Malloc;

130 CustomName = std::nullopt;

131 }

132 }

133

135 return std::tie(Kind, CustomName) == std::tie(Other.Kind, Other.CustomName);

136 }

137

139 return !(*this == Other);

140 }

141

142 void Profile(llvm::FoldingSetNodeID &ID) const {

143 ID.AddInteger(Kind);

144

145 if (Kind == AF_Custom)

146 ID.AddString(CustomName.value());

147 }

148};

149

150}

151

152

153

154

156

157

158

160

161

162

164

165

166

167

168

169namespace {

170

171class RefState {

173

174 Allocated,

175

176 AllocatedOfSizeZero,

177

178 Released,

179

180

181 Relinquished,

182

183

184

185 Escaped

186 };

187

188 const Stmt *S;

189

191 AllocationFamily Family;

192

193 RefState(Kind k, const Stmt *s, AllocationFamily family)

194 : S(s), K(k), Family(family) {

195 assert(family.Kind != AF_None);

196 }

197

198public:

199 bool isAllocated() const { return K == Allocated; }

200 bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }

201 bool isReleased() const { return K == Released; }

202 bool isRelinquished() const { return K == Relinquished; }

203 bool isEscaped() const { return K == Escaped; }

204 AllocationFamily getAllocationFamily() const { return Family; }

205 const Stmt *getStmt() const { return S; }

206

207 bool operator==(const RefState &X) const {

208 return K == X.K && S == X.S && Family == X.Family;

209 }

210

211 static RefState getAllocated(AllocationFamily family, const Stmt *s) {

212 return RefState(Allocated, s, family);

213 }

214 static RefState getAllocatedOfSizeZero(const RefState *RS) {

215 return RefState(AllocatedOfSizeZero, RS->getStmt(),

216 RS->getAllocationFamily());

217 }

218 static RefState getReleased(AllocationFamily family, const Stmt *s) {

219 return RefState(Released, s, family);

220 }

221 static RefState getRelinquished(AllocationFamily family, const Stmt *s) {

222 return RefState(Relinquished, s, family);

223 }

224 static RefState getEscaped(const RefState *RS) {

225 return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily());

226 }

227

228 void Profile(llvm::FoldingSetNodeID &ID) const {

229 ID.AddInteger(K);

230 ID.AddPointer(S);

231 Family.Profile(ID);

232 }

233

234 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {

235 switch (K) {

236#define CASE(ID) case ID: OS << #ID; break;

237 CASE(Allocated)

238 CASE(AllocatedOfSizeZero)

239 CASE(Released)

240 CASE(Relinquished)

241 CASE(Escaped)

242 }

243 }

244

245 LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }

246};

247

248}

249

251

252

254

255

256

257

260 AllocationFamily Family,

261 std::optional RetVal = std::nullopt);

262

263

264

265

266

267

268

269

271

272namespace {

273

274

275enum OwnershipAfterReallocKind {

276

277 OAR_ToBeFreedAfterFailure,

278

279 OAR_FreeOnFailure,

280

281

282

283

284

285

286

287 OAR_DoNotTrackAfterFailure

288};

289

290

291

292

293

294

295

296struct ReallocPair {

297

298

300 OwnershipAfterReallocKind Kind;

301

302 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)

303 : ReallocatedSym(S), Kind(K) {}

304 void Profile(llvm::FoldingSetNodeID &ID) const {

305 ID.AddInteger(Kind);

306 ID.AddPointer(ReallocatedSym);

307 }

308 bool operator==(const ReallocPair &X) const {

309 return ReallocatedSym == X.ReallocatedSym &&

311 }

312};

313

314}

315

317

320 if (Call.getDecl() || !isa(Call.getDecl()))

321 return false;

323}

324

327 if (Call.getDecl() || !isa(Call.getDecl()))

328 return false;

330}

331

332

333

336}

337

338

339

340

341

342namespace {

343

344class MallocChecker

345 : public Checker<check::DeadSymbols, check::PointerEscape,

346 check::ConstPointerEscape, check::PreStmt,

347 check::EndFunction, check::PreCall, check::PostCall,

348 eval::Call, check::NewAllocator,

349 check::PostStmt, check::PostObjCMessage,

350 check::Location, eval::Assume> {

351public:

352

353

354

355

356 bool ShouldIncludeOwnershipAnnotatedFunctions = false;

357

358 bool ShouldRegisterNoOwnershipChangeVisitor = false;

359

360

361

362 enum CheckKind {

363

364

365

366 CK_MallocChecker,

367 CK_NewDeleteChecker,

368 CK_NewDeleteLeaksChecker,

369 CK_MismatchedDeallocatorChecker,

370 CK_InnerPointerChecker,

371 CK_TaintedAllocChecker,

372 CK_NumCheckKinds

373 };

374

375 using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;

376

377 bool ChecksEnabled[CK_NumCheckKinds] = {false};

379

390 bool Assumption) const;

391 void checkLocation(SVal l, bool isLoad, const Stmt *S,

393

402

404 const char *NL, const char *Sep) const override;

405

406private:

407 mutable std::unique_ptr BT_DoubleFree[CK_NumCheckKinds];

408 mutable std::unique_ptr BT_DoubleDelete;

409 mutable std::unique_ptr BT_Leak[CK_NumCheckKinds];

410 mutable std::unique_ptr BT_UseFree[CK_NumCheckKinds];

411 mutable std::unique_ptr BT_BadFree[CK_NumCheckKinds];

412 mutable std::unique_ptr BT_FreeAlloca[CK_NumCheckKinds];

413 mutable std::unique_ptr BT_MismatchedDealloc;

414 mutable std::unique_ptr BT_OffsetFree[CK_NumCheckKinds];

415 mutable std::unique_ptr BT_UseZerroAllocated[CK_NumCheckKinds];

416 mutable std::unique_ptr BT_TaintedAlloc;

417

418#define CHECK_FN(NAME) \

419 void NAME(ProgramStateRef State, const CallEvent &Call, CheckerContext &C) \

420 const;

421

429 CHECK_FN(checkIfFreeNameIndex)

430 CHECK_FN(checkCXXNewOrCXXDelete)

439

442

443 using CheckFn =

444 std::function<void(const MallocChecker *, ProgramStateRef State,

446

448

449

450 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetdelim},

451 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetdelim},

452 };

453

455

456

457 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetdelim},

458 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::checkGetdelim},

459 };

460

462 {{CDM::CLibrary, {"free"}, 1}, &MallocChecker::checkFree},

463 {{CDM::CLibrary, {"if_freenameindex"}, 1},

464 &MallocChecker::checkIfFreeNameIndex},

465 {{CDM::CLibrary, {"kfree"}, 1}, &MallocChecker::checkFree},

466 {{CDM::CLibrary, {"g_free"}, 1}, &MallocChecker::checkFree},

467 };

468

470 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);

471 static bool isFreeingOwnershipAttrCall(const CallEvent &Call);

472 static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);

473 static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);

474

475 friend class NoMemOwnershipChangeVisitor;

476

478 {{CDM::CLibrary, {"alloca"}, 1}, &MallocChecker::checkAlloca},

479 {{CDM::CLibrary, {"_alloca"}, 1}, &MallocChecker::checkAlloca},

480

481

482

483 {{CDM::CLibrary, {"__builtin_alloca_with_align"}, 2},

484 &MallocChecker::checkAlloca},

485 };

486

488 {{CDM::CLibrary, {"malloc"}, 1}, &MallocChecker::checkBasicAlloc},

489 {{CDM::CLibrary, {"malloc"}, 3}, &MallocChecker::checkKernelMalloc},

490 {{CDM::CLibrary, {"calloc"}, 2}, &MallocChecker::checkCalloc},

491 {{CDM::CLibrary, {"valloc"}, 1}, &MallocChecker::checkBasicAlloc},

492 {{CDM::CLibrary, {"strndup"}, 2}, &MallocChecker::checkStrdup},

493 {{CDM::CLibrary, {"strdup"}, 1}, &MallocChecker::checkStrdup},

494 {{CDM::CLibrary, {"_strdup"}, 1}, &MallocChecker::checkStrdup},

495 {{CDM::CLibrary, {"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},

496 {{CDM::CLibrary, {"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},

497 {{CDM::CLibrary, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},

498 {{CDM::CLibrary, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},

499 {{CDM::CLibrary, {"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},

500 {{CDM::CLibrary, {"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},

501 {{CDM::CLibrary, {"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},

502 {{CDM::CLibrary, {"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},

503 {{CDM::CLibrary, {"g_memdup"}, 2}, &MallocChecker::checkGMemdup},

504 {{CDM::CLibrary, {"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},

505 {{CDM::CLibrary, {"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},

506 {{CDM::CLibrary, {"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},

507 {{CDM::CLibrary, {"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},

508 };

509

511 {{CDM::CLibrary, {"realloc"}, 2},

512 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},

513 {{CDM::CLibrary, {"reallocf"}, 2},

514 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)},

515 {{CDM::CLibrary, {"g_realloc"}, 2},

516 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},

517 {{CDM::CLibrary, {"g_try_realloc"}, 2},

518 std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)},

519 {{CDM::CLibrary, {"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},

520 {{CDM::CLibrary, {"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},

521 };

522

524 bool hasOwnershipReturns(const CallEvent &Call) const;

525 bool hasOwnershipTakesHolds(const CallEvent &Call) const;

528 AllocationFamily Family) const;

529

532 AllocationFamily Family) const;

533

534

535 mutable std::optional<uint64_t> KernelZeroFlagVal;

536

537 using KernelZeroSizePtrValueTy = std::optional;

538

539

540

541

542 mutable std::optional KernelZeroSizePtrValue;

543

544

545

548 AllocationFamily Family) const;

549

550

551

552

553

554

555

556

557

561 std::optional RetVal = std::nullopt);

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

582

583

584

585

586

587

588

592 bool isAlloca) const;

593

594

595

596

597

598

599

600

601

602

606

607

608

609

610

611

612

613

614

615

619 AllocationFamily Family) const;

620

621

622

623 [[nodiscard]] std::optional

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

646 const OwnershipAttr *Att,

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

670 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,

671 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

696 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,

697 AllocationFamily Family, bool ReturnsNullOnFailure = false,

698 std::optional ArgValOpt = {}) const;

699

700

701

702

703

704

705

706

707

708

709

710

711

712

716 bool SuffixWithN = false) const;

717

718

719

720

721

722

724 const Expr *Blocks,

725 const Expr *BlockBytes);

726

727

728

729

730

731

735

736

737

738 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,

740

741

743

744

745

747 const Stmt *S) const;

748

749

751

752

753

754

755

756

757

758

759

760

761

762 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,

764 SymbolRef &EscapingSymbol) const;

765

766

771 bool IsConstPointerEscape) const;

772

773

775

776

777

778

779

780 std::optional getCheckIfTracked(AllocationFamily Family,

781 bool IsALeakCheck = false) const;

782

784 bool IsALeakCheck = false) const;

785

786 static bool SummarizeValue(raw_ostream &os, SVal V);

787 static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);

788

790 const Expr *DeallocExpr,

791 AllocationFamily Family) const;

792

795

797 const Expr *DeallocExpr, const RefState *RS,

798 SymbolRef Sym, bool OwnershipTransferred) const;

799

801 const Expr *DeallocExpr, AllocationFamily Family,

802 const Expr *AllocExpr = nullptr) const;

803

806

809

811

814

816 const Expr *FreeExpr,

817 AllocationFamily Family) const;

818

819

820

823

825

826

828 SVal ArgVal) const;

829};

830}

831

832

833

834

835

836namespace {

838protected:

839

840

841

842

843

844

845

846 bool isFreeingCallAsWritten(const CallExpr &Call) const {

847 const auto *MallocChk = static_cast<const MallocChecker *>(&Checker);

848 if (MallocChk->FreeingMemFnMap.lookupAsWritten(Call) ||

849 MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))

850 return true;

851

852 if (const auto *Func =

853 llvm::dyn_cast_or_null(Call.getCalleeDecl()))

854 return MallocChecker::isFreeingOwnershipAttrCall(Func);

855

856 return false;

857 }

858

859 bool hasResourceStateChanged(ProgramStateRef CallEnterState,

861 return CallEnterState->get(Sym) !=

862 CallExitEndState->get(Sym);

863 }

864

865

866

867

868

869 bool doesFnIntendToHandleOwnership(const Decl *Callee,

871 const FunctionDecl *FD = dyn_cast(Callee);

872

873

874

875

876

877

878

879 if (!FD || !FD->hasBody())

880 return false;

882

888 return true;

889

890 if (const auto *Call = Match.getNodeAs<CallExpr>("call"))

891 if (isFreeingCallAsWritten(*Call))

892 return true;

893 }

894

895

896

897 return false;

898 }

899

902 N->getLocation(),

903 N->getState()->getStateManager().getContext().getSourceManager());

904 return std::make_shared(

905 L, "Returning without deallocating memory or storing the pointer for "

906 "later deallocation");

907 }

908

909public:

910 NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)

912

913 void Profile(llvm::FoldingSetNodeID &ID) const override {

914 static int Tag = 0;

915 ID.AddPointer(&Tag);

916 ID.AddPointer(Sym);

917 }

918};

919

920}

921

922

923

924

925

926namespace {

927

928

929

931protected:

932 enum NotificationMode { Normal, ReallocationFailed };

933

934

936

937

938 NotificationMode Mode;

939

940

942

943

944

946

947 bool IsLeak;

948

949public:

950 MallocBugVisitor(SymbolRef S, bool isLeak = false)

951 : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),

952 ReleaseFunctionLC(nullptr), IsLeak(isLeak) {}

953

954 static void *getTag() {

955 static int Tag = 0;

956 return &Tag;

957 }

958

959 void Profile(llvm::FoldingSetNodeID &ID) const override {

960 ID.AddPointer(getTag());

961 ID.AddPointer(Sym);

962 }

963

964

965 static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,

967 return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&

968 (RSCurr &&

969 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&

970 (!RSPrev ||

971 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));

972 }

973

974

975

976 static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,

978 bool IsReleased =

979 (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());

980 assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||

981 (Stmt && RSCurr->getAllocationFamily().Kind == AF_InnerBuffer));

982 return IsReleased;

983 }

984

985

986 static inline bool isRelinquished(const RefState *RSCurr,

987 const RefState *RSPrev, const Stmt *Stmt) {

988 return (

989 isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&

990 (RSCurr && RSCurr->isRelinquished()) &&

991 (!RSPrev || !RSPrev->isRelinquished()));

992 }

993

994

995

996

997

998 static inline bool hasReallocFailed(const RefState *RSCurr,

999 const RefState *RSPrev,

1001 return ((!isa_and_nonnull(Stmt)) &&

1002 (RSCurr &&

1003 (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&

1004 (RSPrev &&

1005 !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));

1006 }

1007

1011

1015 if (!IsLeak)

1016 return nullptr;

1017

1019

1020 return std::make_shared(L, BR.getDescription(),

1021 false);

1022 }

1023

1024private:

1025 class StackHintGeneratorForReallocationFailed

1027 public:

1028 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)

1030

1031 std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {

1032

1033 ++ArgIndex;

1034

1036 llvm::raw_svector_ostream os(buf);

1037

1038 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)

1039 << " parameter failed";

1040

1041 return std::string(os.str());

1042 }

1043

1044 std::string getMessageForReturn(const CallExpr *CallExpr) override {

1045 return "Reallocation of returned value failed";

1046 }

1047 };

1048};

1049}

1050

1051

1052

1054

1055namespace {

1056class StopTrackingCallback final : public SymbolVisitor {

1058

1059public:

1062

1064 state = state->remove(sym);

1065 return true;

1066 }

1067};

1068}

1069

1071 if (!FD)

1072 return false;

1073

1075 if (Kind != OO_New && Kind != OO_Array_New)

1076 return false;

1077

1078

1080

1081

1084}

1085

1087 if (!FD)

1088 return false;

1089

1091 if (Kind != OO_Delete && Kind != OO_Array_Delete)

1092 return false;

1093

1094 bool HasBody = FD->hasBody();

1095

1096

1098

1099

1100

1102 return L.isInvalid() || (!HasBody && SM.isInSystemHeader(L));

1103}

1104

1105

1106

1107

1108

1109bool MallocChecker::isFreeingOwnershipAttrCall(const CallEvent &Call) {

1110 const auto *Func = dyn_cast_or_null(Call.getDecl());

1111

1112 return Func && isFreeingOwnershipAttrCall(Func);

1113}

1114

1115bool MallocChecker::isFreeingOwnershipAttrCall(const FunctionDecl *Func) {

1116 if (Func->hasAttrs()) {

1117 for (const auto *I : Func->specific_attrs()) {

1118 OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();

1119 if (OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds)

1120 return true;

1121 }

1122 }

1123 return false;

1124}

1125

1126bool MallocChecker::isFreeingCall(const CallEvent &Call) const {

1127 if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))

1128 return true;

1129

1130 return isFreeingOwnershipAttrCall(Call);

1131}

1132

1133bool MallocChecker::isAllocatingOwnershipAttrCall(const CallEvent &Call) {

1134 const auto *Func = dyn_cast_or_null(Call.getDecl());

1135

1136 return Func && isAllocatingOwnershipAttrCall(Func);

1137}

1138

1139bool MallocChecker::isAllocatingOwnershipAttrCall(const FunctionDecl *Func) {

1140 for (const auto *I : Func->specific_attrs()) {

1141 if (I->getOwnKind() == OwnershipAttr::Returns)

1142 return true;

1143 }

1144

1145 return false;

1146}

1147

1148bool MallocChecker::isMemCall(const CallEvent &Call) const {

1149 if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) ||

1150 AllocaMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call))

1151 return true;

1152

1153 if (!ShouldIncludeOwnershipAnnotatedFunctions)

1154 return false;

1155

1156 const auto *Func = dyn_cast(Call.getDecl());

1157 return Func && Func->hasAttr();

1158}

1159

1160std::optional

1163

1164

1165

1166

1167

1168

1169

1170

1171

1172

1173

1174

1175

1176

1177

1178

1181

1182 if (!KernelZeroFlagVal) {

1183 switch (OS) {

1184 case llvm::Triple::FreeBSD:

1185 KernelZeroFlagVal = 0x0100;

1186 break;

1187 case llvm::Triple::NetBSD:

1188 KernelZeroFlagVal = 0x0002;

1189 break;

1190 case llvm::Triple::OpenBSD:

1191 KernelZeroFlagVal = 0x0008;

1192 break;

1193 case llvm::Triple::Linux:

1194

1195 KernelZeroFlagVal = 0x8000;

1196 break;

1197 default:

1198

1199

1200

1201

1202

1203 return std::nullopt;

1204 }

1205 }

1206

1207

1208

1209

1210 if (Call.getNumArgs() < 2)

1211 return std::nullopt;

1212

1213 const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);

1214 const SVal V = C.getSVal(FlagsEx);

1215 if (!isa(V)) {

1216

1217

1218 return std::nullopt;

1219 }

1220

1222 NonLoc ZeroFlag = C.getSValBuilder()

1223 .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())

1224 .castAs();

1225 SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,

1226 Flags, ZeroFlag,

1229 return std::nullopt;

1231

1232

1234 std::tie(TrueState, FalseState) = State->assume(MaskedFlags);

1235

1236

1237 if (TrueState && !FalseState) {

1238 SVal ZeroVal = C.getSValBuilder().makeZeroVal(Ctx.CharTy);

1239 return MallocMemAux(C, Call, Call.getArgExpr(0), ZeroVal, TrueState,

1240 AllocationFamily(AF_Malloc));

1241 }

1242

1243 return std::nullopt;

1244}

1245

1247 const Expr *BlockBytes) {

1249 SVal BlocksVal = C.getSVal(Blocks);

1250 SVal BlockBytesVal = C.getSVal(BlockBytes);

1252 SVal TotalSize = SB.evalBinOp(State, BO_Mul, BlocksVal, BlockBytesVal,

1254 return TotalSize;

1255}

1256

1257void MallocChecker::checkBasicAlloc(ProgramStateRef State,

1261 AllocationFamily(AF_Malloc));

1262 State = ProcessZeroAllocCheck(C, Call, 0, State);

1263 C.addTransition(State);

1264}

1265

1266void MallocChecker::checkKernelMalloc(ProgramStateRef State,

1269 std::optional MaybeState =

1270 performKernelMalloc(Call, C, State);

1271 if (MaybeState)

1272 State = *MaybeState;

1273 else

1275 AllocationFamily(AF_Malloc));

1276 C.addTransition(State);

1277}

1278

1280 const FunctionDecl *FD = dyn_cast(Call.getDecl());

1281 assert(FD);

1283

1287 AC.getSizeType();

1288}

1289

1291 const FunctionDecl *FD = dyn_cast(Call.getDecl());

1292 assert(FD);

1294

1298 AC.UnsignedLongTy;

1299}

1300

1303 bool ShouldFreeOnFail) const {

1304

1305

1306

1307

1308

1310 return;

1311

1312 State = ReallocMemAux(C, Call, ShouldFreeOnFail, State,

1313 AllocationFamily(AF_Malloc));

1314 State = ProcessZeroAllocCheck(C, Call, 1, State);

1315 C.addTransition(State);

1316}

1317

1320 State = CallocMem(C, Call, State);

1321 State = ProcessZeroAllocCheck(C, Call, 0, State);

1322 State = ProcessZeroAllocCheck(C, Call, 1, State);

1323 C.addTransition(State);

1324}

1325

1328 bool IsKnownToBeAllocatedMemory = false;

1329 if (suppressDeallocationsInSuspiciousContexts(Call, C))

1330 return;

1331 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,

1332 AllocationFamily(AF_Malloc));

1333 C.addTransition(State);

1334}

1335

1339 AllocationFamily(AF_Alloca));

1340 State = ProcessZeroAllocCheck(C, Call, 0, State);

1341 C.addTransition(State);

1342}

1343

1346 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());

1347 if (!CE)

1348 return;

1350 AllocationFamily(AF_Malloc));

1351

1352 C.addTransition(State);

1353}

1354

1355void MallocChecker::checkIfNameIndex(ProgramStateRef State,

1358

1359

1361 AllocationFamily(AF_IfNameIndex));

1362

1363 C.addTransition(State);

1364}

1365

1366void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,

1369 bool IsKnownToBeAllocatedMemory = false;

1370 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,

1371 AllocationFamily(AF_IfNameIndex));

1372 C.addTransition(State);

1373}

1374

1375void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,

1378 bool IsKnownToBeAllocatedMemory = false;

1379 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());

1380 if (!CE)

1381 return;

1382

1384

1385

1386

1387

1388

1391 case OO_New:

1392 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,

1393 AllocationFamily(AF_CXXNew));

1394 State = ProcessZeroAllocCheck(C, Call, 0, State);

1395 break;

1396 case OO_Array_New:

1397 State = MallocMemAux(C, Call, CE->getArg(0), UndefinedVal(), State,

1398 AllocationFamily(AF_CXXNewArray));

1399 State = ProcessZeroAllocCheck(C, Call, 0, State);

1400 break;

1401 case OO_Delete:

1402 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,

1403 AllocationFamily(AF_CXXNew));

1404 break;

1405 case OO_Array_Delete:

1406 State = FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocatedMemory,

1407 AllocationFamily(AF_CXXNewArray));

1408 break;

1409 default:

1410 assert(false && "not a new/delete operator");

1411 return;

1412 }

1413

1414 C.addTransition(State);

1415}

1416

1419 SValBuilder &svalBuilder = C.getSValBuilder();

1421 State = MallocMemAux(C, Call, Call.getArgExpr(0), zeroVal, State,

1422 AllocationFamily(AF_Malloc));

1423 State = ProcessZeroAllocCheck(C, Call, 0, State);

1424 C.addTransition(State);

1425}

1426

1430 AllocationFamily(AF_Malloc));

1431 State = ProcessZeroAllocCheck(C, Call, 1, State);

1432 C.addTransition(State);

1433}

1434

1438 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));

1439 State = MallocMemAux(C, Call, TotalSize, Init, State,

1440 AllocationFamily(AF_Malloc));

1441 State = ProcessZeroAllocCheck(C, Call, 0, State);

1442 State = ProcessZeroAllocCheck(C, Call, 1, State);

1443 C.addTransition(State);

1444}

1445

1450 SVal TotalSize = evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));

1451 State = MallocMemAux(C, Call, TotalSize, Init, State,

1452 AllocationFamily(AF_Malloc));

1453 State = ProcessZeroAllocCheck(C, Call, 0, State);

1454 State = ProcessZeroAllocCheck(C, Call, 1, State);

1455 C.addTransition(State);

1456}

1457

1459 const Decl *FD = Call.getDecl();

1460 assert(FD && "a CallDescription cannot match a call without a Decl");

1462}

1463

1466

1467

1469 return;

1470

1472 if (!LinePtr)

1473 return;

1474

1475

1476

1477

1478

1479 bool IsKnownToBeAllocated = false;

1480 State = FreeMemAux(C, Call.getArgExpr(0), Call, State, false,

1481 IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,

1482 LinePtr);

1483 if (State)

1484 C.addTransition(State);

1485}

1486

1489

1490

1492 return;

1493

1494

1495

1496 const CallExpr *CE = dyn_cast_or_null(Call.getOriginExpr());

1497 if (!CE)

1498 return;

1499

1500 const auto LinePtr =

1502 const auto Size =

1504 if (!LinePtr || !Size || !LinePtr->getAsRegion())

1505 return;

1506

1507 State = setDynamicExtent(State, LinePtr->getAsRegion(), *Size);

1509 AllocationFamily(AF_Malloc), *LinePtr));

1510}

1511

1514 State = ReallocMemAux(C, Call, false, State,

1515 AllocationFamily(AF_Malloc),

1516 true);

1517 State = ProcessZeroAllocCheck(C, Call, 1, State);

1518 State = ProcessZeroAllocCheck(C, Call, 2, State);

1519 C.addTransition(State);

1520}

1521

1522void MallocChecker::checkOwnershipAttr(ProgramStateRef State,

1525 const auto *CE = dyn_cast_or_null(Call.getOriginExpr());

1526 if (!CE)

1527 return;

1529 if (!FD)

1530 return;

1531 if (ShouldIncludeOwnershipAnnotatedFunctions ||

1532 ChecksEnabled[CK_MismatchedDeallocatorChecker]) {

1533

1534

1536 for (const auto *I : FD->specific_attrs()) {

1537 switch (I->getOwnKind()) {

1538 case OwnershipAttr::Returns:

1539 State = MallocMemReturnsAttr(C, Call, I, State);

1540 break;

1541 case OwnershipAttr::Takes:

1542 case OwnershipAttr::Holds:

1543 State = FreeMemAttr(C, Call, I, State);

1544 break;

1545 }

1546 }

1547 }

1548 C.addTransition(State);

1549}

1550

1552 if (Call.getOriginExpr())

1553 return false;

1554

1556

1557 if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) {

1558 (*Callback)(this, State, Call, C);

1559 return true;

1560 }

1561

1562 if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) {

1563 State = MallocBindRetVal(C, Call, State, false);

1564 (*Callback)(this, State, Call, C);

1565 return true;

1566 }

1567

1568 if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) {

1569 State = MallocBindRetVal(C, Call, State, false);

1570 (*Callback)(this, State, Call, C);

1571 return true;

1572 }

1573

1575 State = MallocBindRetVal(C, Call, State, false);

1576 checkCXXNewOrCXXDelete(State, Call, C);

1577 return true;

1578 }

1579

1581 checkCXXNewOrCXXDelete(State, Call, C);

1582 return true;

1583 }

1584

1585 if (const CheckFn *Callback = AllocaMemFnMap.lookup(Call)) {

1586 State = MallocBindRetVal(C, Call, State, true);

1587 (*Callback)(this, State, Call, C);

1588 return true;

1589 }

1590

1591 if (isFreeingOwnershipAttrCall(Call)) {

1592 checkOwnershipAttr(State, Call, C);

1593 return true;

1594 }

1595

1596 if (isAllocatingOwnershipAttrCall(Call)) {

1597 State = MallocBindRetVal(C, Call, State, false);

1598 checkOwnershipAttr(State, Call, C);

1599 return true;

1600 }

1601

1602 return false;

1603}

1604

1605

1609 if (!State)

1610 return nullptr;

1611

1612 const Expr *Arg = nullptr;

1613

1614 if (const CallExpr *CE = dyn_cast(Call.getOriginExpr())) {

1615 Arg = CE->getArg(IndexOfSizeArg);

1617 dyn_cast(Call.getOriginExpr())) {

1618 if (NE->isArray()) {

1619 Arg = *NE->getArraySize();

1620 } else {

1621 return State;

1622 }

1623 } else {

1624 assert(false && "not a CallExpr or CXXNewExpr");

1625 return nullptr;

1626 }

1627

1628 if (!RetVal)

1629 RetVal = State->getSVal(Call.getOriginExpr(), C.getLocationContext());

1630

1631 assert(Arg);

1632

1633 auto DefArgVal =

1634 State->getSVal(Arg, Call.getLocationContext()).getAs<DefinedSVal>();

1635

1636 if (!DefArgVal)

1637 return State;

1638

1639

1641 SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();

1644

1645 std::tie(TrueState, FalseState) =

1646 State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));

1647

1648 if (TrueState && !FalseState) {

1649 SymbolRef Sym = RetVal->getAsLocSymbol();

1650 if (!Sym)

1651 return State;

1652

1653 const RefState *RS = State->get(Sym);

1654 if (RS) {

1655 if (RS->isAllocated())

1656 return TrueState->set(Sym,

1657 RefState::getAllocatedOfSizeZero(RS));

1658 else

1659 return State;

1660 } else {

1661

1662

1663

1664

1665 return TrueState->add(Sym);

1666 }

1667 }

1668

1669

1670 assert(FalseState);

1671 return FalseState;

1672}

1673

1676 while (!PointeeType.isNull()) {

1677 Result = PointeeType;

1678 PointeeType = PointeeType->getPointeeType();

1679 }

1680 return Result;

1681}

1682

1683

1684

1686

1687 const CXXConstructExpr *ConstructE = NE->getConstructExpr();

1688 if (!ConstructE)

1689 return false;

1690

1691 if (!NE->getAllocatedType()->getAsCXXRecordDecl())

1692 return false;

1693

1695

1696

1697 for (const auto *CtorParam : CtorD->parameters()) {

1698

1700 if (CtorParamPointeeT.isNull())

1701 continue;

1702

1704

1706 return true;

1707 }

1708

1709 return false;

1710}

1711

1715 AllocationFamily Family) const {

1717 return nullptr;

1718

1720 const ParentMap &PM = C.getLocationContext()->getParentMap();

1722

1723

1724

1725

1726

1728 return State;

1729

1730

1731

1732

1733

1735 if (Call.getOriginExpr()->isArray()) {

1736 if (auto SizeEx = NE->getArraySize())

1737 checkTaintedness(C, Call, C.getSVal(*SizeEx), State,

1738 AllocationFamily(AF_CXXNewArray));

1739 }

1740

1742 State = ProcessZeroAllocCheck(C, Call, 0, State, Target);

1743 return State;

1744}

1745

1748 if (C.wasInlined) {

1751 AllocationFamily(Call.getOriginExpr()->isArray() ? AF_CXXNewArray

1752 : AF_CXXNew));

1753 C.addTransition(State);

1754 }

1755}

1756

1758

1759

1760

1761

1762

1763 StringRef FirstSlot = Call.getSelector().getNameForSlot(0);

1764 return FirstSlot == "dataWithBytesNoCopy" ||

1765 FirstSlot == "initWithBytesNoCopy" ||

1766 FirstSlot == "initWithCharactersNoCopy";

1767}

1768

1771

1772

1773 for (unsigned i = 1; i < S.getNumArgs(); ++i)

1774 if (S.getNameForSlot(i) == "freeWhenDone")

1775 return Call.getArgSVal(i).isZeroConstant();

1776

1777 return std::nullopt;

1778}

1779

1782 if (C.wasInlined)

1783 return;

1784

1786 return;

1787

1789 if (!*FreeWhenDone)

1790 return;

1791

1792 if (Call.hasNonZeroCallbackArg())

1793 return;

1794

1795 bool IsKnownToBeAllocatedMemory;

1797 true, IsKnownToBeAllocatedMemory,

1798 AllocationFamily(AF_Malloc),

1799 true);

1800

1801 C.addTransition(State);

1802}

1803

1806 const OwnershipAttr *Att,

1808 if (!State)

1809 return nullptr;

1810

1811 auto attrClassName = Att->getModule()->getName();

1812 auto Family = AllocationFamily(AF_Custom, attrClassName);

1813

1814 if (!Att->args().empty()) {

1815 return MallocMemAux(C, Call,

1816 Call.getArgExpr(Att->args_begin()->getASTIndex()),

1818 }

1820}

1821

1825 bool isAlloca) const {

1826 const Expr *CE = Call.getOriginExpr();

1827

1828

1830 return nullptr;

1831

1832 unsigned Count = C.blockCount();

1834 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();

1837 return State->BindExpr(CE, C.getLocationContext(), RetVal);

1838}

1839

1844 AllocationFamily Family) const {

1845 if (!State)

1846 return nullptr;

1847

1848 assert(SizeEx);

1849 return MallocMemAux(C, Call, C.getSVal(SizeEx), Init, State, Family);

1850}

1851

1852void MallocChecker::reportTaintBug(StringRef Msg, ProgramStateRef State,

1855 AllocationFamily Family) const {

1856 if (ExplodedNode *N = C.generateNonFatalErrorNode(State, this)) {

1857 if (!BT_TaintedAlloc)

1858 BT_TaintedAlloc.reset(new BugType(CheckNames[CK_TaintedAllocChecker],

1859 "Tainted Memory Allocation",

1861 auto R = std::make_unique(*BT_TaintedAlloc, Msg, N);

1862 for (auto TaintedSym : TaintedSyms) {

1863 R->markInteresting(TaintedSym);

1864 }

1865 C.emitReport(std::move(R));

1866 }

1867}

1868

1871 AllocationFamily Family) const {

1872 if (!ChecksEnabled[CK_TaintedAllocChecker])

1873 return;

1874 std::vector TaintedSyms =

1876 if (TaintedSyms.empty())

1877 return;

1878

1882

1883

1885 const llvm::APSInt MaxValInt = BVF.getMaxValue(SizeTy);

1888 std::optional SizeNL = SizeSVal.getAs<NonLoc>();

1889 auto Cmp = SVB.evalBinOpNN(State, BO_GE, *SizeNL, MaxLength, CmpTy)

1891 if (!Cmp)

1892 return;

1893 auto [StateTooLarge, StateNotTooLarge] = State->assume(*Cmp);

1894 if (!StateTooLarge && StateNotTooLarge) {

1895

1896 return;

1897 }

1898

1899 std::string Callee = "Memory allocation function";

1900 if (Call.getCalleeIdentifier())

1901 Callee = Call.getCalleeIdentifier()->getName().str();

1902 reportTaintBug(

1903 Callee + " is called with a tainted (potentially attacker controlled) "

1904 "value. Make sure the value is bound checked.",

1905 State, C, TaintedSyms, Family);

1906}

1907

1911 AllocationFamily Family) const {

1912 if (!State)

1913 return nullptr;

1914

1915 const Expr *CE = Call.getOriginExpr();

1916

1917

1918

1920 "Allocation functions must return a pointer");

1921

1922 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();

1923 SVal RetVal = State->getSVal(CE, C.getLocationContext());

1924

1925

1926 State = State->bindDefaultInitial(RetVal, Init, LCtx);

1927

1928

1929 if (Size.isUndef())

1931

1932 checkTaintedness(C, Call, Size, State, AllocationFamily(AF_Malloc));

1933

1934

1937

1939}

1940

1943 AllocationFamily Family,

1944 std::optional RetVal) {

1945 if (!State)

1946 return nullptr;

1947

1948

1949 if (!RetVal)

1950 RetVal = State->getSVal(E, C.getLocationContext());

1951

1952

1953 if (!RetVal->getAs<Loc>())

1954 return nullptr;

1955

1956 SymbolRef Sym = RetVal->getAsLocSymbol();

1957

1958

1959

1960

1961

1962

1963 if (Sym)

1964 return State->set(Sym, RefState::getAllocated(Family, E));

1965

1966 return State;

1967}

1968

1971 const OwnershipAttr *Att,

1973 if (!State)

1974 return nullptr;

1975

1976 auto attrClassName = Att->getModule()->getName();

1977 auto Family = AllocationFamily(AF_Custom, attrClassName);

1978

1979 bool IsKnownToBeAllocated = false;

1980

1981 for (const auto &Arg : Att->args()) {

1983 FreeMemAux(C, Call, State, Arg.getASTIndex(),

1984 Att->getOwnKind() == OwnershipAttr::Holds,

1985 IsKnownToBeAllocated, Family);

1986 if (StateI)

1987 State = StateI;

1988 }

1989 return State;

1990}

1991

1995 bool Hold, bool &IsKnownToBeAllocated,

1996 AllocationFamily Family,

1997 bool ReturnsNullOnFailure) const {

1998 if (!State)

1999 return nullptr;

2000

2001 if (Call.getNumArgs() < (Num + 1))

2002 return nullptr;

2003

2004 return FreeMemAux(C, Call.getArgExpr(Num), Call, State, Hold,

2005 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);

2006}

2007

2008

2009

2012 const SymbolRef *Ret = State->get(Sym);

2013 if (Ret) {

2014 assert(*Ret && "We should not store the null return symbol");

2017 RetStatusSymbol = *Ret;

2019 }

2020 return false;

2021}

2022

2024 const Expr *E) {

2025 const CallExpr *CE = dyn_cast(E);

2026

2027 if (!CE)

2028 return;

2029

2031 if (!FD)

2032 return;

2033

2034

2035 for (const auto *I : FD->specific_attrs()) {

2036 if (I->getOwnKind() != OwnershipAttr::Takes)

2037 continue;

2038

2039 os << ", which takes ownership of '" << I->getModule()->getName() << '\'';

2040 break;

2041 }

2042}

2043

2045 if (const CallExpr *CE = dyn_cast(E)) {

2046

2047 const FunctionDecl *FD = CE->getDirectCallee();

2048 if (!FD)

2049 return false;

2050

2051 os << '\'' << *FD;

2052

2054 os << "()";

2055

2056 os << '\'';

2057 return true;

2058 }

2059

2060 if (const ObjCMessageExpr *Msg = dyn_cast(E)) {

2061 if (Msg->isInstanceMessage())

2062 os << "-";

2063 else

2064 os << "+";

2065 Msg->getSelector().print(os);

2066 return true;

2067 }

2068

2069 if (const CXXNewExpr *NE = dyn_cast(E)) {

2070 os << "'"

2072 << "'";

2073 return true;

2074 }

2075

2076 if (const CXXDeleteExpr *DE = dyn_cast(E)) {

2077 os << "'"

2078 << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())

2079 << "'";

2080 return true;

2081 }

2082

2083 return false;

2084}

2085

2087

2088 switch (Family.Kind) {

2089 case AF_Malloc:

2090 os << "'malloc()'";

2091 return;

2092 case AF_CXXNew:

2093 os << "'new'";

2094 return;

2095 case AF_CXXNewArray:

2096 os << "'new[]'";

2097 return;

2098 case AF_IfNameIndex:

2099 os << "'if_nameindex()'";

2100 return;

2101 case AF_InnerBuffer:

2102 os << "container-specific allocator";

2103 return;

2104 case AF_Custom:

2105 os << Family.CustomName.value();

2106 return;

2107 case AF_Alloca:

2108 case AF_None:

2109 assert(false && "not a deallocation expression");

2110 }

2111}

2112

2114 switch (Family.Kind) {

2115 case AF_Malloc:

2116 os << "'free()'";

2117 return;

2118 case AF_CXXNew:

2119 os << "'delete'";

2120 return;

2121 case AF_CXXNewArray:

2122 os << "'delete[]'";

2123 return;

2124 case AF_IfNameIndex:

2125 os << "'if_freenameindex()'";

2126 return;

2127 case AF_InnerBuffer:

2128 os << "container-specific deallocator";

2129 return;

2130 case AF_Custom:

2131 os << "function that takes ownership of '" << Family.CustomName.value()

2132 << "\'";

2133 return;

2134 case AF_Alloca:

2135 case AF_None:

2136 assert(false && "not a deallocation expression");

2137 }

2138}

2139

2143 bool Hold, bool &IsKnownToBeAllocated,

2144 AllocationFamily Family, bool ReturnsNullOnFailure,

2145 std::optional ArgValOpt) const {

2146

2147 if (!State)

2148 return nullptr;

2149

2150 SVal ArgVal = ArgValOpt.value_or(C.getSVal(ArgExpr));

2151 if (!isa(ArgVal))

2152 return nullptr;

2154

2155

2156 if (!isa(location))

2157 return nullptr;

2158

2159

2161 std::tie(notNullState, nullState) = State->assume(location);

2162 if (nullState && !notNullState)

2163 return nullptr;

2164

2165

2166

2168 return nullptr;

2169

2171 const Expr *ParentExpr = Call.getOriginExpr();

2172

2173

2174

2175

2176

2177

2178

2179

2180

2181

2182

2183

2184 if (!R) {

2185

2186

2187

2188

2189

2190 if (Family.Kind != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal))

2191 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,

2192 Family);

2193 return nullptr;

2194 }

2195

2197

2198

2199 if (isa(R)) {

2200 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,

2201 Family);

2202 return nullptr;

2203 }

2204

2206

2207

2208

2209 if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {

2210

2211

2212

2213

2214

2215 if (isa(R))

2217 else

2218 HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,

2219 Family);

2220

2221 return nullptr;

2222 }

2223

2225

2226

2227 if (!SrBase)

2228 return nullptr;

2229

2231 const RefState *RsBase = State->get(SymBase);

2232 SymbolRef PreviousRetStatusSymbol = nullptr;

2233

2234 IsKnownToBeAllocated =

2235 RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());

2236

2237 if (RsBase) {

2238

2239

2240 if (RsBase->getAllocationFamily().Kind == AF_Alloca) {

2242 return nullptr;

2243 }

2244

2245

2246 if ((RsBase->isReleased() || RsBase->isRelinquished()) &&

2248 HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),

2249 SymBase, PreviousRetStatusSymbol);

2250 return nullptr;

2251

2252

2253

2254 } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||

2255 RsBase->isEscaped()) {

2256

2257

2258 bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family;

2259 if (!DeallocMatchesAlloc) {

2260 HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr,

2261 RsBase, SymBase, Hold);

2262 return nullptr;

2263 }

2264

2265

2266

2268 if (Offset.isValid() &&

2269 !Offset.hasSymbolicOffset() &&

2270 Offset.getOffset() != 0) {

2271 const Expr *AllocExpr = cast(RsBase->getStmt());

2272 HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,

2273 Family, AllocExpr);

2274 return nullptr;

2275 }

2276 }

2277 }

2278

2280 HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,

2281 Family);

2282 return nullptr;

2283 }

2284

2285

2286 State = State->remove(SymBase);

2287

2288

2289

2290 if (ReturnsNullOnFailure) {

2291 SVal RetVal = C.getSVal(ParentExpr);

2293 if (RetStatusSymbol) {

2294 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);

2295 State = State->set(SymBase, RetStatusSymbol);

2296 }

2297 }

2298

2299

2300

2301

2302

2303 assert(!RsBase || (RsBase && RsBase->getAllocationFamily() == Family));

2304

2305

2306

2307

2308 State = State->invalidateRegions({location}, Call.getOriginExpr(),

2309 C.blockCount(), C.getLocationContext(),

2310 false,

2311 nullptr);

2312

2313

2314 if (Hold)

2315 return State->set(SymBase,

2316 RefState::getRelinquished(Family,

2317 ParentExpr));

2318

2319 return State->set(SymBase,

2320 RefState::getReleased(Family, ParentExpr));

2321}

2322

2323std::optionalMallocChecker::CheckKind

2324MallocChecker::getCheckIfTracked(AllocationFamily Family,

2325 bool IsALeakCheck) const {

2326 switch (Family.Kind) {

2327 case AF_Malloc:

2328 case AF_Alloca:

2329 case AF_Custom:

2330 case AF_IfNameIndex: {

2331 if (ChecksEnabled[CK_MallocChecker])

2332 return CK_MallocChecker;

2333 return std::nullopt;

2334 }

2335 case AF_CXXNew:

2336 case AF_CXXNewArray: {

2337 if (IsALeakCheck) {

2338 if (ChecksEnabled[CK_NewDeleteLeaksChecker])

2339 return CK_NewDeleteLeaksChecker;

2340 }

2341 else {

2342 if (ChecksEnabled[CK_NewDeleteChecker])

2343 return CK_NewDeleteChecker;

2344 }

2345 return std::nullopt;

2346 }

2347 case AF_InnerBuffer: {

2348 if (ChecksEnabled[CK_InnerPointerChecker])

2349 return CK_InnerPointerChecker;

2350 return std::nullopt;

2351 }

2352 case AF_None: {

2353 assert(false && "no family");

2354 return std::nullopt;

2355 }

2356 }

2357 assert(false && "unhandled family");

2358 return std::nullopt;

2359}

2360

2361std::optionalMallocChecker::CheckKind

2363 bool IsALeakCheck) const {

2364 if (C.getState()->contains(Sym))

2365 return CK_MallocChecker;

2366

2367 const RefState *RS = C.getState()->get(Sym);

2368 assert(RS);

2369 return getCheckIfTracked(RS->getAllocationFamily(), IsALeakCheck);

2370}

2371

2372bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {

2373 if (std::optionalnonloc::ConcreteInt IntVal =

2375 os << "an integer (" << IntVal->getValue() << ")";

2376 else if (std::optionalloc::ConcreteInt ConstAddr =

2378 os << "a constant address (" << ConstAddr->getValue() << ")";

2380 os << "the address of the label '" << Label->getLabel()->getName() << "'";

2381 else

2382 return false;

2383

2384 return true;

2385}

2386

2387bool MallocChecker::SummarizeRegion(raw_ostream &os,

2389 switch (MR->getKind()) {

2390 case MemRegion::FunctionCodeRegionKind: {

2391 const NamedDecl *FD = cast(MR)->getDecl();

2392 if (FD)

2393 os << "the address of the function '" << *FD << '\'';

2394 else

2395 os << "the address of a function";

2396 return true;

2397 }

2398 case MemRegion::BlockCodeRegionKind:

2399 os << "block text";

2400 return true;

2401 case MemRegion::BlockDataRegionKind:

2402

2403 os << "a block";

2404 return true;

2405 default: {

2407

2408 if (isa(MS)) {

2409 const VarRegion *VR = dyn_cast(MR);

2411 if (VR)

2413 else

2414 VD = nullptr;

2415

2416 if (VD)

2417 os << "the address of the local variable '" << VD->getName() << "'";

2418 else

2419 os << "the address of a local stack variable";

2420 return true;

2421 }

2422

2423 if (isa(MS)) {

2424 const VarRegion *VR = dyn_cast(MR);

2426 if (VR)

2428 else

2429 VD = nullptr;

2430

2431 if (VD)

2432 os << "the address of the parameter '" << VD->getName() << "'";

2433 else

2434 os << "the address of a parameter";

2435 return true;

2436 }

2437

2438 if (isa(MS)) {

2439 const VarRegion *VR = dyn_cast(MR);

2441 if (VR)

2443 else

2444 VD = nullptr;

2445

2446 if (VD) {

2448 os << "the address of the static variable '" << VD->getName() << "'";

2449 else

2450 os << "the address of the global variable '" << VD->getName() << "'";

2451 } else

2452 os << "the address of a global variable";

2453 return true;

2454 }

2455

2456 return false;

2457 }

2458 }

2459}

2460

2463 const Expr *DeallocExpr,

2464 AllocationFamily Family) const {

2465

2466 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2467 C.addSink();

2468 return;

2469 }

2470

2471 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);

2472 if (!CheckKind)

2473 return;

2474

2476 if (!BT_BadFree[*CheckKind])

2477 BT_BadFree[*CheckKind].reset(new BugType(

2479

2481 llvm::raw_svector_ostream os(buf);

2482

2484 while (const ElementRegion *ER = dyn_cast_or_null(MR))

2485 MR = ER->getSuperRegion();

2486

2487 os << "Argument to ";

2489 os << "deallocator";

2490

2491 os << " is ";

2492 bool Summarized = MR ? SummarizeRegion(os, MR)

2493 : SummarizeValue(os, ArgVal);

2494 if (Summarized)

2495 os << ", which is not memory allocated by ";

2496 else

2497 os << "not memory allocated by ";

2498

2500

2501 auto R = std::make_unique(*BT_BadFree[*CheckKind],

2502 os.str(), N);

2503 R->markInteresting(MR);

2504 R->addRange(Range);

2505 C.emitReport(std::move(R));

2506 }

2507}

2508

2511

2512 std::optionalMallocChecker::CheckKind CheckKind;

2513

2514 if (ChecksEnabled[CK_MallocChecker])

2515 CheckKind = CK_MallocChecker;

2516 else if (ChecksEnabled[CK_MismatchedDeallocatorChecker])

2517 CheckKind = CK_MismatchedDeallocatorChecker;

2518 else {

2519 C.addSink();

2520 return;

2521 }

2522

2524 if (!BT_FreeAlloca[*CheckKind])

2525 BT_FreeAlloca[*CheckKind].reset(new BugType(

2527

2528 auto R = std::make_unique(

2529 *BT_FreeAlloca[*CheckKind],

2530 "Memory allocated by 'alloca()' should not be deallocated", N);

2531 R->markInteresting(ArgVal.getAsRegion());

2532 R->addRange(Range);

2533 C.emitReport(std::move(R));

2534 }

2535}

2536

2537void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,

2539 const Expr *DeallocExpr,

2540 const RefState *RS, SymbolRef Sym,

2541 bool OwnershipTransferred) const {

2542

2543 if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) {

2544 C.addSink();

2545 return;

2546 }

2547

2549 if (!BT_MismatchedDealloc)

2550 BT_MismatchedDealloc.reset(

2551 new BugType(CheckNames[CK_MismatchedDeallocatorChecker],

2553

2555 llvm::raw_svector_ostream os(buf);

2556

2557 const Expr *AllocExpr = cast(RS->getStmt());

2559 llvm::raw_svector_ostream AllocOs(AllocBuf);

2561 llvm::raw_svector_ostream DeallocOs(DeallocBuf);

2562

2563 if (OwnershipTransferred) {

2565 os << DeallocOs.str() << " cannot";

2566 else

2567 os << "Cannot";

2568

2569 os << " take ownership of memory";

2570

2572 os << " allocated by " << AllocOs.str();

2573 } else {

2574 os << "Memory";

2576 os << " allocated by " << AllocOs.str();

2577

2578 os << " should be deallocated by ";

2580

2582 os << ", not " << DeallocOs.str();

2583

2585 }

2586

2587 auto R = std::make_unique(*BT_MismatchedDealloc,

2588 os.str(), N);

2589 R->markInteresting(Sym);

2590 R->addRange(Range);

2591 R->addVisitor(Sym);

2592 C.emitReport(std::move(R));

2593 }

2594}

2595

2598 AllocationFamily Family,

2599 const Expr *AllocExpr) const {

2600

2601 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2602 C.addSink();

2603 return;

2604 }

2605

2606 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);

2607 if (!CheckKind)

2608 return;

2609

2611 if (!N)

2612 return;

2613

2614 if (!BT_OffsetFree[*CheckKind])

2615 BT_OffsetFree[*CheckKind].reset(new BugType(

2617

2619 llvm::raw_svector_ostream os(buf);

2621 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);

2622

2624 assert(MR && "Only MemRegion based symbols can have offset free errors");

2625

2627 assert((Offset.isValid() &&

2628 !Offset.hasSymbolicOffset() &&

2629 Offset.getOffset() != 0) &&

2630 "Only symbols with a valid offset can have offset free errors");

2631

2632 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();

2633

2634 os << "Argument to ";

2636 os << "deallocator";

2637 os << " is offset by "

2638 << offsetBytes

2639 << " "

2640 << ((abs(offsetBytes) > 1) ? "bytes" : "byte")

2641 << " from the start of ";

2642 if (AllocExpr && printMemFnName(AllocNameOs, C, AllocExpr))

2643 os << "memory allocated by " << AllocNameOs.str();

2644 else

2645 os << "allocated memory";

2646

2647 auto R = std::make_unique(*BT_OffsetFree[*CheckKind],

2648 os.str(), N);

2650 R->addRange(Range);

2651 C.emitReport(std::move(R));

2652}

2653

2656

2657 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] &&

2658 !ChecksEnabled[CK_InnerPointerChecker]) {

2659 C.addSink();

2660 return;

2661 }

2662

2663 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);

2664 if (!CheckKind)

2665 return;

2666

2668 if (!BT_UseFree[*CheckKind])

2669 BT_UseFree[*CheckKind].reset(new BugType(

2671

2672 AllocationFamily AF =

2673 C.getState()->get(Sym)->getAllocationFamily();

2674

2675 auto R = std::make_unique(

2676 *BT_UseFree[*CheckKind],

2677 AF.Kind == AF_InnerBuffer

2678 ? "Inner pointer of container used after re/deallocation"

2679 : "Use of memory after it is freed",

2680 N);

2681

2682 R->markInteresting(Sym);

2683 R->addRange(Range);

2684 R->addVisitor(Sym);

2685

2686 if (AF.Kind == AF_InnerBuffer)

2688

2689 C.emitReport(std::move(R));

2690 }

2691}

2692

2696

2697 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2698 C.addSink();

2699 return;

2700 }

2701

2702 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);

2703 if (!CheckKind)

2704 return;

2705

2707 if (!BT_DoubleFree[*CheckKind])

2708 BT_DoubleFree[*CheckKind].reset(new BugType(

2710

2711 auto R = std::make_unique(

2712 *BT_DoubleFree[*CheckKind],

2713 (Released ? "Attempt to free released memory"

2714 : "Attempt to free non-owned memory"),

2715 N);

2716 R->addRange(Range);

2717 R->markInteresting(Sym);

2718 if (PrevSym)

2719 R->markInteresting(PrevSym);

2720 R->addVisitor(Sym);

2721 C.emitReport(std::move(R));

2722 }

2723}

2724

2726

2727 if (!ChecksEnabled[CK_NewDeleteChecker]) {

2728 C.addSink();

2729 return;

2730 }

2731

2732 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);

2733 if (!CheckKind)

2734 return;

2735

2737 if (!BT_DoubleDelete)

2738 BT_DoubleDelete.reset(new BugType(CheckNames[CK_NewDeleteChecker],

2739 "Double delete",

2741

2742 auto R = std::make_unique(

2743 *BT_DoubleDelete, "Attempt to delete released memory", N);

2744

2745 R->markInteresting(Sym);

2746 R->addVisitor(Sym);

2747 C.emitReport(std::move(R));

2748 }

2749}

2750

2753

2754 if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) {

2755 C.addSink();

2756 return;

2757 }

2758

2759 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(C, Sym);

2760

2761 if (!CheckKind)

2762 return;

2763

2765 if (!BT_UseZerroAllocated[*CheckKind])

2766 BT_UseZerroAllocated[*CheckKind].reset(

2767 new BugType(CheckNames[*CheckKind], "Use of zero allocated",

2769

2770 auto R = std::make_unique(

2771 *BT_UseZerroAllocated[*CheckKind],

2772 "Use of memory allocated with size zero", N);

2773

2774 R->addRange(Range);

2775 if (Sym) {

2776 R->markInteresting(Sym);

2777 R->addVisitor(Sym);

2778 }

2779 C.emitReport(std::move(R));

2780 }

2781}

2782

2783void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,

2785 const Expr *FreeExpr,

2786 AllocationFamily Family) const {

2787 if (!ChecksEnabled[CK_MallocChecker]) {

2788 C.addSink();

2789 return;

2790 }

2791

2792 std::optionalMallocChecker::CheckKind CheckKind = getCheckIfTracked(Family);

2793 if (!CheckKind)

2794 return;

2795

2797 if (!BT_BadFree[*CheckKind])

2798 BT_BadFree[*CheckKind].reset(new BugType(

2800

2802 llvm::raw_svector_ostream Os(Buf);

2803

2805 while (const ElementRegion *ER = dyn_cast_or_null(MR))

2806 MR = ER->getSuperRegion();

2807

2808 Os << "Argument to ";

2810 Os << "deallocator";

2811

2812 Os << " is a function pointer";

2813

2814 auto R = std::make_unique(*BT_BadFree[*CheckKind],

2815 Os.str(), N);

2816 R->markInteresting(MR);

2817 R->addRange(Range);

2818 C.emitReport(std::move(R));

2819 }

2820}

2821

2825 AllocationFamily Family, bool SuffixWithN) const {

2826 if (!State)

2827 return nullptr;

2828

2829 const CallExpr *CE = cast(Call.getOriginExpr());

2830

2831 if (SuffixWithN && CE->getNumArgs() < 3)

2832 return nullptr;

2834 return nullptr;

2835

2836 const Expr *arg0Expr = CE->getArg(0);

2837 SVal Arg0Val = C.getSVal(arg0Expr);

2838 if (!isa(Arg0Val))

2839 return nullptr;

2841

2842 SValBuilder &svalBuilder = C.getSValBuilder();

2843

2845 State, arg0Val, svalBuilder.makeNullWithType(arg0Expr->getType()));

2846

2847

2849

2850

2851 SVal TotalSize = C.getSVal(Arg1);

2852 if (SuffixWithN)

2853 TotalSize = evalMulForBufferSize(C, Arg1, CE->getArg(2));

2854 if (!isa(TotalSize))

2855 return nullptr;

2856

2857

2860 svalBuilder.makeIntValWithWidth(

2861 svalBuilder.getContext().getSizeType(), 0));

2862

2864 std::tie(StatePtrIsNull, StatePtrNotNull) = State->assume(PtrEQ);

2866 std::tie(StateSizeIsZero, StateSizeNotZero) = State->assume(SizeZero);

2867

2868

2869 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;

2870 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;

2871

2872

2873

2874 if (PrtIsNull && !SizeIsZero) {

2877 return stateMalloc;

2878 }

2879

2880

2881 if (PrtIsNull && SizeIsZero)

2882 return State;

2883

2884 assert(!PrtIsNull);

2885

2886 bool IsKnownToBeAllocated = false;

2887

2888

2889 if (SizeIsZero)

2890

2891

2892

2893

2895 C, Call, StateSizeIsZero, 0, false, IsKnownToBeAllocated, Family))

2896 return stateFree;

2897

2898

2900 FreeMemAux(C, Call, State, 0, false, IsKnownToBeAllocated, Family)) {

2901

2903 MallocMemAux(C, Call, TotalSize, UnknownVal(), stateFree, Family);

2904 if (!stateRealloc)

2905 return nullptr;

2906

2907 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;

2908 if (ShouldFreeOnFail)

2909 Kind = OAR_FreeOnFailure;

2910 else if (!IsKnownToBeAllocated)

2911 Kind = OAR_DoNotTrackAfterFailure;

2912

2913

2915 SVal RetVal = stateRealloc->getSVal(CE, C.getLocationContext());

2917 assert(FromPtr && ToPtr &&

2918 "By this point, FreeMemAux and MallocMemAux should have checked "

2919 "whether the argument or the return value is symbolic!");

2920

2921

2922

2923 stateRealloc = stateRealloc->set(ToPtr,

2924 ReallocPair(FromPtr, Kind));

2925

2926 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr);

2927 return stateRealloc;

2928 }

2929 return nullptr;

2930}

2931

2935 if (!State)

2936 return nullptr;

2937

2938 if (Call.getNumArgs() < 2)

2939 return nullptr;

2940

2941 SValBuilder &svalBuilder = C.getSValBuilder();

2943 SVal TotalSize =

2944 evalMulForBufferSize(C, Call.getArgExpr(0), Call.getArgExpr(1));

2945

2946 return MallocMemAux(C, Call, TotalSize, zeroVal, State,

2947 AllocationFamily(AF_Malloc));

2948}

2949

2950MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,

2954

2955

2957 const MemRegion *ReferenceRegion = nullptr;

2958

2959 while (N) {

2961 if (!State->get(Sym))

2962 break;

2963

2964

2965

2966 if (!ReferenceRegion) {

2967 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) {

2968 SVal Val = State->getSVal(MR);

2971

2972

2974 ReferenceRegion = MR;

2975 }

2976 }

2977 }

2978

2979

2980

2982 if (NContext == LeakContext ||

2984 AllocNode = N;

2986 }

2987

2988 return LeakInfo(AllocNode, ReferenceRegion);

2989}

2990

2993

2994 if (!ChecksEnabled[CK_MallocChecker] &&

2995 !ChecksEnabled[CK_NewDeleteLeaksChecker])

2996 return;

2997

2998 const RefState *RS = C.getState()->get(Sym);

2999 assert(RS && "cannot leak an untracked symbol");

3000 AllocationFamily Family = RS->getAllocationFamily();

3001

3002 if (Family.Kind == AF_Alloca)

3003 return;

3004

3005 std::optionalMallocChecker::CheckKind CheckKind =

3006 getCheckIfTracked(Family, true);

3007

3008 if (!CheckKind)

3009 return;

3010

3011 assert(N);

3012 if (!BT_Leak[*CheckKind]) {

3013

3014

3015

3016

3017

3018 BT_Leak[*CheckKind].reset(new BugType(CheckNames[*CheckKind], "Memory leak",

3020 true));

3021 }

3022

3023

3024

3025

3028 const MemRegion *Region = nullptr;

3029 std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);

3030

3032 if (AllocationStmt)

3034 C.getSourceManager(),

3036

3038 llvm::raw_svector_ostream os(buf);

3040 os << "Potential leak of memory pointed to by ";

3042 } else {

3043 os << "Potential memory leak";

3044 }

3045

3046 auto R = std::make_unique(

3047 *BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,

3049 R->markInteresting(Sym);

3050 R->addVisitor(Sym, true);

3051 if (ShouldRegisterNoOwnershipChangeVisitor)

3052 R->addVisitor(Sym, this);

3053 C.emitReport(std::move(R));

3054}

3055

3056void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,

3058{

3060 RegionStateTy OldRS = state->get();

3061 RegionStateTy::Factory &F = state->get_context();

3062

3063 RegionStateTy RS = OldRS;

3065 for (auto [Sym, State] : RS) {

3066 if (SymReaper.isDead(Sym)) {

3067 if (State.isAllocated() || State.isAllocatedOfSizeZero())

3068 Errors.push_back(Sym);

3069

3070 RS = F.remove(RS, Sym);

3071 }

3072 }

3073

3074 if (RS == OldRS) {

3075

3076 assert(state->get() ==

3077 C.getState()->get());

3078 assert(state->get() ==

3079 C.getState()->get());

3080 return;

3081 }

3082

3083

3084 ReallocPairsTy RP = state->get();

3085 for (auto [Sym, ReallocPair] : RP) {

3086 if (SymReaper.isDead(Sym) || SymReaper.isDead(ReallocPair.ReallocatedSym)) {

3087 state = state->remove(Sym);

3088 }

3089 }

3090

3091

3092 FreeReturnValueTy FR = state->get();

3093 for (auto [Sym, RetSym] : FR) {

3094 if (SymReaper.isDead(Sym) || SymReaper.isDead(RetSym)) {

3095 state = state->remove(Sym);

3096 }

3097 }

3098

3099

3101 if (!Errors.empty()) {

3103 N = C.generateNonFatalErrorNode(C.getState(), &Tag);

3104 if (N) {

3106 HandleLeak(Sym, N, C);

3107 }

3108 }

3109 }

3110

3111 C.addTransition(state->set(RS), N);

3112}

3113

3114void MallocChecker::checkPostCall(const CallEvent &Call,

3116 if (const auto *PostFN = PostFnMap.lookup(Call)) {

3117 (*PostFN)(this, C.getState(), Call, C);

3118 return;

3119 }

3120}

3121

3122void MallocChecker::checkPreCall(const CallEvent &Call,

3124

3125 if (const auto *DC = dyn_cast(&Call)) {

3127

3128 if (!ChecksEnabled[CK_NewDeleteChecker])

3130 checkUseAfterFree(Sym, C, DE->getArgument());

3131

3133 return;

3134

3136 bool IsKnownToBeAllocated;

3137 State = FreeMemAux(

3139 false, IsKnownToBeAllocated,

3140 AllocationFamily(DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew));

3141

3142 C.addTransition(State);

3143 return;

3144 }

3145

3146 if (const auto *DC = dyn_cast(&Call)) {

3147 SymbolRef Sym = DC->getCXXThisVal().getAsSymbol();

3148 if (!Sym || checkDoubleDelete(Sym, C))

3149 return;

3150 }

3151

3152

3153

3154 if (const auto *PreFN = PreFnMap.lookup(Call)) {

3155 (*PreFN)(this, C.getState(), Call, C);

3156 return;

3157 }

3158

3159

3162 if (!FD)

3163 return;

3164

3165 if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call))

3166 return;

3167 }

3168

3169

3171 SymbolRef Sym = CC->getCXXThisVal().getAsSymbol();

3172 if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr()))

3173 return;

3174 }

3175

3176

3177 for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {

3178 SVal ArgSVal = Call.getArgSVal(I);

3179 if (isa(ArgSVal)) {

3181 if (!Sym)

3182 continue;

3183 if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))

3184 return;

3185 }

3186 }

3187}

3188

3189void MallocChecker::checkPreStmt(const ReturnStmt *S,

3191 checkEscapeOnReturn(S, C);

3192}

3193

3194

3195

3196

3197void MallocChecker::checkEndFunction(const ReturnStmt *S,

3199 checkEscapeOnReturn(S, C);

3200}

3201

3202void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,

3204 if (!S)

3205 return;

3206

3207 const Expr *E = S->getRetValue();

3208 if (E)

3209 return;

3210

3211

3213 SVal RetVal = C.getSVal(E);

3215 if (!Sym)

3216

3217

3218

3220 if (isa<FieldRegion, ElementRegion>(MR))

3223 Sym = BMR->getSymbol();

3224

3225

3226 if (Sym)

3227 checkUseAfterFree(Sym, C, E);

3228}

3229

3230

3231

3232

3233void MallocChecker::checkPostStmt(const BlockExpr *BE,

3235

3236

3237

3239 return;

3240

3243 cast(C.getSVal(BE).getAsRegion());

3244

3246 if (ReferencedVars.empty())

3247 return;

3248

3251 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();

3252

3253 for (const auto &Var : ReferencedVars) {

3254 const VarRegion *VR = Var.getCapturedRegion();

3257 }

3258 Regions.push_back(VR);

3259 }

3260

3261 state =

3262 state->scanReachableSymbols(Regions).getState();

3263 C.addTransition(state);

3264}

3265

3267 assert(Sym);

3268 const RefState *RS = C.getState()->get(Sym);

3269 return (RS && RS->isReleased());

3270}

3271

3272bool MallocChecker::suppressDeallocationsInSuspiciousContexts(

3274 if (Call.getNumArgs() == 0)

3275 return false;

3276

3277 StringRef FunctionStr = "";

3278 if (const auto *FD = dyn_cast(C.getStackFrame()->getDecl()))

3280 if (Body->getBeginLoc().isValid())

3281 FunctionStr =

3283 {FD->getBeginLoc(), Body->getBeginLoc()}),

3284 C.getSourceManager(), C.getLangOpts());

3285

3286

3287 if (!FunctionStr.contains("__isl_"))

3288 return false;

3289

3291

3292 for (const Expr *Arg : cast(Call.getOriginExpr())->arguments())

3293 if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol())

3294 if (const RefState *RS = State->get(Sym))

3295 State = State->set(Sym, RefState::getEscaped(RS));

3296

3297 C.addTransition(State);

3298 return true;

3299}

3300

3302 const Stmt *S) const {

3303

3305 HandleUseAfterFree(C, S->getSourceRange(), Sym);

3306 return true;

3307 }

3308

3309 return false;

3310}

3311

3313 const Stmt *S) const {

3314 assert(Sym);

3315

3316 if (const RefState *RS = C.getState()->get(Sym)) {

3317 if (RS->isAllocatedOfSizeZero())

3318 HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym);

3319 }

3320 else if (C.getState()->contains(Sym)) {

3321 HandleUseZeroAlloc(C, S->getSourceRange(), Sym);

3322 }

3323}

3324

3326

3328 HandleDoubleDelete(C, Sym);

3329 return true;

3330 }

3331 return false;

3332}

3333

3334

3335void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,

3338 if (Sym) {

3339 checkUseAfterFree(Sym, C, S);

3340 checkUseZeroAllocated(Sym, C, S);

3341 }

3342}

3343

3344

3345

3348 bool Assumption) const {

3349 RegionStateTy RS = state->get();

3350 for (SymbolRef Sym : llvm::make_first_range(RS)) {

3351

3355 state = state->remove(Sym);

3356 }

3357

3358

3359

3360 ReallocPairsTy RP = state->get();

3361 for (auto [Sym, ReallocPair] : RP) {

3362

3366 continue;

3367

3368 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;

3369 if (const RefState *RS = state->get(ReallocSym)) {

3370 if (RS->isReleased()) {

3371 switch (ReallocPair.Kind) {

3372 case OAR_ToBeFreedAfterFailure:

3373 state = state->set(ReallocSym,

3374 RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));

3375 break;

3376 case OAR_DoNotTrackAfterFailure:

3377 state = state->remove(ReallocSym);

3378 break;

3379 default:

3380 assert(ReallocPair.Kind == OAR_FreeOnFailure);

3381 }

3382 }

3383 }

3384 state = state->remove(Sym);

3385 }

3386

3387 return state;

3388}

3389

3390bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(

3393 SymbolRef &EscapingSymbol) const {

3394 assert(Call);

3395 EscapingSymbol = nullptr;

3396

3397

3398

3399

3400

3401 if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))

3402 return true;

3403

3404

3406

3407

3408 if (Call->isInSystemHeader() || Call->argumentsMayEscape())

3409 return true;

3410

3411

3412

3414 return false;

3415

3416

3417

3418

3419

3421 return *FreeWhenDone;

3422

3423

3424

3425

3426

3427 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);

3428 if (FirstSlot.ends_with("NoCopy"))

3429 return true;

3430

3431

3432

3433

3434

3435 if (FirstSlot.starts_with("addPointer") ||

3436 FirstSlot.starts_with("insertPointer") ||

3437 FirstSlot.starts_with("replacePointer") ||

3438 FirstSlot == "valueWithPointer") {

3439 return true;

3440 }

3441

3442

3443

3444

3445 if (Msg->getMethodFamily() == OMF_init) {

3446 EscapingSymbol = Msg->getReceiverSVal().getAsSymbol();

3447 return true;

3448 }

3449

3450

3451

3452 return false;

3453 }

3454

3455

3456 const FunctionDecl *FD = cast(Call)->getDecl();

3457 if (!FD)

3458 return true;

3459

3460

3461

3462 if (isMemCall(*Call))

3463 return false;

3464

3465

3466 if (Call->isInSystemHeader())

3467 return true;

3468

3469

3471 if (!II)

3472 return true;

3473 StringRef FName = II->getName();

3474

3475

3476

3477 if (FName.ends_with("NoCopy")) {

3478

3479

3480

3481 for (unsigned i = 1; i < Call->getNumArgs(); ++i) {

3482 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts();

3483 if (const DeclRefExpr *DE = dyn_cast(ArgE)) {

3484 StringRef DeallocatorName = DE->getFoundDecl()->getName();

3485 if (DeallocatorName == "kCFAllocatorNull")

3486 return false;

3487 }

3488 }

3489 return true;

3490 }

3491

3492

3493

3494

3495

3496 if (FName == "funopen")

3497 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0))

3498 return false;

3499

3500

3501

3502

3503 if (FName == "setbuf" || FName =="setbuffer" ||

3504 FName == "setlinebuf" || FName == "setvbuf") {

3505 if (Call->getNumArgs() >= 1) {

3506 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();

3507 if (const DeclRefExpr *ArgDRE = dyn_cast(ArgE))

3508 if (const VarDecl *D = dyn_cast(ArgDRE->getDecl()))

3510 return true;

3511 }

3512 }

3513

3514

3515

3516

3517

3518

3519 if (FName == "CGBitmapContextCreate" ||

3520 FName == "CGBitmapContextCreateWithData" ||

3521 FName == "CVPixelBufferCreateWithBytes" ||

3522 FName == "CVPixelBufferCreateWithPlanarBytes" ||

3523 FName == "OSAtomicEnqueue") {

3524 return true;

3525 }

3526

3527 if (FName == "postEvent" &&

3529 return true;

3530 }

3531

3532 if (FName == "connectImpl" &&

3534 return true;

3535 }

3536

3537 if (FName == "singleShotImpl" &&

3539 return true;

3540 }

3541

3542

3543

3544

3545

3546 if (Call->argumentsMayEscape())

3547 return true;

3548

3549

3550

3551 return false;

3552}

3553

3558 return checkPointerEscapeAux(State, Escaped, Call, Kind,

3559 false);

3560}

3561

3566

3567 return checkPointerEscapeAux(State, Escaped, Call, Kind,

3568 true);

3569}

3570

3572 return (RS->getAllocationFamily().Kind == AF_CXXNewArray ||

3573 RS->getAllocationFamily().Kind == AF_CXXNew);

3574}

3575

3579 bool IsConstPointerEscape) const {

3580

3581

3582 SymbolRef EscapingSymbol = nullptr;

3584 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,

3585 EscapingSymbol) &&

3586 !EscapingSymbol) {

3587 return State;

3588 }

3589

3591 if (EscapingSymbol && EscapingSymbol != sym)

3592 continue;

3593

3594 if (const RefState *RS = State->get(sym))

3595 if (RS->isAllocated() || RS->isAllocatedOfSizeZero())

3597 State = State->set(sym, RefState::getEscaped(RS));

3598 }

3599 return State;

3600}

3601

3603 SVal ArgVal) const {

3604 if (!KernelZeroSizePtrValue)

3605 KernelZeroSizePtrValue =

3607

3608 const llvm::APSInt *ArgValKnown =

3609 C.getSValBuilder().getKnownValue(State, ArgVal);

3610 return ArgValKnown && *KernelZeroSizePtrValue &&

3611 ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue;

3612}

3613

3616 ReallocPairsTy currMap = currState->get();

3617 ReallocPairsTy prevMap = prevState->get();

3618

3619 for (const ReallocPairsTy::value_type &Pair : prevMap) {

3621 if (!currMap.lookup(sym))

3622 return sym;

3623 }

3624

3625 return nullptr;

3626}

3627

3630 StringRef N = II->getName();

3631 if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {

3632 if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||

3633 N.contains_insensitive("intrusive") ||

3634 N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {

3635 return true;

3636 }

3637 }

3638 }

3639 return false;

3640}

3641

3647

3648 const RefState *RSCurr = state->get(Sym);

3649 const RefState *RSPrev = statePrev->get(Sym);

3650

3652

3653

3654 if (!S && (!RSCurr || RSCurr->getAllocationFamily().Kind != AF_InnerBuffer))

3655 return nullptr;

3656

3658

3659

3660

3661

3662

3663

3664

3665

3666

3667 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||

3668 ReleaseFunctionLC->isParentOf(CurrentLC))) {

3669 if (const auto *AE = dyn_cast(S)) {

3670

3672 if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||

3673 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {

3675

3676

3677 return nullptr;

3678 }

3679 } else if (const auto *CE = dyn_cast(S)) {

3680

3681

3682 if (const auto *MD =

3683 dyn_cast_or_null(CE->getDirectCallee())) {

3685

3686

3689

3690

3691 return nullptr;

3692 }

3693 }

3694 }

3695 }

3696

3697

3698

3699

3700

3701 StringRef Msg;

3702 std::unique_ptr StackHint = nullptr;

3704 llvm::raw_svector_ostream OS(Buf);

3705

3706 if (Mode == Normal) {

3707 if (isAllocated(RSCurr, RSPrev, S)) {

3708 Msg = "Memory is allocated";

3709 StackHint = std::make_unique(

3710 Sym, "Returned allocated memory");

3711 } else if (isReleased(RSCurr, RSPrev, S)) {

3712 const auto Family = RSCurr->getAllocationFamily();

3713 switch (Family.Kind) {

3714 case AF_Alloca:

3715 case AF_Malloc:

3716 case AF_Custom:

3717 case AF_CXXNew:

3718 case AF_CXXNewArray:

3719 case AF_IfNameIndex:

3720 Msg = "Memory is released";

3721 StackHint = std::make_unique(

3722 Sym, "Returning; memory was released");

3723 break;

3724 case AF_InnerBuffer: {

3727 const auto *TypedRegion = cast(ObjRegion);

3729 OS << "Inner buffer of '" << ObjTy << "' ";

3730

3732 OS << "deallocated by call to destructor";

3733 StackHint = std::make_unique(

3734 Sym, "Returning; inner buffer was deallocated");

3735 } else {

3736 OS << "reallocated by call to '";

3737 const Stmt *S = RSCurr->getStmt();

3738 if (const auto *MemCallE = dyn_cast(S)) {

3739 OS << MemCallE->getMethodDecl()->getDeclName();

3740 } else if (const auto *OpCallE = dyn_cast(S)) {

3741 OS << OpCallE->getDirectCallee()->getDeclName();

3742 } else if (const auto *CallE = dyn_cast(S)) {

3745 CEMgr.getSimpleCall(CallE, state, CurrentLC, {nullptr, 0});

3746 if (const auto *D = dyn_cast_or_null(Call->getDecl()))

3747 OS << D->getDeclName();

3748 else

3749 OS << "unknown";

3750 }

3751 OS << "'";

3752 StackHint = std::make_unique(

3753 Sym, "Returning; inner buffer was reallocated");

3754 }

3755 Msg = OS.str();

3756 break;

3757 }

3758 case AF_None:

3759 assert(false && "Unhandled allocation family!");

3760 return nullptr;

3761 }

3762

3763

3764 assert(!ReleaseFunctionLC && "There should be only one release point");

3766

3767

3768

3769

3771 if (const auto *DD = dyn_cast(LC->getDecl())) {

3773

3774

3775

3777

3778

3779

3780 return nullptr;

3781 }

3782

3783

3784

3785

3786

3787

3788

3789

3790

3791

3792

3793

3794

3795

3796

3797

3798

3799

3800

3801

3802

3803

3804

3805

3806

3808 }

3809 }

3810

3811 } else if (isRelinquished(RSCurr, RSPrev, S)) {

3812 Msg = "Memory ownership is transferred";

3813 StackHint = std::make_unique(Sym, "");

3814 } else if (hasReallocFailed(RSCurr, RSPrev, S)) {

3815 Mode = ReallocationFailed;

3816 Msg = "Reallocation failed";

3817 StackHint = std::make_unique(

3818 Sym, "Reallocation failed");

3819

3821

3822 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) &&

3823 "We only support one failed realloc at a time.");

3825 FailedReallocSymbol = sym;

3826 }

3827 }

3828

3829

3830 } else if (Mode == ReallocationFailed) {

3831 assert(FailedReallocSymbol && "No symbol to look for.");

3832

3833

3834 if (!statePrev->get(FailedReallocSymbol)) {

3835

3836 Msg = "Attempt to reallocate memory";

3837 StackHint = std::make_unique(

3838 Sym, "Returned reallocated memory");

3839 FailedReallocSymbol = nullptr;

3841 }

3842 }

3843

3844 if (Msg.empty()) {

3845 assert(!StackHint);

3846 return nullptr;

3847 }

3848

3849 assert(StackHint);

3850

3851

3853 if (!S) {

3854 assert(RSCurr->getAllocationFamily().Kind == AF_InnerBuffer);

3856 if (!PostImplCall)

3857 return nullptr;

3860 } else {

3863 }

3864

3865 auto P = std::make_shared(Pos, Msg, true);

3867 return P;

3868}

3869

3870void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,

3871 const char *NL, const char *Sep) const {

3872

3873 RegionStateTy RS = State->get();

3874

3875 if (!RS.isEmpty()) {

3876 Out << Sep << "MallocChecker :" << NL;

3877 for (auto [Sym, Data] : RS) {

3878 const RefState *RefS = State->get(Sym);

3879 AllocationFamily Family = RefS->getAllocationFamily();

3880 std::optionalMallocChecker::CheckKind CheckKind =

3881 getCheckIfTracked(Family);

3882 if (!CheckKind)

3883 CheckKind = getCheckIfTracked(Family, true);

3884

3886 Out << " : ";

3887 Data.dump(Out);

3888 if (CheckKind)

3889 Out << " (" << CheckNames[*CheckKind].getName() << ")";

3890 Out << NL;

3891 }

3892 }

3893}

3894

3895namespace clang {

3896namespace ento {

3897namespace allocation_state {

3898

3901 AllocationFamily Family(AF_InnerBuffer);

3902 return State->set(Sym, RefState::getReleased(Family, Origin));

3903}

3904

3905}

3906}

3907}

3908

3909

3910

3912 MallocChecker *checker = mgr.getChecker();

3913 checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;

3914 checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =

3916}

3917

3918void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {

3920 checker->ShouldIncludeOwnershipAnnotatedFunctions =

3922 checker->ShouldRegisterNoOwnershipChangeVisitor =

3924 checker, "AddNoOwnershipChangeNotes");

3925}

3926

3927bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {

3928 return true;

3929}

3930

3931#define REGISTER_CHECKER(name) \

3932 void ento::register##name(CheckerManager &mgr) { \

3933 MallocChecker *checker = mgr.getChecker(); \

3934 checker->ChecksEnabled[MallocChecker::CK_##name] = true; \

3935 checker->CheckNames[MallocChecker::CK_##name] = \

3936 mgr.getCurrentCheckerName(); \

3937 } \

3938 \

3939 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }

3940

enum clang::sema::@1725::IndirectLocalPathEntry::EntryKind Kind

static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

Defines the C++ template declaration subclasses.

Defines the clang::Expr interface and subclasses for C++ expressions.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

llvm::MachO::Target Target

static bool isFromStdNamespace(const CallEvent &Call)

static bool isStandardNew(const FunctionDecl *FD)

#define REGISTER_CHECKER(name)

static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)

static QualType getDeepPointeeType(QualType T)

static bool isReleased(SymbolRef Sym, CheckerContext &C)

Check if the memory associated with this symbol was released.

static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)

Print expected name of an allocator based on the deallocator's family derived from the DeallocExpr.

static bool isStandardDelete(const FunctionDecl *FD)

static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)

static bool isStandardNewDelete(const T &FD)

Tells if the callee is one of the builtin new/delete operators, including placement operators and oth...

static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)

static bool isGRealloc(const CallEvent &Call)

static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)

Print expected name of a deallocator based on the allocator's family.

static bool isStandardRealloc(const CallEvent &Call)

static bool didPreviousFreeFail(ProgramStateRef State, SymbolRef Sym, SymbolRef &RetStatusSymbol)

Checks if the previous call to free on the given symbol failed - if free failed, returns true.

static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, AllocationFamily Family, std::optional< SVal > RetVal=std::nullopt)

Update the RefState to reflect the new memory allocation.

static bool printMemFnName(raw_ostream &os, CheckerContext &C, const Expr *E)

Print names of allocators and deallocators.

static void printOwnershipTakesList(raw_ostream &os, CheckerContext &C, const Expr *E)

static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)

static std::optional< bool > getFreeWhenDoneArg(const ObjCMethodCall &Call)

static bool checkIfNewOrNewArrayFamily(const RefState *RS)

#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)

Declares an immutable map of type NameTy, suitable for placement into the ProgramState.

#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)

Declares an immutable set of type NameTy, suitable for placement into the ProgramState.

static bool contains(const std::set< tok::TokenKind > &Terminators, const Token &Tok)

Defines the SourceManager interface.

__DEVICE__ long long abs(long long __n)

__device__ __2f16 float __ockl_bool s

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

SourceManager & getSourceManager()

CanQualType getSizeType() const

Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.

const TargetInfo & getTargetInfo() const

bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const

Interprets an option's string value as a boolean.

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

Represents a call to a C++ constructor.

CXXConstructorDecl * getConstructor() const

Get the constructor that this expression will (ultimately) call.

Represents a C++ constructor within a class.

Represents a delete expression for memory deallocation and destructor calls, e.g.

Represents a C++ destructor within a class.

const CXXRecordDecl * getParent() const

Return the parent of this method declaration, which is the class in which this method is defined.

Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".

Represents a C++ struct/union/class.

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

Expr * getArg(unsigned Arg)

getArg - Return the specified argument.

FunctionDecl * getDirectCallee()

If the callee is a FunctionDecl, return it. Otherwise return null.

unsigned getNumArgs() const

getNumArgs - Return the number of actual arguments to this call.

static CharSourceRange getTokenRange(SourceRange R)

DeclContext * getParent()

getParent - Returns the containing DeclContext.

A reference to a declared variable, function, enum, etc.

Decl - This represents one declaration (or definition), e.g.

bool isInStdNamespace() const

ASTContext & getASTContext() const LLVM_READONLY

llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const

SourceLocation getLocation() const

void print(raw_ostream &Out, unsigned Indentation=0, bool PrintInstantiation=false) const

virtual Decl * getCanonicalDecl()

Retrieves the "canonical" declaration of the given declaration.

SourceLocation getBeginLoc() const LLVM_READONLY

This represents one expression.

Represents a function declaration or definition.

const ParmVarDecl * getParamDecl(unsigned i) const

Stmt * getBody(const FunctionDecl *&Definition) const

Retrieve the body (definition) of the function.

ArrayRef< ParmVarDecl * > parameters() const

bool isOverloadedOperator() const

Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".

OverloadedOperatorKind getOverloadedOperator() const

getOverloadedOperator - Which C++ overloaded operator this function represents, if any.

QualType getDeclaredReturnType() const

Get the declared return type, which may differ from the actual return type if the return type is dedu...

bool hasBody(const FunctionDecl *&Definition) const

Returns true if the function has a body.

One of these records is kept for each identifier that is lexed.

StringRef getName() const

Return the actual identifier string.

static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)

Returns a string for the source that the range encompasses.

It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...

bool isParentOf(const LocationContext *LC) const

const Decl * getDecl() const

const LocationContext * getParent() const

It might return null.

const StackFrameContext * getStackFrame() const

This represents a decl that may have a name.

IdentifierInfo * getIdentifier() const

Get the identifier that names this declaration, if there is one.

StringRef getName() const

Get the name of identifier for this declaration as a StringRef.

std::string getQualifiedNameAsString() const

std::string getNameAsString() const

Get a human-readable name for the declaration, even if it is one of the special kinds of names (C++ c...

An expression that sends a message to the given Objective-C object or class.

bool isConsumedExpr(Expr *E) const

Represents a program point just after an implicit call event.

std::optional< T > getAs() const

Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...

A (possibly-)qualified type.

QualType getDesugaredType(const ASTContext &Context) const

Return the specified type with any "sugar" removed from the 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;.

Smart pointer class that efficiently represents Objective-C method names.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

bool isInSystemHeader(SourceLocation Loc) const

Returns if a SourceLocation is in a system header.

A trivial tuple used to represent a source range.

It represents a stack frame of the call stack (based on CallEvent).

Stmt - This represents one statement.

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

const llvm::Triple & getTriple() const

Returns the target triple of the primary target.

CXXRecordDecl * getAsCXXRecordDecl() const

Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...

bool isFunctionPointerType() const

QualType getPointeeType() const

If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.

Represents a variable declaration or definition.

bool isStaticLocal() const

Returns true if a variable with function scope is a static local variable.

Maps string IDs to AST nodes matched by parts of a matcher.

A record of the "type" of an APSInt, used for conversions.

Represents a call to any sort of function that might have a FunctionDecl.

APSIntPtr getMaxValue(const llvm::APSInt &v)

BlockDataRegion - A region that represents a block instance.

llvm::iterator_range< referenced_vars_iterator > referenced_vars() const

StringRef getDescription() const

A verbose warning message that is appropriate for displaying next to the source code that introduces ...

ProgramStateManager & getStateManager() const

const SourceManager & getSourceManager() const

BugReporterVisitors are used to add custom diagnostics along a path.

virtual void Profile(llvm::FoldingSetNodeID &ID) const =0

virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC, PathSensitiveBugReport &BR)=0

Return a diagnostic piece which should be associated with the given node.

virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, const ExplodedNode *N, PathSensitiveBugReport &BR)

Provide custom definition for the final diagnostic piece on the path - the piece, which is displayed ...

Represents the memory allocation call in a C++ new-expression.

Represents a non-static C++ member function call, no matter how it is written.

An immutable map from CallDescriptions to arbitrary data.

Represents an abstract call to a function or method along a particular path.

virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const

See CheckerManager::runCheckersForPrintState.

const AnalyzerOptions & getAnalyzerOptions() const

CHECKER * registerChecker(AT &&... Args)

Used to register checkers.

CheckerNameRef getCurrentCheckerName() const

This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...

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...

ElementRegion is used to represent both array elements and casts.

const ProgramStateRef & getState() const

pred_iterator pred_begin()

const Stmt * getStmtForDiagnostics() const

If the node's program point corresponds to a statement, retrieve that statement.

ProgramPoint getLocation() const

getLocation - Returns the edge associated with the given node.

const LocationContext * getLocationContext() const

ExplodedNode * getFirstPred()

static bool isLocType(QualType T)

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.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const

RegionOffset getAsOffset() const

Compute the offset within the top level memory object.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const

virtual void printPretty(raw_ostream &os) const

Print the region for use in diagnostics.

const RegionTy * getAs() const

virtual bool canPrintPretty() const

Returns true if this region can be printed in a user-friendly way.

MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...

Represents any expression that calls an Objective-C method.

static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)

Create a location for the beginning of the declaration.

static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)

Create a location corresponding to the given declaration.

void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)

Marks a symbol as interesting.

PathDiagnosticLocation getLocation() const override

The primary location of the bug report that points at the undesirable behavior in the code.

void addCallStackHint(PathDiagnosticPieceRef Piece, std::unique_ptr< StackHintGenerator > StackHint)

void markInvalid(const void *Tag, const void *Data)

Marks the current report as invalid, meaning that it is probably a false positive and should not be r...

CallEventManager & getCallEventManager()

A Range represents the closed range [from, to].

Represent a region's offset within the top level base region.

DefinedOrUnknownSVal makeZeroVal(QualType type)

Construct an SVal representing '0' for the specified type.

BasicValueFactory & getBasicValueFactory()

ASTContext & getContext()

nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)

virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0

Create a new value which represents a binary expression with two non- location operands.

QualType getConditionType() const

SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)

SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)

DefinedSVal getConjuredHeapSymbolVal(const Expr *E, const LocationContext *LCtx, unsigned Count)

Conjure a symbol representing heap allocated memory region.

loc::MemRegionVal getAllocaRegionVal(const Expr *E, const LocationContext *LCtx, unsigned Count)

Create an SVal representing the result of an alloca()-like call, that is, an AllocaRegion on the stac...

SVal - This represents a symbolic expression, which can be either an L-value or an R-value.

bool isUnknownOrUndef() const

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

SymbolRef getLocSymbolInBase() const

Get the symbol in the SVal or its base region.

T castAs() const

Convert to the specified SVal type, asserting that this SVal is of the desired type.

Constructs a Stack hint for the given symbol.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const

virtual void dumpToStream(raw_ostream &os) const

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.

virtual bool VisitSymbol(SymbolRef sym)=0

A visitor method invoked by ProgramStateManager::scanReachableSymbols.

SymbolicRegion - A special, "non-concrete" region.

SymbolRef getSymbol() const

It might return null.

TypedRegion - An abstract class representing regions that are typed.

const VarDecl * getDecl() const override=0

const StackFrameContext * getStackFrame() const

It might return null.

Value representing integer constant.

Defines the clang::TargetInfo interface.

__inline void unsigned int _2

const internal::VariadicDynCastAllOfMatcher< Stmt, CXXDeleteExpr > cxxDeleteExpr

Matches delete expressions.

const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr

Matches call expressions.

SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)

Returns the results of matching Matcher on Node.

internal::Matcher< T > findAll(const internal::Matcher< T > &Matcher)

Matches if the node or any descendant matches.

const internal::VariadicAllOfMatcher< Stmt > stmt

Matches statements.

const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf

Matches if any of the given matchers matches.

ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin)

std::unique_ptr< BugReporterVisitor > getInnerPointerBRVisitor(SymbolRef Sym)

This function provides an additional visitor that augments the bug report with information relevant t...

const MemRegion * getContainerObjRegion(ProgramStateRef State, SymbolRef Sym)

'Sym' represents a pointer to the inner buffer of a container object.

const char *const MemoryError

const char *const TaintedData

std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)

Returns the tainted Symbols for a given Statement and state.

PointerEscapeKind

Describes the different reasons a pointer escapes during analysis.

@ PSK_DirectEscapeOnCall

The pointer has been passed to a function call directly.

ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR, DefinedOrUnknownSVal Extent)

Set the dynamic extent Extent of the region MR.

void registerInnerPointerCheckerAux(CheckerManager &Mgr)

Register the part of MallocChecker connected to InnerPointerChecker.

llvm::DenseSet< SymbolRef > InvalidatedSymbols

std::optional< SVal > getPointeeVal(SVal PtrSVal, ProgramStateRef State)

std::optional< int > tryExpandAsInteger(StringRef Macro, const Preprocessor &PP)

Try to parse the value of a defined preprocessor macro.

std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef

bool NE(InterpState &S, CodePtr OpPC)

bool Zero(InterpState &S, CodePtr OpPC)

The JSON file list parser is used to communicate input to InstallAPI.

OverloadedOperatorKind

Enumeration specifying the different kinds of C++ overloaded operators.

bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)

bool operator!=(CanQual< T > x, CanQual< U > y)

const FunctionProtoType * T

const char * getOperatorSpelling(OverloadedOperatorKind Operator)

Retrieve the spelling of the given overloaded operator, without the preceding "operator" keyword.

@ Other

Other implicit parameter.