[llvm-branch-commits] [clang] [SSAF] Flatten 'UnsafeBufferReachableAnalysisResult' to a plain set (PR #219041)
Ziqing Luo via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Aug 29 22:04:29 PDT 2026
https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/219041
>From acb8ba41bb413a71161be0ec159b1920c75b0332 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Tue, 25 Aug 2026 17:47:02 -0700
Subject: [PATCH] [SSAF] Flatten 'UnsafeBufferReachableAnalysisResult' to a
plain set
Previously, an 'UnsafeBufferReachableAnalysisResult' was organized as
a map from contributors to their mutually exclusive
sub-results. Because this extra layer of contributor information
proved unnecessary, this commit flattens the result into a plain set.
The source transformation expects the result to be a plain set, so
this is a prerequisite step for
rdar://185840466
---
.../UnsafeBufferUsageAnalysis.h | 3 ++-
.../UnsafeBufferUsageAnalysis.cpp | 20 +++++++++----------
.../Transformations/CppBoundedBuffers.cpp | 11 ++++------
...achable-excludes-type-constrained-main.cpp | 3 ---
...e-excludes-type-constrained-new-delete.cpp | 16 +++++----------
.../CppBoundedBuffersTest.cpp | 4 +---
.../UnsafeBufferReachableAnalysisTest.cpp | 5 +----
7 files changed, 23 insertions(+), 39 deletions(-)
diff --git a/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h b/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
index aa19c8a7e945e..d677ec4834664 100644
--- a/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
+++ b/clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
@@ -54,7 +54,8 @@ struct UnsafeBufferReachableAnalysisResult final : AnalysisResult {
return AnalysisName(UnsafeBufferReachableAnalysisResultName.str());
}
- std::map<EntityId, EntityPointerLevelSet> Reachables;
+ /// Whole-program set of pointers (EPLs) reachable from unsafe buffer usage.
+ EntityPointerLevelSet Reachables;
};
} // namespace clang::ssaf
diff --git a/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp b/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
index 4fc6d058de368..eed4925a2b298 100644
--- a/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
+++ b/clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
@@ -8,7 +8,10 @@
// UnsafeBufferUsageAnalysis is a noop analysis.
//
// UnsafeBufferUsageAnalysisResult is a map from EntityIds to
-// EntityPointerLevelSets
+// EntityPointerLevelSets.
+//
+// UnsafeBufferReachableAnalysisResult is a flat set of EntityPointerLevels
+// reachable from unsafe buffer usage.
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h"
@@ -98,7 +101,7 @@ json::Object serializeUnsafeBufferReachableAnalysisResult(
json::Object Result;
Result[UnsafeBufferReachableAnalysisResultName] =
- entityPointerLevelMapToJSON(R.Reachables, IdToJSON);
+ entityPointerLevelSetToJSON(R.Reachables, IdToJSON);
return Result;
}
@@ -113,7 +116,7 @@ deserializeUnsafeBufferReachableAnalysisResult(
Obj, "an object with a key %s",
UnsafeBufferReachableAnalysisResultName.data());
- auto Reachables = entityPointerLevelMapFromJSON(*Content, IdFromJSON);
+ auto Reachables = entityPointerLevelSetFromJSON(*Content, IdFromJSON);
if (!Reachables)
return Reachables.takeError();
@@ -173,7 +176,7 @@ class UnsafeBufferReachableAnalysis
auto R = SubGraph.getDestNodes(*EPL);
for (const auto &Dst : R) {
- auto [It, Inserted] = getResult().Reachables[Id].insert(Dst);
+ auto [It, Inserted] = getResult().Reachables.insert(Dst);
if (Inserted)
WorkList.push_back(&*It);
}
@@ -187,9 +190,8 @@ class UnsafeBufferReachableAnalysis
// Simple DFS:
std::vector<EPLPtr> Worklist;
- for (auto &[Id, EPLs] : Reachables)
- for (auto &EPL : EPLs)
- Worklist.push_back(&EPL);
+ for (auto &EPL : Reachables)
+ Worklist.push_back(&EPL);
while (!Worklist.empty()) {
EPLPtr Node = Worklist.back();
@@ -233,9 +235,7 @@ class UnsafeBufferReachableAnalysis
for (auto &[Contributor, EPLs] : UnsafePtrs) {
auto FilteredRange = llvm::make_filter_range(EPLs, HasNoTypeConstraint);
- if (!FilteredRange.empty())
- getResult().Reachables[Contributor].insert(FilteredRange.begin(),
- FilteredRange.end());
+ getResult().Reachables.insert(FilteredRange.begin(), FilteredRange.end());
}
return llvm::Error::success();
}
diff --git a/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp b/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
index 180d5e9f9c7d4..4f0d1c0065084 100644
--- a/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
+++ b/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
@@ -211,12 +211,11 @@ using ReturnLevels = std::map<const FunctionDecl *, Levels>;
/// Reverse index from the whole-program reachability result onto entity names,
/// so a declaration in this TU can look up its reachable pointer levels.
class ReachabilityMap {
- const std::map<EntityId, EntityPointerLevelSet> &Reachables;
+ const EntityPointerLevelSet &Reachables;
std::map<EntityName, EntityId> NameToId;
public:
- ReachabilityMap(const WPASuite &Suite,
- const std::map<EntityId, EntityPointerLevelSet> &Reachables)
+ ReachabilityMap(const WPASuite &Suite, const EntityPointerLevelSet &Reachables)
: Reachables(Reachables) {
Suite.getIdTable().forEach([this](const EntityName &Name, EntityId Id) {
NameToId.emplace(Name, Id);
@@ -230,10 +229,8 @@ class ReachabilityMap {
auto NameIt = NameToId.find(*Name);
if (NameIt == NameToId.end())
return Levels;
- auto ReachIt = Reachables.find(NameIt->second);
- if (ReachIt == Reachables.end())
- return Levels;
- for (const EntityPointerLevel &EPL : ReachIt->second)
+ auto [Begin, End] = Reachables.equal_range(NameIt->second);
+ for (const EntityPointerLevel &EPL : llvm::make_range(Begin, End))
Levels.insert(EPL.getPointerLevel());
return Levels;
}
diff --git a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
index 91449e2511aa2..094f74c82fc90 100644
--- a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
+++ b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
@@ -46,9 +46,6 @@ void foo(int *q) {
// In the reachable result 'q' is present but 'argv' is not.
// CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
-
-// 'foo' contributes unsafe pointer 'q'.
-// CHECK: "@": [[CONTRIBUTOR_FOO]]$WS},$WS[
// CHECK: "@": [[Q_ID]]$PTR_L1
// CHECK-NOT: "@":
diff --git a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
index 22df8ad075ef9..6902a384a67f5 100644
--- a/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
+++ b/clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
@@ -87,20 +87,14 @@ void bar() {
// CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
-// 'bar' contributes unsafe pointer 'y' but not 'x':
-// CHECK: "@": [[CONTRIBUTOR_BAR]]$WS},$WS[
-// CHECK: "@": [[BAR_Y]]$PTR_L1
-// CHECK-NOT: "@": [[BAR_X]]$PTR_L1
-
-// 'foo' contributes unsafe pointers 'q' and 'r':
-// CHECK: "@": [[CONTRIBUTOR_FOO]]$WS},$WS[
+// 'bar' contributes 'y' but not 'x'; 'foo' contributes 'q' and 'r'; 'operator
+// delete' contributes 'delete_local'. None of the type-constrained pointers
+// appear.
+// CHECK-DAG: "@": [[BAR_Y]]$PTR_L1
// CHECK-DAG: "@": [[FOO_Q]]$PTR_L1
// CHECK-DAG: "@": [[FOO_R]]$PTR_L1
-// CHECK-NOT: "@":
-
-// 'operator delete' contributes unsafe pointer 'delete_local':
-// CHECK: "@": [[CONTRIBUTOR_DELETE]]$WS},$WS[
// CHECK-DAG: "@": [[DELETE_LOCAL]]$PTR_L1
+// CHECK-NOT: "@": [[BAR_X]]$PTR_L1
// The type-constrained pointers never appear in the reachable result:
// CHECK-NOT: "@": [[NEW_RET]]$WS
diff --git a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
index 5f44260612404..3e1c512b9c3a3 100644
--- a/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
@@ -100,10 +100,8 @@ class CppBoundedBuffersTest : public TestFixture {
if (!Name || Levels.empty())
return;
EntityId Id = getIdTable(Suite).getId(*Name);
- EntityPointerLevelSet Set;
for (unsigned Level : Levels)
- Set.insert(buildEntityPointerLevel(Id, Level));
- Result.Reachables[Id] = std::move(Set);
+ Result.Reachables.insert(buildEntityPointerLevel(Id, Level));
}
// Parses \p Code, lets \p Mark populate the reachable result, runs the
diff --git a/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp b/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
index b057b6b1ed5bf..aec1cd993343d 100644
--- a/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp
@@ -150,10 +150,7 @@ class UnsafeBufferReachableAnalysisTest : public TestFixture {
ADD_FAILURE_AT(__FILE__, Line) << llvm::toString(ROrErr.takeError());
return std::nullopt;
}
- EntityPointerLevelSet Result;
- for (const auto &[Id, EPLs] : ROrErr->Reachables)
- Result.insert(EPLs.begin(), EPLs.end());
- return Result;
+ return ROrErr->Reachables;
}
using Node = std::pair<char, unsigned>;
More information about the llvm-branch-commits
mailing list