clang: lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
25#include "llvm/ADT/DenseMap.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/ADT/MapVector.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/Support/ErrorHandling.h"
31#include
32#include
33#include
34
35#define DEBUG_TYPE "dataflow"
36
38namespace dataflow {
39
40
41
42
45
46
47static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
48 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
49 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
50 llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;
51 for (auto &Entry : DeclToLoc1) {
52 auto It = DeclToLoc2.find(Entry.first);
53 if (It != DeclToLoc2.end() && Entry.second == It->second)
54 Result.insert({Entry.first, Entry.second});
55 }
57}
58
59
60
61
62
63
64template
65static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
67
68 for (const auto &Entry : Map2) {
69 [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
70
71
72 assert(It->second == Entry.second);
73 }
74
76}
77
78
79
80
81
82
83
85 switch (K) {
88 return true;
89 default:
90 return false;
91 }
92}
93
98
99
100
101
102
103
104 switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
106 return true;
108 return false;
111 }
112 llvm_unreachable("All cases covered in switch");
113}
114
115
116
117
118
124
125
127
128
129
130
131
132
133
134
135
136
137
138
139
142 auto &A = JoinedEnv.arena();
143 auto &JoinedVal = A.makeAtomRef(A.makeAtom());
146 A.makeEquals(JoinedVal, Expr1)),
148 A.makeEquals(JoinedVal, Expr2))));
149 return &A.makeBoolValue(JoinedVal);
150 }
151
153 if (JoinedVal)
154 Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
155
156 return JoinedVal;
157}
158
163
165
166
167
170
172
173
175
176
177
178
179 bool TruePrev = PrevEnv.proves(PrevBool.formula());
180 bool TrueCur = CurrentEnv.proves(CurBool.formula());
181 if (TruePrev && TrueCur)
183 if (!TruePrev && !TrueCur &&
187
189 }
190
191
192
193
194 if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
196
200}
201
202
203
204template
206 const llvm::MapVector<Key, Value *> &Map2,
210 for (auto &Entry : Map1) {
211 Key K = Entry.first;
212 assert(K != nullptr);
213
214 Value *Val = Entry.second;
215 assert(Val != nullptr);
216
217 auto It = Map2.find(K);
218 if (It == Map2.end())
219 continue;
220 assert(It->second != nullptr);
221
224 Model))
225 return false;
226 }
227
228 return true;
229}
230
231
232static llvm::MapVector<const StorageLocation *, Value *>
233joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
234 const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
237 llvm::MapVector<const StorageLocation *, Value *> Result;
238 for (auto &Entry : LocToVal) {
240 assert(Loc != nullptr);
241
242 Value *Val = Entry.second;
243 assert(Val != nullptr);
244
245 auto It = LocToVal2.find(Loc);
246 if (It == LocToVal2.end())
247 continue;
248 assert(It->second != nullptr);
249
251 Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
252 Result.insert({Loc, JoinedVal});
253 }
254 }
255
257}
258
259
260
261template
262static llvm::MapVector<Key, Value *>
264 const llvm::MapVector<Key, Value *> &PrevMap,
267 llvm::MapVector<Key, Value *> WidenedMap;
268 for (auto &Entry : CurMap) {
269 Key K = Entry.first;
270 assert(K != nullptr);
271
272 Value *Val = Entry.second;
273 assert(Val != nullptr);
274
275 auto PrevIt = PrevMap.find(K);
276 if (PrevIt == PrevMap.end())
277 continue;
278 assert(PrevIt->second != nullptr);
279
281 WidenedMap.insert({K, Val});
282 continue;
283 }
284
286 K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
287 WidenedMap.insert({K, WidenedVal});
290 }
291
292 return WidenedMap;
293}
294
295namespace {
296
297
298
299
300class ResultObjectVisitor : public AnalysisASTVisitor {
301public:
302
303
304
305
306 explicit ResultObjectVisitor(
307 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
308 RecordStorageLocation *LocForRecordReturnVal,
309 DataflowAnalysisContext &DACtx)
310 : ResultObjectMap(ResultObjectMap),
311 LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
312
313
314
315
316
317 void traverseConstructorInits(const CXXConstructorDecl *Ctor,
318 RecordStorageLocation *ThisPointeeLoc) {
319 assert(ThisPointeeLoc != nullptr);
320 for (const CXXCtorInitializer *Init : Ctor->inits()) {
321 Expr *InitExpr = Init->getInit();
322 if (FieldDecl *Field = Init->getMember();
323 Field != nullptr && Field->getType()->isRecordType()) {
325 ThisPointeeLoc->getChild(*Field)));
326 } else if (Init->getBaseClass()) {
327 PropagateResultObject(InitExpr, ThisPointeeLoc);
328 }
329
330
331
332 TraverseStmt(InitExpr);
333
334
335
336 if (auto *DefaultInit = dyn_cast(InitExpr))
337 TraverseStmt(DefaultInit->getExpr());
338 }
339 }
340
341 bool VisitVarDecl(VarDecl *VD) override {
342 if (VD->getType()->isRecordType() && VD->hasInit())
343 PropagateResultObject(
344 VD->getInit(),
346 return true;
347 }
348
349 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override {
350 if (MTE->getType()->isRecordType())
351 PropagateResultObject(
352 MTE->getSubExpr(),
354 return true;
355 }
356
357 bool VisitReturnStmt(ReturnStmt *Return) override {
358 Expr *RetValue = Return->getRetValue();
359 if (RetValue != nullptr && RetValue->getType()->isRecordType() &&
361 PropagateResultObject(RetValue, LocForRecordReturnVal);
362 return true;
363 }
364
365 bool VisitExpr(Expr *E) override {
366
367
368
369
370
371 if (E->isPRValue() && E->getType()->isRecordType() &&
372 !ResultObjectMap.contains(E))
373 PropagateResultObject(
375 return true;
376 }
377
378 void
379 PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,
380 RecordStorageLocation *Loc) {
381 for (auto [Base, Init] : InitList.base_inits()) {
382 assert(Base->getType().getCanonicalType() ==
383 Init->getType().getCanonicalType());
384
385
386
387
388 PropagateResultObject(Init, Loc);
389 }
390
391 for (auto [Field, Init] : InitList.field_inits()) {
392
393
394 if (Field->getType()->isRecordType())
395 PropagateResultObject(
397 }
398 }
399
400
401
402
403 void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
404 if (!E->isPRValue() || !E->getType()->isRecordType()) {
405 assert(false);
406
407
408 return;
409 }
410
411 ResultObjectMap[E] = Loc;
412
413
414
415
419
420
421
423 return;
424 }
425 if (auto *Op = dyn_cast(E);
426 Op && Op->getOpcode() == BO_Cmp) {
427
428 return;
429 }
430
431 if (auto *InitList = dyn_cast(E)) {
432 if (!InitList->isSemanticForm())
433 return;
434 if (InitList->isTransparent()) {
435 PropagateResultObject(InitList->getInit(0), Loc);
436 return;
437 }
438
439 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
440 Loc);
441 return;
442 }
443
444 if (auto *ParenInitList = dyn_cast(E)) {
445 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
446 Loc);
447 return;
448 }
449
450 if (auto *Op = dyn_cast(E); Op && Op->isCommaOp()) {
451 PropagateResultObject(Op->getRHS(), Loc);
452 return;
453 }
454
455 if (auto *Cond = dyn_cast(E)) {
456 PropagateResultObject(Cond->getTrueExpr(), Loc);
457 PropagateResultObject(Cond->getFalseExpr(), Loc);
458 return;
459 }
460
461 if (auto *SE = dyn_cast(E)) {
462 PropagateResultObject(cast(SE->getSubStmt()->body_back()), Loc);
463 return;
464 }
465
466 if (auto *DIE = dyn_cast(E)) {
467 PropagateResultObject(DIE->getExpr(), Loc);
468 return;
469 }
470
471
472
473 SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
474 LLVM_DEBUG({
476 E->dump();
477 });
478 assert(Children.size() == 1);
480 PropagateResultObject(cast(S), Loc);
481 }
482
483private:
484 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
485 RecordStorageLocation *LocForRecordReturnVal;
486 DataflowAnalysisContext &DACtx;
487};
488
489}
490
492 if (InitialTargetStmt == nullptr)
493 return;
494
495 if (InitialTargetFunc == nullptr) {
497 ResultObjectMap =
498 std::make_shared(buildResultObjectMap(
500 nullptr));
501 return;
502 }
503
505
506 for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
507 assert(ParamDecl != nullptr);
509 }
510
511 if (InitialTargetFunc->getReturnType()->isRecordType())
514
515 if (const auto *MethodDecl = dyn_cast(InitialTargetFunc)) {
516 auto *Parent = MethodDecl->getParent();
517 assert(Parent != nullptr);
518
519 if (Parent->isLambda()) {
520 for (const auto &Capture : Parent->captures()) {
521 if (Capture.capturesVariable()) {
523 assert(VarDecl != nullptr);
525 } else if (Capture.capturesThis()) {
526 if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
529 SurroundingMethodDecl->getFunctionObjectParameterType();
532 } else if (auto *FieldBeingInitialized =
533 dyn_cast(Parent->getLambdaContextDecl())) {
534
540 } else {
541 assert(false && "Unexpected this-capturing lambda context.");
542 }
543 }
544 }
545 } else if (MethodDecl->isImplicitObjectMemberFunction()) {
546 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
547 auto &ThisLoc =
550
551
552
555 }
556 }
557
558
559
560 ResultObjectMap =
561 std::make_shared(buildResultObjectMap(
563 LocForRecordReturnVal));
564}
565
566
567
568
569void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
570
571
572 DACtx->addModeledFields(Referenced.Fields);
573
576 continue;
577
578
579
580
581
582
584 }
585
588 continue;
591 }
592}
593
596 Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
598}
599
602 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
603}
604
607
608 if (const auto *MethodCall = dyn_cast(Call)) {
609 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
611 Env.ThisPointeeLoc =
613
614
615 }
616 }
617
618 if (Call->getType()->isRecordType() && Call->isPRValue())
620
621 Env.pushCallInternal(Call->getDirectCallee(),
623
624 return Env;
625}
626
629
632
633 Env.pushCallInternal(Call->getConstructor(),
635
636 return Env;
637}
638
639void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
641
642
643
646
647 CallStack.push_back(FuncDecl);
648
650
651 const auto *ParamIt = FuncDecl->param_begin();
652
653
654
655 for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
656 assert(ParamIt != FuncDecl->param_end());
657 const VarDecl *Param = *ParamIt;
659 }
660
661 ResultObjectMap = std::make_shared(
663 LocForRecordReturnVal));
664}
665
667
668
669
670
671
672
673
674 this->LocToVal = std::move(CalleeEnv.LocToVal);
675 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
676
677 if (Call->isGLValue()) {
678 if (CalleeEnv.ReturnLoc != nullptr)
680 } else if (->getType()->isVoidType()) {
681 if (CalleeEnv.ReturnVal != nullptr)
683 }
684}
685
688
689 this->LocToVal = std::move(CalleeEnv.LocToVal);
690 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
691}
692
695 assert(DACtx == Other.DACtx);
696
697 if (ReturnVal != Other.ReturnVal)
698 return false;
699
700 if (ReturnLoc != Other.ReturnLoc)
701 return false;
702
703 if (LocForRecordReturnVal != Other.LocForRecordReturnVal)
704 return false;
705
706 if (ThisPointeeLoc != Other.ThisPointeeLoc)
707 return false;
708
709 if (DeclToLoc != Other.DeclToLoc)
710 return false;
711
712 if (ExprToLoc != Other.ExprToLoc)
713 return false;
714
716 return false;
717
719 return false;
720
721 return true;
722}
723
726 assert(DACtx == PrevEnv.DACtx);
727 assert(ReturnVal == PrevEnv.ReturnVal);
728 assert(ReturnLoc == PrevEnv.ReturnLoc);
729 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
730 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
731 assert(CallStack == PrevEnv.CallStack);
732 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
733 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
734 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
735
737
738
739
740
741
742
743
744 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
745 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
746 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
747
748 ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
749 Model, Effect);
750
751 LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
752 Model, Effect);
753 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
754 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
755 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
756 LocToVal.size() != PrevEnv.LocToVal.size())
758
759 return Effect;
760}
761
765 assert(EnvA.DACtx == EnvB.DACtx);
766 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
767 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
768 assert(EnvA.CallStack == EnvB.CallStack);
769 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
770 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
771 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
772
774
775 JoinedEnv.CallStack = EnvA.CallStack;
776 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
777 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
778 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
779 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
780 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
781
784 JoinedEnv.ReturnVal = nullptr;
785 } else {
786 JoinedEnv.ReturnVal =
787 joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
788 EnvB, JoinedEnv, Model);
789 }
790
791 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
792 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
793 else
794 JoinedEnv.ReturnLoc = nullptr;
795
796 JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);
797
798
799
801 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
802
803 JoinedEnv.LocToVal =
804 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
805
807 JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
808 JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
809 }
810
811 return JoinedEnv;
812}
813
818 if (Val1 == nullptr || Val2 == nullptr)
819
820
821
822
823 return nullptr;
824
826
827 return Val1;
828
829 return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
830}
831
833 return DACtx->createStorageLocation(Type);
834}
835
837
838
839
840 return DACtx->getStableStorageLocation(D);
841}
842
844
845
846
847 return DACtx->getStableStorageLocation(E);
848}
849
851 assert(!DeclToLoc.contains(&D));
852
853
854
855
858 DeclToLoc[&D] = &Loc;
859}
860
862 auto It = DeclToLoc.find(&D);
863 if (It == DeclToLoc.end())
864 return nullptr;
865
867
868 return Loc;
869}
870
872
874
875
876
880 assert(!ExprToLoc.contains(&CanonE));
881 ExprToLoc[&CanonE] = &Loc;
882}
883
885
889 return It == ExprToLoc.end() ? nullptr : &*It->second;
890}
891
895 assert(RecordPRValue.isPRValue());
896
897 assert(ResultObjectMap != nullptr);
899 assert(Loc != nullptr);
900
901
902 if (Loc == nullptr)
904 DACtx->getStableStorageLocation(RecordPRValue));
905 return *Loc;
906}
907
909 return DACtx->getOrCreateNullPointerValue(PointeeType);
910}
911
914 llvm::DenseSet Visited;
915 int CreatedValuesCount = 0;
918 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
919 << '\n';
920 }
921}
922
924
926 LocToVal[&Loc] = &Val;
927}
928
931
933
935 ExprToVal[&CanonE] = &Val;
936}
937
939
941 return LocToVal.lookup(&Loc);
942}
943
946 if (Loc == nullptr)
947 return nullptr;
949}
950
952
954
957 return It == ExprToVal.end() ? nullptr : It->second;
958 }
959
961 if (It == ExprToLoc.end())
962 return nullptr;
963 return getValue(*It->second);
964}
965
967 llvm::DenseSet Visited;
968 int CreatedValuesCount = 0;
969 Value *Val = createValueUnlessSelfReferential(Type, Visited, 0,
970 CreatedValuesCount);
972 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
973 << '\n';
974 }
975 return Val;
976}
977
978Value *Environment::createValueUnlessSelfReferential(
979 QualType Type, llvm::DenseSet &Visited, int Depth,
980 int &CreatedValuesCount) {
981 assert(.isNull());
984
985
988 return nullptr;
989
991 CreatedValuesCount++;
993 }
994
996
997
998
999 CreatedValuesCount++;
1001 }
1002
1003 if (Type->isPointerType()) {
1004 CreatedValuesCount++;
1005 QualType PointeeType = Type->getPointeeType();
1006 StorageLocation &PointeeLoc =
1007 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1008
1009 return &arena().create(PointeeLoc);
1010 }
1011
1012 return nullptr;
1013}
1014
1016Environment::createLocAndMaybeValue(QualType Ty,
1017 llvm::DenseSet &Visited,
1018 int Depth, int &CreatedValuesCount) {
1019 if (!Visited.insert(Ty.getCanonicalType()).second)
1021 auto EraseVisited = llvm::make_scope_exit(
1022 [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
1023
1024 Ty = Ty.getNonReferenceType();
1025
1026 if (Ty->isRecordType()) {
1029 return Loc;
1030 }
1031
1033
1034 if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1035 CreatedValuesCount))
1037
1038 return Loc;
1039}
1040
1042 QualType Type,
1043 llvm::DenseSet &Visited,
1044 int Depth,
1045 int &CreatedValuesCount) {
1046 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1047 if (FieldType->isRecordType()) {
1050 Visited, Depth + 1, CreatedValuesCount);
1051 } else {
1052 if (getValue(FieldLoc) != nullptr)
1053 return;
1054 if (!Visited.insert(FieldType.getCanonicalType()).second)
1055 return;
1056 if (Value *Val = createValueUnlessSelfReferential(
1057 FieldType, Visited, Depth + 1, CreatedValuesCount))
1059 Visited.erase(FieldType.getCanonicalType());
1060 }
1061 };
1062
1063 for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
1064 assert(Field != nullptr);
1065 QualType FieldType = Field->getType();
1066
1067 if (FieldType->isReferenceType()) {
1068 Loc.setChild(*Field,
1069 &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1070 CreatedValuesCount));
1071 } else {
1072 StorageLocation *FieldLoc = Loc.getChild(*Field);
1073 assert(FieldLoc != nullptr);
1074 initField(FieldType, *FieldLoc);
1075 }
1076 }
1077 for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {
1078
1079
1080 assert(!FieldType->isReferenceType());
1081 initField(FieldType, Loc.getSyntheticField(FieldName));
1082 }
1083}
1084
1085StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
1086 QualType Ty,
1087 const Expr *InitExpr) {
1088 if (Ty->isReferenceType()) {
1089
1090
1091
1092 if (InitExpr) {
1094 return *InitExprLoc;
1095 }
1096
1097
1098
1099
1100
1101 return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
1102 }
1103
1104 StorageLocation &Loc =
1106
1107 if (Ty->isRecordType()) {
1108 auto &RecordLoc = cast(Loc);
1109 if (!InitExpr)
1110 initializeFieldsWithValues(RecordLoc);
1111 } else {
1112 Value *Val = nullptr;
1113 if (InitExpr)
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127 Val = getValue(*InitExpr);
1128 if (!Val)
1129 Val = createValue(Ty);
1130 if (Val)
1131 setValue(Loc, *Val);
1132 }
1133
1134 return Loc;
1135}
1136
1138 DACtx->addFlowConditionConstraint(FlowConditionToken, F);
1139}
1140
1142 return DACtx->flowConditionImplies(FlowConditionToken, F);
1143}
1144
1146 return DACtx->flowConditionAllows(FlowConditionToken, F);
1147}
1148
1150 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1151 if (LocForRecordReturnVal != nullptr)
1152 LocToName[LocForRecordReturnVal] = "(returned record)";
1153 if (ThisPointeeLoc != nullptr)
1154 LocToName[ThisPointeeLoc] = "this";
1155
1156 OS << "DeclToLoc:\n";
1157 for (auto [D, L] : DeclToLoc) {
1158 auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1159 OS << " [" << Iter->second << ", " << L << "]\n";
1160 }
1161 OS << "ExprToLoc:\n";
1162 for (auto [E, L] : ExprToLoc)
1163 OS << " [" << E << ", " << L << "]\n";
1164
1165 OS << "ExprToVal:\n";
1166 for (auto [E, V] : ExprToVal)
1167 OS << " [" << E << ", " << V << ": " << *V << "]\n";
1168
1169 OS << "LocToVal:\n";
1170 for (auto [L, V] : LocToVal) {
1171 OS << " [" << L;
1172 if (auto Iter = LocToName.find(L); Iter != LocToName.end())
1173 OS << " (" << Iter->second << ")";
1174 OS << ", " << V << ": " << *V << "]\n";
1175 }
1176
1178 if (Func->getReturnType()->isReferenceType()) {
1179 OS << "ReturnLoc: " << ReturnLoc;
1180 if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1181 OS << " (" << Iter->second << ")";
1182 OS << "\n";
1183 } else if (Func->getReturnType()->isRecordType() ||
1185 OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";
1186 } else if (->getReturnType()->isVoidType()) {
1187 if (ReturnVal == nullptr)
1188 OS << "ReturnVal: nullptr\n";
1189 else
1190 OS << "ReturnVal: " << *ReturnVal << "\n";
1191 }
1192
1194 OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";
1195 }
1196 }
1197
1198 OS << "\n";
1199 DACtx->dumpFlowCondition(FlowConditionToken, OS);
1200}
1201
1203
1204Environment::PrValueToResultObject Environment::buildResultObjectMap(
1209
1210 PrValueToResultObject Map = buildResultObjectMap(
1211 DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1212
1213 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1214 if (const auto *Ctor = dyn_cast(FuncDecl))
1215 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1216
1217 return Map;
1218}
1219
1220Environment::PrValueToResultObject Environment::buildResultObjectMap(
1221 DataflowAnalysisContext *DACtx, Stmt *S,
1222 RecordStorageLocation *ThisPointeeLoc,
1223 RecordStorageLocation *LocForRecordReturnVal) {
1224 PrValueToResultObject Map;
1225 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1226 Visitor.TraverseStmt(S);
1227 return Map;
1228}
1229
1233 if (ImplicitObject == nullptr)
1234 return nullptr;
1238 return nullptr;
1239 }
1240 return cast_or_null(
1242}
1243
1247 if (Base == nullptr)
1248 return nullptr;
1252 return nullptr;
1253 }
1255}
1256
1257}
1258}
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable, bool IsVolatile, bool IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
Defines the clang::Expr interface and subclasses for C++ expressions.
SmallVector< AnnotatedLine *, 1 > Children
If this token starts a block, this contains all the unwrapped lines in it.
static bool RetValue(InterpState &S, CodePtr &Pt)
C Language Family Type Representation.
Represents a member of a struct/union/class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents a call to a C++ constructor.
Represents a call to a member function that may be written either with member call syntax (e....
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
DeclContext * getParent()
getParent - Returns the containing DeclContext.
ASTContext & getASTContext() const LLVM_READONLY
This represents one expression.
Represents a function declaration or definition.
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
param_iterator param_end()
param_iterator param_begin()
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
FunctionDecl * getDefinition()
Get the definition for this declaration.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
A (possibly-)qualified type.
Represents a struct/union/class.
Stmt - This represents one statement.
The base class of the type hierarchy.
bool isBooleanType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isReferenceType() const
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
bool isRecordType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
const Formula & makeAtomRef(Atom A)
Returns a formula for the variable A.
const Formula & makeNot(const Formula &Val)
Returns a formula for the negation of Val.
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of StorageLocation), forwarding args to the constructor,...
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
Atom joinFlowConditions(Atom FirstToken, Atom SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
Supplements Environment with non-standard comparison and join operations.
Holds the state of the program (store and heap) at a given program point.
bool allows(const Formula &) const
Returns true if the formula may be true when this point is reached.
Definition DataflowEnvironment.cpp:1145
LatticeEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
Definition DataflowEnvironment.cpp:724
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
Definition DataflowEnvironment.cpp:908
RecordStorageLocation * getThisPointeeStorageLocation() const
Returns the storage location assigned to the this pointee in the environment or null if the this poin...
Environment pushCall(const CallExpr *Call) const
Creates and returns an environment to use for an inline analysis of the callee.
Definition DataflowEnvironment.cpp:605
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
Definition DataflowEnvironment.cpp:861
LLVM_DUMP_METHOD void dump() const
Definition DataflowEnvironment.cpp:1202
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type)
Initializes the fields (including synthetic fields) of Loc with values, unless values of the field ty...
Definition DataflowEnvironment.cpp:912
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Definition DataflowEnvironment.cpp:832
Environment fork() const
Returns a new environment that is a copy of this one.
Definition DataflowEnvironment.cpp:594
void popCall(const CallExpr *Call, const Environment &CalleeEnv)
Moves gathered information back into this from a CalleeEnv created via pushCall.
Definition DataflowEnvironment.cpp:666
bool equivalentTo(const Environment &Other, Environment::ValueModel &Model) const
Returns true if and only if the environment is equivalent to Other, i.e the two environments:
Definition DataflowEnvironment.cpp:693
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
bool proves(const Formula &) const
Returns true if the formula is always true when this point is reached.
Definition DataflowEnvironment.cpp:1141
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
Definition DataflowEnvironment.cpp:938
const FunctionDecl * getCurrentFunc() const
Returns the function currently being analyzed, or null if the code being analyzed isn't part of a fun...
BoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
StorageLocation & createObject(QualType Ty, const Expr *InitExpr=nullptr)
Creates an object (i.e.
void assume(const Formula &)
Record a fact that must be true if this point in the program is reached.
Definition DataflowEnvironment.cpp:1137
Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken)
Creates an environment that uses DACtx to store objects that encompass the state of a program.
static Value * joinValues(QualType Ty, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Returns a value that approximates both Val1 and Val2, or null if no such value can be produced.
Definition DataflowEnvironment.cpp:814
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
Definition DataflowEnvironment.cpp:850
void removeDecl(const ValueDecl &D)
Removes the location assigned to D in the environment (if any).
Definition DataflowEnvironment.cpp:871
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue) const
Returns the location of the result object for a record-type prvalue.
Definition DataflowEnvironment.cpp:893
ExprJoinBehavior
How to treat expression state (ExprToLoc and ExprToVal) in a join.
static Environment join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model, ExprJoinBehavior ExprBehavior)
Joins two environments by taking the intersection of storage locations and values that are stored in ...
Definition DataflowEnvironment.cpp:762
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
Definition DataflowEnvironment.cpp:966
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
Definition DataflowEnvironment.cpp:923
void setThisPointeeStorageLocation(RecordStorageLocation &Loc)
Sets the storage location assigned to the this pointee in the environment.
Atom getFlowConditionToken() const
Returns a boolean variable that identifies the flow condition (FC).
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const
Returns whether this Environment can be extended to analyze the given Callee (i.e.
Definition DataflowEnvironment.cpp:600
std::enable_if_t< std::is_base_of_v< StorageLocation, T >, T * > get(const ValueDecl &D) const
Returns the result of casting getStorageLocation(...) to a subclass of StorageLocation (using cast_or...
void initialize()
Assigns storage locations and values to all parameters, captures, global variables,...
Definition DataflowEnvironment.cpp:491
Models a symbolic pointer. Specifically, any value of type T*.
A storage location for a record (struct, class, or union).
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
static bool compareKeyToValueMaps(const llvm::MapVector< Key, Value * > &Map1, const llvm::MapVector< Key, Value * > &Map2, const Environment &Env1, const Environment &Env2, Environment::ValueModel &Model)
Definition DataflowEnvironment.cpp:205
static llvm::DenseMap< const ValueDecl *, StorageLocation * > intersectDeclToLoc(const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc1, const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc2)
Returns a map consisting of key-value entries that are present in both maps.
Definition DataflowEnvironment.cpp:47
static bool equateUnknownValues(Value::Kind K)
Definition DataflowEnvironment.cpp:84
bool areEquivalentValues(const Value &Val1, const Value &Val2)
An equivalence relation for values.
static llvm::MapVector< Key, Value * > widenKeyToValueMap(const llvm::MapVector< Key, Value * > &CurMap, const llvm::MapVector< Key, Value * > &PrevMap, Environment &CurEnv, const Environment &PrevEnv, Environment::ValueModel &Model, LatticeEffect &Effect)
Definition DataflowEnvironment.cpp:263
static constexpr int MaxCompositeValueDepth
Definition DataflowEnvironment.cpp:43
static constexpr int MaxCompositeValueSize
Definition DataflowEnvironment.cpp:44
ReferencedDecls getReferencedDecls(const FunctionDecl &FD)
Returns declarations that are declared in or referenced from FD.
RecordStorageLocation * getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env)
Returns the storage location for the implicit object of a CXXMemberCallExpr, or null if none is defin...
Definition DataflowEnvironment.cpp:1230
static WidenResult widenDistinctValues(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv, Environment::ValueModel &Model)
Definition DataflowEnvironment.cpp:159
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
static llvm::MapVector< const StorageLocation *, Value * > joinLocToVal(const llvm::MapVector< const StorageLocation *, Value * > &LocToVal, const llvm::MapVector< const StorageLocation *, Value * > &LocToVal2, const Environment &Env1, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Definition DataflowEnvironment.cpp:233
static MapT joinExprMaps(const MapT &Map1, const MapT &Map2)
Definition DataflowEnvironment.cpp:65
static bool compareDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment::ValueModel &Model)
Definition DataflowEnvironment.cpp:94
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
Definition DataflowEnvironment.cpp:1244
static Value * joinDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Attempts to join distinct values Val1 and Val2 in Env1 and Env2, respectively, of the same type Type.
Definition DataflowEnvironment.cpp:119
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Type
The name was classified as a type.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
A collection of several types of declarations, all referenced from the same function.
llvm::SetVector< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
FieldSet Fields
Non-static member variables.
llvm::SetVector< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
The result of a widen operation.