[clang] [LifetimeSafety] Detect expiry of loans to trivially destructed types (PR #168855)
Kashika Akhouri via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 21 01:07:19 PST 2025
================
@@ -66,6 +66,9 @@ void FactsGenerator::run() {
else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
Element.getAs<CFGAutomaticObjDtor>())
handleDestructor(*DtorOpt);
+ else if (std::optional<CFGLifetimeEnds> LifetimeEnds =
+ Element.getAs<CFGLifetimeEnds>())
+ handleTrivialDestructors(*LifetimeEnds);
----------------
kashika0112 wrote:
The test cases are passing now (after removing the destructor handling). The issue was that in handleLifetimeEnds I was using a break statement after it found the first expireFact. After removing that break, all tests are passing. Just to give an example.
For the first one:
Test:
```
void definite_multiple_pointers() {
std::string *p, *q, *r;
{
std::string s;
p = &s;
q = &s;
r = &s;
}
std::cout<< *p;
std::cout<< *q;
std::cout<< *r;
}
```
CFG with handleDestructor:
```
Function: definite_multiple_pointers
Block B2:
End of Block
Block B1:
Issue (0 (Path: s), ToOrigin: 0 (Expr: DeclRefExpr))
OriginFlow (Dest: 1 (Expr: UnaryOperator), Src: 0 (Expr: DeclRefExpr))
Use (2 (Decl: p), Write)
OriginFlow (Dest: 2 (Decl: p), Src: 1 (Expr: UnaryOperator))
Issue (1 (Path: s), ToOrigin: 3 (Expr: DeclRefExpr))
OriginFlow (Dest: 4 (Expr: UnaryOperator), Src: 3 (Expr: DeclRefExpr))
Use (5 (Decl: q), Write)
OriginFlow (Dest: 5 (Decl: q), Src: 4 (Expr: UnaryOperator))
Issue (2 (Path: s), ToOrigin: 6 (Expr: DeclRefExpr))
OriginFlow (Dest: 7 (Expr: UnaryOperator), Src: 6 (Expr: DeclRefExpr))
Use (8 (Decl: r), Write)
OriginFlow (Dest: 8 (Decl: r), Src: 7 (Expr: UnaryOperator))
Expire (0 (Path: s))
Expire (1 (Path: s))
Expire (2 (Path: s))
Expire (0 (Path: s))
Issue (3 (Path: operator<<), ToOrigin: 9 (Expr: DeclRefExpr))
OriginFlow (Dest: 10 (Expr: ImplicitCastExpr), Src: 9 (Expr: DeclRefExpr))
Issue (4 (Path: cout), ToOrigin: 11 (Expr: DeclRefExpr))
Use (2 (Decl: p), Read)
OriginFlow (Dest: 12 (Expr: ImplicitCastExpr), Src: 2 (Decl: p))
OriginFlow (Dest: 13 (Expr: ImplicitCastExpr), Src: 14 (Expr: UnaryOperator))
Issue (5 (Path: operator<<), ToOrigin: 15 (Expr: DeclRefExpr))
OriginFlow (Dest: 16 (Expr: ImplicitCastExpr), Src: 15 (Expr: DeclRefExpr))
Issue (6 (Path: cout), ToOrigin: 17 (Expr: DeclRefExpr))
Use (5 (Decl: q), Read)
OriginFlow (Dest: 18 (Expr: ImplicitCastExpr), Src: 5 (Decl: q))
OriginFlow (Dest: 19 (Expr: ImplicitCastExpr), Src: 20 (Expr: UnaryOperator))
Issue (7 (Path: operator<<), ToOrigin: 21 (Expr: DeclRefExpr))
OriginFlow (Dest: 22 (Expr: ImplicitCastExpr), Src: 21 (Expr: DeclRefExpr))
Issue (8 (Path: cout), ToOrigin: 23 (Expr: DeclRefExpr))
Use (8 (Decl: r), Read)
OriginFlow (Dest: 24 (Expr: ImplicitCastExpr), Src: 8 (Decl: r))
OriginFlow (Dest: 25 (Expr: ImplicitCastExpr), Src: 26 (Expr: UnaryOperator))
End of Block
Block B0:
End of Block
```
CFG without handleDestructor (only LifetimeEnds)
```
Function: definite_multiple_pointers
Block B2:
End of Block
Block B1:
Issue (0 (Path: s), ToOrigin: 0 (Expr: DeclRefExpr))
OriginFlow (Dest: 1 (Expr: UnaryOperator), Src: 0 (Expr: DeclRefExpr))
Use (2 (Decl: p), Write)
OriginFlow (Dest: 2 (Decl: p), Src: 1 (Expr: UnaryOperator))
Issue (1 (Path: s), ToOrigin: 3 (Expr: DeclRefExpr))
OriginFlow (Dest: 4 (Expr: UnaryOperator), Src: 3 (Expr: DeclRefExpr))
Use (5 (Decl: q), Write)
OriginFlow (Dest: 5 (Decl: q), Src: 4 (Expr: UnaryOperator))
Issue (2 (Path: s), ToOrigin: 6 (Expr: DeclRefExpr))
OriginFlow (Dest: 7 (Expr: UnaryOperator), Src: 6 (Expr: DeclRefExpr))
Use (8 (Decl: r), Write)
OriginFlow (Dest: 8 (Decl: r), Src: 7 (Expr: UnaryOperator))
Expire (0 (Path: s))
Expire (1 (Path: s))
Expire (2 (Path: s))
Issue (3 (Path: operator<<), ToOrigin: 9 (Expr: DeclRefExpr))
OriginFlow (Dest: 10 (Expr: ImplicitCastExpr), Src: 9 (Expr: DeclRefExpr))
Issue (4 (Path: cout), ToOrigin: 11 (Expr: DeclRefExpr))
Use (2 (Decl: p), Read)
OriginFlow (Dest: 12 (Expr: ImplicitCastExpr), Src: 2 (Decl: p))
OriginFlow (Dest: 13 (Expr: ImplicitCastExpr), Src: 14 (Expr: UnaryOperator))
Issue (5 (Path: operator<<), ToOrigin: 15 (Expr: DeclRefExpr))
OriginFlow (Dest: 16 (Expr: ImplicitCastExpr), Src: 15 (Expr: DeclRefExpr))
Issue (6 (Path: cout), ToOrigin: 17 (Expr: DeclRefExpr))
Use (5 (Decl: q), Read)
OriginFlow (Dest: 18 (Expr: ImplicitCastExpr), Src: 5 (Decl: q))
OriginFlow (Dest: 19 (Expr: ImplicitCastExpr), Src: 20 (Expr: UnaryOperator))
Issue (7 (Path: operator<<), ToOrigin: 21 (Expr: DeclRefExpr))
OriginFlow (Dest: 22 (Expr: ImplicitCastExpr), Src: 21 (Expr: DeclRefExpr))
Issue (8 (Path: cout), ToOrigin: 23 (Expr: DeclRefExpr))
Use (8 (Decl: r), Read)
OriginFlow (Dest: 24 (Expr: ImplicitCastExpr), Src: 8 (Decl: r))
OriginFlow (Dest: 25 (Expr: ImplicitCastExpr), Src: 26 (Expr: UnaryOperator))
End of Block
Block B0:
End of Block
```
Given this, should I remove handleDestructor now?
https://github.com/llvm/llvm-project/pull/168855
More information about the cfe-commits
mailing list