Skip to content

Commit 977be2e

Browse files
usx95github-actions[bot]
authored andcommitted
Automerge: [LifetimeSafety] Introduce a liveness-based lifetime policy (#159991)
This PR replaces the forward `ExpiredLoansAnalysis` with a backward `LiveOriginAnalysis` that tracks which origins are live at each program point, along with confidence levels (Definite or Maybe). The new approach: - Tracks liveness of origins rather than expiration of loans - Uses a backward dataflow analysis to determine which origins are live at each point. - Provides more precise confidence levels for use-after-free warnings and avoids previous false-positives The `LifetimeChecker` now checks for use-after-free by examining if an origin is live when a loan expires, rather than checking if a loan is expired when an origin is used. More details describing the design flaw in using `ExpiredLoans` is mentioned in llvm/llvm-project#156959 (comment) Fixes: llvm/llvm-project#156959 (With this, we can build LLVM with no false-positives 🎉 ) <details> <summary> Benchmark report </summary> # Lifetime Analysis Performance Report > Generated on: 2025-09-24 13:08:03 --- ## Test Case: Pointer Cycle in Loop **Timing Results:** | N (Input Size) | Total Time | Analysis Time (%) | Fact Generator (%) | Loan Propagation (%) | Live Origins (%) | |:---------------|-----------:|------------------:|-------------------:|---------------------:|------------------:| | 50 | 54.12 ms | 80.80% | 0.00% | 80.42% | 0.00% | | 75 | 150.22 ms | 91.54% | 0.00% | 91.19% | 0.00% | | 100 | 317.12 ms | 94.90% | 0.00% | 94.77% | 0.00% | | 200 | 2.40 s | 98.58% | 0.00% | 98.54% | 0.03% | | 300 | 9.85 s | 99.25% | 0.00% | 99.24% | 0.01% | **Complexity Analysis:** | Analysis Phase | Complexity O(n<sup>k</sup>) | |:------------------|:--------------------------| | Total Analysis | O(n<sup>3.47</sup> &pm; 0.06) | | FactGenerator | (Negligible) | | LoanPropagation | O(n<sup>3.47</sup> &pm; 0.06) | | LiveOrigins | (Negligible) | --- ## Test Case: CFG Merges **Timing Results:** | N (Input Size) | Total Time | Analysis Time (%) | Fact Generator (%) | Loan Propagation (%) | Live Origins (%) | |:---------------|-----------:|------------------:|-------------------:|---------------------:|------------------:| | 400 | 105.22 ms | 72.61% | 0.68% | 71.38% | 0.52% | | 1000 | 610.74 ms | 88.88% | 0.33% | 88.32% | 0.23% | | 2000 | 2.50 s | 95.32% | 0.21% | 94.99% | 0.11% | | 5000 | 17.20 s | 98.20% | 0.14% | 98.01% | 0.05% | **Complexity Analysis:** | Analysis Phase | Complexity O(n<sup>k</sup>) | |:------------------|:--------------------------| | Total Analysis | O(n<sup>2.14</sup> &pm; 0.00) | | FactGenerator | O(n<sup>1.59</sup> &pm; 0.05) | | LoanPropagation | O(n<sup>2.14</sup> &pm; 0.00) | | LiveOrigins | O(n<sup>1.19</sup> &pm; 0.04) | --- ## Test Case: Deeply Nested Loops **Timing Results:** | N (Input Size) | Total Time | Analysis Time (%) | Fact Generator (%) | Loan Propagation (%) | Live Origins (%) | |:---------------|-----------:|------------------:|-------------------:|---------------------:|------------------:| | 50 | 141.95 ms | 91.14% | 0.00% | 90.99% | 0.00% | | 100 | 1.09 s | 98.17% | 0.00% | 98.13% | 0.00% | | 150 | 3.87 s | 99.28% | 0.00% | 99.27% | 0.00% | | 200 | 9.81 s | 99.61% | 0.00% | 99.60% | 0.00% | **Complexity Analysis:** | Analysis Phase | Complexity O(n<sup>k</sup>) | |:------------------|:--------------------------| | Total Analysis | O(n<sup>3.23</sup> &pm; 0.02) | | FactGenerator | (Negligible) | | LoanPropagation | O(n<sup>3.23</sup> &pm; 0.02) | | LiveOrigins | (Negligible) | --- ## Test Case: Switch Fan-out **Timing Results:** | N (Input Size) | Total Time | Analysis Time (%) | Fact Generator (%) | Loan Propagation (%) | Live Origins (%) | |:---------------|-----------:|------------------:|-------------------:|---------------------:|------------------:| | 500 | 155.10 ms | 72.03% | 0.47% | 67.49% | 4.06% | | 1000 | 568.40 ms | 85.60% | 0.24% | 80.53% | 4.83% | | 2000 | 2.25 s | 93.00% | 0.13% | 86.99% | 5.88% | | 4000 | 9.06 s | 96.62% | 0.10% | 89.68% | 6.84% | **Complexity Analysis:** | Analysis Phase | Complexity O(n<sup>k</sup>) | |:------------------|:--------------------------| | Total Analysis | O(n<sup>2.07</sup> &pm; 0.01) | | FactGenerator | O(n<sup>1.52</sup> &pm; 0.13) | | LoanPropagation | O(n<sup>2.06</sup> &pm; 0.01) | | LiveOrigins | O(n<sup>2.23</sup> &pm; 0.00) | --- <details>
2 parents 45ea560 + 6bbd7ea commit 977be2e

File tree

6 files changed

+991
-489
lines changed

6 files changed

+991
-489
lines changed

clang/include/clang/Analysis/Analyses/LifetimeSafety.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@
2929
namespace clang::lifetimes {
3030

3131
/// Enum to track the confidence level of a potential error.
32-
enum class Confidence {
32+
enum class Confidence : uint8_t {
3333
None,
3434
Maybe, // Reported as a potential error (-Wlifetime-safety-strict)
3535
Definite // Reported as a definite error (-Wlifetime-safety-permissive)
3636
};
3737

38+
enum class LivenessKind : uint8_t {
39+
Dead, // Not alive
40+
Maybe, // Live on some path but not all paths (may-be-live)
41+
Must // Live on all paths (must-be-live)
42+
};
43+
3844
class LifetimeSafetyReporter {
3945
public:
4046
LifetimeSafetyReporter() = default;
@@ -55,6 +61,7 @@ class Fact;
5561
class FactManager;
5662
class LoanPropagationAnalysis;
5763
class ExpiredLoansAnalysis;
64+
class LiveOriginAnalysis;
5865
struct LifetimeFactory;
5966

6067
/// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
@@ -89,6 +96,7 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
8996
// TODO(opt): Consider using a bitset to represent the set of loans.
9097
using LoanSet = llvm::ImmutableSet<LoanID>;
9198
using OriginSet = llvm::ImmutableSet<OriginID>;
99+
using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
92100

93101
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
94102
/// `Fact`. identified by a lifetime-related event (`Fact`).
@@ -110,8 +118,16 @@ class LifetimeSafetyAnalysis {
110118
/// Returns the set of loans an origin holds at a specific program point.
111119
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
112120

113-
/// Returns the set of loans that have expired at a specific program point.
114-
std::vector<LoanID> getExpiredLoansAtPoint(ProgramPoint PP) const;
121+
/// Returns the set of origins that are live at a specific program point,
122+
/// along with the confidence level of their liveness.
123+
///
124+
/// An origin is considered live if there are potential future uses of that
125+
/// origin after the given program point. The confidence level indicates
126+
/// whether the origin is definitely live (Definite) due to being domintated
127+
/// by a set of uses or only possibly live (Maybe) only on some but not all
128+
/// control flow paths.
129+
std::vector<std::pair<OriginID, LivenessKind>>
130+
getLiveOriginsAtPoint(ProgramPoint PP) const;
115131

116132
/// Finds the OriginID for a given declaration.
117133
/// Returns a null optional if not found.
@@ -138,7 +154,7 @@ class LifetimeSafetyAnalysis {
138154
std::unique_ptr<LifetimeFactory> Factory;
139155
std::unique_ptr<FactManager> FactMgr;
140156
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
141-
std::unique_ptr<ExpiredLoansAnalysis> ExpiredLoans;
157+
std::unique_ptr<LiveOriginAnalysis> LiveOrigins;
142158
};
143159
} // namespace internal
144160
} // namespace clang::lifetimes

0 commit comments

Comments
 (0)