clang: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

23#include "llvm/ADT/SmallSet.h"

24#include "llvm/ADT/Statistic.h"

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

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

27#include "llvm/Support/SaveAndRestore.h"

28#include

29

30using namespace clang;

31using namespace ento;

32

33#define DEBUG_TYPE "ExprEngine"

34

36 "The # of times we split the path due to imprecise dynamic dispatch info");

37

39 "The # of times we inlined a call");

40

42 "The # of times we reached inline count maximum");

43

46

50

51

52 assert(Entry->empty());

54

55

57

58

60

62

63

64

65 bool isNew;

67 Node->addPredecessor(Pred, G);

68 if (isNew) {

72 }

73}

74

75

76

77static std::pair<const Stmt*,

79 const Stmt *S = nullptr;

80 const CFGBlock *Blk = nullptr;

82

83

84

85 while (Node) {

87

89 if (std::optional SP = PP.getAs<StmtPoint>()) {

90 S = SP->getStmt();

91 break;

92 } else if (std::optional CEE = PP.getAs<CallExitEnd>()) {

93 S = CEE->getCalleeContext()->getCallSite();

94 if (S)

95 break;

96

97

98

99

100 std::optional CE;

101 do {

104 } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());

105

106

107 } else if (std::optional BE = PP.getAs<BlockEdge>()) {

108 Blk = BE->getSrc();

109 }

110 } else if (std::optional CE = PP.getAs<CallEnter>()) {

111

112 if (CE->getCalleeContext() == SF)

113 break;

114 }

115

116 if (Node->pred_empty())

117 return std::make_pair(nullptr, nullptr);

118

120 }

121

122 return std::make_pair(S, Blk);

123}

124

125

126

127

128

129

132

133 if (!isa(V))

134 return V;

135

136

139 if (ExpectedTy == ActualTy)

140 return V;

141

142

145 return V;

146

147

151 CXXBasePaths Paths(true, true,

152 false);

156 }

157 }

158

159

160

161

163}

164

168

169 const Stmt *LastSt = nullptr;

170 const CFGBlock *Blk = nullptr;

171 std::tie(LastSt, Blk) = getLastStmt(Pred);

172 if (!Blk || !LastSt) {

173 Dst.Add(Pred);

174 return;

175 }

176

177

178

179

180

181

184 removeDead(Pred, Dst, dyn_cast(LastSt), LCtx,

187}

188

191 const Decl *RuntimeCallee = calleeCtx->getDecl();

192 const Decl *StaticDecl = Call->getDecl();

193 assert(RuntimeCallee);

194 if (!StaticDecl)

195 return true;

197}

198

199

200

203 assert(isa(Call) &&

204 "The call event is not a destructor call!");

205

206 const auto &DtorCall = cast(Call);

207

208 auto ThisVal = DtorCall.getCXXThisVal();

209

210 if (auto ThisElementRegion = dyn_cast(ThisVal.getAsRegion())) {

211 auto ArrayRegion = ThisElementRegion->getAsArrayOffset().getRegion();

212 auto ElementType = ThisElementRegion->getElementType();

213

214 auto ElementCount =

216

217 if (!ElementCount.isConstant())

218 return 0;

219

220 return ElementCount.getAsInteger()->getLimitedValue();

221 }

222

223 return 0;

224}

225

226ProgramStateRef ExprEngine::removeStateTraitsUsedForArrayEvaluation(

229

230 assert(LCtx && "Location context must be provided!");

231

232 if (E) {

234 State = removePendingInitLoop(State, E, LCtx);

235

237 State = removeIndexOfElementToConstruct(State, E, LCtx);

238 }

239

241 State = removePendingArrayDestruction(State, LCtx);

242

243 return State;

244}

245

246

247

248

249

250

251

252

253

255

258

259

260

263

266

267 const Stmt *LastSt = nullptr;

268 const CFGBlock *Blk = nullptr;

269 std::tie(LastSt, Blk) = getLastStmt(CEBNode);

270

271

272

275

276

277

278

279

280

281

282

283 bool ShouldRepeatCall = false;

284

285 if (const auto *DtorDecl =

286 dyn_cast_or_null(Call->getDecl())) {

288 ShouldRepeatCall = *Idx > 0;

289

290 auto ThisVal = svalBuilder.getCXXThis(DtorDecl->getParent(), calleeCtx);

291 state = state->killBinding(ThisVal);

292 }

293 }

294

295

296 if (CE) {

297 if (const ReturnStmt *RS = dyn_cast_or_null(LastSt)) {

299 SVal V = state->getSVal(RS, LCtx);

300

301

305 if (!ReturnedTy.isNull()) {

306 if (const Expr *Ex = dyn_cast(CE)) {

309 }

310 }

311 }

312

313 state = state->BindExpr(CE, callerCtx, V);

314 }

315

316

317 if (const CXXConstructExpr *CCE = dyn_cast(CE)) {

319 svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);

320 SVal ThisV = state->getSVal(This);

321 ThisV = state->getSVal(ThisV.castAs<Loc>());

322 state = state->BindExpr(CCE, callerCtx, ThisV);

323

324 ShouldRepeatCall = shouldRepeatCtorCall(state, CCE, callerCtx);

325 }

326

327 if (const auto *CNE = dyn_cast(CE)) {

328

329

330

331

332

333 SVal AllocV = state->getSVal(CNE, callerCtx);

334 AllocV = svalBuilder.evalCast(

337

338 state = addObjectUnderConstruction(state, CNE, calleeCtx->getParent(),

339 AllocV);

340 }

341 }

342

343 if (!ShouldRepeatCall) {

344 state = removeStateTraitsUsedForArrayEvaluation(

345 state, dyn_cast_or_null(CE), callerCtx);

346 }

347

348

349

350

351

352

356 auto Loc = isa(LastSt)

359 nullptr, &retValBind)};

360 const CFGBlock *PrePurgeBlock =

361 isa(LastSt) ? Blk : &CEBNode->getCFG().getExit();

362 bool isNew;

365 if (!isNew)

366 return;

367

369 currBldrCtx = &Ctx;

370

371

372

373

374 removeDead(BindedRetNode, CleanedNodes, nullptr, calleeCtx,

377 currBldrCtx = nullptr;

378 } else {

379 CleanedNodes.Add(CEBNode);

380 }

381

383

384

386 bool isNew;

387 ProgramStateRef CEEState = (N == CEBNode) ? state : N->getState();

388

391 if (!isNew)

392 return;

393

394

395

396

400

402

404 if (llvm::isa_and_nonnull(CE)) {

407 CEENode, *UpdatedCall, *this,

408 true);

409 for (ExplodedNode *I : DstPostPostCallCallback) {

411 cast(*UpdatedCall), DstPostCall, I, *this,

412 true);

413 }

414 } else {

416 *UpdatedCall, *this,

417 true);

418 }

422 *this,

423 true);

424 } else if (CE &&

425 !(isa(CE) &&

428 *this, true);

429 } else {

430 Dst.insert(DstPostCall);

431 }

432

433

435 PSI != PSE; ++PSI) {

436 unsigned Idx = calleeCtx->getIndex() + (ShouldRepeatCall ? 0 : 1);

437

439 }

440 }

441}

442

444

445

446

447

448

451}

452

455 return Cfg->size() >= AMgr.options.MinCFGSizeTreatFunctionsAsLarge;

456}

457

461}

462

463void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx,

464 bool &IsRecursive, unsigned &StackDepth) {

465 IsRecursive = false;

466 StackDepth = 0;

467

468 while (LCtx) {

469 if (const StackFrameContext *SFC = dyn_cast(LCtx)) {

470 const Decl *DI = SFC->getDecl();

471

472

473

474 if (DI == D) {

475 IsRecursive = true;

476 ++StackDepth;

478 continue;

479 }

480

481

483 if (!isSmall(CalleeADC))

484 ++StackDepth;

485 }

487 }

488}

489

490

491

492

493

494

495

496namespace {

497 enum DynamicDispatchMode {

498 DynamicDispatchModeInlined = 1,

499 DynamicDispatchModeConservative

500 };

501}

502

506

511 if (Call.isForeign() && !isSecondPhaseCTU()) {

516 if (DoInline) {

517 inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);

518 return;

519 }

520 const bool BState = State->get();

521 if (!BState) {

522

524

525 ConservativeEvalState = State->set(true);

526 conservativeEvalCall(Call, Bldr, Pred, ConservativeEvalState);

527 } else {

528 conservativeEvalCall(Call, Bldr, Pred, State);

529 }

530 return;

531 }

532 inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);

533}

534

538 assert(D);

539

544 !cast(Call).isConversionFromLambda()) {

546 assert(BR && "If we have the block definition we should have its region");

549 cast(D),

550 BR);

551 }

552

553

554 const Expr *CallE = Call.getOriginExpr();

555

556

560 currBldrCtx->blockCount(), currStmtIdx);

561

563

564

565

566 State = State->enterStackFrame(Call, CalleeSFC);

567

568 bool isNew;

570 N->addPredecessor(Pred, G);

571 if (isNew)

573 }

574

575

576

578

579 NumInlinedCalls++;

581

582

583

584

585

586

587

588

589 if (!isSecondPhaseCTU())

590

591 if (VisitedCallees)

592 VisitedCallees->insert(D);

593}

594

596 const Stmt *CallE) {

598 if (!ReplayState)

599 return nullptr;

600

601 assert(ReplayState == CallE && "Backtracked to the wrong call.");

602 (void)CallE;

603

605}

606

609

612

613

614

618

619

620

623 evalCall(dstCallEvaluated, N, *CallTemplate);

624 }

625

626

627

628

629

631 *this);

632}

633

636 const Expr *E = Call.getOriginExpr();

637

638

639 if (E || isa(E))

640 return State;

641

643 for (unsigned CallI = 0, CallN = Call.getNumArgs(); CallI != CallN; ++CallI) {

644 unsigned I = Call.getASTArgumentIndex(CallI);

647 (void)VV;

649 ->getStackFrame()->getParent()

651 State = finishObjectConstruction(State, {E, I}, LC);

652 }

653 }

654

655 return State;

656}

657

658void ExprEngine::finishArgumentConstruction(ExplodedNodeSet &Dst,

663 if (CleanedState == State) {

665 return;

666 }

667

668 const Expr *E = Call.getOriginExpr();

672 "Finish argument construction");

674 B.generateNode(PP, CleanedState, Pred);

675}

676

679

680

681

682

683

684

685

686

689 Call, *this);

690

691

692

693

697

698

699

702 finishArgumentConstruction(dstArgumentCleanup, I, Call);

703

706 Call, *this);

707

708

709

710

711

712

713

718 Escaped.clear();

719 {

720 unsigned Arg = -1;

722 ++Arg;

723 QualType ParamTy = PVD->getType();

724 if (ParamTy.isNull() ||

726 continue;

729 continue;

730 if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion())

731 Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee));

732 }

733 }

734

737

738 if (State == I->getState())

740 else

742 }

743}

744

748 const Expr *E = Call.getOriginExpr();

749 if (E)

750 return State;

751

752

754 switch (Msg->getMethodFamily()) {

755 default:

756 break;

760

761 return State->BindExpr(E, LCtx, Msg->getReceiverSVal());

762 }

763 }

765 SVal ThisV = C->getCXXThisVal();

766 ThisV = State->getSVal(ThisV.castAs<Loc>());

767 return State->BindExpr(E, LCtx, ThisV);

768 }

769

772 unsigned Count = currBldrCtx->blockCount();

774

776 assert(RTC->getStmt() == Call.getOriginExpr());

777 EvalCallOptions CallOpts;

779 Call.getOriginExpr(), State, currBldrCtx, LCtx,

780 RTC->getConstructionContext(), CallOpts);

782 assert(TargetR);

783

784

785

786

787

791 State = State->invalidateRegions(TargetR, E, Count, LCtx,

792 false, nullptr,

793 &Call, &ITraits);

794

796 } else {

797

798

799

800

801 const auto *CNE = dyn_cast(E);

802 if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {

805

806

807 SVal ElementCount;

808 if (const Expr *SizeExpr = CNE->getArraySize().value_or(nullptr)) {

809 ElementCount = State->getSVal(SizeExpr, LCtx);

810 } else {

811 ElementCount = svalBuilder.makeIntVal(1, true);

812 }

813

815

817 svalBuilder.evalBinOp(State, BO_Mul, ElementCount, ElementSize,

819

820

821

822 if (Size.isUndef())

824

826 } else {

827 R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);

828 }

829 }

830 return State->BindExpr(E, LCtx, R);

831}

832

833

834

837 State = Call.invalidateRegions(currBldrCtx->blockCount(), State);

839

840

842 Bldr.generateNode(Call.getProgramPoint(false, &PT), State, Pred);

843}

844

845ExprEngine::CallInlinePolicy

851 switch (Call.getKind()) {

855 break;

859 return CIP_DisallowedAlways;

860 break;

863 return CIP_DisallowedAlways;

864

866

868

871 : nullptr;

872

873 if (llvm::isa_and_nonnull(CC) &&

874 !Opts.MayInlineCXXAllocator)

875 return CIP_DisallowedOnce;

876

878 if (!shouldInlineArrayConstruction(Pred->getState(), CtorExpr, CurLC))

879 return CIP_DisallowedOnce;

880 }

881

882

885 (void)ADC;

886

887

889 break;

890

891

892

894 return CIP_DisallowedAlways;

895

897

898

900 !Opts.ShouldIncludeTemporaryDtorsInCFG)

901 return CIP_DisallowedOnce;

902

903

904

905

907 return CIP_DisallowedOnce;

908

909

910

912 return CIP_DisallowedOnce;

913 }

914

915 break;

916 }

918

919

920 return CIP_Allowed;

921 }

924 return CIP_DisallowedAlways;

925

926

929 (void)ADC;

930

934 return CIP_DisallowedOnce;

935 }

936 }

937

938

940 !Opts.MayInlineCXXTemporaryDtors)

941 return CIP_DisallowedOnce;

942

943

944

945

947 return CIP_DisallowedOnce;

948 break;

949 }

951 [[fallthrough]];

953 if (Opts.MayInlineCXXAllocator)

954 break;

955

956

957 return CIP_DisallowedAlways;

959 if (!Opts.MayInlineObjCMethod)

960 return CIP_DisallowedAlways;

963 return CIP_DisallowedAlways;

964 break;

965 }

966

967 return CIP_Allowed;

968}

969

970

972 StringRef Name) {

975}

976

977

978

979

980

982 return hasMember(Ctx, RD, "begin") ||

983 hasMember(Ctx, RD, "iterator") ||

984 hasMember(Ctx, RD, "iterator_category");

985}

986

987

988

989

990

991

994 if (const CXXMethodDecl *MD = dyn_cast(FD))

996 return false;

997}

998

999

1000

1002 const CXXDestructorDecl *Dtor = dyn_cast(FD);

1003 if (!Dtor)

1004 return false;

1005

1008 if (II->isStr("shared_ptr"))

1009 return true;

1010

1011 return false;

1012}

1013

1014

1015

1016

1017

1018

1021

1023 return false;

1024

1025

1028 if (const FunctionDecl *FD = dyn_cast(CalleeADC->getDecl())) {

1029

1030 if (!Opts.MayInlineTemplateFunctions)

1032 return false;

1033

1034

1035 if (!Opts.MayInlineCXXStandardLibrary)

1038 return false;

1039

1040

1041

1042 if (!Opts.MayInlineCXXContainerMethods)

1045 return false;

1046

1047

1048

1049

1050

1051 if (!Opts.MayInlineCXXSharedPtrDtor)

1053 return false;

1054 }

1055 }

1056

1057

1058

1059 const CFG *CalleeCFG = CalleeADC->getCFG();

1060 if (!CalleeCFG)

1061 return false;

1062

1063

1064 if (isHuge(CalleeADC))

1065 return false;

1066

1067

1068

1070 return false;

1071

1072 return true;

1073}

1074

1075bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,

1078 if (D)

1079 return false;

1080

1085

1086

1087

1088

1090 return true;

1091

1093 return false;

1094

1095

1096 std::optional MayInline = Engine.FunctionSummaries->mayInline(D);

1097 if (MayInline) {

1098 if (!*MayInline)

1099 return false;

1100

1101 } else {

1102

1103

1104 if (mayInlineDecl(CalleeADC)) {

1106 } else {

1108 return false;

1109 }

1110 }

1111

1112

1113

1114

1115

1116 CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts, CallOpts);

1117 if (CIP != CIP_Allowed) {

1118 if (CIP == CIP_DisallowedAlways) {

1119 assert(!MayInline || *MayInline);

1121 }

1122 return false;

1123 }

1124

1125

1126 bool IsRecursive = false;

1127 unsigned StackDepth = 0;

1128 examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);

1130 (!isSmall(CalleeADC) || IsRecursive))

1131 return false;

1132

1133

1135 Opts.MaxTimesInlineLarge) &&

1136 isLarge(CalleeADC)) {

1137 NumReachedInlineCountMax++;

1138 return false;

1139 }

1140

1141 if (HowToInline == Inline_Minimal && (!isSmall(CalleeADC) || IsRecursive))

1142 return false;

1143

1144 return true;

1145}

1146

1147bool ExprEngine::shouldInlineArrayConstruction(const ProgramStateRef State,

1150 if (!CE)

1151 return false;

1152

1153

1154 if (const auto *CAT = dyn_cast(CE->getType())) {

1156

1157

1158

1159

1160

1161

1162

1163

1164

1165 return shouldInlineArrayDestruction(ArrSize);

1166 }

1167

1168

1170 return shouldInlineArrayDestruction(*Size);

1171

1172 return false;

1173}

1174

1175bool ExprEngine::shouldInlineArrayDestruction(uint64_t Size) {

1176

1178

1179

1180 return Size <= maxAllowedSize && Size > 0;

1181}

1182

1183bool ExprEngine::shouldRepeatCtorCall(ProgramStateRef State,

1186

1187 if (E)

1188 return false;

1189

1191

1192

1193 if (const auto *CAT = dyn_cast(Ty)) {

1196 }

1197

1200

1201 return false;

1202}

1203

1206 if (!ICall)

1207 return false;

1208

1209 const CXXMethodDecl *MD = dyn_cast_or_null(ICall->getDecl());

1210 if (!MD)

1211 return false;

1213 return false;

1214

1216}

1217

1221

1224

1225

1227 performTrivialCopy(Bldr, Pred, *Call);

1228 return;

1229 }

1230

1231

1232

1233

1234 const Expr *E = Call->getOriginExpr();

1235

1237 if (InlinedFailedState) {

1238

1239 State = InlinedFailedState;

1240 } else {

1244 if (shouldInlineCall(*Call, D, Pred, CallOpts)) {

1247

1248

1251 return;

1252 }

1253

1254

1256 conservativeEvalCall(*Call, Bldr, Pred, State);

1257 return;

1258 }

1259 }

1260 ctuBifurcate(*Call, D, Bldr, Pred, State);

1261 return;

1262 }

1263 }

1264

1265

1266

1267 State = removeStateTraitsUsedForArrayEvaluation(

1268 State, dyn_cast_or_null(E), Call->getLocationContext());

1269

1270

1271 conservativeEvalCall(*Call, Bldr, Pred, State);

1272}

1273

1274void ExprEngine::BifurcateCall(const MemRegion *BifurReg,

1277 assert(BifurReg);

1279

1280

1281

1283 const unsigned *BState =

1284 State->get(BifurReg);

1285 if (BState) {

1286

1287 if (*BState == DynamicDispatchModeInlined)

1288 ctuBifurcate(Call, D, Bldr, Pred, State);

1289

1290

1291

1292 conservativeEvalCall(Call, Bldr, Pred, State);

1293 return;

1294 }

1295

1296

1297

1299 State->set(BifurReg,

1300 DynamicDispatchModeInlined);

1301 ctuBifurcate(Call, D, Bldr, Pred, IState);

1302

1304 State->set(BifurReg,

1305 DynamicDispatchModeConservative);

1306 conservativeEvalCall(Call, Bldr, Pred, NoIState);

1307

1308 NumOfDynamicDispatchPathSplits++;

1309}

1310

1315

1317

1320 ei = dstPreVisit.end(); it != ei; ++it) {

1322 }

1323 }

1324}

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

static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD)

Returns true if the given C++ class is a container or iterator.

static ProgramStateRef getInlineFailedState(ProgramStateRef State, const Stmt *CallE)

static std::pair< const Stmt *, const CFGBlock * > getLastStmt(const ExplodedNode *Node)

static bool isTrivialObjectAssignment(const CallEvent &Call)

static bool isCXXSharedPtrDtor(const FunctionDecl *FD)

Returns true if the given function is the destructor of a class named "shared_ptr".

static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, StringRef Name)

Returns true if the given C++ class contains a member with the given name.

static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, const StackFrameContext *calleeCtx)

STATISTIC(NumOfDynamicDispatchPathSplits, "The # of times we split the path due to imprecise dynamic dispatch info")

static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy, StoreManager &StoreMgr)

Adjusts a return value when the called function's return type does not match the caller's expression ...

static bool isContainerMethod(const ASTContext &Ctx, const FunctionDecl *FD)

Returns true if the given function refers to a method of a C++ container or iterator.

static unsigned getElementCountOfArrayBeingDestructed(const CallEvent &Call, const ProgramStateRef State, SValBuilder &SVB)

llvm::MachO::Target Target

#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)

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

#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)

Declares a program state trait for type Type called Name, and introduce a type named NameTy.

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

SourceManager & getSourceManager()

DeclarationNameTable DeclarationNames

const LangOptions & getLangOpts() const

uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const

Return number of constant array elements.

AnalysisDeclContext * getContext(const Decl *D)

AnalysisDeclContext contains the context data for the function, method or block under analysis.

const BlockInvocationContext * getBlockInvocationContext(const LocationContext *ParentLC, const BlockDecl *BD, const void *Data)

Obtain a context of the block invocation using its parent context.

const Decl * getDecl() const

static bool isInStdNamespace(const Decl *D)

const StackFrameContext * getStackFrame(LocationContext const *ParentLC, const Stmt *S, const CFGBlock *Blk, unsigned BlockCount, unsigned Index)

Obtain a context of the call stack using its parent context.

ASTContext & getASTContext() const

bool isBodyAutosynthesized() const

CFG::BuildOptions & getCFGBuildOptions()

Stores options for the analyzer from the command line.

bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const

Returns the option controlling which C++ member functions will be considered for inlining.

unsigned maxBlockVisitOnPath

The maximum number of times the analyzer visits a block.

IPAKind getIPAMode() const

Returns the inter-procedural analysis mode.

CTUPhase1InliningKind getCTUPhase1Inlining() const

AnalysisPurgeMode AnalysisPurgeOpt

unsigned InlineMaxStackDepth

The inlining stack depth limit.

Represents a single basic block in a source-level CFG.

succ_iterator succ_begin()

unsigned succ_size() const

Represents C++ constructor call.

std::optional< T > getAs() const

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

Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.

unsigned size() const

Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...

bool isLinear() const

Returns true if the CFG has no branches.

unsigned getNumBlockIDs() const

Returns the total number of BlockIDs allocated (which start at 0).

BasePaths - Represents the set of paths from a derived class to one of its (direct or indirect) bases...

Represents a call to a C++ constructor.

CXXConstructionKind getConstructionKind() const

Determine whether this constructor is actually constructing a base class (rather than a complete obje...

Represents a C++ destructor within a class.

Represents a static or instance method of a struct/union/class.

const CXXRecordDecl * getParent() const

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

bool isMoveAssignmentOperator() const

Determine whether this is a move assignment operator.

bool isCopyAssignmentOperator() const

Determine whether this is a copy-assignment operator, regardless of whether it was declared implicitl...

Represents a C++ struct/union/class.

bool hasTrivialDestructor() const

Determine whether this class has a trivial destructor (C++ [class.dtor]p3)

bool hasMemberName(DeclarationName N) const

Determine whether this class has a member with the given name, possibly in a non-dependent base class...

bool isDerivedFrom(const CXXRecordDecl *Base) const

Determine whether this class is derived from the class Base.

Represents a point when we begin processing an inlined call.

const CFGBlock * getEntry() const

Returns the entry block in the CFG for the entered function.

const StackFrameContext * getCalleeContext() const

Represents a point when we finish the call exit sequence (for inlined call).

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

ConstructionContext's subclasses describe different ways of constructing an object in C++.

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

virtual Decl * getCanonicalDecl()

Retrieves the "canonical" declaration of the given declaration.

IdentifierInfo * getAsIdentifierInfo() const

Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...

This is a meta program point, which should be skipped by all the diagnostic reasoning etc.

This represents one expression.

Represents a function declaration or definition.

bool isTrivial() const

Whether this function is "trivial" in some specialized C++ senses.

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

IdentifierInfo & get(StringRef Name)

Return the identifier token info for the specified named identifier.

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

const Decl * getDecl() const

LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const

const LocationContext * getParent() const

It might return null.

const StackFrameContext * getStackFrame() const

DeclarationName getDeclName() const

Get the actual, stored name of the declaration, which may be a special name.

Represents a parameter to a function.

@ PostStmtPurgeDeadSymbolsKind

const StackFrameContext * getStackFrame() 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.

QualType getCanonicalType() const

bool isConstQualified() const

Determine whether this type is const-qualified.

ReturnStmt - This represents a return, optionally of an expression: return; return 4;.

bool isInSystemHeader(SourceLocation Loc) const

Returns if a SourceLocation is in a system header.

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

unsigned getIndex() const

const Stmt * getCallSite() const

const CFGBlock * getCallSiteBlock() const

Stmt - This represents one statement.

bool isPointerType() const

CanQualType getCanonicalTypeUnqualified() const

bool isReferenceType() const

const CXXRecordDecl * getPointeeCXXRecordDecl() const

If this is a pointer or reference to a RecordType, return the CXXRecordDecl that the type refers to.

QualType getPointeeType() const

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

bool isObjCObjectPointerType() const

static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)

AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)

AnalysisDeclContextManager & getAnalysisDeclContextManager()

AnalyzerOptions & options

bool shouldInlineCall() const

AnalyzerOptions & getAnalyzerOptions() override

BlockDataRegion - A region that represents a block instance.

Represents a call to a C++ constructor.

const CXXConstructorDecl * getDecl() const override

Returns the declaration of the function or method that will be called.

const CXXConstructExpr * getOriginExpr() const override

Returns the expression whose value will be the result of this call.

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

const FunctionDecl * getDecl() const override

Returns the declaration of the function or method that will be called.

Manages the lifetime of CallEvent objects.

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

CallEventRef getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State)

Gets an outside caller given a callee context.

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

CallEventRef< T > cloneWithState(ProgramStateRef NewState) const

Returns a copy of this CallEvent, but using the given state.

static QualType getDeclaredResultType(const Decl *D)

Returns the result type of a function or method declaration.

static bool isVariadic(const Decl *D)

Returns true if the given decl is known to be variadic.

void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng)

Run checkers for pre-visiting obj-c messages.

void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &CE, ExprEngine &Eng, const EvalCallOptions &CallOpts)

Run checkers for evaluating a call.

void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined=false)

Run checkers for post-visiting obj-c messages.

void runCheckersForPostStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined=false)

Run checkers for post-visiting Stmts.

void runCheckersForNewAllocator(const CXXAllocatorCall &Call, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng, bool wasInlined=false)

Run checkers between C++ operator new and constructor calls.

void runCheckersForPreStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng)

Run checkers for pre-visiting Stmts.

void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, bool wasInlined=false)

Run checkers for post-visiting obj-c messages.

WorkList * getCTUWorkList() const

WorkList * getWorkList() const

void enqueue(ExplodedNodeSet &Set)

Enqueue the given set of nodes onto the work list.

ExplodedNode * getNode(const ProgramPoint &L, ProgramStateRef State, bool IsSink=false, bool *IsNew=nullptr)

Retrieve the node associated with a (Location,State) pair, where the 'Location' is a ProgramPoint in ...

ImplTy::iterator iterator

void insert(const ExplodedNodeSet &S)

void Add(ExplodedNode *N)

const ProgramStateRef & getState() const

void addPredecessor(ExplodedNode *V, ExplodedGraph &G)

addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...

const StackFrameContext * getStackFrame() const

const LocationContext * getLocationContext() const

ProgramStateManager & getStateManager()

void processCallEnter(NodeBuilderContext &BC, CallEnter CE, ExplodedNode *Pred)

Generate the entry node of the callee.

void processBeginOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst, const BlockEdge &L)

Called by CoreEngine.

void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out, const Stmt *ReferenceStmt, const LocationContext *LC, const Stmt *DiagnosticStmt=nullptr, ProgramPoint::Kind K=ProgramPoint::PreStmtPurgeDeadSymbolsKind)

Run the analyzer's garbage collection - remove dead symbols and bindings from the state.

std::pair< ProgramStateRef, SVal > handleConstructionContext(const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx, const LocationContext *LCtx, const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx=0)

A convenient wrapper around computeObjectUnderConstruction and updateObjectsUnderConstruction.

void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred, ExplodedNodeSet &Dst)

VisitReturnStmt - Transfer function logic for return statements.

const CoreEngine & getCoreEngine() const

void processCallExit(ExplodedNode *Pred)

Generate the sequence of nodes that simulate the call exit and the post visit for CallExpr.

static std::optional< SVal > getObjectUnderConstruction(ProgramStateRef State, const ConstructionContextItem &Item, const LocationContext *LC)

By looking at a certain item that may be potentially part of an object's ConstructionContext,...

CFGElement getCurrentCFGElement()

Return the CFG element corresponding to the worklist element that is currently being processed by Exp...

@ Inline_Minimal

Do minimal inlining of callees.

ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State, ArrayRef< std::pair< SVal, SVal > > LocAndVals, const LocationContext *LCtx, PointerEscapeKind Kind, const CallEvent *Call)

Call PointerEscape callback when a value escapes as a result of bind.

static std::optional< unsigned > getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E, const LocationContext *LCtx)

Retreives which element is being constructed in a non-POD type array.

void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &Dst)

VisitCall - Transfer function for function calls.

ASTContext & getContext() const

getContext - Return the ASTContext associated with this analysis.

StoreManager & getStoreManager()

CFGBlock::ConstCFGElementRef getCFGElementRef() const

void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const CallEvent &Call)

Evaluate a call, running pre- and post-call checkers and allowing checkers to be responsible for hand...

static std::optional< unsigned > getPendingArrayDestruction(ProgramStateRef State, const LocationContext *LCtx)

Retreives which element is being destructed in a non-POD type array.

CheckerManager & getCheckerManager() const

ProgramStateRef bindReturnValue(const CallEvent &Call, const LocationContext *LCtx, ProgramStateRef State)

Create a new state in which the call return value is binded to the call origin expression.

void removeDeadOnEndOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst)

Remove dead bindings/symbols before exiting a function.

void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred, const CallEvent &Call, const EvalCallOptions &CallOpts={})

Default implementation of call evaluation.

AnalysisManager & getAnalysisManager()

static std::optional< unsigned > getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E, const LocationContext *LCtx)

Retreives the size of the array in the pending ArrayInitLoopExpr.

std::optional< bool > mayInline(const Decl *D)

void markMayInline(const Decl *D)

unsigned getNumTimesInlined(const Decl *D)

void markShouldNotInline(const Decl *D)

void bumpNumTimesInlined(const Decl *D)

MemRegion - The root abstract class for all memory regions.

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

const CFGBlock * getBlock() const

Return the CFGBlock associated with this builder.

unsigned blockCount() const

Returns the number of times the current basic block has been visited on the exploded graph path.

This is the simplest builder which generates nodes in the ExplodedGraph.

ExplodedNode * generateNode(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred)

Generates a node in the ExplodedGraph.

void takeNodes(const ExplodedNodeSet &S)

Represents any expression that calls an Objective-C method.

While alive, includes the current analysis stack in a crash trace.

CallEventManager & getCallEventManager()

Information about invalidation for a particular region/symbol.

@ TK_DoNotInvalidateSuperRegion

void setTrait(SymbolRef Sym, InvalidationKinds IK)

Defines the runtime definition of the called function.

const MemRegion * getDispatchRegion()

When other definitions are possible, returns the region whose runtime type determines the method defi...

bool mayHaveOtherDefinitions()

Check if the definition we have is precise.

nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)

QualType getArrayIndexType() const

SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)

Cast a given SVal to another SVal using given QualType's.

DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)

Create a new symbol with a unique 'name'.

loc::MemRegionVal getCXXThis(const CXXMethodDecl *D, const StackFrameContext *SFC)

Return a memory region for the 'this' object reference.

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

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

Conjure a symbol representing heap allocated memory region.

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

QualType getType(const ASTContext &) const

Try to get a reasonable type for the given value.

const MemRegion * getAsRegion() const

T castAs() const

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

This builder class is useful for generating nodes that resulted from visiting a statement.

ExplodedNode * generateNode(const Stmt *S, ExplodedNode *Pred, ProgramStateRef St, const ProgramPointTag *tag=nullptr, ProgramPoint::Kind K=ProgramPoint::PostStmtKind)

SVal evalDerivedToBase(SVal Derived, const CastExpr *Cast)

Evaluates a chain of derived-to-base casts through the path specified in Cast.

virtual void enqueue(const WorkListUnit &U)=0

LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getRegion() const

Get the underlining region.

@ PSK_EscapeOutParameters

Escape for a new symbol that was generated into a region that the analyzer cannot follow during a con...

DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB, QualType Ty)

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

Set the dynamic extent Extent of the region MR.

@ CE_CXXInheritedConstructor

DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB)

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

@ IPAK_DynamicDispatch

Enable inlining of dynamically dispatched methods.

@ IPAK_DynamicDispatchBifurcate

Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailabl...

@ CIMK_Destructors

Refers to destructors (implicit or explicit).

@ CIMK_MemberFunctions

Refers to regular member function and operator calls.

@ CIMK_Constructors

Refers to constructors (implicit or explicit).

Hints for figuring out of a call should be inlined during evalCall().

bool IsTemporaryLifetimeExtendedViaAggregate

This call is a constructor for a temporary that is lifetime-extended by binding it to a reference-typ...

bool IsTemporaryCtorOrDtor

This call is a constructor or a destructor of a temporary value.

bool IsArrayCtorOrDtor

This call is a constructor or a destructor for a single element within an array, a part of array cons...

bool IsCtorOrDtorWithImproperlyModeledTargetRegion

This call is a constructor or a destructor for which we do not currently compute the this-region corr...

Traits for storing the call processing policy inside GDM.