Skip to content

Commit 2528e13

Browse files
committed
basic error report for use after free
1 parent 7ec322f commit 2528e13

File tree

7 files changed

+525
-63
lines changed

7 files changed

+525
-63
lines changed

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

Lines changed: 49 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;
@@ -66,6 +88,7 @@ using OriginID = ID<struct OriginTag>;
6688
// TODO(opt): Consider using a bitset to represent the set of loans.
6789
using LoanSet = llvm::ImmutableSet<LoanID>;
6890
using OriginSet = llvm::ImmutableSet<OriginID>;
91+
using ExpiredLoanMap = llvm::ImmutableMap<LoanID, const Fact *>;
6992

7093
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
7194
/// `Fact`. identified by a lifetime-related event (`Fact`).
@@ -78,7 +101,8 @@ using ProgramPoint = const Fact *;
78101
/// encapsulates the various dataflow analyses.
79102
class LifetimeSafetyAnalysis {
80103
public:
81-
LifetimeSafetyAnalysis(AnalysisDeclContext &AC);
104+
LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
105+
LifetimeSafetyReporter *Reporter);
82106
~LifetimeSafetyAnalysis();
83107

84108
void run();
@@ -87,7 +111,7 @@ class LifetimeSafetyAnalysis {
87111
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
88112

89113
/// Returns the set of loans that have expired at a specific program point.
90-
LoanSet getExpiredLoansAtPoint(ProgramPoint PP) const;
114+
ExpiredLoanMap getExpiredLoansAtPoint(ProgramPoint PP) const;
91115

92116
/// Finds the OriginID for a given declaration.
93117
/// Returns a null optional if not found.
@@ -110,6 +134,7 @@ class LifetimeSafetyAnalysis {
110134

111135
private:
112136
AnalysisDeclContext &AC;
137+
LifetimeSafetyReporter *Reporter;
113138
std::unique_ptr<LifetimeFactory> Factory;
114139
std::unique_ptr<FactManager> FactMgr;
115140
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
@@ -118,4 +143,25 @@ class LifetimeSafetyAnalysis {
118143
} // namespace internal
119144
} // namespace clang::lifetimes
120145

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

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,10 @@ 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", [LifetimeSafetyPermissive,
539+
LifetimeSafetyStrict]>;
537540

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

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10641,9 +10641,14 @@ def warn_dangling_reference_captured_by_unknown : Warning<
1064110641
"object whose reference is captured will be destroyed at the end of "
1064210642
"the full-expression">, InGroup<DanglingCapture>;
1064310643

10644-
def warn_experimental_lifetime_safety_dummy_warning : Warning<
10645-
"todo: remove this warning after we have atleast one warning based on the lifetime analysis">,
10646-
InGroup<LifetimeSafety>, DefaultIgnore;
10644+
def warn_lifetime_safety_use_after_free_permissive : Warning<
10645+
"object whose reference is captured does not live long enough">,
10646+
InGroup<LifetimeSafetyPermissive>, DefaultIgnore;
10647+
def warn_lifetime_safety_use_after_free_strict : Warning<
10648+
"object whose reference is captured may not live long enough">,
10649+
InGroup<LifetimeSafetyStrict>, DefaultIgnore;
10650+
def note_lifetime_safety_used_here : Note<"later used here">;
10651+
def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
1064710652

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

0 commit comments

Comments
 (0)