Skip to content

Commit 24a5d8a

Browse files
committed
Revert "[LifetimeSafety] Reorganize code into modular components (llvm#162474)"
This reverts commit 2eb8c47 since it completely breaks dylib build.
1 parent de67a78 commit 24a5d8a

31 files changed

+1754
-2207
lines changed

.github/new-prs-labeler.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,8 +1096,8 @@ clang:openmp:
10961096
- llvm/test/Transforms/OpenMP/**
10971097

10981098
clang:temporal-safety:
1099-
- clang/include/clang/Analysis/Analyses/LifetimeSafety/**
1100-
- clang/lib/Analysis/LifetimeSafety/**
1099+
- clang/include/clang/Analysis/Analyses/LifetimeSafety*
1100+
- clang/lib/Analysis/LifetimeSafety*
11011101
- clang/unittests/Analysis/LifetimeSafety*
11021102
- clang/test/Sema/*lifetime-safety*
11031103
- clang/test/Sema/*lifetime-analysis*
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
#include "clang/AST/DeclCXX.h"
1414

15-
namespace clang ::lifetimes {
15+
namespace clang {
16+
namespace lifetimes {
1617

1718
/// Returns the most recent declaration of the method to ensure all
1819
/// lifetime-bound attributes from redeclarations are considered.
@@ -37,7 +38,7 @@ bool isAssignmentOperatorLifetimeBound(const CXXMethodDecl *CMD);
3738
/// lifetimebound, either due to an explicit lifetimebound attribute on the
3839
/// method or because it's a normal assignment operator.
3940
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD);
40-
41-
} // namespace clang::lifetimes
41+
} // namespace lifetimes
42+
} // namespace clang
4243

4344
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMEANNOTATIONS_H
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
//===- LifetimeSafety.h - C++ Lifetime Safety Analysis -*----------- C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines the entry point for a dataflow-based static analysis
10+
// that checks for C++ lifetime violations.
11+
//
12+
// The analysis is based on the concepts of "origins" and "loans" to track
13+
// pointer lifetimes and detect issues like use-after-free and dangling
14+
// pointers. See the RFC for more details:
15+
// https://discourse.llvm.org/t/rfc-intra-procedural-lifetime-analysis-in-clang/86291
16+
//
17+
//===----------------------------------------------------------------------===//
18+
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
19+
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
20+
#include "clang/Analysis/AnalysisDeclContext.h"
21+
#include "clang/Analysis/CFG.h"
22+
#include "clang/Basic/SourceLocation.h"
23+
#include "llvm/ADT/DenseMapInfo.h"
24+
#include "llvm/ADT/ImmutableMap.h"
25+
#include "llvm/ADT/ImmutableSet.h"
26+
#include "llvm/ADT/StringMap.h"
27+
#include <memory>
28+
29+
namespace clang::lifetimes {
30+
31+
/// Enum to track the confidence level of a potential error.
32+
enum class Confidence : uint8_t {
33+
None,
34+
Maybe, // Reported as a potential error (-Wlifetime-safety-strict)
35+
Definite // Reported as a definite error (-Wlifetime-safety-permissive)
36+
};
37+
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+
44+
class LifetimeSafetyReporter {
45+
public:
46+
LifetimeSafetyReporter() = default;
47+
virtual ~LifetimeSafetyReporter() = default;
48+
49+
virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
50+
SourceLocation FreeLoc,
51+
Confidence Confidence) {}
52+
};
53+
54+
/// The main entry point for the analysis.
55+
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
56+
LifetimeSafetyReporter *Reporter);
57+
58+
namespace internal {
59+
// Forward declarations of internal types.
60+
class Fact;
61+
class FactManager;
62+
class LoanPropagationAnalysis;
63+
class ExpiredLoansAnalysis;
64+
class LiveOriginAnalysis;
65+
struct LifetimeFactory;
66+
67+
/// A generic, type-safe wrapper for an ID, distinguished by its `Tag` type.
68+
/// Used for giving ID to loans and origins.
69+
template <typename Tag> struct ID {
70+
uint32_t Value = 0;
71+
72+
bool operator==(const ID<Tag> &Other) const { return Value == Other.Value; }
73+
bool operator!=(const ID<Tag> &Other) const { return !(*this == Other); }
74+
bool operator<(const ID<Tag> &Other) const { return Value < Other.Value; }
75+
ID<Tag> operator++(int) {
76+
ID<Tag> Tmp = *this;
77+
++Value;
78+
return Tmp;
79+
}
80+
void Profile(llvm::FoldingSetNodeID &IDBuilder) const {
81+
IDBuilder.AddInteger(Value);
82+
}
83+
};
84+
85+
using LoanID = ID<struct LoanTag>;
86+
using OriginID = ID<struct OriginTag>;
87+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, LoanID ID) {
88+
return OS << ID.Value;
89+
}
90+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OriginID ID) {
91+
return OS << ID.Value;
92+
}
93+
94+
// Using LLVM's immutable collections is efficient for dataflow analysis
95+
// as it avoids deep copies during state transitions.
96+
// TODO(opt): Consider using a bitset to represent the set of loans.
97+
using LoanSet = llvm::ImmutableSet<LoanID>;
98+
using OriginSet = llvm::ImmutableSet<OriginID>;
99+
using OriginLoanMap = llvm::ImmutableMap<OriginID, LoanSet>;
100+
101+
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
102+
/// `Fact`. identified by a lifetime-related event (`Fact`).
103+
///
104+
/// A `ProgramPoint` has "after" semantics: it represents the location
105+
/// immediately after its corresponding `Fact`.
106+
using ProgramPoint = const Fact *;
107+
108+
/// Running the lifetime safety analysis and querying its results. It
109+
/// encapsulates the various dataflow analyses.
110+
class LifetimeSafetyAnalysis {
111+
public:
112+
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
113+
LifetimeSafetyReporter *Reporter);
114+
~LifetimeSafetyAnalysis();
115+
116+
void run();
117+
118+
/// Returns the set of loans an origin holds at a specific program point.
119+
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
120+
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;
131+
132+
/// Finds the OriginID for a given declaration.
133+
/// Returns a null optional if not found.
134+
std::optional<OriginID> getOriginIDForDecl(const ValueDecl *D) const;
135+
136+
/// Finds the LoanID's for the loan created with the specific variable as
137+
/// their Path.
138+
std::vector<LoanID> getLoanIDForVar(const VarDecl *VD) const;
139+
140+
/// Retrieves program points that were specially marked in the source code
141+
/// for testing.
142+
///
143+
/// The analysis recognizes special function calls of the form
144+
/// `void("__lifetime_test_point_<name>")` as test points. This method returns
145+
/// a map from the annotation string (<name>) to the corresponding
146+
/// `ProgramPoint`. This allows test harnesses to query the analysis state at
147+
/// user-defined locations in the code.
148+
/// \note This is intended for testing only.
149+
llvm::StringMap<ProgramPoint> getTestPoints() const;
150+
151+
private:
152+
AnalysisDeclContext &AC;
153+
LifetimeSafetyReporter *Reporter;
154+
std::unique_ptr<LifetimeFactory> Factory;
155+
std::unique_ptr<FactManager> FactMgr;
156+
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
157+
std::unique_ptr<LiveOriginAnalysis> LiveOrigins;
158+
};
159+
} // namespace internal
160+
} // namespace clang::lifetimes
161+
162+
namespace llvm {
163+
template <typename Tag>
164+
struct DenseMapInfo<clang::lifetimes::internal::ID<Tag>> {
165+
using ID = clang::lifetimes::internal::ID<Tag>;
166+
167+
static inline ID getEmptyKey() {
168+
return {DenseMapInfo<uint32_t>::getEmptyKey()};
169+
}
170+
171+
static inline ID getTombstoneKey() {
172+
return {DenseMapInfo<uint32_t>::getTombstoneKey()};
173+
}
174+
175+
static unsigned getHashValue(const ID &Val) {
176+
return DenseMapInfo<uint32_t>::getHashValue(Val.Value);
177+
}
178+
179+
static bool isEqual(const ID &LHS, const ID &RHS) { return LHS == RHS; }
180+
};
181+
} // namespace llvm
182+
183+
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H

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

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)