@@ -317,6 +317,7 @@ class ReturnOfOriginFact : public Fact {
317317class UseFact : public Fact {
318318 OriginID UsedOrigin;
319319 const Expr *UseExpr;
320+ bool IsWritten = false ;
320321
321322public:
322323 static bool classof (const Fact *F) { return F->getKind () == Kind::Use; }
@@ -326,11 +327,13 @@ class UseFact : public Fact {
326327
327328 OriginID getUsedOrigin () const { return UsedOrigin; }
328329 const Expr *getUseExpr () const { return UseExpr; }
330+ void markAsWritten () { IsWritten = true ; }
331+ bool isWritten () const { return IsWritten; }
329332
330333 void dump (llvm::raw_ostream &OS, const OriginManager &OM) const override {
331334 OS << " Use (" ;
332335 OM.dump (getUsedOrigin (), OS);
333- OS << " )\n " ;
336+ OS << " " << ( isWritten () ? " Write " : " Read " ) << " )\n " ;
334337 }
335338};
336339
@@ -428,6 +431,8 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
428431 addAssignOriginFact (*VD, *InitExpr);
429432 }
430433
434+ void VisitDeclRefExpr (const DeclRefExpr *DRE) { handleUse (DRE); }
435+
431436 void VisitCXXNullPtrLiteralExpr (const CXXNullPtrLiteralExpr *N) {
432437 // / TODO: Handle nullptr expr as a special 'null' loan. Uninitialized
433438 // / pointers can use the same type of loan.
@@ -461,10 +466,6 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
461466 }
462467 }
463468 }
464- } else if (UO->getOpcode () == UO_Deref) {
465- // This is a pointer use, like '*p'.
466- OriginID OID = FactMgr.getOriginMgr ().get (*UO->getSubExpr ());
467- CurrentBlockFacts.push_back (FactMgr.createFact <UseFact>(OID, UO));
468469 }
469470 }
470471
@@ -479,20 +480,13 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
479480 }
480481
481482 void VisitBinaryOperator (const BinaryOperator *BO) {
482- if (BO->isAssignmentOp ()) {
483- const Expr *LHSExpr = BO->getLHS ();
484- const Expr *RHSExpr = BO->getRHS ();
485-
486- // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
487- // LHS must be a pointer/reference type that can be an origin.
488- // RHS must also represent an origin (either another pointer/ref or an
489- // address-of).
490- if (const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
491- if (const auto *VD_LHS =
492- dyn_cast<ValueDecl>(DRE_LHS->getDecl ()->getCanonicalDecl ());
493- VD_LHS && hasOrigin (VD_LHS->getType ()))
494- addAssignOriginFact (*VD_LHS, *RHSExpr);
495- }
483+ if (BO->isAssignmentOp ())
484+ handleAssignment (BO->getLHS (), BO->getRHS ());
485+ }
486+
487+ void VisitCXXOperatorCallExpr (const CXXOperatorCallExpr *OCE) {
488+ if (OCE->isAssignmentOp () && OCE->getNumArgs () == 2 )
489+ handleAssignment (OCE->getArg (0 ), OCE->getArg (1 ));
496490 }
497491
498492 void VisitCXXFunctionalCastExpr (const CXXFunctionalCastExpr *FCE) {
@@ -559,9 +553,49 @@ class FactGeneratorVisitor : public ConstStmtVisitor<FactGeneratorVisitor> {
559553 return false ;
560554 }
561555
556+ void handleAssignment (const Expr *LHSExpr, const Expr *RHSExpr) {
557+ // Find the underlying variable declaration for the left-hand side.
558+ if (const auto *DRE_LHS =
559+ dyn_cast<DeclRefExpr>(LHSExpr->IgnoreParenImpCasts ())) {
560+ markUseAsWrite (DRE_LHS);
561+ if (const auto *VD_LHS = dyn_cast<ValueDecl>(DRE_LHS->getDecl ()))
562+ if (hasOrigin (VD_LHS->getType ()))
563+ // We are interested in assignments like `ptr1 = ptr2` or `ptr = &var`
564+ // LHS must be a pointer/reference type that can be an origin.
565+ // RHS must also represent an origin (either another pointer/ref or an
566+ // address-of).
567+ addAssignOriginFact (*VD_LHS, *RHSExpr);
568+ }
569+ }
570+
571+ // A DeclRefExpr is a use of the referenced decl. It is checked for
572+ // use-after-free unless it is being written to (e.g. on the left-hand side
573+ // of an assignment).
574+ void handleUse (const DeclRefExpr *DRE) {
575+ const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl ());
576+ if (VD && hasOrigin (VD->getType ())) {
577+ OriginID OID = FactMgr.getOriginMgr ().get (*VD);
578+ UseFact *UF = FactMgr.createFact <UseFact>(OID, 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+
562590 FactManager &FactMgr;
563591 const CFGBlock *CurrentBlock = nullptr ;
564592 llvm::SmallVector<Fact *> CurrentBlockFacts;
593+ // To distinguish between reads and writes for use-after-free checks, this map
594+ // stores the `UseFact` for each `DeclRefExpr`. We initially identify all
595+ // `DeclRefExpr`s as "read" uses. When an assignment is processed, the use
596+ // corresponding to the left-hand side is updated to be a "write", thereby
597+ // exempting it from the check.
598+ llvm::DenseMap<const DeclRefExpr *, UseFact *> UseFacts;
565599};
566600
567601class FactGenerator : public RecursiveASTVisitor <FactGenerator> {
@@ -1076,7 +1110,8 @@ class LifetimeChecker {
10761110 // / graph. It determines if the loans held by the used origin have expired
10771111 // / at the point of use.
10781112 void checkUse (const UseFact *UF) {
1079-
1113+ if (UF->isWritten ())
1114+ return ;
10801115 OriginID O = UF->getUsedOrigin ();
10811116
10821117 // Get the set of loans that the origin might hold at this program point.
0 commit comments