blob: be0d405bd308699af5a8d2efcbed094939ffb9d1 [file] [edit]
//===- LifetimeSafety.cpp - C++ Lifetime Safety Analysis -*--------- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the main LifetimeSafetyAnalysis class, which coordinates
// the various components (fact generation, loan propagation, live origins
// analysis, and checking) to detect lifetime safety violations in C++ code.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Checker.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
#include "clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
#include <memory>
namespace clang::lifetimes {
namespace internal {
#ifndef NDEBUG
static void DebugOnlyFunction(AnalysisDeclContext &AC, const CFG &Cfg,
FactManager &FactMgr) {
std::string Name;
if (const Decl *D = AC.getDecl()) {
if (const auto *ND = dyn_cast<NamedDecl>(D))
Name = ND->getQualifiedNameAsString();
};
DEBUG_WITH_TYPE(Name.c_str(), AC.getDecl()->dumpColor());
DEBUG_WITH_TYPE(Name.c_str(), Cfg.dump(AC.getASTContext().getLangOpts(),
/*ShowColors=*/true));
DEBUG_WITH_TYPE(Name.c_str(), FactMgr.dump(Cfg, AC));
}
#endif
LifetimeSafetyAnalysis::LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter)
: AC(AC), Reporter(Reporter) {}
void LifetimeSafetyAnalysis::run() {
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
const CFG &Cfg = *AC.getCFG();
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
/*ShowColors=*/true));
FactMgr = std::make_unique<FactManager>(AC, Cfg);
FactsGenerator FactGen(*FactMgr, AC);
FactGen.run();
DEBUG_WITH_TYPE("LifetimeFacts", FactMgr->dump(Cfg, AC));
// Debug print facts for a specific function using
// -debug-only=EnableFilterByFunctionName,YourFunctionNameFoo
DEBUG_WITH_TYPE("EnableFilterByFunctionName",
DebugOnlyFunction(AC, Cfg, *FactMgr));
/// TODO(opt): Consider optimizing individual blocks before running the
/// dataflow analysis.
/// 1. Expression Origins: These are assigned once and read at most once,
/// forming simple chains. These chains can be compressed into a single
/// assignment.
/// 2. Block-Local Loans: Origins of expressions are never read by other
/// blocks; only Decls are visible. Therefore, loans in a block that
/// never reach an Origin associated with a Decl can be safely dropped by
/// the analysis.
/// 3. Collapse ExpireFacts belonging to same source location into a single
/// Fact.
LoanPropagation = std::make_unique<LoanPropagationAnalysis>(
Cfg, AC, *FactMgr, Factory.OriginMapFactory, Factory.LoanSetFactory);
LiveOrigins = std::make_unique<LiveOriginsAnalysis>(
Cfg, AC, *FactMgr, Factory.LivenessMapFactory);
DEBUG_WITH_TYPE("LiveOrigins",
LiveOrigins->dump(llvm::dbgs(), FactMgr->getTestPoints()));
runLifetimeChecker(*LoanPropagation, *LiveOrigins, *FactMgr, AC, Reporter);
}
void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
LifetimeSafetyStats &Stats) {
Stmt *FunctionBody = AC.getBody();
if (FunctionBody == nullptr)
return;
OM.collectMissingOrigins(*FunctionBody, Stats);
}
} // namespace internal
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
LifetimeSafetyReporter *Reporter,
LifetimeSafetyStats &Stats, bool CollectStats) {
internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
Analysis.run();
if (CollectStats)
collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
}
} // namespace clang::lifetimes