@@ -109,7 +109,75 @@ STATISTIC(NumTimesRetriedWithoutInlining,
109
109
// to the object's location, so that on every such statement the location
110
110
// could have been retrieved.
111
111
112
- typedef std::pair<const Stmt *, const LocationContext *> ConstructedObjectKey;
112
+ // / ConstructedObjectKey is used for being able to find the path-sensitive
113
+ // / memory region of a freshly constructed object while modeling the AST node
114
+ // / that syntactically represents the object that is being constructed.
115
+ // / Semantics of such nodes may sometimes require access to the region that's
116
+ // / not otherwise present in the program state, or to the very fact that
117
+ // / the construction context was present and contained references to these
118
+ // / AST nodes.
119
+ class ConstructedObjectKey {
120
+ typedef std::pair<
121
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *>,
122
+ const LocationContext *> ConstructedObjectKeyImpl;
123
+
124
+ ConstructedObjectKeyImpl Impl;
125
+
126
+ const void *getAnyASTNodePtr () const {
127
+ if (const Stmt *S = getStmt ())
128
+ return S;
129
+ else
130
+ return getCXXCtorInitializer ();
131
+ }
132
+
133
+ public:
134
+ ConstructedObjectKey (
135
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
136
+ const LocationContext *LC)
137
+ : Impl(P, LC) {
138
+ // This is the full list of statements that require additional actions when
139
+ // encountered. This list may be expanded when new actions are implemented.
140
+ assert (getCXXCtorInitializer () || isa<DeclStmt>(getStmt ()) ||
141
+ isa<CXXNewExpr>(getStmt ()) || isa<CXXBindTemporaryExpr>(getStmt ()) ||
142
+ isa<MaterializeTemporaryExpr>(getStmt ()));
143
+ }
144
+
145
+ const Stmt *getStmt () const {
146
+ return Impl.first .dyn_cast <const Stmt *>();
147
+ }
148
+
149
+ const CXXCtorInitializer *getCXXCtorInitializer () const {
150
+ return Impl.first .dyn_cast <const CXXCtorInitializer *>();
151
+ }
152
+
153
+ const LocationContext *getLocationContext () const {
154
+ return Impl.second ;
155
+ }
156
+
157
+ void print (llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) {
158
+ OS << ' (' << getLocationContext () << ' ,' << getAnyASTNodePtr () << " ) " ;
159
+ if (const Stmt *S = getStmt ()) {
160
+ S->printPretty (OS, Helper, PP);
161
+ } else {
162
+ const CXXCtorInitializer *I = getCXXCtorInitializer ();
163
+ OS << I->getAnyMember ()->getNameAsString ();
164
+ }
165
+ }
166
+
167
+ void Profile (llvm::FoldingSetNodeID &ID) const {
168
+ ID.AddPointer (Impl.first .getOpaqueValue ());
169
+ ID.AddPointer (Impl.second );
170
+ }
171
+
172
+ bool operator ==(const ConstructedObjectKey &RHS) const {
173
+ return Impl == RHS.Impl ;
174
+ }
175
+
176
+ bool operator <(const ConstructedObjectKey &RHS) const {
177
+ return Impl < RHS.Impl ;
178
+ }
179
+ };
180
+
113
181
typedef llvm::ImmutableMap<ConstructedObjectKey, SVal>
114
182
ObjectsUnderConstructionMap;
115
183
REGISTER_TRAIT_WITH_PROGRAMSTATE (ObjectsUnderConstruction,
@@ -378,26 +446,31 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
378
446
return State;
379
447
}
380
448
381
- ProgramStateRef
382
- ExprEngine::addObjectUnderConstruction (ProgramStateRef State, const Stmt *S,
383
- const LocationContext *LC, SVal V) {
384
- ConstructedObjectKey Key (S, LC->getCurrentStackFrame ());
449
+ ProgramStateRef ExprEngine::addObjectUnderConstruction (
450
+ ProgramStateRef State,
451
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
452
+ const LocationContext *LC, SVal V) {
453
+ ConstructedObjectKey Key (P, LC->getCurrentStackFrame ());
385
454
// FIXME: Currently the state might already contain the marker due to
386
455
// incorrect handling of temporaries bound to default parameters.
387
456
assert (!State->get <ObjectsUnderConstruction>(Key) ||
388
- isa<CXXBindTemporaryExpr>(S ));
457
+ isa<CXXBindTemporaryExpr>(Key. getStmt () ));
389
458
return State->set <ObjectsUnderConstruction>(Key, V);
390
459
}
391
460
392
- Optional<SVal> ExprEngine::getObjectUnderConstruction (ProgramStateRef State,
393
- const Stmt *S, const LocationContext *LC) {
394
- ConstructedObjectKey Key (S, LC->getCurrentStackFrame ());
461
+ Optional<SVal> ExprEngine::getObjectUnderConstruction (
462
+ ProgramStateRef State,
463
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
464
+ const LocationContext *LC) {
465
+ ConstructedObjectKey Key (P, LC->getCurrentStackFrame ());
395
466
return Optional<SVal>::create (State->get <ObjectsUnderConstruction>(Key));
396
467
}
397
468
398
- ProgramStateRef ExprEngine::finishObjectConstruction (ProgramStateRef State,
399
- const Stmt *S, const LocationContext *LC) {
400
- ConstructedObjectKey Key (S, LC->getCurrentStackFrame ());
469
+ ProgramStateRef ExprEngine::finishObjectConstruction (
470
+ ProgramStateRef State,
471
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
472
+ const LocationContext *LC) {
473
+ ConstructedObjectKey Key (P, LC->getCurrentStackFrame ());
401
474
assert (State->contains <ObjectsUnderConstruction>(Key));
402
475
return State->remove <ObjectsUnderConstruction>(Key);
403
476
}
@@ -409,7 +482,7 @@ bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State,
409
482
while (LC != ToLC) {
410
483
assert (LC && " ToLC must be a parent of FromLC!" );
411
484
for (auto I : State->get <ObjectsUnderConstruction>())
412
- if (I.first .second == LC)
485
+ if (I.first .getLocationContext () == LC)
413
486
return false ;
414
487
415
488
LC = LC->getParent ();
@@ -451,10 +524,9 @@ static void printObjectsUnderConstructionForContext(raw_ostream &Out,
451
524
for (auto I : State->get <ObjectsUnderConstruction>()) {
452
525
ConstructedObjectKey Key = I.first ;
453
526
SVal Value = I.second ;
454
- if (Key.second != LC)
527
+ if (Key.getLocationContext () != LC)
455
528
continue ;
456
- Out << ' (' << Key.second << ' ,' << Key.first << " ) " ;
457
- Key.first ->printPretty (Out, nullptr , PP);
529
+ Key.print (Out, nullptr , PP);
458
530
Out << " : " << Value << NL;
459
531
}
460
532
}
@@ -677,9 +749,11 @@ void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
677
749
Engine.enqueue (Dst, currBldrCtx->getBlock (), currStmtIdx);
678
750
}
679
751
680
- void ExprEngine::ProcessInitializer (const CFGInitializer Init ,
752
+ void ExprEngine::ProcessInitializer (const CFGInitializer CFGInit ,
681
753
ExplodedNode *Pred) {
682
- const CXXCtorInitializer *BMI = Init.getInitializer ();
754
+ const CXXCtorInitializer *BMI = CFGInit.getInitializer ();
755
+ const Expr *Init = BMI->getInit ()->IgnoreImplicit ();
756
+ const LocationContext *LC = Pred->getLocationContext ();
683
757
684
758
PrettyStackTraceLoc CrashInfo (getContext ().getSourceManager (),
685
759
BMI->getSourceLocation (),
@@ -692,19 +766,21 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
692
766
ProgramStateRef State = Pred->getState ();
693
767
SVal thisVal = State->getSVal (svalBuilder.getCXXThis (decl, stackFrame));
694
768
695
- ExplodedNodeSet Tmp (Pred) ;
769
+ ExplodedNodeSet Tmp;
696
770
SVal FieldLoc;
697
771
698
772
// Evaluate the initializer, if necessary
699
773
if (BMI->isAnyMemberInitializer ()) {
700
774
// Constructors build the object directly in the field,
701
775
// but non-objects must be copied in from the initializer.
702
- if (const auto *CtorExpr = findDirectConstructorForCurrentCFGElement ()) {
703
- assert (BMI->getInit ()->IgnoreImplicit () == CtorExpr);
704
- (void )CtorExpr;
776
+ if (getObjectUnderConstruction (State, BMI, LC)) {
705
777
// The field was directly constructed, so there is no need to bind.
778
+ // But we still need to stop tracking the object under construction.
779
+ State = finishObjectConstruction (State, BMI, LC);
780
+ NodeBuilder Bldr (Pred, Tmp, *currBldrCtx);
781
+ PostStore PS (Init, LC, /* Loc*/ nullptr , /* tag*/ nullptr );
782
+ Bldr.generateNode (PS, State, Pred);
706
783
} else {
707
- const Expr *Init = BMI->getInit ()->IgnoreImplicit ();
708
784
const ValueDecl *Field;
709
785
if (BMI->isIndirectMemberInitializer ()) {
710
786
Field = BMI->getIndirectMember ();
@@ -738,15 +814,12 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
738
814
InitVal = State->getSVal (BMI->getInit (), stackFrame);
739
815
}
740
816
741
- assert (Tmp.size () == 1 && " have not generated any new nodes yet" );
742
- assert (*Tmp.begin () == Pred && " have not generated any new nodes yet" );
743
- Tmp.clear ();
744
-
745
817
PostInitializer PP (BMI, FieldLoc.getAsRegion (), stackFrame);
746
818
evalBind (Tmp, Init, Pred, FieldLoc, InitVal, /* isInit=*/ true , &PP);
747
819
}
748
820
} else {
749
821
assert (BMI->isBaseInitializer () || BMI->isDelegatingInitializer ());
822
+ Tmp.insert (Pred);
750
823
// We already did all the work when visiting the CXXConstructExpr.
751
824
}
752
825
@@ -755,8 +828,10 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
755
828
PostInitializer PP (BMI, FieldLoc.getAsRegion (), stackFrame);
756
829
ExplodedNodeSet Dst;
757
830
NodeBuilder Bldr (Tmp, Dst, *currBldrCtx);
758
- for (const auto I : Tmp)
759
- Bldr.generateNode (PP, I->getState (), I);
831
+ for (const auto I : Tmp) {
832
+ ProgramStateRef State = I->getState ();
833
+ Bldr.generateNode (PP, State, I);
834
+ }
760
835
761
836
// Enqueue the new nodes onto the work list.
762
837
Engine.enqueue (Dst, currBldrCtx->getBlock (), currStmtIdx);
@@ -2119,11 +2194,11 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
2119
2194
while (LC != ToLC) {
2120
2195
assert (LC && " ToLC must be a parent of FromLC!" );
2121
2196
for (auto I : State->get <ObjectsUnderConstruction>())
2122
- if (I.first .second == LC) {
2197
+ if (I.first .getLocationContext () == LC) {
2123
2198
// The comment above only pardons us for not cleaning up a
2124
2199
// CXXBindTemporaryExpr. If any other statements are found here,
2125
2200
// it must be a separate problem.
2126
- assert (isa<CXXBindTemporaryExpr>(I.first .first ));
2201
+ assert (isa<CXXBindTemporaryExpr>(I.first .getStmt () ));
2127
2202
State = State->remove <ObjectsUnderConstruction>(I.first );
2128
2203
}
2129
2204
0 commit comments