CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
136 lines
5.6 KiB
C++
136 lines
5.6 KiB
C++
//===- 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, LifetimeSafetySemaHelper *SemaHelper,
|
|
const LifetimeSafetyOpts &LSOpts)
|
|
: AC(AC), SemaHelper(SemaHelper), LSOpts(LSOpts) {}
|
|
|
|
void LifetimeSafetyAnalysis::run() {
|
|
llvm::TimeTraceScope TimeProfile("LifetimeSafetyAnalysis");
|
|
|
|
const CFG &Cfg = *AC.getCFG();
|
|
if (LSOpts.MaxCFGBlocks > 0 && Cfg.getNumBlockIDs() > LSOpts.MaxCFGBlocks) {
|
|
DEBUG_WITH_TYPE(
|
|
"LifetimeSafety", std::string FuncName = "<unknown>";
|
|
if (const Decl *D = AC.getDecl()) if (const auto *ND =
|
|
dyn_cast<NamedDecl>(D))
|
|
FuncName = ND->getQualifiedNameAsString();
|
|
llvm::dbgs() << "LifetimeSafety: Skipping function " << FuncName
|
|
<< "due to large CFG: " << Cfg.getNumBlockIDs()
|
|
<< " blocks (threshold: " << LSOpts.MaxCFGBlocks << ")\n");
|
|
return;
|
|
}
|
|
|
|
FactMgr = std::make_unique<FactManager>(AC, Cfg);
|
|
|
|
FactsGenerator FactGen(*FactMgr, AC);
|
|
FactGen.run();
|
|
|
|
/// 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);
|
|
|
|
MovedLoans = std::make_unique<MovedLoansAnalysis>(
|
|
Cfg, AC, *FactMgr, *LoanPropagation, *LiveOrigins, FactMgr->getLoanMgr(),
|
|
Factory.MovedLoansMapFactory);
|
|
|
|
runLifetimeChecker(*LoanPropagation, *MovedLoans, *LiveOrigins, *FactMgr, AC,
|
|
SemaHelper);
|
|
|
|
DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(),
|
|
/*ShowColors=*/true));
|
|
|
|
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));
|
|
DEBUG_WITH_TYPE("LiveOrigins",
|
|
LiveOrigins->dump(llvm::dbgs(), FactMgr->getTestPoints()));
|
|
}
|
|
|
|
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,
|
|
LifetimeSafetySemaHelper *SemaHelper,
|
|
LifetimeSafetyStats &Stats, bool CollectStats) {
|
|
LifetimeSafetyOpts LSOpts;
|
|
LSOpts.MaxCFGBlocks =
|
|
AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks;
|
|
|
|
internal::LifetimeSafetyAnalysis Analysis(AC, SemaHelper, LSOpts);
|
|
Analysis.run();
|
|
if (CollectStats)
|
|
collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
|
|
}
|
|
} // namespace clang::lifetimes
|