[clang] [LifetimeSafety] Detect dangling fields (PR #177363)

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 26 07:23:52 PST 2026


================
@@ -136,19 +136,63 @@ class OriginFlowFact : public Fact {
             const OriginManager &OM) const override;
 };
 
+/// Represents that an origin escapes the current scope through various means.
+/// This is the base class for different escape scenarios.
 class OriginEscapesFact : public Fact {
   OriginID OID;
-  const Expr *EscapeExpr;
 
 public:
+  /// The way an origin can escape the current scope.
+  enum class EscapeKind : uint8_t {
+    Return, /// Escapes via return statement.
+    Field,  /// Escapes via assignment to a field.
+    // FIXME: Add support for escape to global (dangling global ptr).
+  } EscKind;
+
   static bool classof(const Fact *F) {
     return F->getKind() == Kind::OriginEscapes;
   }
 
-  OriginEscapesFact(OriginID OID, const Expr *EscapeExpr)
-      : Fact(Kind::OriginEscapes), OID(OID), EscapeExpr(EscapeExpr) {}
+  OriginEscapesFact(OriginID OID, EscapeKind EscKind)
+      : Fact(Kind::OriginEscapes), OID(OID), EscKind(EscKind) {}
   OriginID getEscapedOriginID() const { return OID; }
-  const Expr *getEscapeExpr() const { return EscapeExpr; };
+  EscapeKind getEscapeKind() const { return EscKind; }
+};
+
+/// Represents that an origin escapes via a return statement.
+class ReturnEscapeFact : public OriginEscapesFact {
+  const Expr *ReturnExpr;
+
+public:
+  ReturnEscapeFact(OriginID OID, const Expr *ReturnExpr)
+      : OriginEscapesFact(OID, EscapeKind::Return), ReturnExpr(ReturnExpr) {}
+
+  static bool classof(const Fact *F) {
+    return F->getKind() == Kind::OriginEscapes &&
+           static_cast<const OriginEscapesFact *>(F)->getEscapeKind() ==
+               EscapeKind::Return;
+  }
+  const Expr *getReturnExpr() const { return ReturnExpr; };
+  void dump(llvm::raw_ostream &OS, const LoanManager &,
+            const OriginManager &OM) const override;
+};
+
+/// Represents that an origin escapes via assignment to a field.
+/// Example: `this->view = local_var;` where local_var outlives the assignment
+/// but not the object containing the field.
+class FieldEscapeFact : public OriginEscapesFact {
----------------
usx95 wrote:

Hmm. This is slightly challenging to do atm. This needs some more work on LoanPropagation dataflow to do this tracking.

The reason is we mark all the fields escaped at funciton exits. We need to track one step back on LoanPropagation to identify which OriginFlow is responsible of propagating the current loans to the escaped origin. That OriginFlow could have an expression attached to it responsible for that flow.

FWIW, this goes in the direction of making the diagnostics highlight **all** **the  expressions** responsible for a loan making into a "use"/"escape". We need to track the complete chain of originflow responsible for the current loanset of an origin.

https://github.com/llvm/llvm-project/pull/177363


More information about the cfe-commits mailing list