Skip to content

Commit f590db6

Browse files
committed
[LifetimeSafety] Implement a basic use-after-free diagnostic
1 parent e50372c commit f590db6

File tree

7 files changed

+573
-61
lines changed

7 files changed

+573
-61
lines changed

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

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,35 @@
1919
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
2020
#include "clang/Analysis/AnalysisDeclContext.h"
2121
#include "clang/Analysis/CFG.h"
22+
#include "clang/Basic/SourceLocation.h"
23+
#include "llvm/ADT/DenseMapInfo.h"
24+
#include "llvm/ADT/ImmutableMap.h"
2225
#include "llvm/ADT/ImmutableSet.h"
2326
#include "llvm/ADT/StringMap.h"
2427
#include <memory>
2528

2629
namespace clang::lifetimes {
2730

31+
/// Enum to track the confidence level of a potential error.
32+
enum class Confidence {
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+
class LifetimeSafetyReporter {
39+
public:
40+
LifetimeSafetyReporter() = default;
41+
virtual ~LifetimeSafetyReporter() = default;
42+
43+
virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
44+
SourceLocation FreeLoc,
45+
Confidence Confidence) {}
46+
};
47+
2848
/// The main entry point for the analysis.
29-
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC);
49+
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
50+
LifetimeSafetyReporter *Reporter);
3051

3152
namespace internal {
3253
// Forward declarations of internal types.
@@ -53,6 +74,7 @@ template <typename Tag> struct ID {
5374
IDBuilder.AddInteger(Value);
5475
}
5576
};
77+
5678
template <typename Tag>
5779
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
5880
return OS << ID.Value;
@@ -78,7 +100,8 @@ using ProgramPoint = const Fact *;
78100
/// encapsulates the various dataflow analyses.
79101
class LifetimeSafetyAnalysis {
80102
public:
81-
LifetimeSafetyAnalysis(AnalysisDeclContext &AC);
103+
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
104+
LifetimeSafetyReporter *Reporter);
82105
~LifetimeSafetyAnalysis();
83106

84107
void run();
@@ -87,7 +110,7 @@ class LifetimeSafetyAnalysis {
87110
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
88111

89112
/// Returns the set of loans that have expired at a specific program point.
90-
LoanSet getExpiredLoansAtPoint(ProgramPoint PP) const;
113+
std::vector<LoanID> getExpiredLoansAtPoint(ProgramPoint PP) const;
91114

92115
/// Finds the OriginID for a given declaration.
93116
/// Returns a null optional if not found.
@@ -110,6 +133,7 @@ class LifetimeSafetyAnalysis {
110133

111134
private:
112135
AnalysisDeclContext &AC;
136+
LifetimeSafetyReporter *Reporter;
113137
std::unique_ptr<LifetimeFactory> Factory;
114138
std::unique_ptr<FactManager> FactMgr;
115139
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
@@ -118,4 +142,25 @@ class LifetimeSafetyAnalysis {
118142
} // namespace internal
119143
} // namespace clang::lifetimes
120144

145+
namespace llvm {
146+
template <typename Tag>
147+
struct DenseMapInfo<clang::lifetimes::internal::ID<Tag>> {
148+
using ID = clang::lifetimes::internal::ID<Tag>;
149+
150+
static inline ID getEmptyKey() {
151+
return {DenseMapInfo<uint32_t>::getEmptyKey()};
152+
}
153+
154+
static inline ID getTombstoneKey() {
155+
return {DenseMapInfo<uint32_t>::getTombstoneKey()};
156+
}
157+
158+
static unsigned getHashValue(const ID &Val) {
159+
return DenseMapInfo<uint32_t>::getHashValue(Val.Value);
160+
}
161+
162+
static bool isEqual(const ID &LHS, const ID &RHS) { return LHS == RHS; }
163+
};
164+
} // namespace llvm
165+
121166
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,14 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment,
533533
DanglingGsl,
534534
ReturnStackAddress]>;
535535

536-
def LifetimeSafety : DiagGroup<"experimental-lifetime-safety">;
536+
def LifetimeSafetyPermissive : DiagGroup<"experimental-lifetime-safety-permissive">;
537+
def LifetimeSafetyStrict : DiagGroup<"experimental-lifetime-safety-strict">;
538+
def LifetimeSafety : DiagGroup<"experimental-lifetime-safety",
539+
[LifetimeSafetyPermissive, LifetimeSafetyStrict]> {
540+
code Documentation = [{
541+
Experimental warnings to detect use-after-free and related temporal safety bugs based on lifetime safety analysis.
542+
}];
543+
}
537544

538545
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
539546
def DllexportExplicitInstantiationDecl : DiagGroup<"dllexport-explicit-instantiation-decl">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10668,9 +10668,15 @@ def warn_dangling_reference_captured_by_unknown : Warning<
1066810668
"object whose reference is captured will be destroyed at the end of "
1066910669
"the full-expression">, InGroup<DanglingCapture>;
1067010670

10671-
def warn_experimental_lifetime_safety_dummy_warning : Warning<
10672-
"todo: remove this warning after we have atleast one warning based on the lifetime analysis">,
10673-
InGroup<LifetimeSafety>, DefaultIgnore;
10671+
// Diagnostics based on the Lifetime safety analysis.
10672+
def warn_lifetime_safety_loan_expires_permissive : Warning<
10673+
"object whose reference is captured does not live long enough">,
10674+
InGroup<LifetimeSafetyPermissive>, DefaultIgnore;
10675+
def warn_lifetime_safety_loan_expires_strict : Warning<
10676+
"object whose reference is captured may not live long enough">,
10677+
InGroup<LifetimeSafetyStrict>, DefaultIgnore;
10678+
def note_lifetime_safety_used_here : Note<"later used here">;
10679+
def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
1067410680

1067510681
// For non-floating point, expressions of the form x == x or x != x
1067610682
// should result in a warning, since these always evaluate to a constant.

0 commit comments

Comments
 (0)