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