24#include "llvm/ADT/DenseMap.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/TimeProfiler.h"
39 llvm_unreachable(
"unknown liveness kind");
45struct PendingWarning {
47 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *> CausingFact;
51class LifetimeChecker {
53 llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
54 llvm::DenseMap<const ParmVarDecl *, const Expr *> AnnotationWarningsMap;
55 const LoanPropagationAnalysis &LoanPropagation;
56 const LiveOriginsAnalysis &LiveOrigins;
57 const FactManager &FactMgr;
58 LifetimeSafetyReporter *Reporter;
62 LifetimeChecker(
const LoanPropagationAnalysis &LoanPropagation,
63 const LiveOriginsAnalysis &LiveOrigins,
const FactManager &FM,
65 : LoanPropagation(LoanPropagation), LiveOrigins(LiveOrigins), FactMgr(FM),
66 Reporter(Reporter), AST(ADC.getASTContext()) {
68 for (
const Fact *F : FactMgr.getFacts(B))
69 if (
const auto *EF = F->getAs<ExpireFact>())
71 else if (
const auto *OEF = F->getAs<OriginEscapesFact>())
72 checkAnnotations(OEF);
73 issuePendingWarnings();
78 if (AST.
getLangOpts().EnableLifetimeSafetyInference)
84 void checkAnnotations(
const OriginEscapesFact *OEF) {
85 OriginID EscapedOID = OEF->getEscapedOriginID();
86 LoanSet EscapedLoans = LoanPropagation.getLoans(EscapedOID, OEF);
87 for (
LoanID LID : EscapedLoans) {
88 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
89 if (
const auto *PL = dyn_cast<PlaceholderLoan>(L)) {
90 const ParmVarDecl *PVD = PL->getParmVarDecl();
91 if (PVD->hasAttr<LifetimeBoundAttr>())
93 AnnotationWarningsMap.try_emplace(PVD, OEF->getEscapeExpr());
109 void checkExpiry(
const ExpireFact *EF) {
110 LoanID ExpiredLoan = EF->getLoanID();
111 LivenessMap Origins = LiveOrigins.getLiveOriginsAt(EF);
115 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
116 BestCausingFact =
nullptr;
118 for (
auto &[OID, LiveInfo] : Origins) {
119 LoanSet HeldLoans = LoanPropagation.getLoans(OID, EF);
120 if (!HeldLoans.contains(ExpiredLoan))
124 if (CurConfidence < NewConfidence) {
125 CurConfidence = NewConfidence;
126 BestCausingFact = LiveInfo.CausingFact;
129 if (!BestCausingFact)
132 Confidence LastConf = FinalWarningsMap.lookup(ExpiredLoan).ConfidenceLevel;
133 if (LastConf >= CurConfidence)
135 FinalWarningsMap[ExpiredLoan] = {EF->getExpiryLoc(),
140 void issuePendingWarnings() {
143 for (
const auto &[LID,
Warning] : FinalWarningsMap) {
144 const Loan *L = FactMgr.getLoanMgr().getLoan(LID);
146 const Expr *IssueExpr = BL->getIssueExpr();
147 llvm::PointerUnion<const UseFact *, const OriginEscapesFact *>
148 CausingFact =
Warning.CausingFact;
150 SourceLocation ExpiryLoc =
Warning.ExpiryLoc;
152 if (
const auto *UF = CausingFact.dyn_cast<
const UseFact *>())
153 Reporter->reportUseAfterFree(IssueExpr, UF->getUseExpr(), ExpiryLoc,
155 else if (
const auto *OEF =
156 CausingFact.dyn_cast<
const OriginEscapesFact *>())
157 Reporter->reportUseAfterReturn(IssueExpr, OEF->getEscapeExpr(),
160 llvm_unreachable(
"Unhandled CausingFact type");
166 static const FunctionDecl *getCrossTUDecl(
const ParmVarDecl &PVD,
168 const auto *FD = dyn_cast<FunctionDecl>(PVD.getDeclContext());
171 if (!FD->isExternallyVisible())
173 const FileID DefinitionFile =
SM.getFileID(FD->getLocation());
174 for (
const FunctionDecl *Redecl : FD->redecls())
175 if (
SM.getFileID(Redecl->getLocation()) != DefinitionFile)
181 void suggestAnnotations() {
184 SourceManager &
SM = AST.getSourceManager();
185 for (
const auto &[PVD, EscapeExpr] : AnnotationWarningsMap) {
186 if (
const FunctionDecl *CrossTUDecl = getCrossTUDecl(*PVD,
SM))
187 Reporter->suggestAnnotation(
189 CrossTUDecl->getParamDecl(PVD->getFunctionScopeIndex()),
196 void inferAnnotations() {
202 for (
const auto &[ConstPVD, EscapeExpr] : AnnotationWarningsMap) {
203 ParmVarDecl *PVD =
const_cast<ParmVarDecl *
>(ConstPVD);
204 if (!PVD->hasAttr<LifetimeBoundAttr>())
206 LifetimeBoundAttr::CreateImplicit(AST, PVD->getLocation()));
216 llvm::TimeTraceScope TimeProfile(
"LifetimeChecker");
217 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)
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)