Author: Ziqing Luo
Date: 2026-08-30T17:40:00-07:00
New Revision: dac951d25ca9e2ce2f5eed708064dabcede10313

URL: 
https://github.com/llvm/llvm-project/commit/dac951d25ca9e2ce2f5eed708064dabcede10313
DIFF: 
https://github.com/llvm/llvm-project/commit/dac951d25ca9e2ce2f5eed708064dabcede10313.diff

LOG: [SSAF] Flatten 'UnsafeBufferReachableAnalysisResult' to a plain set 
(#219041)

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

Added: 
    

Modified: 
    
clang/include/clang/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.h
    
clang/lib/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageAnalysis.cpp
    
clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
    
clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-main.cpp
    
clang/test/Analysis/Scalable/TypeConstrainedPointers/unsafe-buffer-reachable-excludes-type-constrained-new-delete.cpp
    
clang/unittests/ScalableStaticAnalysis/SourceTransformation/CppBoundedBuffersTest.cpp
    
clang/unittests/ScalableStaticAnalysis/WholeProgramAnalysis/UnsafeBufferReachableAnalysisTest.cpp

Removed: 
    


################################################################################
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..1057c04ca0718 100644
--- 
a/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
+++ 
b/clang/lib/ScalableStaticAnalysis/SourceTransformation/Transformations/CppBoundedBuffers.cpp
@@ -211,12 +211,12 @@ 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)
+                  const EntityPointerLevelSet &Reachables)
       : Reachables(Reachables) {
     Suite.getIdTable().forEach([this](const EntityName &Name, EntityId Id) {
       NameToId.emplace(Name, Id);
@@ -230,10 +230,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..7bfe39f98768f 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>;
@@ -532,16 +529,14 @@ class UnsafeBufferReachableAnalysisSourceTest : public 
TestFixture {
     }
 
     std::set<Node> Result;
-    for (const auto &[Id, EPLs] : ROrErr->Reachables) {
-      for (const EntityPointerLevel &EPL : EPLs) {
-        auto NameIt = IdToParamName.find(EPL.getEntity());
-        if (NameIt == IdToParamName.end()) {
-          ADD_FAILURE_AT(__FILE__, Line)
-              << "reachable entity has no known source-level name";
-          continue;
-        }
-        Result.insert({NameIt->second, EPL.getPointerLevel()});
+    for (const EntityPointerLevel &EPL : ROrErr->Reachables) {
+      auto NameIt = IdToParamName.find(EPL.getEntity());
+      if (NameIt == IdToParamName.end()) {
+        ADD_FAILURE_AT(__FILE__, Line)
+            << "reachable entity has no known source-level name";
+        continue;
       }
+      Result.insert({NameIt->second, EPL.getPointerLevel()});
     }
     return Result;
   }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to