@@ -50,6 +50,11 @@ struct Loan {
50
50
51
51
Loan (LoanID id, AccessPath path, const Expr *IssueExpr)
52
52
: ID(id), Path(path), IssueExpr(IssueExpr) {}
53
+
54
+ void dump (llvm::raw_ostream &OS) const {
55
+ OS << ID << " (Path: " ;
56
+ OS << Path.D ->getNameAsString () << " )" ;
57
+ }
53
58
};
54
59
55
60
// / An Origin is a symbolic identifier that represents the set of possible
@@ -120,17 +125,19 @@ class OriginManager {
120
125
121
126
// TODO: Mark this method as const once we remove the call to getOrCreate.
122
127
OriginID get (const Expr &E) {
123
- // Origin of DeclRefExpr is that of the declaration it refers to.
128
+ auto It = ExprToOriginID.find (&E);
129
+ if (It != ExprToOriginID.end ())
130
+ return It->second ;
131
+ // If the expression itself has no specific origin, and it's a reference
132
+ // to a declaration, its origin is that of the declaration it refers to.
133
+ // For pointer types, where we don't pre-emptively create an origin for the
134
+ // DeclRefExpr itself.
124
135
if (const auto *DRE = dyn_cast<DeclRefExpr>(&E))
125
136
return get (*DRE->getDecl ());
126
- auto It = ExprToOriginID.find (&E);
127
137
// TODO: This should be an assert(It != ExprToOriginID.end()). The current
128
138
// implementation falls back to getOrCreate to avoid crashing on
129
139
// yet-unhandled pointer expressions, creating an empty origin for them.
130
- if (It == ExprToOriginID.end ())
131
- return getOrCreate (E);
132
-
133
- return It->second ;
140
+ return getOrCreate (E);
134
141
}
135
142
136
143
OriginID get (const ValueDecl &D) {
@@ -149,10 +156,6 @@ class OriginManager {
149
156
if (It != ExprToOriginID.end ())
150
157
return It->second ;
151
158
152
- if (const auto *DRE = dyn_cast<DeclRefExpr>(&E)) {
153
- // Origin of DeclRefExpr is that of the declaration it refers to.
154
- return getOrCreate (*DRE->getDecl ());
155
- }
156
159
OriginID NewID = getNextOriginID ();
157
160
addOrigin (NewID, E);
158
161
ExprToOriginID[&E] = NewID;
@@ -235,7 +238,8 @@ class Fact {
235
238
return nullptr ;
236
239
}
237
240
238
- virtual void dump (llvm::raw_ostream &OS, const OriginManager &) const {
241
+ virtual void dump (llvm::raw_ostream &OS, const LoanManager &,
242
+ const OriginManager &) const {
239
243
OS << " Fact (Kind: " << static_cast <int >(K) << " )\n " ;
240
244
}
241
245
};
@@ -250,8 +254,11 @@ class IssueFact : public Fact {
250
254
IssueFact (LoanID LID, OriginID OID) : Fact(Kind::Issue), LID(LID), OID(OID) {}
251
255
LoanID getLoanID () const { return LID; }
252
256
OriginID getOriginID () const { return OID; }
253
- void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
254
- OS << " Issue (LoanID: " << getLoanID () << " , ToOrigin: " ;
257
+ void dump (llvm::raw_ostream &OS, const LoanManager &LM,
258
+ const OriginManager &OM) const override {
259
+ OS << " Issue (" ;
260
+ LM.getLoan (getLoanID ()).dump (OS);
261
+ OS << " , ToOrigin: " ;
255
262
OM.dump (getOriginID (), OS);
256
263
OS << " )\n " ;
257
264
}
@@ -270,8 +277,11 @@ class ExpireFact : public Fact {
270
277
LoanID getLoanID () const { return LID; }
271
278
SourceLocation getExpiryLoc () const { return ExpiryLoc; }
272
279
273
- void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
274
- OS << " Expire (LoanID: " << getLoanID () << " )\n " ;
280
+ void dump (llvm::raw_ostream &OS, const LoanManager &LM,
281
+ const OriginManager &) const override {
282
+ OS << " Expire (" ;
283
+ LM.getLoan (getLoanID ()).dump (OS);
284
+ OS << " )\n " ;
275
285
}
276
286
};
277
287
@@ -288,7 +298,8 @@ class AssignOriginFact : public Fact {
288
298
: Fact(Kind::AssignOrigin), OIDDest(OIDDest), OIDSrc(OIDSrc) {}
289
299
OriginID getDestOriginID () const { return OIDDest; }
290
300
OriginID getSrcOriginID () const { return OIDSrc; }
291
- void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
301
+ void dump (llvm::raw_ostream &OS, const LoanManager &,
302
+ const OriginManager &OM) const override {
292
303
OS << " AssignOrigin (Dest: " ;
293
304
OM.dump (getDestOriginID (), OS);
294
305
OS << " , Src: " ;
@@ -307,7 +318,8 @@ class ReturnOfOriginFact : public Fact {
307
318
308
319
ReturnOfOriginFact (OriginID OID) : Fact(Kind::ReturnOfOrigin), OID(OID) {}
309
320
OriginID getReturnedOriginID () const { return OID; }
310
- void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
321
+ void dump (llvm::raw_ostream &OS, const LoanManager &,
322
+ const OriginManager &OM) const override {
311
323
OS << " ReturnOfOrigin (" ;
312
324
OM.dump (getReturnedOriginID (), OS);
313
325
OS << " )\n " ;
@@ -333,10 +345,11 @@ class UseFact : public Fact {
333
345
void markAsWritten () { IsWritten = true ; }
334
346
bool isWritten () const { return IsWritten; }
335
347
336
- void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
348
+ void dump (llvm::raw_ostream &OS, const LoanManager &,
349
+ const OriginManager &OM) const override {
337
350
OS << " Use (" ;
338
351
OM.dump (getUsedOrigin (OM), OS);
339
- OS << " " << (isWritten () ? " Write" : " Read" ) << " )\n " ;
352
+ OS << " , " << (isWritten () ? " Write" : " Read" ) << " )\n " ;
340
353
}
341
354
};
342
355
@@ -353,7 +366,8 @@ class TestPointFact : public Fact {
353
366
354
367
StringRef getAnnotation () const { return Annotation; }
355
368
356
- void dump (llvm::raw_ostream &OS, const OriginManager &) const override {
369
+ void dump (llvm::raw_ostream &OS, const LoanManager &,
370
+ const OriginManager &) const override {
357
371
OS << " TestPoint (Annotation: \" " << getAnnotation () << " \" )\n " ;
358
372
}
359
373
};
@@ -392,7 +406,7 @@ class FactManager {
392
406
if (It != BlockToFactsMap.end ()) {
393
407
for (const Fact *F : It->second ) {
394
408
llvm::dbgs () << " " ;
395
- F->dump (llvm::dbgs (), OriginMgr);
409
+ F->dump (llvm::dbgs (), LoanMgr, OriginMgr);
396
410
}
397
411
}
398
412
llvm::dbgs () << " End of Block\n " ;
@@ -438,12 +452,31 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
438
452
void VisitDeclStmt (const DeclStmt *DS) {
439
453
for (const Decl *D : DS->decls ())
440
454
if (const auto *VD = dyn_cast<VarDecl>(D))
441
- if (hasOrigin (VD-> getType () ))
455
+ if (hasOrigin (VD))
442
456
if (const Expr *InitExpr = VD->getInit ())
443
457
addAssignOriginFact (*VD, *InitExpr);
444
458
}
445
459
446
- void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
460
+ void VisitDeclRefExpr (const DeclRefExpr *DRE) {
461
+ handleUse (DRE);
462
+ // For non-pointer/non-view types, a reference to the variable's storage
463
+ // is a borrow. We create a loan for it.
464
+ // For pointer/view types, we stick to the existing model for now and do
465
+ // not create an extra origin for the l-value expression itself.
466
+
467
+ // TODO: A single origin for a `DeclRefExpr` for a pointer or view type is
468
+ // not sufficient to model the different levels of indirection. The current
469
+ // single-origin model cannot distinguish between a loan to the variable's
470
+ // storage and a loan to what it points to. A multi-origin model would be
471
+ // required for this.
472
+ if (!isPointerType (DRE->getType ())) {
473
+ if (const Loan *L = createLoan (DRE)) {
474
+ OriginID ExprOID = FactMgr.getOriginMgr ().getOrCreate (*DRE);
475
+ CurrentBlockFacts.push_back (
476
+ FactMgr.createFact <IssueFact>(L->ID , ExprOID));
477
+ }
478
+ }
479
+ }
447
480
448
481
void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
449
482
// / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
@@ -452,38 +485,31 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
452
485
}
453
486
454
487
void VisitImplicitCastExpr (const ImplicitCastExpr *ICE) {
455
- if (!hasOrigin (ICE-> getType () ))
488
+ if (!hasOrigin (ICE))
456
489
return ;
457
490
// An ImplicitCastExpr node itself gets an origin, which flows from the
458
491
// origin of its sub-expression (after stripping its own parens/casts).
459
- // TODO: Consider if this is actually useful in practice. Alternatively, we
460
- // could directly use the sub-expression's OriginID instead of creating a
461
- // new one.
462
492
addAssignOriginFact (*ICE, *ICE->getSubExpr ());
463
493
}
464
494
465
495
void VisitUnaryOperator (const UnaryOperator *UO) {
466
496
if (UO->getOpcode () == UO_AddrOf) {
467
497
const Expr *SubExpr = UO->getSubExpr ();
468
- if (const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
469
- if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl ())) {
470
- // Check if it's a local variable.
471
- if (VD->hasLocalStorage ()) {
472
- OriginID OID = FactMgr.getOriginMgr ().getOrCreate (*UO);
473
- AccessPath AddrOfLocalVarPath (VD);
474
- const Loan &L =
475
- FactMgr.getLoanMgr ().addLoan (AddrOfLocalVarPath, UO);
476
- CurrentBlockFacts.push_back (
477
- FactMgr.createFact <IssueFact>(L.ID , OID));
478
- }
479
- }
480
- }
498
+ // Taking address of a pointer-type expression is not yet supported and
499
+ // will be supported in multi-origin model.
500
+ if (isPointerType (SubExpr->getType ()))
501
+ return ;
502
+ // The origin of an address-of expression (e.g., &x) is the origin of
503
+ // its sub-expression (x). This fact will cause the dataflow analysis
504
+ // to propagate any loans held by the sub-expression's origin to the
505
+ // origin of this UnaryOperator expression.
506
+ addAssignOriginFact (*UO, *SubExpr);
481
507
}
482
508
}
483
509
484
510
void VisitReturnStmt (const ReturnStmt *RS) {
485
511
if (const Expr *RetExpr = RS->getRetValue ()) {
486
- if (hasOrigin (RetExpr-> getType () )) {
512
+ if (hasOrigin (RetExpr)) {
487
513
OriginID OID = FactMgr.getOriginMgr ().getOrCreate (*RetExpr);
488
514
CurrentBlockFacts.push_back (
489
515
FactMgr.createFact <ReturnOfOriginFact>(OID));
@@ -506,20 +532,6 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
506
532
// expression.
507
533
if (VisitTestPoint (FCE))
508
534
return ;
509
- // Visit as normal otherwise.
510
- Base::VisitCXXFunctionalCastExpr (FCE);
511
- }
512
-
513
- private:
514
- // Check if a type has an origin.
515
- bool hasOrigin (QualType QT) { return QT->isPointerOrReferenceType (); }
516
-
517
- template <typename Destination, typename Source>
518
- void addAssignOriginFact (const Destination &D, const Source &S) {
519
- OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
520
- OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
521
- CurrentBlockFacts.push_back (
522
- FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
523
535
}
524
536
525
537
void handleDestructor (const CFGAutomaticObjDtor &DtorOpt) {
@@ -544,6 +556,41 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
544
556
}
545
557
}
546
558
559
+ private:
560
+ static bool isPointerType (QualType QT) {
561
+ return QT->isPointerOrReferenceType ();
562
+ }
563
+
564
+ // Check if a type has an origin.
565
+ static bool hasOrigin (const Expr *E) {
566
+ return E->isGLValue () || isPointerType (E->getType ());
567
+ }
568
+
569
+ static bool hasOrigin (const VarDecl *VD) {
570
+ return isPointerType (VD->getType ());
571
+ }
572
+
573
+ // / Creates a loan for the storage path of a given declaration reference.
574
+ // / This function should be called whenever a DeclRefExpr represents a borrow.
575
+ // / \param DRE The declaration reference expression that initiates the borrow.
576
+ // / \return The new Loan on success, nullptr otherwise.
577
+ const Loan *createLoan (const DeclRefExpr *DRE) {
578
+ if (const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl ())) {
579
+ AccessPath Path (VD);
580
+ // The loan is created at the location of the DeclRefExpr.
581
+ return &FactMgr.getLoanMgr ().addLoan (Path, DRE);
582
+ }
583
+ return nullptr ;
584
+ }
585
+
586
+ template <typename Destination, typename Source>
587
+ void addAssignOriginFact (const Destination &D, const Source &S) {
588
+ OriginID DestOID = FactMgr.getOriginMgr ().getOrCreate (D);
589
+ OriginID SrcOID = FactMgr.getOriginMgr ().get (S);
590
+ CurrentBlockFacts.push_back (
591
+ FactMgr.createFact <AssignOriginFact>(DestOID, SrcOID));
592
+ }
593
+
547
594
// / Checks if the expression is a `void("__lifetime_test_point_...")` cast.
548
595
// / If so, creates a `TestPointFact` and returns true.
549
596
bool VisitTestPoint (const CXXFunctionalCastExpr *FCE) {
@@ -566,25 +613,26 @@ class FactGenerator : public ConstStmtVisitor<FactGenerator> {
566
613
}
567
614
568
615
void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
616
+ if (!hasOrigin (LHSExpr))
617
+ return ;
569
618
// Find the underlying variable declaration for the left-hand side.
570
619
if (const auto *DRE_LHS =
571
620
dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ())) {
572
621
markUseAsWrite (DRE_LHS);
573
622
if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
574
- if (hasOrigin (LHSExpr->getType ()))
575
- // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
576
- // LHS must be a pointer/reference type that can be an origin.
577
- // RHS must also represent an origin (either another pointer/ref or an
578
- // address-of).
579
- addAssignOriginFact (*VD_LHS, *RHSExpr);
623
+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`.
624
+ // LHS must be a pointer/reference type that can be an origin. RHS must
625
+ // also represent an origin (either another pointer/ref or an
626
+ // address-of).
627
+ addAssignOriginFact (*VD_LHS, *RHSExpr);
580
628
}
581
629
}
582
630
583
- // A DeclRefExpr is a use of the referenced decl. It is checked for
584
- // use-after-free unless it is being written to (e.g. on the left-hand side
585
- // of an assignment).
631
+ // A DeclRefExpr will be treated as a use of the referenced decl. It will be
632
+ // checked for use-after-free unless it is later marked as being written to
633
+ // (e.g. on the left-hand side of an assignment).
586
634
void handleUse (const DeclRefExpr *DRE) {
587
- if (hasOrigin (DRE->getType ())) {
635
+ if (isPointerType (DRE->getType ())) {
588
636
UseFact *UF = FactMgr.createFact <UseFact>(DRE);
589
637
CurrentBlockFacts.push_back (UF);
590
638
assert (!UseFacts.contains (DRE));
0 commit comments