clang 24.0.0git
LifetimeSafety.cpp
Go to the documentation of this file.
1//===- LifetimeSafety.cpp - C++ Lifetime Safety Analysis -*--------- 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 main LifetimeSafetyAnalysis class, which coordinates
10// the various components (fact generation, loan propagation, live origins
11// analysis, and checking) to detect lifetime safety violations in C++ code.
12//
13//===----------------------------------------------------------------------===//
15#include "clang/AST/Decl.h"
16#include "clang/AST/Expr.h"
17#include "clang/AST/Type.h"
26#include "clang/Analysis/CFG.h"
27#include "llvm/ADT/FoldingSet.h"
28#include "llvm/Support/Debug.h"
29#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/TimeProfiler.h"
31#include <memory>
32
33namespace clang::lifetimes {
34namespace internal {
35
36#ifndef NDEBUG
37static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
38 FactManager &FactMgr,
39 const LoanPropagationAnalysis *LPA) {
40 std::string Name;
41 if (const Decl *D = AC.getDecl()) {
42 if (const auto *ND = dyn_cast<NamedDecl>(D))
43 Name = ND->getQualifiedNameAsString();
44 };
45 DEBUG_WITH_TYPE(Name.c_str(), AC.getDecl()->dumpColor());
46 DEBUG_WITH_TYPE(Name.c_str(), Cfg.dump(AC.getASTContext().getLangOpts(),
47 /*ShowColors=*/true));
48 DEBUG_WITH_TYPE(Name.c_str(), FactMgr.dump(Cfg, AC, LPA));
49}
50#endif
51
54 const LifetimeSafetyOpts &LSOpts)
55 : AC(AC), SemaHelper(SemaHelper), LSOpts(LSOpts) {}
56
58 llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
59
60 const CFG &Cfg = *AC.getCFG();
61 if (LSOpts.MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > LSOpts.MaxCFGBlocks) {
62 DEBUG_WITH_TYPE(
63 "LifetimeSafety", std::string FuncName = "<unknown>";
64 if (const Decl *D = AC.getDecl()) if (const auto *ND =
65 dyn_cast<NamedDecl>(D))
66 FuncName = ND->getQualifiedNameAsString();
67 llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
68 << "due to large CFG: " << Cfg.getNumBlockIDs()
69 << " blocks (threshold: " << LSOpts.MaxCFGBlocks << ")\n");
70 return;
71 }
72
73 FactMgr = std::make_unique<FactManager>(AC, Cfg);
74
75 FactsGenerator FactGen(*FactMgr, AC);
76 FactGen.run();
77
78 /// TODO(opt): Consider optimizing individual blocks before running the
79 /// dataflow analysis.
80 /// 1. Expression Origins: These are assigned once and read at most once,
81 /// forming simple chains. These chains can be compressed into a single
82 /// assignment.
83 /// 2. Block-Local Loans: Origins of expressions are never read by other
84 /// blocks; only Decls are visible. Therefore, loans in a block that
85 /// never reach an Origin associated with a Decl can be safely dropped by
86 /// the analysis.
87 /// 3. Collapse ExpireFacts belonging to same source location into a single
88 /// Fact.
89 LoanPropagation = std::make_unique<LoanPropagationAnalysis>(
90 Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory);
91
92 LiveOrigins = std::make_unique<LiveOriginsAnalysis>(
93 Cfg, AC, *FactMgr, Factory.LivenessMapFactory);
94
95 MovedLoans = std::make_unique<MovedLoansAnalysis>(
96 Cfg, AC, *FactMgr, *LoanPropagation, *LiveOrigins, FactMgr->getLoanMgr(),
97 Factory.MovedLoansMapFactory);
98
99 runLifetimeChecker(*LoanPropagation, *MovedLoans, *LiveOrigins, *FactMgr, AC,
100 SemaHelper, LSOpts);
101
102 DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
103 /*ShowColors=*/true));
104
105 DEBUG_WITH_TYPE("LifetimeFacts",
106 FactMgr->dump(Cfg, AC, LoanPropagation.get()));
107
108 // Debug print facts for a specific function using
109 // -debug-only=EnableFilterByFunctionName,YourFunctionNameFoo
110 DEBUG_WITH_TYPE("EnableFilterByFunctionName",
111 DebugOnlyFunction(AC, Cfg, *FactMgr, LoanPropagation.get()));
112 DEBUG_WITH_TYPE("LiveOrigins",
113 LiveOrigins->dump(llvm::dbgs(), FactMgr->getTestPoints()));
114}
115
117 LifetimeSafetyStats &Stats) {
118 Stmt *FunctionBody = AC.getBody();
119 if (FunctionBody == nullptr)
120 return;
121 OM.collectMissingOrigins(*FunctionBody, Stats);
122}
123} // namespace internal
124
126 LifetimeSafetySemaHelper *SemaHelper,
127 const LifetimeSafetyOpts &LSOpts,
128 LifetimeSafetyStats &Stats, bool CollectStats) {
129 internal::LifetimeSafetyAnalysis Analysis(AC, SemaHelper, LSOpts);
130 Analysis.run();
131 if (CollectStats)
132 collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
133}
134} // namespace clang::lifetimes
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
C Language Family Type Representation.
const LangOptions & getLangOpts() const
Definition ASTContext.h:965
AnalysisDeclContext contains the context data for the function, method or block under analysis.
ASTContext & getASTContext() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1271
void dump(const LangOptions &LO, bool ShowColors) const
dump - A simple pretty printer of a CFG that outputs to stderr.
Definition CFG.cpp:6361
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1464
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
void dumpColor() const
Stmt - This represents one statement.
Definition Stmt.h:86
Abstract interface for operations requiring Sema access.
void dump(const CFG &Cfg, AnalysisDeclContext &AC, const LoanPropagationAnalysis *LPA=nullptr) const
Definition Facts.cpp:153
Running the lifetime safety analysis and querying its results.
LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, const LifetimeSafetyOpts &LSOpts)
Manages the creation, storage, and retrieval of origins for pointer-like variables and expressions.
Definition Origins.h:125
void collectMissingOrigins(Stmt &FunctionBody, LifetimeSafetyStats &LSStats)
Collects statistics about expressions that lack associated origins.
Definition Origins.cpp:315
static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg, FactManager &FactMgr, const LoanPropagationAnalysis *LPA)
void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const MovedLoansAnalysis &MovedLoans, const LiveOriginsAnalysis &LiveOrigins, FactManager &FactMgr, AnalysisDeclContext &ADC, LifetimeSafetySemaHelper *SemaHelper, const LifetimeSafetyOpts &LSOpts)
Runs the lifetime checker, which detects use-after-free errors by examining loan expiration points an...
Definition Checker.cpp:544
void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM, LifetimeSafetyStats &Stats)
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, const LifetimeSafetyOpts &Opts, LifetimeSafetyStats &Stats, bool CollectStats)
The main entry point for the analysis.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
A structure to hold the statistics related to LifetimeAnalysis.