@@ -119,6 +119,7 @@ class OriginManager {
119
119
return AllOrigins.back ();
120
120
}
121
121
122
+ // TODO: Mark this method as const once we remove the call to getOrCreate.
122
123
OriginID get (const Expr &E) {
123
124
// Origin of DeclRefExpr is that of the declaration it refers to.
124
125
if (const auto *DRE = dyn_cast<DeclRefExpr>(&E))
@@ -315,22 +316,28 @@ class ReturnOfOriginFact : public Fact {
315
316
};
316
317
317
318
class UseFact : public Fact {
318
- OriginID UsedOrigin;
319
319
const Expr *UseExpr;
320
+ // True if this use is a write operation (e.g., left-hand side of assignment).
321
+ // Write operations are exempted from use-after-free checks.
322
+ bool IsWritten = false ;
320
323
321
324
public:
322
325
static bool classof (const Fact *F) { return F->getKind () == Kind::Use; }
323
326
324
- UseFact (OriginID UsedOrigin, const Expr *UseExpr)
325
- : Fact(Kind::Use), UsedOrigin(UsedOrigin), UseExpr(UseExpr) {}
327
+ UseFact (const Expr *UseExpr) : Fact(Kind::Use), UseExpr(UseExpr) {}
326
328
327
- OriginID getUsedOrigin () const { return UsedOrigin; }
329
+ OriginID getUsedOrigin (const OriginManager &OM) const {
330
+ // TODO: Remove const cast and make OriginManager::get as const.
331
+ return const_cast <OriginManager &>(OM).get (*UseExpr);
332
+ }
328
333
const Expr *getUseExpr () const { return UseExpr; }
334
+ void markAsWritten () { IsWritten = true ; }
335
+ bool isWritten () const { return IsWritten; }
329
336
330
337
void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
331
338
OS << " Use (" ;
332
- OM.dump (getUsedOrigin (), OS);
333
- OS << " )\n " ;
339
+ OM.dump (getUsedOrigin (OM ), OS);
340
+ OS << " " << ( isWritten () ? " Write " : " Read " ) << " )\n " ;
334
341
}
335
342
};
336
343
@@ -423,6 +430,8 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
423
430
addAssignOriginFact (*VD, *InitExpr);
424
431
}
425
432
433
+ void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
434
+
426
435
void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
427
436
// / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
428
437
// / pointers can use the same type of loan.
@@ -456,10 +465,6 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
456
465
}
457
466
}
458
467
}
459
- } else if (UO->getOpcode () == UO_Deref) {
460
- // This is a pointer use, like '*p'.
461
- OriginID OID = FactMgr.getOriginMgr ().get (*UO->getSubExpr ());
462
- CurrentBlockFacts.push_back (FactMgr.createFact <UseFact>(OID, UO));
463
468
}
464
469
}
465
470
@@ -474,20 +479,13 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
474
479
}
475
480
476
481
void VisitBinaryOperator (const BinaryOperator *BO) {
477
- if (BO->isAssignmentOp ()) {
478
- const Expr *LHSExpr = BO->getLHS ();
479
- const Expr *RHSExpr = BO->getRHS ();
480
-
481
- // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
482
- // LHS must be a pointer/reference type that can be an origin.
483
- // RHS must also represent an origin (either another pointer/ref or an
484
- // address-of).
485
- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
486
- if (const auto *VD_LHS =
487
- dyn_cast<ValueDecl>(DRE_LHS->getDecl ()->getCanonicalDecl ());
488
- VD_LHS && hasOrigin (VD_LHS->getType ()))
489
- addAssignOriginFact (*VD_LHS, *RHSExpr);
490
- }
482
+ if (BO->isAssignmentOp ())
483
+ handleAssignment (BO->getLHS (), BO->getRHS ());
484
+ }
485
+
486
+ void VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *OCE) {
487
+ if (OCE->isAssignmentOp () && OCE->getNumArgs () == 2 )
488
+ handleAssignment (OCE->getArg (0 ), OCE->getArg (1 ));
491
489
}
492
490
493
491
void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
@@ -554,8 +552,46 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
554
552
return false ;
555
553
}
556
554
555
+ void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
556
+ // Find the underlying variable declaration for the left-hand side.
557
+ if (const auto *DRE_LHS =
558
+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ())) {
559
+ markUseAsWrite (DRE_LHS);
560
+ if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
561
+ if (hasOrigin (LHSExpr->getType ()))
562
+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
563
+ // LHS must be a pointer/reference type that can be an origin.
564
+ // RHS must also represent an origin (either another pointer/ref or an
565
+ // address-of).
566
+ addAssignOriginFact (*VD_LHS, *RHSExpr);
567
+ }
568
+ }
569
+
570
+ // A DeclRefExpr is a use of the referenced decl. It is checked for
571
+ // use-after-free unless it is being written to (e.g. on the left-hand side
572
+ // of an assignment).
573
+ void handleUse (const DeclRefExpr *DRE) {
574
+ if (hasOrigin (DRE->getType ())) {
575
+ UseFact *UF = FactMgr.createFact <UseFact>(DRE);
576
+ CurrentBlockFacts.push_back (UF);
577
+ assert (!UseFacts.contains (DRE));
578
+ UseFacts[DRE] = UF;
579
+ }
580
+ }
581
+
582
+ void markUseAsWrite (const DeclRefExpr *DRE) {
583
+ assert (UseFacts.contains (DRE));
584
+ UseFacts[DRE]->markAsWritten ();
585
+ }
586
+
557
587
FactManager &FactMgr;
558
588
llvm::SmallVector<Fact *> CurrentBlockFacts;
589
+ // To distinguish between reads and writes for use-after-free checks, this map
590
+ // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
591
+ // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
592
+ // corresponding to the left-hand side is updated to be a "write", thereby
593
+ // exempting it from the check.
594
+ llvm::DenseMap<const DeclRefExpr *, UseFact *> UseFacts;
559
595
};
560
596
561
597
class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
@@ -1069,8 +1105,9 @@ class LifetimeChecker {
1069
1105
// / graph. It determines if the loans held by the used origin have expired
1070
1106
// / at the point of use.
1071
1107
void checkUse (const UseFact *UF) {
1072
-
1073
- OriginID O = UF->getUsedOrigin ();
1108
+ if (UF->isWritten ())
1109
+ return ;
1110
+ OriginID O = UF->getUsedOrigin (FactMgr.getOriginMgr ());
1074
1111
1075
1112
// Get the set of loans that the origin might hold at this program point.
1076
1113
LoanSet HeldLoans = LoanPropagation.getLoans (O, UF);
0 commit comments