================
@@ -0,0 +1,380 @@
+//===- 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 "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;
+}
+
+AliasAssignmentSearchResult getAliasListCore(
+    const AssignmentQueryContext &Context, const CFGBlock *Block,
+    const LoanID EndLoanID, OriginID *TargetOID,
+    const std::optional<OriginDestExpr> LastDestDecl = std::nullopt,
+    const std::optional<OriginID> LastOriginID = std::nullopt) {
+  std::optional<OriginID> CurrOrigin = std::nullopt;
+  std::optional<OriginDestExpr> DestDecl = LastDestDecl;
+  std::optional<const Expr *> SrcExpr = std::nullopt;
+  llvm::SmallVector<AssignmentPair> AliasStmts;
+  const auto Facts = Context.FactMgr.getFacts(Block);
+  bool FetchLoan = false;
+  auto IssueOriginID = LastOriginID;
+
+  for (const auto &F : llvm::reverse(Facts)) {
+    if (const auto *OFF = F->getAs<OriginFlowFact>()) {
+      if (IssueOriginID.has_value() &&
+          OFF->getDestOriginID() == IssueOriginID.value())
+        FetchLoan = true;
+
+      if (OFF->getDestOriginID() == *TargetOID) {
+        const auto HeldLoans =
+            Context.LoanPropagation.getLoans(OFF->getSrcOriginID(), OFF);
+
+        if (HeldLoans.contains(EndLoanID)) {
+          const auto TargetOrigin =
+              Context.FactMgr.getOriginMgr().getOrigin(OFF->getDestOriginID());
+
+          if (!DestDecl.has_value()) {
+            if (const ValueDecl *DVecl = TargetOrigin.getDecl();
+                DVecl && !DVecl->getLocation().isInvalid()) {
+              if (llvm::isa<FieldDecl>(DVecl)) {
+                const auto *CurrExpr = Context.FactMgr.getOriginMgr()
+                                           .getOrigin(OFF->getSrcOriginID())
+                                           .getExpr();
+                if (CurrExpr)
+                  DestDecl = getFieldFromAssignmentExpr(
+                      CurrExpr, Context.ADC.getParentMap());
+              } else {
+                CurrOrigin = *TargetOID;
+                DestDecl = DVecl;
+              }
+            }
+          } else {
+            auto SExpr = GetPureSrcExpr(TargetOrigin.getExpr());
+            if (!SExpr.has_value()) {
+              const auto SrcOrigin = Context.FactMgr.getOriginMgr().getOrigin(
+                  OFF->getSrcOriginID());
+              SExpr = GetPureSrcExpr(SrcOrigin.getExpr());
+            }
+
+            if (SExpr.has_value()) {
+              AliasStmts.push_back({DestDecl.value(), SExpr.value()});
+              SrcExpr = SExpr.value();
+              DestDecl = std::nullopt;
+              CurrOrigin = std::nullopt;
+            }
+          }
+          *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.has_value()) {
+        for (const OriginList *Cur = UF->getUsedOrigins(); Cur;
+             Cur = Cur->peelOuterOrigin()) {
+          if (Cur->getOuterOriginID() == CurrOrigin.value() &&
+              UF->isWritten()) {
+            const auto UExpr = GetPureSrcExpr(UF->getUseExpr());
+            if (UExpr.has_value()) {
+              if (const auto *UDExpr =
+                      llvm::dyn_cast<DeclRefExpr>(UExpr.value())) {
+                DestDecl = UDExpr;
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (FetchLoan) {
+      return {AliasStmts, true, DestDecl, IssueOriginID};
+    }
+  }
+  return {AliasStmts, false, DestDecl, IssueOriginID};
+}
+
+std::optional<llvm::SmallVector<AssignmentPair>>
+getAliasListInMultiBlock(const AssignmentQueryContext &Context,
+                         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](const AssignmentPair StartStmt,
+                                              const AssignmentPair EndStmt) {
+    llvm::SmallVector<AssignmentPair> AliasStmts;
+    for (auto Stmt = StartStmt; Stmt != EndStmt; Stmt = VistedExprs.at(Stmt))
+      AliasStmts.push_back(Stmt);
+    AliasStmts.push_back(EndStmt);
+    return AliasStmts;
+  };
+
+  PendingBlocks.push_back(StartBlock);
+
+  for (size_t i = 0; i < PendingBlocks.size(); ++i) {
+    const CFGBlock *CurrBlock = PendingBlocks[i];
+
+    const auto [BlockAliasList, Success, CurrLastDestDecl, CurrLastOriginID] =
+        getAliasListCore(Context, CurrBlock, EndLoanID, StartOID, LastDestDecl,
+                         LastOriginID);
+    if (CurrLastDestDecl)
+      LastDestDecl = CurrLastDestDecl;
+    if (CurrLastOriginID.has_value())
+      LastOriginID = CurrLastOriginID;
+
+    if (!BlockAliasList.empty()) {
+      if (VistedExprs.empty())
+        StartStmt = BlockAliasList[0];
+
+      for (size_t i = 0; i < BlockAliasList.size() - 1; ++i)
+        VistedExprs.insert({BlockAliasList[i], BlockAliasList[i + 1]});
+
+      if (EndStmt.has_value())
+        VistedExprs.insert({EndStmt.value(), BlockAliasList[0]});
+
+      EndStmt = BlockAliasList[BlockAliasList.size() - 1];
+    }
+
+    if (Success && StartStmt.has_value() && EndStmt.has_value())
+      return AliasStmtFilter(StartStmt.value(), EndStmt.value());
+
+    for (const auto &Block : CurrBlock->preds())
+      if (Block && VistedBlocks.insert(Block).second)
+        PendingBlocks.push_back(Block);
+
+    if (VistedBlocks.size() >= 32 && StartStmt.has_value() &&
----------------
suoyuan666 wrote:

This is just a temporary solution. I should have written a comment here.
Because I didn't think the search should go on indefinitely, I wanted to set a 
boundary, but I hadn't figured out a suitable condition, so I stopped after 
searching 32 CFGBlocks.

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