25#include "llvm/ADT/DenseMap.h"
26#include "llvm/Support/ErrorHandling.h"
27#include "llvm/Support/TimeProfiler.h"
40 llvm_unreachable(
"unknown liveness kind");
46struct PendingWarning {
48 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
52class LifetimeChecker {
54 llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
55 llvm::DenseMap<const ParmVarDecl *, const Expr *> AnnotationWarningsMap;
56 const LoanPropagationAnalysis &LoanPropagation;
57 const LiveOriginsAnalysis &LiveOrigins;
58 const FactManager &FactMgr;
59 LifetimeSafetyReporter *Reporter;
63 LifetimeChecker(
const LoanPropagationAnalysis &LoanPropagation,
64 const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FM,
66 : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
67 Reporter(Reporter), AST(ADC.getASTContext()) {
69 for (
const Fact *F : FactMgr.getFacts(B))
70 if (
const auto *EF = F->getAs<ExpireFact>())
72 else if (
const auto *OEF = F->getAs<OriginEscapesFact>())
73 checkAnnotations(OEF);
74 issuePendingWarnings();
79 if (AST.
getLangOpts().EnableLifetimeSafetyInference)
85 void checkAnnotations(
const OriginEscapesFact *OEF) {
86 OriginID EscapedOID = OEF->getEscapedOriginID();
87 LoanSet EscapedLoans = LoanPropagation.getLoans(EscapedOID, OEF);
88 for (
LoanID LID : EscapedLoans) {
89 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
90 if (
const auto *PL = dyn_cast<PlaceholderLoan>(L)) {
91 const ParmVarDecl *PVD = PL->getParmVarDecl();
92 if (PVD->hasAttr<LifetimeBoundAttr>())
94 AnnotationWarningsMap.try_emplace(PVD, OEF->getEscapeExpr());
110 void checkExpiry(
const ExpireFact *EF) {
111 LoanID ExpiredLoan = EF->getLoanID();
112 LivenessMap Origins = LiveOrigins.getLiveOriginsAt(EF);
116 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
117 BestCausingFact =
nullptr;
119 for (
auto &[OID, LiveInfo] : Origins) {
120 LoanSet HeldLoans = LoanPropagation.getLoans(OID, EF);
121 if (!HeldLoans.contains(ExpiredLoan))
125 if (CurConfidence < NewConfidence) {
126 CurConfidence = NewConfidence;
127 BestCausingFact = LiveInfo.CausingFact;
130 if (!BestCausingFact)
133 Confidence LastConf = FinalWarningsMap.lookup(ExpiredLoan).ConfidenceLevel;
134 if (LastConf >= CurConfidence)
136 FinalWarningsMap[ExpiredLoan] = {EF->getExpiryLoc(),
141 void issuePendingWarnings() {
144 for (
const auto &[LID,
Warning] : FinalWarningsMap) {
145 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
147 const Expr *IssueExpr = BL->getIssueExpr();
148 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
149 CausingFact =
Warning.CausingFact;
151 SourceLocation ExpiryLoc =
Warning.ExpiryLoc;
153 if (
const auto *UF = CausingFact.dyn_cast<
const UseFact *>())
154 Reporter->reportUseAfterFree(IssueExpr, UF->getUseExpr(), ExpiryLoc,
156 else if (
const auto *OEF =
157 CausingFact.dyn_cast<
const OriginEscapesFact *>())
158 Reporter->reportUseAfterReturn(IssueExpr, OEF->getEscapeExpr(),
161 llvm_unreachable(
"Unhandled CausingFact type");
167 static const FunctionDecl *getCrossTUDecl(
const ParmVarDecl &PVD,
169 const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext());
172 if (!FD->isExternallyVisible())
174 const FileID DefinitionFile =
SM.getFileID(FD->getLocation());
175 for (
const FunctionDecl *Redecl : FD->redecls())
176 if (
SM.getFileID(Redecl->getLocation()) != DefinitionFile)
182 void suggestAnnotations() {
185 SourceManager &
SM = AST.getSourceManager();
186 for (
const auto &[PVD, EscapeExpr] : AnnotationWarningsMap) {
187 if (
const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD,
SM))
188 Reporter->suggestAnnotation(
190 CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
197 void inferAnnotations() {
198 for (
const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
199 ParmVarDecl *PVD =
const_cast<ParmVarDecl *
>(ConstPVD);
200 const auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
206 ParmVarDecl *InferredPVD =
const_cast<ParmVarDecl *
>(
207 FD->getParamDecl(PVD->getFunctionScopeIndex()));
208 if (!InferredPVD->hasAttr<LifetimeBoundAttr>())
209 InferredPVD->addAttr(
210 LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
220 llvm::TimeTraceScope TimeProfile(
"LifetimeChecker");
221 LifetimeChecker Checker(LP, LO, FactMgr, ADC, Reporter);
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const LangOptions & getLangOpts() const
AnalysisDeclContext contains the context data for the function, method or block under analysis.
Represents a single basic block in a source-level CFG.
Encodes a location in the source.
llvm::ImmutableSet< LoanID > LoanSet
utils::ID< struct LoanTag > LoanID
utils::ID< struct OriginTag > OriginID
llvm::ImmutableMap< OriginID, LivenessInfo > LivenessMap
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...
static Confidence livenessKindToConfidence(LivenessKind K)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
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())
U cast(CodeGen::Address addr)