clang 22.0.0git
Checker.cpp
Go to the documentation of this file.
1//===- Checker.cpp - C++ Lifetime Safety Checker ----------------*- 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 implements the LifetimeChecker, which detects use-after-free
10// errors by checking if live origins hold loans that have expired.
11//
12//===----------------------------------------------------------------------===//
13
15#include "clang/AST/Expr.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/TimeProfiler.h"
26
28
30 switch (K) {
34 return Confidence::Maybe;
36 return Confidence::None;
37 }
38 llvm_unreachable("unknown liveness kind");
39}
40
41namespace {
42
43/// Struct to store the complete context for a potential lifetime violation.
44struct PendingWarning {
45 SourceLocation ExpiryLoc; // Where the loan expired.
46 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
47 Confidence ConfidenceLevel;
48};
49
50class LifetimeChecker {
51private:
52 llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
53 const LoanPropagationAnalysis &LoanPropagation;
54 const LiveOriginsAnalysis &LiveOrigins;
55 const FactManager &FactMgr;
56 LifetimeSafetyReporter *Reporter;
57
58public:
59 LifetimeChecker(const LoanPropagationAnalysis &LoanPropagation,
60 const LiveOriginsAnalysis &LiveOrigins, const FactManager &FM,
61 AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
62 : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
63 Reporter(Reporter) {
64 for (const CFGBlock *B : *ADC.getAnalysis<PostOrderCFGView>())
65 for (const Fact *F : FactMgr.getFacts(B))
66 if (const auto *EF = F->getAs<ExpireFact>())
67 checkExpiry(EF);
68 issuePendingWarnings();
69 }
70
71 /// Checks for use-after-free & use-after-return errors when a loan expires.
72 ///
73 /// This method examines all live origins at the expiry point and determines
74 /// if any of them hold the expiring loan. If so, it creates a pending
75 /// warning with the appropriate confidence level based on the liveness
76 /// information. The confidence reflects whether the origin is definitely
77 /// or maybe live at this point.
78 ///
79 /// Note: This implementation considers only the confidence of origin
80 /// liveness. Future enhancements could also consider the confidence of loan
81 /// propagation (e.g., a loan may only be held on some execution paths).
82 void checkExpiry(const ExpireFact *EF) {
83 LoanID ExpiredLoan = EF->getLoanID();
84 LivenessMap Origins = LiveOrigins.getLiveOriginsAt(EF);
85 Confidence CurConfidence = Confidence::None;
86 // The UseFact or OriginEscapesFact most indicative of a lifetime error,
87 // prioritized by earlier source location.
88 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
89 BestCausingFact = nullptr;
90
91 for (auto &[OID, LiveInfo] : Origins) {
92 LoanSet HeldLoans = LoanPropagation.getLoans(OID, EF);
93 if (!HeldLoans.contains(ExpiredLoan))
94 continue;
95 // Loan is defaulted.
96 Confidence NewConfidence = livenessKindToConfidence(LiveInfo.Kind);
97 if (CurConfidence < NewConfidence) {
98 CurConfidence = NewConfidence;
99 BestCausingFact = LiveInfo.CausingFact;
100 }
101 }
102 if (!BestCausingFact)
103 return;
104 // We have a use-after-free.
105 Confidence LastConf = FinalWarningsMap.lookup(ExpiredLoan).ConfidenceLevel;
106 if (LastConf >= CurConfidence)
107 return;
108 FinalWarningsMap[ExpiredLoan] = {/*ExpiryLoc=*/EF->getExpiryLoc(),
109 /*BestCausingFact=*/BestCausingFact,
110 /*ConfidenceLevel=*/CurConfidence};
111 }
112
113 void issuePendingWarnings() {
114 if (!Reporter)
115 return;
116 for (const auto &[LID, Warning] : FinalWarningsMap) {
117 const Loan &L = FactMgr.getLoanMgr().getLoan(LID);
118 const Expr *IssueExpr = L.IssueExpr;
119 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
120 CausingFact = Warning.CausingFact;
121 Confidence Confidence = Warning.ConfidenceLevel;
122 SourceLocation ExpiryLoc = Warning.ExpiryLoc;
123
124 if (const auto *UF = CausingFact.dyn_cast<const UseFact *>())
125 Reporter->reportUseAfterFree(IssueExpr, UF->getUseExpr(), ExpiryLoc,
126 Confidence);
127 else if (const auto *OEF =
128 CausingFact.dyn_cast<const OriginEscapesFact *>())
129 Reporter->reportUseAfterReturn(IssueExpr, OEF->getEscapeExpr(),
130 ExpiryLoc, Confidence);
131 else
132 llvm_unreachable("Unhandled CausingFact type");
133 }
134 }
135};
136} // namespace
137
139 const LiveOriginsAnalysis &LO,
140 const FactManager &FactMgr, AnalysisDeclContext &ADC,
141 LifetimeSafetyReporter *Reporter) {
142 llvm::TimeTraceScope TimeProfile("LifetimeChecker");
143 LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
144}
145
146} // namespace clang::lifetimes::internal
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the clang::SourceLocation class and associated facilities.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a single basic block in a source-level CFG.
Definition CFG.h:605
Encodes a location in the source.
llvm::ImmutableSet< LoanID > LoanSet
utils::ID< struct LoanTag > LoanID
Definition Loans.h:23
llvm::ImmutableMap< OriginID, LivenessInfo > LivenessMap
Definition LiveOrigins.h:76
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const LiveOriginsAnalysis &LiveOrigins, const FactManager &FactMgr, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
Runs the lifetime checker, which detects use-after-free errors by examining loan expiration points an...
Definition Checker.cpp:138
static Confidence livenessKindToConfidence(LivenessKind K)
Definition Checker.cpp:29
Confidence
Enum to track the confidence level of a potential error.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
for(const auto &A :T->param_types())