@@ -119,6 +119,7 @@ class OriginManager {
119119 return AllOrigins.back ();
120120 }
121121
122+ // TODO: Mark this method as const once we remove the call to getOrCreate.
122123 OriginID get (const Expr &E) {
123124 // Origin of DeclRefExpr is that of the declaration it refers to.
124125 if (const auto *DRE = dyn_cast<DeclRefExpr>(&E))
@@ -315,22 +316,28 @@ class ReturnOfOriginFact : public Fact {
315316};
316317
317318class UseFact : public Fact {
318- OriginID UsedOrigin;
319319 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 ;
320323
321324public:
322325 static bool classof (const Fact *F) { return F->getKind () == Kind::Use; }
323326
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) {}
326328
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+ }
328333 const Expr *getUseExpr () const { return UseExpr; }
334+ void markAsWritten () { IsWritten = true ; }
335+ bool isWritten () const { return IsWritten; }
329336
330337 void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
331338 OS << " Use (" ;
332- OM.dump (getUsedOrigin (), OS);
333- OS << " )\n " ;
339+ OM.dump (getUsedOrigin (OM ), OS);
340+ OS << " " << ( isWritten () ? " Write " : " Read " ) << " )\n " ;
334341 }
335342};
336343
@@ -425,6 +432,8 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
425432 addAssignOriginFact (*VD, *InitExpr);
426433 }
427434
435+ void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
436+
428437 void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
429438 // / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
430439 // / pointers can use the same type of loan.
@@ -458,10 +467,6 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
458467 }
459468 }
460469 }
461- } else if (UO->getOpcode () == UO_Deref) {
462- // This is a pointer use, like '*p'.
463- OriginID OID = FactMgr.getOriginMgr ().get (*UO->getSubExpr ());
464- CurrentBlockFacts.push_back (FactMgr.createFact <UseFact>(OID, UO));
465470 }
466471 }
467472
@@ -476,20 +481,13 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
476481 }
477482
478483 void VisitBinaryOperator (const BinaryOperator *BO) {
479- if (BO->isAssignmentOp ()) {
480- const Expr *LHSExpr = BO->getLHS ();
481- const Expr *RHSExpr = BO->getRHS ();
482-
483- // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
484- // LHS must be a pointer/reference type that can be an origin.
485- // RHS must also represent an origin (either another pointer/ref or an
486- // address-of).
487- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
488- if (const auto *VD_LHS =
489- dyn_cast<ValueDecl>(DRE_LHS->getDecl ()->getCanonicalDecl ());
490- VD_LHS && hasOrigin (VD_LHS->getType ()))
491- addAssignOriginFact (*VD_LHS, *RHSExpr);
492- }
484+ if (BO->isAssignmentOp ())
485+ handleAssignment (BO->getLHS (), BO->getRHS ());
486+ }
487+
488+ void VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *OCE) {
489+ if (OCE->isAssignmentOp () && OCE->getNumArgs () == 2 )
490+ handleAssignment (OCE->getArg (0 ), OCE->getArg (1 ));
493491 }
494492
495493 void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
@@ -556,8 +554,47 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
556554 return false ;
557555 }
558556
557+ void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
558+ // Find the underlying variable declaration for the left-hand side.
559+ if (const auto *DRE_LHS =
560+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ())) {
561+ markUseAsWrite (DRE_LHS);
562+ if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
563+ if (hasOrigin (VD_LHS->getType ()))
564+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
565+ // LHS must be a pointer/reference type that can be an origin.
566+ // RHS must also represent an origin (either another pointer/ref or an
567+ // address-of).
568+ addAssignOriginFact (*VD_LHS, *RHSExpr);
569+ }
570+ }
571+
572+ // A DeclRefExpr is a use of the referenced decl. It is checked for
573+ // use-after-free unless it is being written to (e.g. on the left-hand side
574+ // of an assignment).
575+ void handleUse (const DeclRefExpr *DRE) {
576+ const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl ());
577+ if (VD && hasOrigin (VD->getType ())) {
578+ UseFact *UF = FactMgr.createFact <UseFact>(DRE);
579+ CurrentBlockFacts.push_back (UF);
580+ assert (!UseFacts.contains (DRE));
581+ UseFacts[DRE] = UF;
582+ }
583+ }
584+
585+ void markUseAsWrite (const DeclRefExpr *DRE) {
586+ assert (UseFacts.contains (DRE));
587+ UseFacts[DRE]->markAsWritten ();
588+ }
589+
559590 FactManager &FactMgr;
560591 llvm::SmallVector<Fact *> CurrentBlockFacts;
592+ // To distinguish between reads and writes for use-after-free checks, this map
593+ // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
594+ // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
595+ // corresponding to the left-hand side is updated to be a "write", thereby
596+ // exempting it from the check.
597+ llvm::DenseMap<const DeclRefExpr *, UseFact *> UseFacts;
561598};
562599
563600class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
@@ -1073,8 +1110,9 @@ class LifetimeChecker {
10731110 // / graph. It determines if the loans held by the used origin have expired
10741111 // / at the point of use.
10751112 void checkUse (const UseFact *UF) {
1076-
1077- OriginID O = UF->getUsedOrigin ();
1113+ if (UF->isWritten ())
1114+ return ;
1115+ OriginID O = UF->getUsedOrigin (FactMgr.getOriginMgr ());
10781116
10791117 // Get the set of loans that the origin might hold at this program point.
10801118 LoanSet HeldLoans = LoanPropagation.getLoans (O, UF);
0 commit comments