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
