Skip to content

Commit bbd60c0

Browse files
authored
[LifetimeSafety] Add missing origins stats for lifetime analysis (#166568)
This PR adds the implementation for printing missing origin stats for lifetime analysis. **Purpose:** This capability is added to track the expression types with missing origin. While retrieving the origins from origin manager, some expressions show missing origins. Currently these are created on the fly using getOrCreate function. For analysing the coverage of the check, it will be necessary to see what kind of expressions have a missing origin. It prints the counts in this form: `QualType : count` and `StmtClassName : count`. **Approach:** 1. The signature of the runLifetimeAnalysis function is changed to return the LifetimeAnalysis object which will be used to get the origin manager which can be used for finding the count of missing origins. 2. The count of missing origins is kept in origin manager while the CFG is visited as part of the analysis. Example output: For the file llvm-project/llvm/lib/Demangle/Demangle.cpp: ``` *** LifetimeSafety Missing Origin per QualType: (QualType : count) : value_type : 1 char * : 3 *** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) : BinaryOperator : 3 UnaryOperator : 1 Total missing origins: 4 ```
1 parent f54df0d commit bbd60c0

File tree

10 files changed

+154
-5
lines changed

10 files changed

+154
-5
lines changed

clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
2222

2323
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
24+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
2425
#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
2526
#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
27+
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
2628
#include "clang/Analysis/AnalysisDeclContext.h"
2729

2830
namespace clang::lifetimes {
@@ -62,9 +64,14 @@ class LifetimeSafetyReporter {
6264

6365
/// The main entry point for the analysis.
6466
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
65-
LifetimeSafetyReporter *Reporter);
67+
LifetimeSafetyReporter *Reporter,
68+
LifetimeSafetyStats &Stats, bool CollectStats);
6669

6770
namespace internal {
71+
72+
void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
73+
LifetimeSafetyStats &Stats);
74+
6875
/// An object to hold the factories for immutable collections, ensuring
6976
/// that all created states share the same underlying memory management.
7077
struct LifetimeFactory {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- LifetimeStats.h - Lifetime Safety Statistics -------------*- 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 declares the data structures and utility function for collection of
10+
// statistics related to Lifetime Safety analysis.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H
15+
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H
16+
17+
#include "clang/AST/TypeBase.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/StringMap.h"
20+
21+
namespace clang::lifetimes {
22+
/// A structure to hold the statistics related to LifetimeAnalysis.
23+
/// These are accumulated across all analyzed functions and printed
24+
/// when -print-stats is enabled.
25+
struct LifetimeSafetyStats {
26+
/// A map from `StmtClassName` to their missing origin counts.
27+
llvm::StringMap<unsigned> ExprStmtClassToMissingOriginCount;
28+
/// A map from `QualType` to their missing origin counts.
29+
llvm::DenseMap<const clang::Type *, unsigned> ExprTypeToMissingOriginCount;
30+
};
31+
32+
/// Utility function to print missing origin stats.
33+
void printStats(const LifetimeSafetyStats &Stats);
34+
} // namespace clang::lifetimes
35+
36+
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_LIFETIMESTATS_H

clang/include/clang/Analysis/Analyses/LifetimeSafety/Origins.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "clang/AST/Decl.h"
1818
#include "clang/AST/Expr.h"
1919
#include "clang/AST/TypeBase.h"
20+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
2021
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
22+
#include "llvm/Support/raw_ostream.h"
2123

2224
namespace clang::lifetimes::internal {
2325

@@ -150,6 +152,9 @@ class OriginManager {
150152

151153
void dump(OriginID OID, llvm::raw_ostream &OS) const;
152154

155+
/// Collects statistics about expressions that lack associated origins.
156+
void collectMissingOrigins(Stmt &FunctionBody, LifetimeSafetyStats &LSStats);
157+
153158
private:
154159
OriginID getNextOriginID() { return NextOriginID++; }
155160

clang/include/clang/Sema/AnalysisBasedWarnings.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
#define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
1515

1616
#include "clang/AST/Decl.h"
17+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
1718
#include "clang/Sema/ScopeInfo.h"
18-
#include "llvm/ADT/DenseMap.h"
19-
#include "llvm/ADT/MapVector.h"
2019
#include <memory>
2120

2221
namespace clang {
@@ -101,6 +100,11 @@ class AnalysisBasedWarnings {
101100
/// a single function.
102101
unsigned MaxUninitAnalysisBlockVisitsPerFunction;
103102

103+
/// Statistics collected during lifetime safety analysis.
104+
/// These are accumulated across all analyzed functions and printed
105+
/// when -print-stats is enabled.
106+
clang::lifetimes::LifetimeSafetyStats LSStats;
107+
104108
/// @}
105109

106110
public:

clang/lib/Analysis/LifetimeSafety/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_clang_library(clangAnalysisLifetimeSafety
55
LifetimeAnnotations.cpp
66
LifetimeSafety.cpp
77
LiveOrigins.cpp
8+
LifetimeStats.cpp
89
Loans.cpp
910
LoanPropagation.cpp
1011
Origins.cpp

clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
#include "clang/Analysis/Analyses/LifetimeSafety/Checker.h"
1919
#include "clang/Analysis/Analyses/LifetimeSafety/Facts.h"
2020
#include "clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h"
21+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
2122
#include "clang/Analysis/Analyses/LifetimeSafety/LiveOrigins.h"
2223
#include "clang/Analysis/Analyses/LifetimeSafety/LoanPropagation.h"
24+
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
2325
#include "clang/Analysis/AnalysisDeclContext.h"
2426
#include "clang/Analysis/CFG.h"
2527
#include "llvm/ADT/FoldingSet.h"
@@ -90,11 +92,22 @@ void LifetimeSafetyAnalysis::run() {
9092

9193
runLifetimeChecker(*LoanPropagation, *LiveOrigins, *FactMgr, AC, Reporter);
9294
}
95+
96+
void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM,
97+
LifetimeSafetyStats &Stats) {
98+
Stmt *FunctionBody = AC.getBody();
99+
if (FunctionBody == nullptr)
100+
return;
101+
OM.collectMissingOrigins(*FunctionBody, Stats);
102+
}
93103
} // namespace internal
94104

95105
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
96-
LifetimeSafetyReporter *Reporter) {
106+
LifetimeSafetyReporter *Reporter,
107+
LifetimeSafetyStats &Stats, bool CollectStats) {
97108
internal::LifetimeSafetyAnalysis Analysis(AC, Reporter);
98109
Analysis.run();
110+
if (CollectStats)
111+
collectLifetimeStats(AC, Analysis.getFactManager().getOriginMgr(), Stats);
99112
}
100113
} // namespace clang::lifetimes
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===- LifetimeStats.cpp - Lifetime Safety Statistics -*------------ 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 defines the data structures and utility function for collection of
10+
// staticstics related to Lifetimesafety analysis.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
15+
#include "clang/AST/TypeBase.h"
16+
#include "llvm/Support/raw_ostream.h"
17+
18+
namespace clang::lifetimes {
19+
void printStats(const LifetimeSafetyStats &Stats) {
20+
llvm::errs() << "\n*** LifetimeSafety Missing Origin per QualType: "
21+
"(QualType : count) :\n\n";
22+
unsigned TotalMissingOrigins = 0;
23+
for (const auto &[ExprType, MissingOriginCount] :
24+
Stats.ExprTypeToMissingOriginCount) {
25+
QualType QT = QualType(ExprType, 0);
26+
llvm::errs() << QT.getAsString() << " : " << MissingOriginCount << '\n';
27+
TotalMissingOrigins += MissingOriginCount;
28+
}
29+
llvm::errs() << "\n\n*** LifetimeSafety Missing Origin per StmtClassName: "
30+
"(StmtClassName : count) :\n\n";
31+
for (const auto &[ExprStmtClassName, MissingOriginCount] :
32+
Stats.ExprStmtClassToMissingOriginCount) {
33+
llvm::errs() << ExprStmtClassName << " : " << MissingOriginCount << '\n';
34+
}
35+
llvm::errs() << "\nTotal missing origins: " << TotalMissingOrigins << "\n";
36+
llvm::errs() << "\n****************************************\n";
37+
}
38+
} // namespace clang::lifetimes

clang/lib/Analysis/LifetimeSafety/Origins.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,42 @@
1111
#include "clang/AST/Attr.h"
1212
#include "clang/AST/DeclCXX.h"
1313
#include "clang/AST/DeclTemplate.h"
14+
#include "clang/AST/Expr.h"
15+
#include "clang/AST/RecursiveASTVisitor.h"
1416
#include "clang/AST/TypeBase.h"
1517
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
18+
#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeStats.h"
19+
#include "llvm/ADT/StringMap.h"
1620

1721
namespace clang::lifetimes::internal {
22+
namespace {
23+
/// A utility class to traverse the function body in the analysis
24+
/// context and collect the count of expressions with missing origins.
25+
class MissingOriginCollector
26+
: public RecursiveASTVisitor<MissingOriginCollector> {
27+
public:
28+
MissingOriginCollector(
29+
const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList,
30+
LifetimeSafetyStats &LSStats)
31+
: ExprToOriginList(ExprToOriginList), LSStats(LSStats) {}
32+
bool VisitExpr(Expr *E) {
33+
if (!hasOrigins(E))
34+
return true;
35+
// Check if we have an origin for this expression.
36+
if (!ExprToOriginList.contains(E)) {
37+
// No origin found: count this as missing origin.
38+
LSStats.ExprTypeToMissingOriginCount[E->getType().getTypePtr()]++;
39+
LSStats.ExprStmtClassToMissingOriginCount[std::string(
40+
E->getStmtClassName())]++;
41+
}
42+
return true;
43+
}
44+
45+
private:
46+
const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList;
47+
LifetimeSafetyStats &LSStats;
48+
};
49+
} // namespace
1850

1951
bool hasOrigins(QualType QT) {
2052
return QT->isPointerOrReferenceType() || isGslPointerType(QT);
@@ -157,4 +189,10 @@ const Origin &OriginManager::getOrigin(OriginID ID) const {
157189
return AllOrigins[ID.Value];
158190
}
159191

192+
void OriginManager::collectMissingOrigins(Stmt &FunctionBody,
193+
LifetimeSafetyStats &LSStats) {
194+
MissingOriginCollector Collector(this->ExprToList, LSStats);
195+
Collector.TraverseStmt(const_cast<Stmt *>(&FunctionBody));
196+
}
197+
160198
} // namespace clang::lifetimes::internal

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3135,7 +3135,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
31353135
if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) {
31363136
if (AC.getCFG()) {
31373137
lifetimes::LifetimeSafetyReporterImpl LifetimeSafetyReporter(S);
3138-
lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter);
3138+
lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetyReporter, LSStats,
3139+
S.CollectStats);
31393140
}
31403141
}
31413142
// Check for violations of "called once" parameter properties.
@@ -3231,4 +3232,5 @@ void clang::sema::AnalysisBasedWarnings::PrintStats() const {
32313232
<< " average block visits per function.\n"
32323233
<< " " << MaxUninitAnalysisBlockVisitsPerFunction
32333234
<< " max block visits per function.\n";
3235+
clang::lifetimes::printStats(LSStats);
32343236
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// RUN: %clang_cc1 -print-stats -fexperimental-lifetime-safety -Wexperimental-lifetime-safety %s 2>&1 | FileCheck %s
2+
3+
4+
// CHECK: *** LifetimeSafety Missing Origin per QualType: (QualType : count) :
5+
// CHECK: *** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :

0 commit comments

Comments
 (0)