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

47

48

49

50

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

85#include "llvm/ADT/SmallVector.h"

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

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

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

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

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

91#include

92#include

93#include

94

95using namespace clang;

96using namespace ento;

97using namespace std::placeholders;

98

99

100

101

102

103

104

105

106namespace {

107

108

109enum AllocationFamilyKind {

110 AF_None,

111 AF_Malloc,

112 AF_CXXNew,

113 AF_CXXNewArray,

114 AF_IfNameIndex,

115 AF_Alloca,

116 AF_InnerBuffer,

117 AF_Custom,

118};

119

120struct AllocationFamily {

121 AllocationFamilyKind Kind;

122 std::optional CustomName;

123

124 explicit AllocationFamily(AllocationFamilyKind AKind,

125 std::optional Name = std::nullopt)

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

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

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

129

130

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

132 Kind = AF_Malloc;

133 CustomName = std::nullopt;

134 }

135 }

136

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

139 }

140

142 return !(*this == Other);

143 }

144

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

146 ID.AddInteger(Kind);

147

148 if (Kind == AF_Custom)

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

150 }

151};

152

153}

154

155

156

157

159

160

161

163

164

165

167

168

169

170

171

172namespace {

173

174class RefState {

175 enum Kind {

176

177 Allocated,

178

179 AllocatedOfSizeZero,

180

181 Released,

182

183

184 Relinquished,

185

186

187

188 Escaped

189 };

190

191 const Stmt *S;

192

193 Kind K;

194 AllocationFamily Family;

195

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

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

198 assert(family.Kind != AF_None);

199 }

200

201public:

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

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

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

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

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

207 AllocationFamily getAllocationFamily() const { return Family; }

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

209

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

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

212 }

213

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

215 return RefState(Allocated, s, family);

216 }

217 static RefState getAllocatedOfSizeZero(const RefState *RS) {

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

219 RS->getAllocationFamily());

220 }

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

222 return RefState(Released, s, family);

223 }

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

225 return RefState(Relinquished, s, family);

226 }

227 static RefState getEscaped(const RefState *RS) {

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

229 }

230

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

232 ID.AddInteger(K);

233 ID.AddPointer(S);

234 Family.Profile(ID);

235 }

236

237 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {

238 switch (K) {

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

240 CASE(Allocated)

241 CASE(AllocatedOfSizeZero)

242 CASE(Released)

243 CASE(Relinquished)

244 CASE(Escaped)

245 }

246 }

247

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

249};

250

251}

252

254

255

257

258

259

260

263 AllocationFamily Family,

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

265

266

267

268

269

270

271

272

274

275namespace {

276

277

278enum OwnershipAfterReallocKind {

279

280 OAR_ToBeFreedAfterFailure,

281

282 OAR_FreeOnFailure,

283

284

285

286

287

288

289

290 OAR_DoNotTrackAfterFailure

291};

292

293

294

295

296

297

298

299struct ReallocPair {

300

301

303 OwnershipAfterReallocKind Kind;

304

305 ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)

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

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

308 ID.AddInteger(Kind);

309 ID.AddPointer(ReallocatedSym);

310 }

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

312 return ReallocatedSym == X.ReallocatedSym &&

313 Kind == X.Kind;

314 }

315};

316

317}

318

320

327

334

335

336

340

341namespace {

342

343

344

345

346

347

348#define BUGTYPE_PROVIDER(NAME, DEF) \

349 struct NAME : virtual public CheckerFrontend { \

350 BugType NAME##Bug{this, DEF, categories::MemoryError}; \

351 };

352

354

356

357

358

359

360

362 true};

363};

364

371

372#undef BUGTYPE_PROVIDER

373

374template <typename... BT_PROVIDERS>

375struct DynMemFrontend : virtual public CheckerFrontend, public BT_PROVIDERS... {

376 template const T *getAs() const {

377 if constexpr (std::is_same_v<T, CheckerFrontend> ||

378 (std::is_same_v<T, BT_PROVIDERS> || ...))

379 return static_cast<const T *>(this);

380 return nullptr;

381 }

382};

383

384

385

386

387

388class MallocChecker

390 check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape,

391 check::PreStmt, check::EndFunction, check::PreCall,

392 check::PostCall, eval::Call, check::NewAllocator,

393 check::PostStmt, check::PostObjCMessage, check::Location,

394 eval::Assume> {

395public:

396

397

398

399

400 bool ShouldIncludeOwnershipAnnotatedFunctions = false;

401

402 bool ShouldRegisterNoOwnershipChangeVisitor = false;

403

404

405

406

407

408

409

410

411 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,

412 UseZeroAllocated>

413 MallocChecker;

414 DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>

415 NewDeleteChecker;

416 DynMemFrontend NewDeleteLeaksChecker;

417 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;

418 DynMemFrontend InnerPointerChecker;

419

420

421 CheckerFrontendWithBugType TaintedAllocChecker{"Tainted Memory Allocation",

423

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

425

426 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;

427 void checkPostCall(const CallEvent &Call, CheckerContext &C) const;

428 bool evalCall(const CallEvent &Call, CheckerContext &C) const;

429

431 handleSmartPointerConstructorArguments(const CallEvent &Call,

434 CheckerContext &C,

436 void checkNewAllocator(const CXXAllocatorCall &Call, CheckerContext &C) const;

437 void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;

438 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;

439 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;

440 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;

441 void checkEndFunction(const ReturnStmt *S, CheckerContext &C) const;

443 bool Assumption) const;

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

445 CheckerContext &C) const;

446

449 const CallEvent *Call,

453 const CallEvent *Call,

455

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

458

459 StringRef getDebugTag() const override { return "MallocChecker"; }

460

461private:

462#define CHECK_FN(NAME) \

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

464 const;

465

473 CHECK_FN(checkIfFreeNameIndex)

474 CHECK_FN(checkCXXNewOrCXXDelete)

479 CHECK_FN(preGetDelimOrGetLine)

480 CHECK_FN(checkGetDelimOrGetLine)

483

486

487 using CheckFn =

490

492

493

494 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},

495 {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},

496 };

497

498 const CallDescriptionMap PostFnMap{

499

500

501 {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},

502 {{CDM::CLibrary, {"getdelim"}, 4},

503 &MallocChecker::checkGetDelimOrGetLine},

504 };

505

506 const CallDescriptionMap FreeingMemFnMap{

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

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

509 &MallocChecker::checkIfFreeNameIndex},

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

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

512 };

513

514 bool isFreeingCall(const CallEvent &Call) const;

515 static bool isFreeingOwnershipAttrCall(const FunctionDecl *Func);

516 static bool isFreeingOwnershipAttrCall(const CallEvent &Call);

517 static bool isAllocatingOwnershipAttrCall(const FunctionDecl *Func);

518 static bool isAllocatingOwnershipAttrCall(const CallEvent &Call);

519

520 friend class NoMemOwnershipChangeVisitor;

521

522 CallDescriptionMap AllocaMemFnMap{

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

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

525

526

527

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

529 &MallocChecker::checkAlloca},

530 };

531

532 CallDescriptionMap AllocatingMemFnMap{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

553 };

554

555 CallDescriptionMap ReallocatingMemFnMap{

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

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

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

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

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

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

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

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

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

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

566 };

567

568 bool isMemCall(const CallEvent &Call) const;

569 bool hasOwnershipReturns(const CallEvent &Call) const;

570 bool hasOwnershipTakesHolds(const CallEvent &Call) const;

571 void reportTaintBug(StringRef Msg, ProgramStateRef State, CheckerContext &C,

572 llvm::ArrayRef TaintedSyms,

573 AllocationFamily Family) const;

574

575 void checkTaintedness(CheckerContext &C, const CallEvent &Call,

577 AllocationFamily Family) const;

578

579

580 mutable std::optional<uint64_t> KernelZeroFlagVal;

581

582 using KernelZeroSizePtrValueTy = std::optional;

583

584

585

586

587 mutable std::optional KernelZeroSizePtrValue;

588

589

590

592 processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,

593 AllocationFamily Family) const;

594

595

596

597

598

599

600

601

602

604 ProcessZeroAllocCheck(CheckerContext &C, const CallEvent &Call,

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

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

625 MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,

627

628

629

630

631

632

633

634 [[nodiscard]] ProgramStateRef MallocBindRetVal(CheckerContext &C,

635 const CallEvent &Call,

637 bool isAlloca) const;

638

639

640

641

642

643

644

645

646

647

649 MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,

651

652

653

654

655

656

657

658

659

660

661 [[nodiscard]] ProgramStateRef MallocMemAux(CheckerContext &C,

662 const CallEvent &Call, SVal Size,

664 AllocationFamily Family) const;

665

666

667

668 [[nodiscard]] std::optional

669 performKernelMalloc(const CallEvent &Call, CheckerContext &C,

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

690 const CallEvent &Call,

691 const OwnershipAttr *Att,

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

715 unsigned Num, bool Hold, bool &IsKnownToBeAllocated,

716 AllocationFamily Family, bool ReturnsNullOnFailure = false) const;

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

737

738

740 FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,

741 ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,

742 AllocationFamily Family, bool ReturnsNullOnFailure = false,

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

744

745

746

747

748

749

750

751

752

753

754

755

756

757

759 ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,

761 bool SuffixWithN = false) const;

762

763

764

765

766

767

768 [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,

769 const Expr *Blocks,

770 const Expr *BlockBytes);

771

772

773

774

775

776

778 const CallEvent &Call,

780

781

782

783 bool suppressDeallocationsInSuspiciousContexts(const CallEvent &Call,

784 CheckerContext &C) const;

785

786

787 bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;

788

789

790

791 void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,

792 const Stmt *S) const;

793

794

795

796

797

798

799

800

801

802

803

804 bool mayFreeAnyEscapedMemoryOrIsModeledExplicitly(const CallEvent *Call,

806 SymbolRef &EscapingSymbol) const;

807

808

813 bool IsConstPointerEscape) const;

814

815

816 void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;

817

818

819

820

821

822

823

824 template

825 const T *getRelevantFrontendAs(AllocationFamily Family) const;

826

827 template

828 const T *getRelevantFrontendAs(CheckerContext &C, SymbolRef Sym) const;

829

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

831 static bool SummarizeRegion(ProgramStateRef State, raw_ostream &os,

832 const MemRegion *MR);

833

834 void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range,

835 const Expr *DeallocExpr,

836 AllocationFamily Family) const;

837

838 void HandleFreeAlloca(CheckerContext &C, SVal ArgVal,

839 SourceRange Range) const;

840

841 void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range,

842 const Expr *DeallocExpr, const RefState *RS,

843 SymbolRef Sym, bool OwnershipTransferred) const;

844

845 void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,

846 const Expr *DeallocExpr, AllocationFamily Family,

847 const Expr *AllocExpr = nullptr) const;

848

849 void HandleUseAfterFree(CheckerContext &C, SourceRange Range,

851

852 void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released,

854

855 void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,

857

858 void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range,

859 const Expr *FreeExpr,

860 AllocationFamily Family) const;

861

862

863

864 static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,

865 CheckerContext &C);

866

867 void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;

868

869

870 bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,

871 SVal ArgVal) const;

872};

873}

874

875

876

877

878

879namespace {

880class NoMemOwnershipChangeVisitor final : public NoOwnershipChangeVisitor {

881protected:

882

883

884

885

886

887

888

889 bool isFreeingCallAsWritten(const CallExpr &Call) const {

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

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

892 MallocChk->ReallocatingMemFnMap.lookupAsWritten(Call))

893 return true;

894

895 if (const auto *Func =

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

897 return MallocChecker::isFreeingOwnershipAttrCall(Func);

898

899 return false;

900 }

901

902 bool hasResourceStateChanged(ProgramStateRef CallEnterState,

904 return CallEnterState->get(Sym) !=

905 CallExitEndState->get(Sym);

906 }

907

908

909

910

911

912 bool doesFnIntendToHandleOwnership(const Decl *Callee,

913 ASTContext &ACtx) final {

914 const FunctionDecl *FD = dyn_cast(Callee);

915

916

917

918

919

920

921

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

923 return false;

924 using namespace clang::ast_matchers;

925

929 for (BoundNodes Match : Matches) {

930 if (Match.getNodeAs("delete"))

931 return true;

932

933 if (const auto *Call = Match.getNodeAs("call"))

934 if (isFreeingCallAsWritten(*Call))

935 return true;

936 }

937

938

939

940 return false;

941 }

942

945 N->getLocation(),

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

947 return std::make_shared(

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

949 "later deallocation");

950 }

951

952public:

953 NoMemOwnershipChangeVisitor(SymbolRef Sym, const MallocChecker *Checker)

954 : NoOwnershipChangeVisitor(Sym, Checker) {}

955

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

957 static int Tag = 0;

958 ID.AddPointer(&Tag);

959 ID.AddPointer(Sym);

960 }

961};

962

963}

964

965

966

967

968

969namespace {

970

971

972

974protected:

975 enum NotificationMode { Normal, ReallocationFailed };

976

977

979

980

981 NotificationMode Mode;

982

983

985

986

987

988 const StackFrameContext *ReleaseFunctionLC;

989

990 bool IsLeak;

991

992public:

993 MallocBugVisitor(SymbolRef S, bool isLeak = false)

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

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

996

997 static void *getTag() {

998 static int Tag = 0;

999 return &Tag;

1000 }

1001

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

1003 ID.AddPointer(getTag());

1004 ID.AddPointer(Sym);

1005 }

1006

1007

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

1009 const Stmt *Stmt) {

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

1011 (RSCurr &&

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

1013 (!RSPrev ||

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

1015 }

1016

1017

1018

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

1020 const Stmt *Stmt) {

1021 bool IsReleased =

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

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

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

1025 return IsReleased;

1026 }

1027

1028

1029 static inline bool isRelinquished(const RefState *RSCurr,

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

1031 return (

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

1033 (RSCurr && RSCurr->isRelinquished()) &&

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

1035 }

1036

1037

1038

1039

1040

1041 static inline bool hasReallocFailed(const RefState *RSCurr,

1042 const RefState *RSPrev,

1043 const Stmt *Stmt) {

1044 return ((!isa_and_nonnull(Stmt)) &&

1045 (RSCurr &&

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

1047 (RSPrev &&

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

1049 }

1050

1052 BugReporterContext &BRC,

1053 PathSensitiveBugReport &BR) override;

1054

1056 const ExplodedNode *EndPathNode,

1057 PathSensitiveBugReport &BR) override {

1058 if (!IsLeak)

1059 return nullptr;

1060

1061 PathDiagnosticLocation L = BR.getLocation();

1062

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

1064 false);

1065 }

1066

1067private:

1068 class StackHintGeneratorForReallocationFailed

1069 : public StackHintGeneratorForSymbol {

1070 public:

1071 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)

1072 : StackHintGeneratorForSymbol(S, M) {}

1073

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

1075

1076 ++ArgIndex;

1077

1078 SmallString<200> buf;

1079 llvm::raw_svector_ostream os(buf);

1080

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

1082 << " parameter failed";

1083

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

1085 }

1086

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

1088 return "Reallocation of returned value failed";

1089 }

1090 };

1091};

1092}

1093

1094

1095

1097

1098namespace {

1099class StopTrackingCallback final : public SymbolVisitor {

1101

1102public:

1103 StopTrackingCallback(ProgramStateRef st) : state(std::move(st)) {}

1105

1106 bool VisitSymbol(SymbolRef sym) override {

1107 state = state->remove(sym);

1108 return true;

1109 }

1110};

1111

1112

1113

1114

1115

1116

1117

1118

1119

1120

1121

1122

1123

1124class EscapeTrackedCallback final : public SymbolVisitor {

1126

1127 explicit EscapeTrackedCallback(ProgramStateRef S) : State(std::move(S)) {}

1128

1129public:

1130 bool VisitSymbol(SymbolRef Sym) override {

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

1132 if (RS->isAllocated() || RS->isAllocatedOfSizeZero()) {

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

1134 }

1135 }

1136 return true;

1137 }

1138

1139

1141 EscapeTrackedRegionsReachableFrom(ArrayRef<const MemRegion *> Roots,

1143 if (Roots.empty())

1144 return State;

1145

1146

1147

1148 SmallVector<const MemRegion *, 10> Regions;

1149 EscapeTrackedCallback Visitor(State);

1150 for (const MemRegion *R : Roots) {

1151 Regions.push_back(R);

1152 }

1153 State->scanReachableSymbols(Regions, Visitor);

1154 return Visitor.State;

1155 }

1156

1157 friend class SymbolVisitor;

1158};

1159}

1160

1162 if (!FD)

1163 return false;

1164

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

1167 return false;

1168

1169

1171

1172

1175}

1176

1178 if (!FD)

1179 return false;

1180

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

1183 return false;

1184

1185 bool HasBody = FD->hasBody();

1186

1187

1189

1190

1191

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

1194}

1195

1196

1197

1198

1199

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

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

1202

1203 return Func && isFreeingOwnershipAttrCall(Func);

1204}

1205

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

1207 if (Func->hasAttrs()) {

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

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

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

1211 return true;

1212 }

1213 }

1214 return false;

1215}

1216

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

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

1219 return true;

1220

1221 return isFreeingOwnershipAttrCall(Call);

1222}

1223

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

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

1226

1227 return Func && isAllocatingOwnershipAttrCall(Func);

1228}

1229

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

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

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

1233 return true;

1234 }

1235

1236 return false;

1237}

1238

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

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

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

1242 return true;

1243

1244 if (!ShouldIncludeOwnershipAnnotatedFunctions)

1245 return false;

1246

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

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

1249}

1250

1251std::optional

1252MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,

1254

1255

1256

1257

1258

1259

1260

1261

1262

1263

1264

1265

1266

1267

1268

1269

1270 ASTContext &Ctx = C.getASTContext();

1272

1273 if (!KernelZeroFlagVal) {

1274 switch (OS) {

1275 case llvm::Triple::FreeBSD:

1276 KernelZeroFlagVal = 0x0100;

1277 break;

1278 case llvm::Triple::NetBSD:

1279 KernelZeroFlagVal = 0x0002;

1280 break;

1281 case llvm::Triple::OpenBSD:

1282 KernelZeroFlagVal = 0x0008;

1283 break;

1284 case llvm::Triple::Linux:

1285

1286 KernelZeroFlagVal = 0x8000;

1287 break;

1288 default:

1289

1290

1291

1292

1293

1294 return std::nullopt;

1295 }

1296 }

1297

1298

1299

1300

1301 if (Call.getNumArgs() < 2)

1302 return std::nullopt;

1303

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

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

1307

1308

1309 return std::nullopt;

1310 }

1311

1312 NonLoc Flags = V.castAs();

1313 NonLoc ZeroFlag = C.getSValBuilder()

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

1315 .castAs();

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

1317 Flags, ZeroFlag,

1319 if (MaskedFlagsUC.isUnknownOrUndef())

1320 return std::nullopt;

1321 DefinedSVal MaskedFlags = MaskedFlagsUC.castAs();

1322

1323

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

1326

1327

1328 if (TrueState && !FalseState) {

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

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

1331 AllocationFamily(AF_Malloc));

1332 }

1333

1334 return std::nullopt;

1335}

1336

1337SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,

1338 const Expr *BlockBytes) {

1339 SValBuilder &SB = C.getSValBuilder();

1340 SVal BlocksVal = C.getSVal(Blocks);

1341 SVal BlockBytesVal = C.getSVal(BlockBytes);

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

1345 return TotalSize;

1346}

1347

1348void MallocChecker::checkBasicAlloc(ProgramStateRef State,

1349 const CallEvent &Call,

1350 CheckerContext &C) const {

1351 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,

1352 AllocationFamily(AF_Malloc));

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

1354 C.addTransition(State);

1355}

1356

1357void MallocChecker::checkKernelMalloc(ProgramStateRef State,

1358 const CallEvent &Call,

1359 CheckerContext &C) const {

1360 std::optional MaybeState =

1361 performKernelMalloc(Call, C, State);

1362 if (MaybeState)

1363 State = *MaybeState;

1364 else

1365 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,

1366 AllocationFamily(AF_Malloc));

1367 C.addTransition(State);

1368}

1369

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

1372 assert(FD);

1377}

1378

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

1381 assert(FD);

1383

1387}

1388

1389void MallocChecker::checkRealloc(ProgramStateRef State, const CallEvent &Call,

1390 CheckerContext &C,

1391 bool ShouldFreeOnFail) const {

1392

1393

1394

1395

1396

1398 return;

1399

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

1401 AllocationFamily(AF_Malloc));

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

1403 C.addTransition(State);

1404}

1405

1406void MallocChecker::checkCalloc(ProgramStateRef State, const CallEvent &Call,

1407 CheckerContext &C) const {

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

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

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

1411 C.addTransition(State);

1412}

1413

1414void MallocChecker::checkFree(ProgramStateRef State, const CallEvent &Call,

1415 CheckerContext &C) const {

1416 bool IsKnownToBeAllocatedMemory = false;

1417 if (suppressDeallocationsInSuspiciousContexts(Call, C))

1418 return;

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

1420 AllocationFamily(AF_Malloc));

1421 C.addTransition(State);

1422}

1423

1424void MallocChecker::checkAlloca(ProgramStateRef State, const CallEvent &Call,

1425 CheckerContext &C) const {

1426 State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,

1427 AllocationFamily(AF_Alloca));

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

1429 C.addTransition(State);

1430}

1431

1432void MallocChecker::checkStrdup(ProgramStateRef State, const CallEvent &Call,

1433 CheckerContext &C) const {

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

1435 if (!CE)

1436 return;

1437 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,

1438 AllocationFamily(AF_Malloc));

1439

1440 C.addTransition(State);

1441}

1442

1443void MallocChecker::checkIfNameIndex(ProgramStateRef State,

1444 const CallEvent &Call,

1445 CheckerContext &C) const {

1446

1447

1448 State = MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State,

1449 AllocationFamily(AF_IfNameIndex));

1450

1451 C.addTransition(State);

1452}

1453

1454void MallocChecker::checkIfFreeNameIndex(ProgramStateRef State,

1455 const CallEvent &Call,

1456 CheckerContext &C) const {

1457 bool IsKnownToBeAllocatedMemory = false;

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

1459 AllocationFamily(AF_IfNameIndex));

1460 C.addTransition(State);

1461}

1462

1465

1466

1467

1470 return nullptr;

1472 if (BuffType.isNull() || !BuffType->isVoidPointerType())

1473 return nullptr;

1474 return CE->getArg(1);

1475}

1476

1477void MallocChecker::checkCXXNewOrCXXDelete(ProgramStateRef State,

1478 const CallEvent &Call,

1479 CheckerContext &C) const {

1480 bool IsKnownToBeAllocatedMemory = false;

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

1482 if (!CE)

1483 return;

1484

1486

1487

1488

1489

1490

1491 const FunctionDecl *FD = C.getCalleeDecl(CE);

1493

1494 auto RetVal = State->getSVal(BufArg, Call.getLocationContext());

1495 State = State->BindExpr(CE, C.getLocationContext(), RetVal);

1496 C.addTransition(State);

1497 return;

1498 }

1499

1501 case OO_New:

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

1503 AllocationFamily(AF_CXXNew));

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

1505 break;

1506 case OO_Array_New:

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

1508 AllocationFamily(AF_CXXNewArray));

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

1510 break;

1511 case OO_Delete:

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

1513 AllocationFamily(AF_CXXNew));

1514 break;

1515 case OO_Array_Delete:

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

1517 AllocationFamily(AF_CXXNewArray));

1518 break;

1519 default:

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

1521 return;

1522 }

1523

1524 C.addTransition(State);

1525}

1526

1527void MallocChecker::checkGMalloc0(ProgramStateRef State, const CallEvent &Call,

1528 CheckerContext &C) const {

1529 SValBuilder &svalBuilder = C.getSValBuilder();

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

1532 AllocationFamily(AF_Malloc));

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

1534 C.addTransition(State);

1535}

1536

1537void MallocChecker::checkGMemdup(ProgramStateRef State, const CallEvent &Call,

1538 CheckerContext &C) const {

1539 State = MallocMemAux(C, Call, Call.getArgExpr(1), UnknownVal(), State,

1540 AllocationFamily(AF_Malloc));

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

1542 C.addTransition(State);

1543}

1544

1545void MallocChecker::checkGMallocN(ProgramStateRef State, const CallEvent &Call,

1546 CheckerContext &C) const {

1547 SVal Init = UndefinedVal();

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

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

1550 AllocationFamily(AF_Malloc));

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

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

1553 C.addTransition(State);

1554}

1555

1556void MallocChecker::checkGMallocN0(ProgramStateRef State, const CallEvent &Call,

1557 CheckerContext &C) const {

1558 SValBuilder &SB = C.getSValBuilder();

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

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

1562 AllocationFamily(AF_Malloc));

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

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

1565 C.addTransition(State);

1566}

1567

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

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

1572}

1573

1574void MallocChecker::preGetDelimOrGetLine(ProgramStateRef State,

1575 const CallEvent &Call,

1576 CheckerContext &C) const {

1577

1578

1580 return;

1581

1583 if (!LinePtr)

1584 return;

1585

1586

1587

1588

1589

1590 bool IsKnownToBeAllocated = false;

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

1592 IsKnownToBeAllocated, AllocationFamily(AF_Malloc), false,

1593 LinePtr);

1594 if (State)

1595 C.addTransition(State);

1596}

1597

1598void MallocChecker::checkGetDelimOrGetLine(ProgramStateRef State,

1599 const CallEvent &Call,

1600 CheckerContext &C) const {

1601

1602

1604 return;

1605

1606

1607

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

1609 if (!CE)

1610 return;

1611

1612 const auto LinePtrOpt = getPointeeVal(Call.getArgSVal(0), State);

1614 if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||

1615 SizeOpt->isUnknownOrUndef())

1616 return;

1617

1618 const auto LinePtr = LinePtrOpt->getAs();

1619 const auto Size = SizeOpt->getAs();

1620 const MemRegion *LinePtrReg = LinePtr->getAsRegion();

1621 if (!LinePtrReg)

1622 return;

1623

1626 AllocationFamily(AF_Malloc), *LinePtr));

1627}

1628

1629void MallocChecker::checkReallocN(ProgramStateRef State, const CallEvent &Call,

1630 CheckerContext &C) const {

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

1632 AllocationFamily(AF_Malloc),

1633 true);

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

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

1636 C.addTransition(State);

1637}

1638

1639void MallocChecker::checkOwnershipAttr(ProgramStateRef State,

1640 const CallEvent &Call,

1641 CheckerContext &C) const {

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

1643 if (!CE)

1644 return;

1645 const FunctionDecl *FD = C.getCalleeDecl(CE);

1646 if (!FD)

1647 return;

1648 if (ShouldIncludeOwnershipAnnotatedFunctions ||

1649 MismatchedDeallocatorChecker.isEnabled()) {

1650

1651

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

1654 switch (I->getOwnKind()) {

1655 case OwnershipAttr::Returns:

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

1657 break;

1658 case OwnershipAttr::Takes:

1659 case OwnershipAttr::Holds:

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

1661 break;

1662 }

1663 }

1664 }

1665 C.addTransition(State);

1666}

1667

1668bool MallocChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {

1669 if (Call.getOriginExpr())

1670 return false;

1671

1673

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

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

1676 return true;

1677 }

1678

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

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

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

1682 return true;

1683 }

1684

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

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

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

1688 return true;

1689 }

1690

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

1693 checkCXXNewOrCXXDelete(State, Call, C);

1694 return true;

1695 }

1696

1698 checkCXXNewOrCXXDelete(State, Call, C);

1699 return true;

1700 }

1701

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

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

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

1705 return true;

1706 }

1707

1708 if (isFreeingOwnershipAttrCall(Call)) {

1709 checkOwnershipAttr(State, Call, C);

1710 return true;

1711 }

1712

1713 if (isAllocatingOwnershipAttrCall(Call)) {

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

1715 checkOwnershipAttr(State, Call, C);

1716 return true;

1717 }

1718

1719 return false;

1720}

1721

1722

1724 CheckerContext &C, const CallEvent &Call, const unsigned IndexOfSizeArg,

1726 if (!State)

1727 return nullptr;

1728

1729 const Expr *Arg = nullptr;

1730

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

1732 Arg = CE->getArg(IndexOfSizeArg);

1733 } else if (const CXXNewExpr *NE =

1734 dyn_cast(Call.getOriginExpr())) {

1735 if (NE->isArray()) {

1736 Arg = *NE->getArraySize();

1737 } else {

1738 return State;

1739 }

1740 } else {

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

1742 return nullptr;

1743 }

1744

1745 if (!RetVal)

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

1747

1748 assert(Arg);

1749

1750 auto DefArgVal =

1751 State->getSVal(Arg, Call.getLocationContext()).getAs();

1752

1753 if (!DefArgVal)

1754 return State;

1755

1756

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

1759 DefinedSVal Zero =

1761

1762 std::tie(TrueState, FalseState) =

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

1764

1765 if (TrueState && !FalseState) {

1766 SymbolRef Sym = RetVal->getAsLocSymbol();

1767 if (!Sym)

1768 return State;

1769

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

1771 if (RS) {

1772 if (RS->isAllocated())

1773 return TrueState->set(

1774 Sym, RefState::getAllocatedOfSizeZero(RS));

1775 return State;

1776 }

1777

1778

1779

1780

1781 return TrueState->add(Sym);

1782 }

1783

1784

1785 assert(FalseState);

1786 return FalseState;

1787}

1788

1790 QualType Result = T, PointeeType = T->getPointeeType();

1791 while (!PointeeType.isNull()) {

1792 Result = PointeeType;

1793 PointeeType = PointeeType->getPointeeType();

1794 }

1795 return Result;

1796}

1797

1798

1799

1801

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

1803 if (!ConstructE)

1804 return false;

1805

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

1807 return false;

1808

1810

1811

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

1813

1815 if (CtorParamPointeeT.isNull())

1816 continue;

1817

1819

1821 return true;

1822 }

1823

1824 return false;

1825}

1826

1828MallocChecker::processNewAllocation(const CXXAllocatorCall &Call,

1829 CheckerContext &C,

1830 AllocationFamily Family) const {

1832 return nullptr;

1833

1834 const CXXNewExpr *NE = Call.getOriginExpr();

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

1837

1838

1839

1840

1841

1843 return State;

1844

1845

1846

1847

1848

1849 SVal Target = Call.getObjectUnderConstruction();

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

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

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

1853 AllocationFamily(AF_CXXNewArray));

1854 }

1855

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

1858 return State;

1859}

1860

1861void MallocChecker::checkNewAllocator(const CXXAllocatorCall &Call,

1862 CheckerContext &C) const {

1863 if (C.wasInlined) {

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

1867 : AF_CXXNew));

1868 C.addTransition(State);

1869 }

1870}

1871

1873

1874

1875

1876

1877

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

1879 return FirstSlot == "dataWithBytesNoCopy" ||

1880 FirstSlot == "initWithBytesNoCopy" ||

1881 FirstSlot == "initWithCharactersNoCopy";

1882}

1883

1886

1887

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

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

1891

1892 return std::nullopt;

1893}

1894

1895void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,

1896 CheckerContext &C) const {

1897 if (C.wasInlined)

1898 return;

1899

1901 return;

1902

1904 if (!*FreeWhenDone)

1905 return;

1906

1907 if (Call.hasNonZeroCallbackArg())

1908 return;

1909

1910 bool IsKnownToBeAllocatedMemory;

1912 true, IsKnownToBeAllocatedMemory,

1913 AllocationFamily(AF_Malloc),

1914 true);

1915

1916 C.addTransition(State);

1917}

1918

1920MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,

1921 const OwnershipAttr *Att,

1923 if (!State)

1924 return nullptr;

1925

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

1927 auto Family = AllocationFamily(AF_Custom, attrClassName);

1928

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

1930 return MallocMemAux(C, Call,

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

1932 UnknownVal(), State, Family);

1933 }

1934 return MallocMemAux(C, Call, UnknownVal(), UnknownVal(), State, Family);

1935}

1936

1937ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,

1938 const CallEvent &Call,

1940 bool isAlloca) const {

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

1942

1943

1945 return nullptr;

1946

1947 unsigned Count = C.blockCount();

1948 SValBuilder &SVB = C.getSValBuilder();

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

1950 DefinedSVal RetVal =

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

1955}

1956

1957ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,

1958 const CallEvent &Call,

1959 const Expr *SizeEx, SVal Init,

1961 AllocationFamily Family) const {

1962 if (!State)

1963 return nullptr;

1964

1965 assert(SizeEx);

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

1967}

1968

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

1970 CheckerContext &C,

1971 llvm::ArrayRef TaintedSyms,

1972 AllocationFamily Family) const {

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

1974 auto R =

1975 std::make_unique(TaintedAllocChecker, Msg, N);

1976 for (const auto *TaintedSym : TaintedSyms) {

1977 R->markInteresting(TaintedSym);

1978 }

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

1980 }

1981}

1982

1983void MallocChecker::checkTaintedness(CheckerContext &C, const CallEvent &Call,

1985 AllocationFamily Family) const {

1986 if (!TaintedAllocChecker.isEnabled())

1987 return;

1988 std::vector TaintedSyms =

1990 if (TaintedSyms.empty())

1991 return;

1992

1993 SValBuilder &SVB = C.getSValBuilder();

1996

1997

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

2000 NonLoc MaxLength =

2001 SVB.makeIntVal(MaxValInt / APSIntType(MaxValInt).getValue(4));

2002 std::optional SizeNL = SizeSVal.getAs();

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

2004 .getAs();

2005 if (!Cmp)

2006 return;

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

2008 if (!StateTooLarge && StateNotTooLarge) {

2009

2010 return;

2011 }

2012

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

2014 if (Call.getCalleeIdentifier())

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

2016 reportTaintBug(

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

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

2019 State, C, TaintedSyms, Family);

2020}

2021

2022ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,

2023 const CallEvent &Call, SVal Size,

2025 AllocationFamily Family) const {

2026 if (!State)

2027 return nullptr;

2028

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

2030

2031

2032

2034 "Allocation functions must return a pointer");

2035

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

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

2038

2039

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

2041

2042

2043 if (Size.isUndef())

2044 Size = UnknownVal();

2045

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

2047

2048

2050 Size.castAs());

2051

2053}

2054

2057 AllocationFamily Family,

2058 std::optional RetVal) {

2059 if (!State)

2060 return nullptr;

2061

2062

2063 if (!RetVal)

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

2065

2066

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

2068 return nullptr;

2069

2070 SymbolRef Sym = RetVal->getAsLocSymbol();

2071

2072

2073

2074

2075

2076

2077 if (Sym)

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

2079

2080 return State;

2081}

2082

2083ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,

2084 const CallEvent &Call,

2085 const OwnershipAttr *Att,

2087 if (!State)

2088 return nullptr;

2089

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

2091 auto Family = AllocationFamily(AF_Custom, attrClassName);

2092

2093 bool IsKnownToBeAllocated = false;

2094

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

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

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

2099 IsKnownToBeAllocated, Family);

2100 if (StateI)

2101 State = StateI;

2102 }

2103 return State;

2104}

2105

2107 const CallEvent &Call,

2109 bool Hold, bool &IsKnownToBeAllocated,

2110 AllocationFamily Family,

2111 bool ReturnsNullOnFailure) const {

2112 if (!State)

2113 return nullptr;

2114

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

2116 return nullptr;

2117

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

2119 IsKnownToBeAllocated, Family, ReturnsNullOnFailure);

2120}

2121

2122

2123

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

2127 if (Ret) {

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

2131 RetStatusSymbol = *Ret;

2133 }

2134 return false;

2135}

2136

2138 const Expr *E) {

2139 const CallExpr *CE = dyn_cast(E);

2140

2141 if (!CE)

2142 return;

2143

2145 if (!FD)

2146 return;

2147

2148

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

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

2151 continue;

2152

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

2154 break;

2155 }

2156}

2157

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

2160

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

2162 if (!FD)

2163 return false;

2164

2165 os << '\'' << *FD;

2166

2168 os << "()";

2169

2170 os << '\'';

2171 return true;

2172 }

2173

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

2175 if (Msg->isInstanceMessage())

2176 os << "-";

2177 else

2178 os << "+";

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

2180 return true;

2181 }

2182

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

2184 os << "'"

2186 << "'";

2187 return true;

2188 }

2189

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

2191 os << "'"

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

2193 << "'";

2194 return true;

2195 }

2196

2197 return false;

2198}

2199

2201

2202 switch (Family.Kind) {

2203 case AF_Malloc:

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

2205 return;

2206 case AF_CXXNew:

2207 os << "'new'";

2208 return;

2209 case AF_CXXNewArray:

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

2211 return;

2212 case AF_IfNameIndex:

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

2214 return;

2215 case AF_InnerBuffer:

2216 os << "container-specific allocator";

2217 return;

2218 case AF_Custom:

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

2220 return;

2221 case AF_Alloca:

2222 case AF_None:

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

2224 }

2225}

2226

2228 switch (Family.Kind) {

2229 case AF_Malloc:

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

2231 return;

2232 case AF_CXXNew:

2233 os << "'delete'";

2234 return;

2235 case AF_CXXNewArray:

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

2237 return;

2238 case AF_IfNameIndex:

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

2240 return;

2241 case AF_InnerBuffer:

2242 os << "container-specific deallocator";

2243 return;

2244 case AF_Custom:

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

2246 << "\'";

2247 return;

2248 case AF_Alloca:

2249 case AF_None:

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

2251 }

2252}

2253

2255MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,

2257 bool Hold, bool &IsKnownToBeAllocated,

2258 AllocationFamily Family, bool ReturnsNullOnFailure,

2259 std::optional ArgValOpt) const {

2260

2261 if (!State)

2262 return nullptr;

2263

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

2266 return nullptr;

2267 DefinedOrUnknownSVal location = ArgVal.castAs();

2268

2269

2271 return nullptr;

2272

2273

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

2276 if (nullState && !notNullState)

2277 return nullptr;

2278

2279

2280

2282 return nullptr;

2283

2284 const MemRegion *R = ArgVal.getAsRegion();

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

2286

2287

2288

2289

2290

2291

2292

2293

2294

2295

2296

2297

2298 if (!R) {

2299

2300

2301

2302

2303

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

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

2306 Family);

2307 return nullptr;

2308 }

2309

2311

2312

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

2315 Family);

2316 return nullptr;

2317 }

2318

2319

2320

2321 if (!R->hasMemorySpace<UnknownSpaceRegion, HeapSpaceRegion>(State)) {

2322

2323

2324

2325

2326

2329 else

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

2331 Family);

2332

2333 return nullptr;

2334 }

2335

2336 const SymbolicRegion *SrBase = dyn_cast(R->getBaseRegion());

2337

2338

2339 if (!SrBase)

2340 return nullptr;

2341

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

2344 SymbolRef PreviousRetStatusSymbol = nullptr;

2345

2346 IsKnownToBeAllocated =

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

2348

2349 if (RsBase) {

2350

2351

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

2354 return nullptr;

2355 }

2356

2357

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

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

2361 SymBase, PreviousRetStatusSymbol);

2362 return nullptr;

2363 }

2364

2365

2366

2367 if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||

2368 RsBase->isEscaped()) {

2369

2370

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

2372 if (!DeallocMatchesAlloc) {

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

2374 RsBase, SymBase, Hold);

2375 return nullptr;

2376 }

2377

2378

2379

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

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

2386 Family, AllocExpr);

2387 return nullptr;

2388 }

2389 }

2390 }

2391

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

2394 Family);

2395 return nullptr;

2396 }

2397

2398

2399 State = State->remove(SymBase);

2400

2401

2402

2403 if (ReturnsNullOnFailure) {

2404 SVal RetVal = C.getSVal(ParentExpr);

2406 if (RetStatusSymbol) {

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

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

2409 }

2410 }

2411

2412

2413

2414

2415

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

2417

2418

2419

2420

2421 State = State->invalidateRegions({location}, Call.getCFGElementRef(),

2422 C.blockCount(), C.getLocationContext(),

2423 false,

2424 nullptr);

2425

2426

2427 if (Hold)

2428 return State->set(SymBase,

2429 RefState::getRelinquished(Family,

2430 ParentExpr));

2431

2432 return State->set(SymBase,

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

2434}

2435

2436template

2437const T *MallocChecker::getRelevantFrontendAs(AllocationFamily Family) const {

2438 switch (Family.Kind) {

2439 case AF_Malloc:

2440 case AF_Alloca:

2441 case AF_Custom:

2442 case AF_IfNameIndex:

2443 return MallocChecker.getAs<T>();

2444 case AF_CXXNew:

2445 case AF_CXXNewArray: {

2446 const T *ND = NewDeleteChecker.getAs<T>();

2447 const T *NDL = NewDeleteLeaksChecker.getAs<T>();

2448

2449

2450 if constexpr (std::is_same_v<T, CheckerFrontend>) {

2451 assert(ND && NDL && "Casting to CheckerFrontend always succeeds");

2452

2453 return (!ND->isEnabled() && NDL->isEnabled()) ? NDL : ND;

2454 }

2455 assert(!(ND && NDL) &&

2456 "NewDelete and NewDeleteLeaks must not share a bug type");

2457 return ND ? ND : NDL;

2458 }

2459 case AF_InnerBuffer:

2460 return InnerPointerChecker.getAs<T>();

2461 case AF_None:

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

2463 return nullptr;

2464 }

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

2466 return nullptr;

2467}

2468template

2469const T *MallocChecker::getRelevantFrontendAs(CheckerContext &C,

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

2472 return MallocChecker.getAs<T>();

2473

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

2475 assert(RS);

2476 return getRelevantFrontendAs(RS->getAllocationFamily());

2477}

2478

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

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

2481 V.getAsnonloc::ConcreteInt())

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

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

2484 V.getAsloc::ConcreteInt())

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

2486 else if (std::optionalloc::GotoLabel Label = V.getAsloc::GotoLabel())

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

2488 else

2489 return false;

2490

2491 return true;

2492}

2493

2494bool MallocChecker::SummarizeRegion(ProgramStateRef State, raw_ostream &os,

2495 const MemRegion *MR) {

2496 switch (MR->getKind()) {

2497 case MemRegion::FunctionCodeRegionKind: {

2499 if (FD)

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

2501 else

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

2503 return true;

2504 }

2505 case MemRegion::BlockCodeRegionKind:

2506 os << "block text";

2507 return true;

2508 case MemRegion::BlockDataRegionKind:

2509

2510 os << "a block";

2511 return true;

2512 default: {

2513 const MemSpaceRegion *MS = MR->getMemorySpace(State);

2514

2516 const VarRegion *VR = dyn_cast(MR);

2517 const VarDecl *VD;

2518 if (VR)

2520 else

2521 VD = nullptr;

2522

2523 if (VD)

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

2525 else

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

2527 return true;

2528 }

2529

2531 const VarRegion *VR = dyn_cast(MR);

2532 const VarDecl *VD;

2533 if (VR)

2535 else

2536 VD = nullptr;

2537

2538 if (VD)

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

2540 else

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

2542 return true;

2543 }

2544

2546 const VarRegion *VR = dyn_cast(MR);

2547 const VarDecl *VD;

2548 if (VR)

2550 else

2551 VD = nullptr;

2552

2553 if (VD) {

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

2556 else

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

2558 } else

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

2560 return true;

2561 }

2562

2563 return false;

2564 }

2565 }

2566}

2567

2568void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,

2569 SourceRange Range,

2570 const Expr *DeallocExpr,

2571 AllocationFamily Family) const {

2572 const BadFree *Frontend = getRelevantFrontendAs(Family);

2573 if (!Frontend)

2574 return;

2575 if (!Frontend->isEnabled()) {

2576 C.addSink();

2577 return;

2578 }

2579

2580 if (ExplodedNode *N = C.generateErrorNode()) {

2581 SmallString<100> buf;

2582 llvm::raw_svector_ostream os(buf);

2583

2584 const MemRegion *MR = ArgVal.getAsRegion();

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

2586 MR = ER->getSuperRegion();

2587

2588 os << "Argument to ";

2590 os << "deallocator";

2591

2592 os << " is ";

2593 bool Summarized =

2594 MR ? SummarizeRegion(C.getState(), os, MR) : SummarizeValue(os, ArgVal);

2595 if (Summarized)

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

2597 else

2598 os << "not memory allocated by ";

2599

2601

2602 auto R = std::make_unique(Frontend->BadFreeBug,

2603 os.str(), N);

2604 R->markInteresting(MR);

2605 R->addRange(Range);

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

2607 }

2608}

2609

2610void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,

2611 SourceRange Range) const {

2612 const FreeAlloca *Frontend;

2613

2614 if (MallocChecker.isEnabled())

2615 Frontend = &MallocChecker;

2616 else if (MismatchedDeallocatorChecker.isEnabled())

2617 Frontend = &MismatchedDeallocatorChecker;

2618 else {

2619 C.addSink();

2620 return;

2621 }

2622

2623 if (ExplodedNode *N = C.generateErrorNode()) {

2624 auto R = std::make_unique(

2625 Frontend->FreeAllocaBug,

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

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

2628 R->addRange(Range);

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

2630 }

2631}

2632

2633void MallocChecker::HandleMismatchedDealloc(CheckerContext &C,

2634 SourceRange Range,

2635 const Expr *DeallocExpr,

2636 const RefState *RS, SymbolRef Sym,

2637 bool OwnershipTransferred) const {

2638 if (!MismatchedDeallocatorChecker.isEnabled()) {

2639 C.addSink();

2640 return;

2641 }

2642

2643 if (ExplodedNode *N = C.generateErrorNode()) {

2644 SmallString<100> buf;

2645 llvm::raw_svector_ostream os(buf);

2646

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

2648 SmallString<20> AllocBuf;

2649 llvm::raw_svector_ostream AllocOs(AllocBuf);

2650 SmallString<20> DeallocBuf;

2651 llvm::raw_svector_ostream DeallocOs(DeallocBuf);

2652

2653 if (OwnershipTransferred) {

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

2656 else

2657 os << "Cannot";

2658

2659 os << " take ownership of memory";

2660

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

2663 } else {

2664 os << "Memory";

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

2667

2668 os << " should be deallocated by ";

2670

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

2673

2675 }

2676

2677 auto R = std::make_unique(

2678 MismatchedDeallocatorChecker.MismatchedDeallocBug, os.str(), N);

2679 R->markInteresting(Sym);

2680 R->addRange(Range);

2681 R->addVisitor(Sym);

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

2683 }

2684}

2685

2686void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,

2687 SourceRange Range, const Expr *DeallocExpr,

2688 AllocationFamily Family,

2689 const Expr *AllocExpr) const {

2690 const OffsetFree *Frontend = getRelevantFrontendAs(Family);

2691 if (!Frontend)

2692 return;

2693 if (!Frontend->isEnabled()) {

2694 C.addSink();

2695 return;

2696 }

2697

2698 ExplodedNode *N = C.generateErrorNode();

2699 if (!N)

2700 return;

2701

2702 SmallString<100> buf;

2703 llvm::raw_svector_ostream os(buf);

2704 SmallString<20> AllocNameBuf;

2705 llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);

2706

2707 const MemRegion *MR = ArgVal.getAsRegion();

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

2709

2710 RegionOffset Offset = MR->getAsOffset();

2711 assert((Offset.isValid() &&

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

2715

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

2717

2718 os << "Argument to ";

2720 os << "deallocator";

2721 os << " is offset by "

2722 << offsetBytes

2723 << " "

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

2725 << " from the start of ";

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

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

2728 else

2729 os << "allocated memory";

2730

2731 auto R = std::make_unique(Frontend->OffsetFreeBug,

2732 os.str(), N);

2734 R->addRange(Range);

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

2736}

2737

2738void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,

2740 const UseFree *Frontend = getRelevantFrontendAs(C, Sym);

2741 if (!Frontend)

2742 return;

2743 if (!Frontend->isEnabled()) {

2744 C.addSink();

2745 return;

2746 }

2747

2748 if (ExplodedNode *N = C.generateErrorNode()) {

2749 AllocationFamily AF =

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

2751

2752 auto R = std::make_unique(

2753 Frontend->UseFreeBug,

2754 AF.Kind == AF_InnerBuffer

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

2756 : "Use of memory after it is released",

2757 N);

2758

2759 R->markInteresting(Sym);

2760 R->addRange(Range);

2761 R->addVisitor(Sym);

2762

2763 if (AF.Kind == AF_InnerBuffer)

2765

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

2767 }

2768}

2769

2770void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,

2773 const DoubleFree *Frontend = getRelevantFrontendAs(C, Sym);

2774 if (!Frontend)

2775 return;

2776 if (!Frontend->isEnabled()) {

2777 C.addSink();

2778 return;

2779 }

2780

2781 if (ExplodedNode *N = C.generateErrorNode()) {

2782 auto R = std::make_unique(

2783 Frontend->DoubleFreeBug,

2784 (Released ? "Attempt to release already released memory"

2785 : "Attempt to release non-owned memory"),

2786 N);

2787 if (Range.isValid())

2788 R->addRange(Range);

2789 R->markInteresting(Sym);

2790 if (PrevSym)

2791 R->markInteresting(PrevSym);

2792 R->addVisitor(Sym);

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

2794 }

2795}

2796

2797void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,

2799 const UseZeroAllocated *Frontend =

2800 getRelevantFrontendAs(C, Sym);

2801 if (!Frontend)

2802 return;

2803 if (!Frontend->isEnabled()) {

2804 C.addSink();

2805 return;

2806 }

2807

2808 if (ExplodedNode *N = C.generateErrorNode()) {

2809 auto R = std::make_unique(

2810 Frontend->UseZeroAllocatedBug, "Use of memory allocated with size zero",

2811 N);

2812

2813 R->addRange(Range);

2814 if (Sym) {

2815 R->markInteresting(Sym);

2816 R->addVisitor(Sym);

2817 }

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

2819 }

2820}

2821

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

2823 SourceRange Range,

2824 const Expr *FreeExpr,

2825 AllocationFamily Family) const {

2826 const BadFree *Frontend = getRelevantFrontendAs(Family);

2827 if (!Frontend)

2828 return;

2829 if (!Frontend->isEnabled()) {

2830 C.addSink();

2831 return;

2832 }

2833

2834 if (ExplodedNode *N = C.generateErrorNode()) {

2835 SmallString<100> Buf;

2836 llvm::raw_svector_ostream Os(Buf);

2837

2838 const MemRegion *MR = ArgVal.getAsRegion();

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

2840 MR = ER->getSuperRegion();

2841

2842 Os << "Argument to ";

2844 Os << "deallocator";

2845

2846 Os << " is a function pointer";

2847

2848 auto R = std::make_unique(Frontend->BadFreeBug,

2849 Os.str(), N);

2850 R->markInteresting(MR);

2851 R->addRange(Range);

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

2853 }

2854}

2855

2857MallocChecker::ReallocMemAux(CheckerContext &C, const CallEvent &Call,

2859 AllocationFamily Family, bool SuffixWithN) const {

2860 if (!State)

2861 return nullptr;

2862

2864

2866 return nullptr;

2867

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

2869 SVal Arg0Val = C.getSVal(arg0Expr);

2871 return nullptr;

2872 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs();

2873

2874 SValBuilder &svalBuilder = C.getSValBuilder();

2875

2876 DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(

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

2878

2879

2880 const Expr *Arg1 = CE->getArg(1);

2881

2882

2883 SVal TotalSize = C.getSVal(Arg1);

2884 if (SuffixWithN)

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

2887 return nullptr;

2888

2889

2890 DefinedOrUnknownSVal SizeZero = svalBuilder.evalEQ(

2891 State, TotalSize.castAs(),

2892 svalBuilder.makeIntValWithWidth(

2893 svalBuilder.getContext().getCanonicalSizeType(), 0));

2894

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

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

2899

2900

2901 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;

2902 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;

2903

2904

2905

2906 if (PrtIsNull && !SizeIsZero) {

2908 C, Call, TotalSize, UndefinedVal(), StatePtrIsNull, Family);

2909 return stateMalloc;

2910 }

2911

2912

2913 if (PrtIsNull && SizeIsZero)

2914 return State;

2915

2916 assert(!PrtIsNull);

2917

2918 bool IsKnownToBeAllocated = false;

2919

2920

2921 if (SizeIsZero)

2922

2923

2924

2925

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

2928 return stateFree;

2929

2930

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

2933

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

2936 if (!stateRealloc)

2937 return nullptr;

2938

2939 OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;

2940 if (ShouldFreeOnFail)

2941 Kind = OAR_FreeOnFailure;

2942 else if (!IsKnownToBeAllocated)

2943 Kind = OAR_DoNotTrackAfterFailure;

2944

2945

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

2949 assert(FromPtr && ToPtr &&

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

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

2952

2953

2954

2955 stateRealloc = stateRealloc->set(ToPtr,

2956 ReallocPair(FromPtr, Kind));

2957

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

2959 return stateRealloc;

2960 }

2961 return nullptr;

2962}

2963

2965 const CallEvent &Call,

2967 if (!State)

2968 return nullptr;

2969

2970 if (Call.getNumArgs() < 2)

2971 return nullptr;

2972

2973 SValBuilder &svalBuilder = C.getSValBuilder();

2975 SVal TotalSize =

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

2977

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

2979 AllocationFamily(AF_Malloc));

2980}

2981

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

2984 CheckerContext &C) {

2986

2987

2988 const ExplodedNode *AllocNode = N;

2989 const MemRegion *ReferenceRegion = nullptr;

2990

2991 while (N) {

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

2994 break;

2995

2996

2997

2998 if (!ReferenceRegion) {

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

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

3003

3004

3006 ReferenceRegion = MR;

3007 }

3008 }

3009 }

3010

3011

3012

3014 if (NContext == LeakContext ||

3016 AllocNode = N;

3018 }

3019

3020 return LeakInfo(AllocNode, ReferenceRegion);

3021}

3022

3023void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,

3024 CheckerContext &C) const {

3025 assert(N && "HandleLeak is only called with a non-null node");

3026

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

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

3029 AllocationFamily Family = RS->getAllocationFamily();

3030

3031 if (Family.Kind == AF_Alloca)

3032 return;

3033

3034 const Leak *Frontend = getRelevantFrontendAs(Family);

3035

3036

3037

3038 if (!Frontend || !Frontend->isEnabled())

3039 return;

3040

3041

3042

3043

3044 PathDiagnosticLocation LocUsedForUniqueing;

3045 const ExplodedNode *AllocNode = nullptr;

3046 const MemRegion *Region = nullptr;

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

3048

3050 if (AllocationStmt)

3052 C.getSourceManager(),

3054

3055 SmallString<200> buf;

3056 llvm::raw_svector_ostream os(buf);

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

3060 } else {

3061 os << "Potential memory leak";

3062 }

3063

3064 auto R = std::make_unique(

3065 Frontend->LeakBug, os.str(), N, LocUsedForUniqueing,

3067 R->markInteresting(Sym);

3068 R->addVisitor(Sym, true);

3069 if (ShouldRegisterNoOwnershipChangeVisitor)

3070 R->addVisitor(Sym, this);

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

3072}

3073

3074void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,

3075 CheckerContext &C) const

3076{

3078 RegionStateTy OldRS = state->get();

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

3080

3081 RegionStateTy RS = OldRS;

3082 SmallVector<SymbolRef, 2> Errors;

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

3084 if (SymReaper.isDead(Sym)) {

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

3086 Errors.push_back(Sym);

3087

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

3089 }

3090 }

3091

3092 if (RS == OldRS) {

3093

3094 assert(state->get() ==

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

3096 assert(state->get() ==

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

3098 return;

3099 }

3100

3101

3102 ReallocPairsTy RP = state->get();

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

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

3105 state = state->remove(Sym);

3106 }

3107 }

3108

3109

3110 FreeReturnValueTy FR = state->get();

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

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

3113 state = state->remove(Sym);

3114 }

3115 }

3116

3117

3118 ExplodedNode *N = C.getPredecessor();

3119 if (!Errors.empty()) {

3120 N = C.generateNonFatalErrorNode(C.getState());

3121 if (N) {

3123 HandleLeak(Sym, N, C);

3124 }

3125 }

3126 }

3127

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

3129}

3130

3131

3132

3133

3135 return Name == "unique_ptr" || Name == "shared_ptr";

3136}

3137

3138

3141

3142 if (const auto *TST = QT->getAs()) {

3143 const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();

3144 if (!TD)

3145 return false;

3146

3147 const auto *ND = dyn_cast_or_null(TD->getTemplatedDecl());

3148 if (!ND)

3149 return false;

3150

3151

3152

3154 }

3155

3156 return false;

3157}

3158

3159

3160

3161

3162

3166 llvm::SmallPtrSetImpl<const MemRegion *> *Out;

3167

3169 llvm::SmallPtrSetImpl<const MemRegion *> &Out)

3171

3175 Out->insert(FR);

3176 }

3177

3179 bool IsVirtual) {

3180

3181 SVal BaseL =

3182 C->getState()->getLValue(BaseDecl, Reg->getAs<SubRegion>(), IsVirtual);

3184

3186 }

3187 return std::nullopt;

3188 }

3189};

3190

3191

3192

3193

3194

3195

3196

3197

3198

3199

3200

3201

3203 std::optional FC = std::nullopt) {

3204

3207 if (!FC)

3208 return true;

3209 FC->consume(FD);

3210 }

3211 }

3212

3213

3216 BaseSpec.getType()->getAsCXXRecordDecl()) {

3217 std::optional NewFC;

3218 if (FC) {

3219 NewFC = FC->switchToBase(BaseDecl, BaseSpec.isVirtual());

3220 if (!NewFC)

3221 continue;

3222 }

3224 if (Found && !FC)

3225 return true;

3226 }

3227 }

3228 return false;

3229}

3230

3231

3234 return false;

3235

3237 if (T->isRecordType() || T->isReferenceType())

3238 return false;

3239

3240

3243}

3244

3245

3246

3249 return false;

3250

3253}

3254

3255

3257 if (!RD)

3258 return false;

3259

3260

3261

3263}

3264

3265

3266

3268

3269 const auto *CD = dyn_cast_or_null(Call.getDecl());

3270 if (!CD)

3271 return false;

3272

3273 const auto *RD = CD->getParent();

3275 return false;

3276

3277

3278 for (const auto *Param : CD->parameters()) {

3279 QualType ParamType = Param->getType();

3282 return true;

3283 }

3284 }

3285

3286 return false;

3287}

3288

3289

3290

3291static void

3294 llvm::SmallPtrSetImpl<const MemRegion *> &Out) {

3295 if (!Reg)

3296 return;

3297

3299 if (!CRD)

3300 return;

3301

3304}

3305

3306

3307

3308ProgramStateRef MallocChecker::handleSmartPointerConstructorArguments(

3311 for (unsigned I = 0, E = std::min(Call.getNumArgs(), CD->getNumParams());

3312 I != E; ++I) {

3313 const Expr *ArgExpr = Call.getArgExpr(I);

3314 if (!ArgExpr)

3315 continue;

3316

3317 QualType ParamType = CD->getParamDecl(I)->getType();

3320

3321 SVal ArgVal = Call.getArgSVal(I);

3323 if (Sym && State->contains(Sym)) {

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

3325 if (RS && (RS->isAllocated() || RS->isAllocatedOfSizeZero())) {

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

3327 }

3328 }

3329 }

3330 }

3331 return State;

3332}

3333

3334

3335

3336

3337ProgramStateRef MallocChecker::handleSmartPointerRelatedCalls(

3339

3340

3342 return handleSmartPointerConstructorArguments(Call, State);

3343 }

3344

3345

3346 llvm::SmallPtrSet<const MemRegion *, 8> SmartPtrFieldRoots;

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

3348 const Expr *AE = Call.getArgExpr(I);

3349 if (!AE)

3350 continue;

3352

3354 continue;

3355

3356

3357 SVal ArgVal = Call.getArgSVal(I);

3358 const MemRegion *ArgRegion = ArgVal.getAsRegion();

3359

3361 SmartPtrFieldRoots);

3362 }

3363

3364

3365 if (!SmartPtrFieldRoots.empty()) {

3366 SmallVector<const MemRegion *, 8> SmartPtrFieldRootsVec(

3367 SmartPtrFieldRoots.begin(), SmartPtrFieldRoots.end());

3368 State = EscapeTrackedCallback::EscapeTrackedRegionsReachableFrom(

3369 SmartPtrFieldRootsVec, State);

3370 }

3371

3372 return State;

3373}

3374

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

3376 CheckerContext &C) const {

3377

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

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

3380 return;

3381 }

3382

3383

3384 C.addTransition(handleSmartPointerRelatedCalls(Call, C, C.getState()));

3385}

3386

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

3388 CheckerContext &C) const {

3389

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

3391 const CXXDeleteExpr *DE = DC->getOriginExpr();

3392

3393

3394

3395

3396

3397 if (!NewDeleteChecker.isEnabled())

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

3400

3402 return;

3403

3405 bool IsKnownToBeAllocated;

3406 State = FreeMemAux(

3408 false, IsKnownToBeAllocated,

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

3410

3411 C.addTransition(State);

3412 return;

3413 }

3414

3415

3416

3417

3418

3419

3420

3421

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

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

3424 if (!Sym)

3425 return;

3427 HandleDoubleFree(C, SourceRange(), true, Sym,

3428 nullptr);

3429 return;

3430 }

3431 }

3432

3433

3434

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

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

3437 return;

3438 }

3439

3440

3441

3442

3443

3444 if (const AnyFunctionCall *FC = dyn_cast(&Call)) {

3445 const FunctionDecl *FD = FC->getDecl();

3446 if (!FD)

3447 return;

3448

3449

3450

3451

3452 if (MallocChecker.isEnabled() && isFreeingCall(Call))

3453 return;

3454 }

3455

3456

3457 if (const CXXInstanceCall *CC = dyn_cast(&Call)) {

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

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

3460 return;

3461 }

3462

3463

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

3465 SVal ArgSVal = Call.getArgSVal(I);

3468 if (!Sym)

3469 continue;

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

3471 return;

3472 }

3473 }

3474}

3475

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

3477 CheckerContext &C) const {

3478 checkEscapeOnReturn(S, C);

3479}

3480

3481

3482

3483

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

3485 CheckerContext &C) const {

3486 checkEscapeOnReturn(S, C);

3487}

3488

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

3490 CheckerContext &C) const {

3491 if (!S)

3492 return;

3493

3495 if (!E)

3496 return;

3497

3498

3500 SVal RetVal = C.getSVal(E);

3502 if (!Sym)

3503

3504

3505 if (const MemRegion *MR = RetVal.getAsRegion())

3507 if (const SymbolicRegion *BMR =

3509 Sym = BMR->getSymbol();

3510

3511

3512 if (Sym)

3513 checkUseAfterFree(Sym, C, E);

3514}

3515

3516

3517

3518

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

3520 CheckerContext &C) const {

3521

3522

3523

3525 return;

3526

3528 const BlockDataRegion *R =

3530

3532 if (ReferencedVars.empty())

3533 return;

3534

3535 SmallVector<const MemRegion*, 10> Regions;

3536 const LocationContext *LC = C.getLocationContext();

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

3538

3539 for (const auto &Var : ReferencedVars) {

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

3543 }

3544 Regions.push_back(VR);

3545 }

3546

3547 state =

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

3549 C.addTransition(state);

3550}

3551

3553 assert(Sym);

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

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

3556}

3557

3558bool MallocChecker::suppressDeallocationsInSuspiciousContexts(

3559 const CallEvent &Call, CheckerContext &C) const {

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

3561 return false;

3562

3563 StringRef FunctionStr = "";

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

3565 if (const Stmt *Body = FD->getBody())

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

3567 FunctionStr =

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

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

3571

3572

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

3574 return false;

3575

3577

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

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

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

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

3582

3583 C.addTransition(State);

3584 return true;

3585}

3586

3587bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,

3588 const Stmt *S) const {

3589

3592 return true;

3593 }

3594

3595 return false;

3596}

3597

3598void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,

3599 const Stmt *S) const {

3600 assert(Sym);

3601

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

3603 if (RS->isAllocatedOfSizeZero())

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

3605 }

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

3608 }

3609}

3610

3611

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

3613 CheckerContext &C) const {

3615 if (Sym) {

3616 checkUseAfterFree(Sym, C, S);

3617 checkUseZeroAllocated(Sym, C, S);

3618 }

3619}

3620

3621

3622

3625 bool Assumption) const {

3626 RegionStateTy RS = state->get();

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

3628

3629 ConstraintManager &CMgr = state->getConstraintManager();

3630 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);

3632 state = state->remove(Sym);

3633 }

3634

3635

3636

3637 ReallocPairsTy RP = state->get();

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

3639

3640 ConstraintManager &CMgr = state->getConstraintManager();

3641 ConditionTruthVal AllocFailed = CMgr.isNull(state, Sym);

3643 continue;

3644

3645 SymbolRef ReallocSym = ReallocPair.ReallocatedSym;

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

3647 if (RS->isReleased()) {

3648 switch (ReallocPair.Kind) {

3649 case OAR_ToBeFreedAfterFailure:

3650 state = state->set(ReallocSym,

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

3652 break;

3653 case OAR_DoNotTrackAfterFailure:

3654 state = state->remove(ReallocSym);

3655 break;

3656 default:

3657 assert(ReallocPair.Kind == OAR_FreeOnFailure);

3658 }

3659 }

3660 }

3661 state = state->remove(Sym);

3662 }

3663

3664 return state;

3665}

3666

3667bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(

3668 const CallEvent *Call,

3670 SymbolRef &EscapingSymbol) const {

3671 assert(Call);

3672 EscapingSymbol = nullptr;

3673

3674

3675

3676

3677

3679 return true;

3680

3681

3682 if (const ObjCMethodCall *Msg = dyn_cast(Call)) {

3683

3684

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

3686 return true;

3687

3688

3689

3691 return false;

3692

3693

3694

3695

3696

3698 return *FreeWhenDone;

3699

3700

3701

3702

3703

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

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

3706 return true;

3707

3708

3709

3710

3711

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

3713 FirstSlot.starts_with("insertPointer") ||

3714 FirstSlot.starts_with("replacePointer") ||

3715 FirstSlot == "valueWithPointer") {

3716 return true;

3717 }

3718

3719

3720

3721

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

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

3724 return true;

3725 }

3726

3727

3728

3729 return false;

3730 }

3731

3732

3734 if (!FD)

3735 return true;

3736

3737

3738

3739 if (isMemCall(*Call))

3740 return false;

3741

3742

3743 if (Call->isInSystemHeader())

3744 return true;

3745

3746

3748 if (!II)

3749 return true;

3750 StringRef FName = II->getName();

3751

3752

3753

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

3755

3756

3757

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

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

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

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

3762 if (DeallocatorName == "kCFAllocatorNull")

3763 return false;

3764 }

3765 }

3766 return true;

3767 }

3768

3769

3770

3771

3772

3773 if (FName == "funopen")

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

3775 return false;

3776

3777

3778

3779

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

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

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

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

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

3786 if (D->getCanonicalDecl()->getName().contains("std"))

3787 return true;

3788 }

3789 }

3790

3791

3792

3793

3794

3795

3796 if (FName == "CGBitmapContextCreate" ||

3797 FName == "CGBitmapContextCreateWithData" ||

3798 FName == "CVPixelBufferCreateWithBytes" ||

3799 FName == "CVPixelBufferCreateWithPlanarBytes" ||

3800 FName == "OSAtomicEnqueue") {

3801 return true;

3802 }

3803

3804 if (FName == "postEvent" &&

3806 return true;

3807 }

3808

3809 if (FName == "connectImpl" &&

3811 return true;

3812 }

3813

3814 if (FName == "singleShotImpl" &&

3816 return true;

3817 }

3818

3819

3820

3821

3822

3823

3824 if (FName == "GetOwnedMessageInternal") {

3825 return true;

3826 }

3827

3828

3829

3830

3831

3832 if (Call->argumentsMayEscape())

3833 return true;

3834

3835

3836

3837 return false;

3838}

3839

3842 const CallEvent *Call,

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

3845 false);

3846}

3847

3850 const CallEvent *Call,

3852

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

3854 true);

3855}

3856

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

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

3860}

3861

3865 bool IsConstPointerEscape) const {

3866

3867

3868 SymbolRef EscapingSymbol = nullptr;

3870 !mayFreeAnyEscapedMemoryOrIsModeledExplicitly(Call, State,

3871 EscapingSymbol) &&

3872 !EscapingSymbol) {

3873 return State;

3874 }

3875

3877 if (EscapingSymbol && EscapingSymbol != sym)

3878 continue;

3879

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

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

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

3884 }

3885 return State;

3886}

3887

3888bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,

3889 SVal ArgVal) const {

3890 if (!KernelZeroSizePtrValue)

3891 KernelZeroSizePtrValue =

3893

3894 const llvm::APSInt *ArgValKnown =

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

3896 return ArgValKnown && *KernelZeroSizePtrValue &&

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

3898}

3899

3902 ReallocPairsTy currMap = currState->get();

3903 ReallocPairsTy prevMap = prevState->get();

3904

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

3907 if (!currMap.lookup(sym))

3908 return sym;

3909 }

3910

3911 return nullptr;

3912}

3913

3916 StringRef N = II->getName();

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

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

3919 N.contains_insensitive("intrusive") ||

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

3921 return true;

3922 }

3923 }

3924 }

3925 return false;

3926}

3927

3929 BugReporterContext &BRC,

3930 PathSensitiveBugReport &BR) {

3933

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

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

3936

3938

3939

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

3941 return nullptr;

3942

3944

3945

3946

3947

3948

3949

3950

3951

3952

3953 if (ReleaseFunctionLC && (ReleaseFunctionLC == CurrentLC ||

3954 ReleaseFunctionLC->isParentOf(CurrentLC))) {

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

3956

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

3959 Op == AtomicExpr::AO__c11_atomic_fetch_sub) {

3961

3962

3963 return nullptr;

3964 }

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

3966

3967

3968 if (const auto *MD =

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

3970 const CXXRecordDecl *RD = MD->getParent();

3971

3972

3973 if (StringRef(RD->getNameAsString()).contains("atomic")) {

3975

3976

3977 return nullptr;

3978 }

3979 }

3980 }

3981 }

3982

3983

3984

3985

3986

3987 StringRef Msg;

3988 std::unique_ptr StackHint = nullptr;

3989 SmallString<256> Buf;

3990 llvm::raw_svector_ostream OS(Buf);

3991

3992 if (Mode == Normal) {

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

3994 Msg = "Memory is allocated";

3995 StackHint = std::make_unique(

3996 Sym, "Returned allocated memory");

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

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

3999 switch (Family.Kind) {

4000 case AF_Alloca:

4001 case AF_Malloc:

4002 case AF_Custom:

4003 case AF_CXXNew:

4004 case AF_CXXNewArray:

4005 case AF_IfNameIndex:

4006 Msg = "Memory is released";

4007 StackHint = std::make_unique(

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

4009 break;

4010 case AF_InnerBuffer: {

4011 const MemRegion *ObjRegion =

4014 QualType ObjTy = TypedRegion->getValueType();

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

4016

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

4019 StackHint = std::make_unique(

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

4021 } else {

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

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

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

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

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

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

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

4030 CallEventRef<> Call =

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

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

4033 OS << D->getDeclName();

4034 else

4035 OS << "unknown";

4036 }

4037 OS << "'";

4038 StackHint = std::make_unique(

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

4040 }

4041 Msg = OS.str();

4042 break;

4043 }

4044 case AF_None:

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

4046 return nullptr;

4047 }

4048

4049

4050

4051

4052

4053

4054

4056

4057

4058 for (const LocationContext *LC = CurrentLC; LC; LC = LC->getParent()) {

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

4061

4062

4063

4065

4066

4067

4068 return nullptr;

4069 }

4070

4071

4072

4073

4074

4075

4076

4077

4078

4079

4080

4081

4082

4083

4084

4085

4086

4087

4088

4089

4090

4091

4092

4093

4094

4096 }

4097 }

4098

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

4100 Msg = "Memory ownership is transferred";

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

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

4103 Mode = ReallocationFailed;

4104 Msg = "Reallocation failed";

4105 StackHint = std::make_unique(

4106 Sym, "Reallocation failed");

4107

4109

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

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

4113 FailedReallocSymbol = sym;

4114 }

4115 }

4116

4117

4118 } else if (Mode == ReallocationFailed) {

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

4120

4121

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

4123

4124 Msg = "Attempt to reallocate memory";

4125 StackHint = std::make_unique(

4126 Sym, "Returned reallocated memory");

4127 FailedReallocSymbol = nullptr;

4129 }

4130 }

4131

4132 if (Msg.empty()) {

4133 assert(!StackHint);

4134 return nullptr;

4135 }

4136

4137 assert(StackHint);

4138

4139

4140 PathDiagnosticLocation Pos;

4141 if (!S) {

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

4143 auto PostImplCall = N->getLocation().getAs();

4144 if (!PostImplCall)

4145 return nullptr;

4146 Pos = PathDiagnosticLocation(PostImplCall->getLocation(),

4148 } else {

4151 }

4152

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

4155 return P;

4156}

4157

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

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

4160

4161 RegionStateTy RS = State->get();

4162

4163 if (!RS.isEmpty()) {

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

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

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

4167 AllocationFamily Family = RefS->getAllocationFamily();

4168

4169 const CheckerFrontend *Frontend =

4170 getRelevantFrontendAs(Family);

4171

4173 Out << " : ";

4174 Data.dump(Out);

4175 if (Frontend && Frontend->isEnabled())

4176 Out << " (" << Frontend->getName() << ")";

4177 Out << NL;

4178 }

4179 }

4180}

4181

4182namespace clang {

4183namespace ento {

4184namespace allocation_state {

4185

4188 AllocationFamily Family(AF_InnerBuffer);

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

4190}

4191

4192}

4193}

4194}

4195

4196

4197

4199 Mgr.getChecker()->InnerPointerChecker.enable(Mgr);

4200}

4201

4202void ento::registerDynamicMemoryModeling(CheckerManager &Mgr) {

4203 auto *Chk = Mgr.getChecker();

4204

4205

4207 Chk->ShouldIncludeOwnershipAnnotatedFunctions =

4208 Mgr.getAnalyzerOptions().getCheckerBooleanOption(DMMName, "Optimistic");

4209 Chk->ShouldRegisterNoOwnershipChangeVisitor =

4211 DMMName, "AddNoOwnershipChangeNotes");

4212}

4213

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

4215 return true;

4216}

4217

4218#define REGISTER_CHECKER(NAME) \

4219 void ento::register##NAME(CheckerManager &Mgr) { \

4220 Mgr.getChecker()->NAME.enable(Mgr); \

4221 } \

4222 \

4223 bool ento::shouldRegister##NAME(const CheckerManager &) { return true; }

4224

4225

#define REGISTER_CHECKER(name)

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 isRvalueByValueRecordWithSmartPtr(const Expr *AE)

Check if an expression is an rvalue record with smart owning pointer fields passed by value.

Definition MallocChecker.cpp:3247

static bool isFromStdNamespace(const CallEvent &Call)

Definition MallocChecker.cpp:1568

static bool isStandardNew(const FunctionDecl *FD)

Definition MallocChecker.cpp:1161

static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE)

Definition MallocChecker.cpp:1800

static QualType getDeepPointeeType(QualType T)

Definition MallocChecker.cpp:1789

static bool isReleased(SymbolRef Sym, CheckerContext &C)

Check if the memory associated with this symbol was released.

Definition MallocChecker.cpp:3552

static void printExpectedAllocName(raw_ostream &os, AllocationFamily Family)

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

Definition MallocChecker.cpp:2200

static void collectSmartPtrFieldRegions(const MemRegion *Reg, QualType RecQT, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)

Collect memory regions of smart owning pointer fields from a record type (including fields from base ...

Definition MallocChecker.cpp:3292

static bool hasSmartPtrField(const CXXRecordDecl *CRD, std::optional< FieldConsumer > FC=std::nullopt)

Check if a record type has smart owning pointer fields (directly or in base classes).

Definition MallocChecker.cpp:3202

static bool isStandardDelete(const FunctionDecl *FD)

Definition MallocChecker.cpp:1177

static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD)

Definition MallocChecker.cpp:3914

static bool isSmartPtrType(QualType QT)

Definition MallocChecker.cpp:3139

static bool isStandardNewDelete(const T &FD)

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

Definition MallocChecker.cpp:337

static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState)

Definition MallocChecker.cpp:3900

static bool isRvalueByValueRecord(const Expr *AE)

Check if an expression is an rvalue record type passed by value.

Definition MallocChecker.cpp:3232

#define BUGTYPE_PROVIDER(NAME, DEF)

Definition MallocChecker.cpp:348

static bool isGRealloc(const CallEvent &Call)

Definition MallocChecker.cpp:1379

static const Expr * getPlacementNewBufferArg(const CallExpr *CE, const FunctionDecl *FD)

Definition MallocChecker.cpp:1463

static bool isSmartPtrRecord(const CXXRecordDecl *RD)

Check if a CXXRecordDecl has a name matching recognized smart pointer names.

Definition MallocChecker.cpp:3256

#define CHECK_FN(NAME)

Definition MallocChecker.cpp:462

static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family)

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

Definition MallocChecker.cpp:2227

static bool isStandardRealloc(const CallEvent &Call)

Definition MallocChecker.cpp:1370

static bool isSmartPtrCall(const CallEvent &Call)

Check if a call is a constructor of a smart owning pointer class that accepts pointer parameters.

Definition MallocChecker.cpp:3267

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.

Definition MallocChecker.cpp:2124

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.

Definition MallocChecker.cpp:2055

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

Print names of allocators and deallocators.

Definition MallocChecker.cpp:2158

static bool isSmartPtrName(StringRef Name)

Definition MallocChecker.cpp:3134

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

Definition MallocChecker.cpp:2137

static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call)

Definition MallocChecker.cpp:1872

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

Definition MallocChecker.cpp:1884

static bool checkIfNewOrNewArrayFamily(const RefState *RS)

Definition MallocChecker.cpp:3857

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

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 getCanonicalSizeType() const

CanQualType UnsignedLongTy

static bool hasSameType(QualType T1, QualType T2)

Determine whether the given types T1 and T2 are equivalent.

QualType getSizeType() const

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

const TargetInfo & getTargetInfo() const

bool hasCaptures() const

True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...

const BlockDecl * getBlockDecl() const

Represents a base class of a C++ class.

Represents binding an expression to a temporary.

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.

Represents a C++ functional cast expression that builds a temporary object.

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)

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

SourceLocation getBeginLoc() const LLVM_READONLY

This represents one expression.

Expr * IgnoreParenCasts() LLVM_READONLY

Skip past any parentheses and casts which might surround this expression until reaching a fixed point...

Expr * IgnoreParenImpCasts() LLVM_READONLY

Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...

Represents a member of a struct/union/class.

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.

ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...

Describes an C or C++ initializer list.

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

Returns a string for the source that the range encompasses.

bool isParentOf(const LocationContext *LC) const

const Decl * getDecl() const

const LocationContext * getParent() const

It might return null.

const StackFrameContext * getStackFrame() const

Represents a prvalue temporary that is written into memory so that a reference can bind to it.

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

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.

bool isNull() const

Return true if this QualType doesn't point to a type yet.

field_range fields() const

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

StringRef getNameForSlot(unsigned argIndex) const

Retrieve the name at a given position in the selector.

unsigned getNumArgs() const

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.

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.

The base class of all kinds of template declarations (e.g., class, function, etc.).

NamedDecl * getTemplatedDecl() const

Get the underlying, templated declaration.

CXXRecordDecl * getAsCXXRecordDecl() const

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

bool isVoidPointerType() const

bool isFunctionPointerType() const

bool isPointerType() const

CanQualType getCanonicalTypeUnqualified() const

QualType getPointeeType() const

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

const T * getAs() const

Member-template getAs'.

bool isStaticLocal() const

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

APSIntPtr getMaxValue(const llvm::APSInt &v)

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.

An immutable map from CallDescriptions to arbitrary data.

CallEventRef getSimpleCall(const CallExpr *E, ProgramStateRef State, const LocationContext *LCtx, CFGBlock::ConstCFGElementRef ElemRef)

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

Checker families (where a single backend class implements multiple related frontends) should derive f...

A CheckerFrontend instance is what the user recognizes as "one checker": it has a public canonical na...

CheckerNameRef getName() const

const AnalyzerOptions & getAnalyzerOptions() const

CheckerNameRef getCurrentCheckerName() const

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

If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...

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

bool isConstrainedTrue() const

Return true if the constraint is perfectly constrained to 'true'.

ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym)

Convenience method to query the state to see if a symbol is null or not null, or if neither assumptio...

const ProgramStateRef & getState() const

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.

RegionOffset getAsOffset() const

Compute the offset within the top level memory object.

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

bool hasMemorySpace(ProgramStateRef State) const

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const

Returns the most specific memory space for this memory region in the given ProgramStateRef.

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.

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

bool hasSymbolicOffset() const

int64_t getOffset() const

DefinedSVal getConjuredHeapSymbolVal(ConstCFGElementRef elem, const LocationContext *LCtx, QualType type, unsigned Count)

Conjure a symbol representing heap allocated memory 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)

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.

SubRegion - A region that subsets another larger region.

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const

virtual void dumpToStream(raw_ostream &os) const

virtual QualType getType() const =0

bool isDead(SymbolRef sym)

Returns whether or not a symbol has been confirmed dead.

SymbolRef getSymbol() const

It might return null.

const VarDecl * getDecl() const override=0

const StackFrameContext * getStackFrame() const

It might return null.

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)

Definition MallocChecker.cpp:4187

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.

llvm::DenseSet< SymbolRef > InvalidatedSymbols

IntrusiveRefCntPtr< const ProgramState > ProgramStateRef

const SymExpr * SymbolRef

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.

Definition MallocChecker.cpp:4198

@ OS

Indicates that the tracking object is a descendant of a referenced-counted OSObject,...

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)

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

OverloadedOperatorKind

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

@ Match

This is not an overload because the signature exactly matches an existing declaration.

bool isa(CodeGen::Address addr)

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

nullptr

This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...

const FunctionProtoType * T

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

const char * getOperatorSpelling(OverloadedOperatorKind Operator)

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

U cast(CodeGen::Address addr)

@ Other

Other implicit parameter.

int const char * function

Helper struct for collecting smart owning pointer field regions.

Definition MallocChecker.cpp:3163

void consume(const FieldDecl *FD)

Definition MallocChecker.cpp:3172

std::optional< FieldConsumer > switchToBase(const CXXRecordDecl *BaseDecl, bool IsVirtual)

Definition MallocChecker.cpp:3178

FieldConsumer(const MemRegion *Reg, CheckerContext &C, llvm::SmallPtrSetImpl< const MemRegion * > &Out)

Definition MallocChecker.cpp:3168

llvm::SmallPtrSetImpl< const MemRegion * > * Out

Definition MallocChecker.cpp:3166

CheckerContext * C

Definition MallocChecker.cpp:3165

const MemRegion * Reg

Definition MallocChecker.cpp:3164