clang: lib/Analysis/FlowSensitive/DataflowEnvironment.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
26#include "llvm/ADT/DenseMap.h"
27#include "llvm/ADT/DenseSet.h"
28#include "llvm/ADT/MapVector.h"
29#include "llvm/ADT/PointerUnion.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/ScopeExit.h"
32#include "llvm/Support/ErrorHandling.h"
33#include
34#include
35#include
36#include
37
38#define DEBUG_TYPE "dataflow"
39
41namespace dataflow {
42
43
44
45
48
49
50static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
51 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
52 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
53 llvm::DenseMap<const ValueDecl *, StorageLocation *> Result;
54 for (auto &Entry : DeclToLoc1) {
55 auto It = DeclToLoc2.find(Entry.first);
56 if (It != DeclToLoc2.end() && Entry.second == It->second)
57 Result.insert({Entry.first, Entry.second});
58 }
60}
61
62
63
64
65
66
67template
68static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
70
71 for (const auto &Entry : Map2) {
72 [[maybe_unused]] auto [It, Inserted] = Result.insert(Entry);
73
74
75 assert(It->second == Entry.second);
76 }
77
79}
80
81
82
83
84
85
86
88 switch (K) {
91 return true;
92 default:
93 return false;
94 }
95}
96
101
102
103
104
105
106
107 switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
109 return true;
111 return false;
114 }
115 llvm_unreachable("All cases covered in switch");
116}
117
118
119
120
121
127
128
129 if (isa(&Val1) && isa(&Val2)) {
130
131
132
133
134
135
136
137
138
139
140
141
142
143 auto &Expr1 = cast(Val1).formula();
144 auto &Expr2 = cast(Val2).formula();
145 auto &A = JoinedEnv.arena();
146 auto &JoinedVal = A.makeAtomRef(A.makeAtom());
149 A.makeEquals(JoinedVal, Expr1)),
151 A.makeEquals(JoinedVal, Expr2))));
152 return &A.makeBoolValue(JoinedVal);
153 }
154
156 if (JoinedVal)
157 Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
158
159 return JoinedVal;
160}
161
166
167 if (isa(Prev) && isa(Current)) {
168
169
170
171 auto &PrevBool = cast(Prev);
172 auto &CurBool = cast(Current);
173
174 if (isa(Prev))
175
176
178
179
180
181
182 bool TruePrev = PrevEnv.proves(PrevBool.formula());
183 bool TrueCur = CurrentEnv.proves(CurBool.formula());
184 if (TruePrev && TrueCur)
186 if (!TruePrev && !TrueCur &&
190
192 }
193
194
195
196
197 if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
199
203}
204
205
206
207template
209 const llvm::MapVector<Key, Value *> &Map2,
213 for (auto &Entry : Map1) {
214 Key K = Entry.first;
215 assert(K != nullptr);
216
217 Value *Val = Entry.second;
218 assert(Val != nullptr);
219
220 auto It = Map2.find(K);
221 if (It == Map2.end())
222 continue;
223 assert(It->second != nullptr);
224
227 Model))
228 return false;
229 }
230
231 return true;
232}
233
234
235static llvm::MapVector<const StorageLocation *, Value *>
236joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
237 const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2,
240 llvm::MapVector<const StorageLocation *, Value *> Result;
241 for (auto &Entry : LocToVal) {
243 assert(Loc != nullptr);
244
245 Value *Val = Entry.second;
246 assert(Val != nullptr);
247
248 auto It = LocToVal2.find(Loc);
249 if (It == LocToVal2.end())
250 continue;
251 assert(It->second != nullptr);
252
254 Loc->getType(), Val, Env1, It->second, Env2, JoinedEnv, Model)) {
256 }
257 }
258
260}
261
262
263
264template
265static llvm::MapVector<Key, Value *>
267 const llvm::MapVector<Key, Value *> &PrevMap,
270 llvm::MapVector<Key, Value *> WidenedMap;
271 for (auto &Entry : CurMap) {
272 Key K = Entry.first;
273 assert(K != nullptr);
274
275 Value *Val = Entry.second;
276 assert(Val != nullptr);
277
278 auto PrevIt = PrevMap.find(K);
279 if (PrevIt == PrevMap.end())
280 continue;
281 assert(PrevIt->second != nullptr);
282
284 WidenedMap.insert({K, Val});
285 continue;
286 }
287
289 K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model);
290 WidenedMap.insert({K, WidenedVal});
293 }
294
295 return WidenedMap;
296}
297
298namespace {
299
300
301
302
303class ResultObjectVisitor : public AnalysisASTVisitor {
304public:
305
306
307
308
309 explicit ResultObjectVisitor(
310 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap,
311 RecordStorageLocation *LocForRecordReturnVal,
312 DataflowAnalysisContext &DACtx)
313 : ResultObjectMap(ResultObjectMap),
314 LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {}
315
316
317
318
319
320 void traverseConstructorInits(const CXXConstructorDecl *Ctor,
321 RecordStorageLocation *ThisPointeeLoc) {
322 assert(ThisPointeeLoc != nullptr);
323 for (const CXXCtorInitializer *Init : Ctor->inits()) {
324 Expr *InitExpr = Init->getInit();
325 if (FieldDecl *Field = Init->getMember();
326 Field != nullptr && Field->getType()->isRecordType()) {
327 PropagateResultObject(InitExpr, cast(
328 ThisPointeeLoc->getChild(*Field)));
329 } else if (Init->getBaseClass()) {
330 PropagateResultObject(InitExpr, ThisPointeeLoc);
331 }
332
333
334
335 TraverseStmt(InitExpr);
336
337
338
339 if (auto *DefaultInit = dyn_cast(InitExpr))
340 TraverseStmt(DefaultInit->getExpr());
341 }
342 }
343
344 bool VisitVarDecl(VarDecl *VD) override {
345 if (VD->getType()->isRecordType() && VD->hasInit())
346 PropagateResultObject(
347 VD->getInit(),
348 &cast(DACtx.getStableStorageLocation(*VD)));
349 return true;
350 }
351
352 bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) override {
353 if (MTE->getType()->isRecordType())
354 PropagateResultObject(
355 MTE->getSubExpr(),
356 &cast(DACtx.getStableStorageLocation(*MTE)));
357 return true;
358 }
359
360 bool VisitReturnStmt(ReturnStmt *Return) override {
361 Expr *RetValue = Return->getRetValue();
362 if (RetValue != nullptr && RetValue->getType()->isRecordType() &&
364 PropagateResultObject(RetValue, LocForRecordReturnVal);
365 return true;
366 }
367
368 bool VisitExpr(Expr *E) override {
369
370
371
372
373
374 if (E->isPRValue() && E->getType()->isRecordType() &&
375 !ResultObjectMap.contains(E))
376 PropagateResultObject(
377 E, &cast(DACtx.getStableStorageLocation(*E)));
378 return true;
379 }
380
381 void
382 PropagateResultObjectToRecordInitList(const RecordInitListHelper &InitList,
383 RecordStorageLocation *Loc) {
384 for (auto [Base, Init] : InitList.base_inits()) {
385 assert(Base->getType().getCanonicalType() ==
386 Init->getType().getCanonicalType());
387
388
389
390
391 PropagateResultObject(Init, Loc);
392 }
393
394 for (auto [Field, Init] : InitList.field_inits()) {
395
396
397 if (Field->getType()->isRecordType())
398 PropagateResultObject(
399 Init, cast(Loc->getChild(*Field)));
400 }
401 }
402
403
404
405
406 void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) {
407 if (->isPRValue() ||
->getType()->isRecordType()) {
408 assert(false);
409
410
411 return;
412 }
413
415
416
417
418
419 if (isa(E) || isa(E) || isa(E) ||
422
423
424
425 isa(E)) {
426 return;
427 }
428 if (auto *Op = dyn_cast(E);
429 Op && Op->getOpcode() == BO_Cmp) {
430
431 return;
432 }
433
434 if (auto *InitList = dyn_cast(E)) {
435 if (!InitList->isSemanticForm())
436 return;
437 if (InitList->isTransparent()) {
438 PropagateResultObject(InitList->getInit(0), Loc);
439 return;
440 }
441
442 PropagateResultObjectToRecordInitList(RecordInitListHelper(InitList),
444 return;
445 }
446
447 if (auto *ParenInitList = dyn_cast(E)) {
448 PropagateResultObjectToRecordInitList(RecordInitListHelper(ParenInitList),
450 return;
451 }
452
453 if (auto *Op = dyn_cast(E); Op && Op->isCommaOp()) {
454 PropagateResultObject(Op->getRHS(), Loc);
455 return;
456 }
457
458 if (auto *Cond = dyn_cast(E)) {
459 PropagateResultObject(Cond->getTrueExpr(), Loc);
460 PropagateResultObject(Cond->getFalseExpr(), Loc);
461 return;
462 }
463
464 if (auto *SE = dyn_cast(E)) {
465 PropagateResultObject(cast(SE->getSubStmt()->body_back()), Loc);
466 return;
467 }
468
469 if (auto *DIE = dyn_cast(E)) {
470 PropagateResultObject(DIE->getExpr(), Loc);
471 return;
472 }
473
474
475
476 SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
477 LLVM_DEBUG({
478 if (Children.size() != 1)
479 E->dump();
480 });
481 assert(Children.size() == 1);
482 for (Stmt *S : Children)
483 PropagateResultObject(cast(S), Loc);
484 }
485
486private:
487 llvm::DenseMap<const Expr *, RecordStorageLocation *> &ResultObjectMap;
488 RecordStorageLocation *LocForRecordReturnVal;
489 DataflowAnalysisContext &DACtx;
490};
491
492}
493
495 if (InitialTargetStmt == nullptr)
496 return;
497
498 if (InitialTargetFunc == nullptr) {
500 ResultObjectMap =
501 std::make_shared(buildResultObjectMap(
503 nullptr));
504 return;
505 }
506
508
509 for (const auto *ParamDecl : InitialTargetFunc->parameters()) {
510 assert(ParamDecl != nullptr);
512 }
513
515 LocForRecordReturnVal = &cast(
517
518 if (const auto *MethodDecl = dyn_cast(InitialTargetFunc)) {
519 auto *Parent = MethodDecl->getParent();
520 assert(Parent != nullptr);
521
522 if (Parent->isLambda()) {
524 if (Capture.capturesVariable()) {
526 assert(VarDecl != nullptr);
528 } else if (Capture.capturesThis()) {
530 const auto *SurroundingMethodDecl = cast(Ancestor);
532 SurroundingMethodDecl->getFunctionObjectParameterType();
534 cast(createObject(ThisPointeeType)));
535 } else if (auto *FieldBeingInitialized =
536 dyn_cast(Parent->getLambdaContextDecl())) {
537
540 FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
541 } else {
542 assert(false && "Unexpected this-capturing lambda context.");
543 }
544 }
545 }
546 } else if (MethodDecl->isImplicitObjectMemberFunction()) {
547 QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType();
548 auto &ThisLoc =
551
552
553
554 if (!isa(MethodDecl))
556 }
557 }
558
559
560
561 ResultObjectMap =
562 std::make_shared(buildResultObjectMap(
564 LocForRecordReturnVal));
565}
566
567
568
569
570void Environment::initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced) {
571
572
573 DACtx->addModeledFields(Referenced.Fields);
574
577 continue;
578
579
580
581
582
583
585 }
586
589 continue;
592 }
593}
594
599}
600
603 return CallStack.size() < MaxDepth && !llvm::is_contained(CallStack, Callee);
604}
605
608
609 if (const auto *MethodCall = dyn_cast(Call)) {
610 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
611 if (!isa(Arg))
612 Env.ThisPointeeLoc =
614
615
616 }
617 }
618
619 if (Call->getType()->isRecordType() && Call->isPRValue())
620 Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
621
622 Env.pushCallInternal(Call->getDirectCallee(),
624
625 return Env;
626}
627
630
631 Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
632 Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call);
633
634 Env.pushCallInternal(Call->getConstructor(),
636
637 return Env;
638}
639
640void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
642
643
644
647
648 CallStack.push_back(FuncDecl);
649
651
652 const auto *ParamIt = FuncDecl->param_begin();
653
654
655
656 for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
657 assert(ParamIt != FuncDecl->param_end());
658 const VarDecl *Param = *ParamIt;
660 }
661
662 ResultObjectMap = std::make_shared(
664 LocForRecordReturnVal));
665}
666
668
669
670
671
672
673
674
675 this->LocToVal = std::move(CalleeEnv.LocToVal);
676 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
677
678 if (Call->isGLValue()) {
679 if (CalleeEnv.ReturnLoc != nullptr)
681 } else if (->getType()->isVoidType()) {
682 if (CalleeEnv.ReturnVal != nullptr)
684 }
685}
686
689
690 this->LocToVal = std::move(CalleeEnv.LocToVal);
691 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
692}
693
696 assert(DACtx == Other.DACtx);
697
698 if (ReturnVal != Other.ReturnVal)
699 return false;
700
701 if (ReturnLoc != Other.ReturnLoc)
702 return false;
703
704 if (LocForRecordReturnVal != Other.LocForRecordReturnVal)
705 return false;
706
707 if (ThisPointeeLoc != Other.ThisPointeeLoc)
708 return false;
709
710 if (DeclToLoc != Other.DeclToLoc)
711 return false;
712
713 if (ExprToLoc != Other.ExprToLoc)
714 return false;
715
717 return false;
718
720 return false;
721
722 return true;
723}
724
727 assert(DACtx == PrevEnv.DACtx);
728 assert(ReturnVal == PrevEnv.ReturnVal);
729 assert(ReturnLoc == PrevEnv.ReturnLoc);
730 assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal);
731 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
732 assert(CallStack == PrevEnv.CallStack);
733 assert(ResultObjectMap == PrevEnv.ResultObjectMap);
734 assert(InitialTargetFunc == PrevEnv.InitialTargetFunc);
735 assert(InitialTargetStmt == PrevEnv.InitialTargetStmt);
736
738
739
740
741
742
743
744
745 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
746 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
747 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
748
749 ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
750 Model, Effect);
751
752 LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
753 Model, Effect);
754 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
755 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
756 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
757 LocToVal.size() != PrevEnv.LocToVal.size())
759
760 return Effect;
761}
762
766 assert(EnvA.DACtx == EnvB.DACtx);
767 assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal);
768 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
769 assert(EnvA.CallStack == EnvB.CallStack);
770 assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap);
771 assert(EnvA.InitialTargetFunc == EnvB.InitialTargetFunc);
772 assert(EnvA.InitialTargetStmt == EnvB.InitialTargetStmt);
773
775
776 JoinedEnv.CallStack = EnvA.CallStack;
777 JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap;
778 JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal;
779 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
780 JoinedEnv.InitialTargetFunc = EnvA.InitialTargetFunc;
781 JoinedEnv.InitialTargetStmt = EnvA.InitialTargetStmt;
782
785 JoinedEnv.ReturnVal = nullptr;
786 } else {
787 JoinedEnv.ReturnVal =
788 joinValues(Func->getReturnType(), EnvA.ReturnVal, EnvA, EnvB.ReturnVal,
789 EnvB, JoinedEnv, Model);
790 }
791
792 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
793 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
794 else
795 JoinedEnv.ReturnLoc = nullptr;
796
797 JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc);
798
799
800
802 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
803
804 JoinedEnv.LocToVal =
805 joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model);
806
808 JoinedEnv.ExprToVal = joinExprMaps(EnvA.ExprToVal, EnvB.ExprToVal);
809 JoinedEnv.ExprToLoc = joinExprMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
810 }
811
812 return JoinedEnv;
813}
814
819 if (Val1 == nullptr || Val2 == nullptr)
820
821
822
823
824 return nullptr;
825
827
828 return Val1;
829
830 return joinDistinctValues(Ty, *Val1, Env1, *Val2, Env2, JoinedEnv, Model);
831}
832
835}
836
838
839
840
842}
843
845
846
847
849}
850
852 assert(!DeclToLoc.contains(&D));
853
854
855
856
857 assert(D.getType()->isReferenceType() || isa(D) ||
860}
861
863 auto It = DeclToLoc.find(&D);
864 if (It == DeclToLoc.end())
865 return nullptr;
866
868
869 return Loc;
870}
871
873
875
876
877
878 assert(E.isGLValue() ||
879 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
881 assert(!ExprToLoc.contains(&CanonE));
882 ExprToLoc[&CanonE] = &Loc;
883}
884
886
887 assert(E.isGLValue() ||
888 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
890 return It == ExprToLoc.end() ? nullptr : &*It->second;
891}
892
896 assert(RecordPRValue.isPRValue());
897
898 assert(ResultObjectMap != nullptr);
900 assert(Loc != nullptr);
901
902
903 if (Loc == nullptr)
904 return cast(
906 return *Loc;
907}
908
911}
912
915 llvm::DenseSet Visited;
916 int CreatedValuesCount = 0;
919 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
920 << '\n';
921 }
922}
923
925
926 assert(!isa(Loc));
927 LocToVal[&Loc] = &Val;
928}
929
932
934
936 ExprToVal[&CanonE] = &Val;
937}
938
940
941 assert(!isa(Loc));
942 return LocToVal.lookup(&Loc);
943}
944
947 if (Loc == nullptr)
948 return nullptr;
950}
951
953
954 assert(.getType()->isRecordType());
955
956 if (E.isPRValue()) {
958 return It == ExprToVal.end() ? nullptr : It->second;
959 }
960
962 if (It == ExprToLoc.end())
963 return nullptr;
964 return getValue(*It->second);
965}
966
968 llvm::DenseSet Visited;
969 int CreatedValuesCount = 0;
970 Value *Val = createValueUnlessSelfReferential(Type, Visited, 0,
971 CreatedValuesCount);
973 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
974 << '\n';
975 }
976 return Val;
977}
978
979Value *Environment::createValueUnlessSelfReferential(
981 int &CreatedValuesCount) {
982 assert(.isNull());
985
986
989 return nullptr;
990
992 CreatedValuesCount++;
994 }
995
997
998
999
1000 CreatedValuesCount++;
1002 }
1003
1004 if (Type->isPointerType()) {
1005 CreatedValuesCount++;
1006 QualType PointeeType = Type->getPointeeType();
1007 StorageLocation &PointeeLoc =
1008 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
1009
1010 return &arena().create(PointeeLoc);
1011 }
1012
1013 return nullptr;
1014}
1015
1016StorageLocation &
1017Environment::createLocAndMaybeValue(QualType Ty,
1018 llvm::DenseSet &Visited,
1019 int Depth, int &CreatedValuesCount) {
1020 if (.insert(Ty.getCanonicalType()).second)
1022 auto EraseVisited = llvm::make_scope_exit(
1023 [&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
1024
1025 Ty = Ty.getNonReferenceType();
1026
1027 if (Ty->isRecordType()) {
1030 return Loc;
1031 }
1032
1034
1035 if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1036 CreatedValuesCount))
1038
1039 return Loc;
1040}
1041
1043 QualType Type,
1044 llvm::DenseSet &Visited,
1045 int Depth,
1046 int &CreatedValuesCount) {
1047 auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
1048 if (FieldType->isRecordType()) {
1049 auto &FieldRecordLoc = cast(FieldLoc);
1051 Visited, Depth + 1, CreatedValuesCount);
1052 } else {
1053 if (getValue(FieldLoc) != nullptr)
1054 return;
1055 if (.insert(FieldType.getCanonicalType()).second)
1056 return;
1057 if (Value *Val = createValueUnlessSelfReferential(
1058 FieldType, Visited, Depth + 1, CreatedValuesCount))
1060 Visited.erase(FieldType.getCanonicalType());
1061 }
1062 };
1063
1064 for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
1065 assert(Field != nullptr);
1066 QualType FieldType = Field->getType();
1067
1068 if (FieldType->isReferenceType()) {
1069 Loc.setChild(*Field,
1070 &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
1071 CreatedValuesCount));
1072 } else {
1073 StorageLocation *FieldLoc = Loc.getChild(*Field);
1074 assert(FieldLoc != nullptr);
1075 initField(FieldType, *FieldLoc);
1076 }
1077 }
1078 for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) {
1079
1080
1081 assert(!FieldType->isReferenceType());
1082 initField(FieldType, Loc.getSyntheticField(FieldName));
1083 }
1084}
1085
1086StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
1087 QualType Ty,
1088 const Expr *InitExpr) {
1089 if (Ty->isReferenceType()) {
1090
1091
1092
1093 if (InitExpr) {
1095 return *InitExprLoc;
1096 }
1097
1098
1099
1100
1101
1102 return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
1103 }
1104
1105 StorageLocation &Loc =
1107
1108 if (Ty->isRecordType()) {
1109 auto &RecordLoc = cast(Loc);
1110 if (!InitExpr)
1112 } else {
1113 Value *Val = nullptr;
1114 if (InitExpr)
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1129 if (!Val)
1131 if (Val)
1133 }
1134
1135 return Loc;
1136}
1137
1140}
1141
1144}
1145
1148}
1149
1151 llvm::DenseMap<const StorageLocation *, std::string> LocToName;
1152 if (LocForRecordReturnVal != nullptr)
1153 LocToName[LocForRecordReturnVal] = "(returned record)";
1154 if (ThisPointeeLoc != nullptr)
1155 LocToName[ThisPointeeLoc] = "this";
1156
1157 OS << "DeclToLoc:\n";
1158 for (auto [D, L] : DeclToLoc) {
1159 auto Iter = LocToName.insert({L, D->getNameAsString()}).first;
1160 OS << " [" << Iter->second << ", " << L << "]\n";
1161 }
1162 OS << "ExprToLoc:\n";
1163 for (auto [E, L] : ExprToLoc)
1164 OS << " [" << E << ", " << L << "]\n";
1165
1166 OS << "ExprToVal:\n";
1167 for (auto [E, V] : ExprToVal)
1168 OS << " [" << E << ", " << V << ": " << *V << "]\n";
1169
1170 OS << "LocToVal:\n";
1171 for (auto [L, V] : LocToVal) {
1172 OS << " [" << L;
1173 if (auto Iter = LocToName.find(L); Iter != LocToName.end())
1174 OS << " (" << Iter->second << ")";
1175 OS << ", " << V << ": " << *V << "]\n";
1176 }
1177
1179 if (Func->getReturnType()->isReferenceType()) {
1180 OS << "ReturnLoc: " << ReturnLoc;
1181 if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end())
1182 OS << " (" << Iter->second << ")";
1183 OS << "\n";
1184 } else if (Func->getReturnType()->isRecordType() ||
1185 isa(Func)) {
1186 OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n";
1187 } else if (->getReturnType()->isVoidType()) {
1188 if (ReturnVal == nullptr)
1189 OS << "ReturnVal: nullptr\n";
1190 else
1191 OS << "ReturnVal: " << *ReturnVal << "\n";
1192 }
1193
1194 if (isa(Func)) {
1195 OS << "ThisPointeeLoc: " << ThisPointeeLoc << "\n";
1196 }
1197 }
1198
1199 OS << "\n";
1201}
1202
1204
1205Environment::PrValueToResultObject Environment::buildResultObjectMap(
1210
1211 PrValueToResultObject Map = buildResultObjectMap(
1212 DACtx, FuncDecl->getBody(), ThisPointeeLoc, LocForRecordReturnVal);
1213
1214 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1215 if (const auto *Ctor = dyn_cast(FuncDecl))
1216 Visitor.traverseConstructorInits(Ctor, ThisPointeeLoc);
1217
1218 return Map;
1219}
1220
1221Environment::PrValueToResultObject Environment::buildResultObjectMap(
1222 DataflowAnalysisContext *DACtx, Stmt *S,
1223 RecordStorageLocation *ThisPointeeLoc,
1224 RecordStorageLocation *LocForRecordReturnVal) {
1225 PrValueToResultObject Map;
1226 ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx);
1227 Visitor.TraverseStmt(S);
1228 return Map;
1229}
1230
1234 if (ImplicitObject == nullptr)
1235 return nullptr;
1238 return &cast(Val->getPointeeLoc());
1239 return nullptr;
1240 }
1241 return cast_or_null(
1243}
1244
1248 if (Base == nullptr)
1249 return nullptr;
1252 return &cast(Val->getPointeeLoc());
1253 return nullptr;
1254 }
1256}
1257
1258}
1259}
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 IsActive, bool IsUnionField, bool InUnion, const Descriptor *D, unsigned FieldOffset)
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::DenseSet< const void * > Visited
static bool RetValue(InterpState &S, CodePtr &Pt)
llvm::MachO::RecordLoc RecordLoc
C Language Family Type Representation.
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]).
Decl * getNonClosureAncestor()
Find the nearest non-closure ancestor of this context, i.e.
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()
QualType getReturnType() const
ArrayRef< ParmVarDecl * > parameters() const
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.
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 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...
void addFlowConditionConstraint(Atom Token, const Formula &Constraint)
Adds Constraint to the flow condition identified by Token.
Atom forkFlowCondition(Atom Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
StorageLocation & getStableStorageLocation(const ValueDecl &D)
Returns a stable storage location for D.
bool flowConditionImplies(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token imply that F is true.
bool flowConditionAllows(Atom Token, const Formula &F)
Returns true if the constraints of the flow condition identified by Token still allow F to be true.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
llvm::StringMap< QualType > getSyntheticFields(QualType Type)
Returns the names and types of the synthetic fields for the given record type.
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token, llvm::raw_ostream &OS=llvm::dbgs())
Supplements Environment with non-standard comparison and join operations.
virtual std::optional< WidenResult > widen(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv)
This function may widen the current value – replace it with an approximation that can reach a fixed p...
virtual void join(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &JoinedVal, Environment &JoinedEnv)
Modifies JoinedVal to approximate both Val1 and Val2.
virtual ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2)
Returns: Same: Val1 is equivalent to Val2, according to the model.
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.
LatticeEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
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.
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 ...
LLVM_DUMP_METHOD void dump() const
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...
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Environment fork() const
Returns a new environment that is a copy of this one.
void popCall(const CallExpr *Call, const Environment &CalleeEnv)
Moves gathered information back into this from a CalleeEnv created via pushCall.
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:
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.
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...
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.
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.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void removeDecl(const ValueDecl &D)
Removes the location assigned to D in the environment (if any).
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue) const
Returns the location of the result object for a record-type prvalue.
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 ...
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
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.
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,...
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)
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.
static bool equateUnknownValues(Value::Kind K)
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)
static constexpr int MaxCompositeValueDepth
static constexpr int MaxCompositeValueSize
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...
static WidenResult widenDistinctValues(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv, Environment::ValueModel &Model)
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)
static MapT joinExprMaps(const MapT &Map1, const MapT &Map2)
static bool compareDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment::ValueModel &Model)
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...
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.
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
@ Other
Other implicit parameter.
A collection of several types of declarations, all referenced from the same function.
llvm::DenseSet< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
llvm::DenseSet< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
FieldSet Fields
Non-static member variables.
The result of a widen operation.