================
@@ -0,0 +1,365 @@
+//===- AssignmentQuery.cpp - C++ Lifetime Safety Checker --------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the LifetimeChecker, which detects use-after-free
+// errors by checking if live origins hold loans that have expired.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/LifetimeSafety/AssignmentQuery.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <cstddef>
+
+namespace {
+
+using namespace clang;
+using namespace clang::lifetimes;
+using namespace clang::lifetimes::internal;
+
+std::optional<const Expr *> GetPureSrcExpr(const Expr *TargetExpr) {
+  if (!TargetExpr)
+    return std::nullopt;
+  const Expr *SExpr = TargetExpr->IgnoreParenCasts();
+  if (!SExpr)
+    return std::nullopt;
+
+  if (llvm::isa<DeclRefExpr, CXXTemporaryObjectExpr, ConditionalOperator,
+                CXXConstructExpr>(SExpr) &&
+      !SExpr->getExprLoc().isInvalid())
+    return SExpr;
+
+  if (const auto *SCExpr = llvm::dyn_cast<CallExpr>(SExpr);
+      SCExpr && !SCExpr->getExprLoc().isInvalid() &&
+      !SCExpr->getCallee()->IgnoreParenCasts()->getExprLoc().isInvalid())
+    return SCExpr;
+
+  if (const auto *SMExpr = llvm::dyn_cast<MemberExpr>(SExpr))
+    return GetPureSrcExpr(SMExpr->getBase());
+  if (const auto *SCExpr = llvm::dyn_cast<CXXMemberCallExpr>(SExpr))
+    return GetPureSrcExpr(SCExpr->getCallee());
+  if (const auto *SUOExpr = llvm::dyn_cast<UnaryOperator>(SExpr))
+    return GetPureSrcExpr(SUOExpr->getSubExpr());
+  if (const auto *SCBExpr = llvm::dyn_cast<CXXBindTemporaryExpr>(SExpr))
+    return GetPureSrcExpr(SCBExpr->getSubExpr());
+
+  return std::nullopt;
+}
+
+/// Specifically handles assignments involving a FieldDecl.
+///
+/// Since we currently only store the FieldDecl without its corresponding
+/// LHS expression, this function attempts to recover or resolve the LHS
+/// context by analyzing the RHS.
+const MemberExpr *getFieldFromAssignmentExpr(const Expr *RHS,
+                                             const ParentMap &CurrParentMap) {
+
+  const Stmt *CurrStmt = CurrParentMap.getParent(RHS);
+  if (!CurrStmt)
+    return nullptr;
+  if (const auto *BinaryOp = llvm::dyn_cast<BinaryOperator>(CurrStmt))
+    return llvm::dyn_cast<MemberExpr>(BinaryOp->getLHS());
+  if (const auto *CXXOp = llvm::dyn_cast<CXXOperatorCallExpr>(CurrStmt);
+      CXXOp && CXXOp->getOperator() == OO_Equal && CXXOp->getNumArgs() == 2)
+    return llvm::dyn_cast<MemberExpr>(CXXOp->getArg(0));
+  return nullptr;
+}
+
+const DeclRefExpr *getLHSExpr(const UseFact *UF, const OriginID OID) {
+  for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+       Cur = Cur->peelOuterOrigin()) {
+    if (Cur->getOuterOriginID() != OID || !UF->isWritten())
+      continue;
+    std::optional<const Expr *> UExpr = GetPureSrcExpr(UF->getUseExpr());
+    if (UExpr) {
+      if (const auto *UDExpr = llvm::dyn_cast<DeclRefExpr>(UExpr.value())) {
+        return UDExpr;
+      }
+    }
+  }
+  return nullptr;
+}
+
+std::optional<OriginDestExpr>
+getLHSDeclOrExpr(const AssignmentQueryContext &Context,
+                 const OriginFlowFact *OFF) {
+  const Origin TargetOrigin =
+      Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+  if (const ValueDecl *DVecl = TargetOrigin.getDecl();
+      DVecl && !DVecl->getLocation().isInvalid()) {
+    if (llvm::isa<FieldDecl>(DVecl)) {
+      const Expr *CurrExpr = Context.FactMgr.getOriginMgr()
+                                 .getOrigin(OFF->getSrcOriginID())
+                                 .getExpr();
+      if (CurrExpr)
+        return getFieldFromAssignmentExpr(CurrExpr, 
Context.ADC.getParentMap());
+    } else {
+      return DVecl;
+    }
+  }
+  return std::nullopt;
+}
+
+std::optional<const Expr *>
+getRHSDeclOrExpr(const AssignmentQueryContext &Context,
+                 const OriginFlowFact *OFF) {
+  const Origin TargetOrigin =
+      Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+  std::optional<const Expr *> SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
+  if (!SExpr) {
+    const Origin SrcOrigin =
+        Context.FactMgr.getOriginMgr().getOrigin(OFF->getSrcOriginID());
+    SExpr = GetPureSrcExpr(SrcOrigin.getExpr());
+  }
+
+  return SExpr;
+}
+
+AliasAssignmentSearchResult getAliasListCore(
+    const AssignmentQueryContext &Context,
+    llvm::SmallVectorImpl<AssignmentPair> &AssignmentList,
+    const CFGBlock *Block, const LoanID EndLoanID, OriginID *TargetOID,
+    const std::optional<OriginDestExpr> LastDestExpr = std::nullopt,
+    const std::optional<OriginID> LastOriginID = std::nullopt) {
+  llvm::ArrayRef<const Fact *> Facts = Context.FactMgr.getFacts(Block);
+  std::optional<OriginID> IssueOriginID = LastOriginID;
+  std::optional<OriginDestExpr> CurrDestExpr = LastDestExpr;
+  std::optional<OriginID> CurrOrigin = std::nullopt;
+
+  const auto InsertAssignmentList = [&](const OriginFlowFact *OFF) {
+    if (!CurrDestExpr) {
+      std::optional<OriginDestExpr> DestExpr = getLHSDeclOrExpr(Context, OFF);
+      if (DestExpr) {
+        if (llvm::isa<const ValueDecl *>(DestExpr.value()))
+          CurrOrigin = *TargetOID;
+        CurrDestExpr = DestExpr;
+      }
+    } else {
+      std::optional<const Expr *> CurrSrcExpr = getRHSDeclOrExpr(Context, OFF);
+      if (CurrSrcExpr) {
+        AssignmentList.push_back({CurrDestExpr.value(), CurrSrcExpr.value()});
+        CurrDestExpr = std::nullopt;
+        CurrOrigin = std::nullopt;
+      }
+    }
+  };
+
+  for (const Fact *F : llvm::reverse(Facts)) {
+    if (const auto *OFF = F->getAs<OriginFlowFact>()) {
+      if (IssueOriginID && OFF->getDestOriginID() == IssueOriginID.value())
+        return {true, CurrDestExpr, IssueOriginID};
+      if (OFF->getDestOriginID() == *TargetOID &&
+          Context.LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF)
+              .contains(EndLoanID)) {
+        InsertAssignmentList(OFF);
+        *TargetOID = OFF->getSrcOriginID();
+      }
+    } else if (const auto *IF = F->getAs<IssueFact>()) {
+      if (IF->getLoanID() == EndLoanID)
+        IssueOriginID = IF->getOriginID();
+    } else if (const auto *UF = F->getAs<UseFact>()) {
+      if (CurrOrigin) {
+        const DeclRefExpr *LHSExpr = getLHSExpr(UF, CurrOrigin.value());
+        if (LHSExpr)
+          CurrDestExpr = LHSExpr;
+      }
+    }
+  }
+
+  return {false, CurrDestExpr, IssueOriginID};
+}
+
+void getAliasListInMultiBlock(
+    const AssignmentQueryContext &Context,
+    llvm::SmallVectorImpl<AssignmentPair> &AssignmentList,
+    const CFGBlock *StartBlock, const LoanID EndLoanID, OriginID *StartOID) {
+  std::optional<OriginDestExpr> LastDestDecl = std::nullopt;
+  llvm::SmallVector<const CFGBlock *> PendingBlocks;
+  std::optional<AssignmentPair> StartStmt = std::nullopt;
+  std::optional<AssignmentPair> EndStmt = std::nullopt;
+  std::optional<OriginID> LastOriginID = std::nullopt;
+  llvm::SmallPtrSet<const CFGBlock *, 32> VistedBlocks;
+  llvm::DenseMap<AssignmentPair, AssignmentPair> VistedExprs;
+
+  const auto AliasStmtFilter = [&VistedExprs,
+                                &AssignmentList](const AssignmentPair 
StartStmt,
+                                                 const AssignmentPair EndStmt) 
{
+    llvm::SmallVector<AssignmentPair> AliasStmts;
+    for (AssignmentPair Stmt = StartStmt; Stmt != EndStmt;
+         Stmt = VistedExprs.at(Stmt))
+      AssignmentList.push_back(Stmt);
+    AssignmentList.push_back(EndStmt);
+    return AliasStmts;
+  };
+
+  PendingBlocks.push_back(StartBlock);
+
+  for (size_t i = 0; i < PendingBlocks.size(); ++i) {
----------------
Xazax-hun wrote:

Is this correct? Like the size of `PendingBlocks` can increase in the loop, 
like you are pushing back to it below. Could you skip processing those?

https://github.com/llvm/llvm-project/pull/188467
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to