https://github.com/steakhal created https://github.com/llvm/llvm-project/pull/209227
Part §6 of rdar://179151023 Depends on #209225. Approved in #205351. From 56e713c6d610a3b7d6821c51022ffd27bc4d0a0c Mon Sep 17 00:00:00 2001 From: Jan Korous <[email protected]> Date: Tue, 12 May 2026 18:39:13 -0700 Subject: [PATCH] [clang][ssaf][NFC] Add unittests for PointerFlow and UnsafeBufferUsage about local entities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part §6 of rdar://179151023 Co-Authored-By: Jan Korous <[email protected]> Co-Authored-By: Claude Opus 4.7 <[email protected]> --- .../Analyses/PointerFlow/PointerFlowTest.cpp | 47 ++++++++++++++++++- .../UnsafeBufferUsageTest.cpp | 47 ++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/clang/unittests/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowTest.cpp b/clang/unittests/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowTest.cpp index b6d2b8b1af3cf..a56a9072be097 100644 --- a/clang/unittests/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowTest.cpp @@ -161,7 +161,8 @@ class PointerFlowTest : public TestFixture { template <typename ContributorDecl = NamedDecl, typename = std::enable_if_t<std::is_base_of_v<NamedDecl, ContributorDecl>>> - bool setUpTest(StringRef Code) { + bool setUpTest(StringRef Code, const SSAFOptions &Opts = {}) { + this->Opts = Opts; // Override the options. AST = tooling::buildASTFromCodeWithArgs( Code, {"-Wno-unused-value", "-Wno-int-to-pointer-cast"}); @@ -1573,4 +1574,48 @@ TEST_F(PointerFlowTest, RefBindFunctionCallInitializer) { EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"r", 1U}, {"g", 1U, true}}})); } +////////////////////////////////////////////////////////////// +// Local-entity inclusion option tests // +////////////////////////////////////////////////////////////// + +TEST_F(PointerFlowTest, LocalPointerSkippedByDefault) { + StringRef Code = R"cpp( + void foo(int *param) { + int *local_ptr = param; + local_ptr = param; + } + )cpp"; + + ASSERT_TRUE(setUpTest(Code)); + + // Without IncludeLocalEntities, the local pointer is not registered as a + // contributor and therefore has no entity summary of its own. + EXPECT_FALSE(getEntitySummary<VarDecl>("local_ptr")); + // The enclosing function still has its summary describing the assignment + // edge from `local_ptr` to `param` (via the initializer). + EXPECT_TRUE(getEntitySummary("foo")); +} + +TEST_F(PointerFlowTest, LocalPointerReportedWhenIncluded) { + SSAFOptions Opts; + Opts.IncludeLocalEntities = true; + StringRef Code = R"cpp( + void foo(int *param) { + int *local_ptr = param; + local_ptr = param; + } + )cpp"; + + ASSERT_TRUE(setUpTest(Code, Opts)); + + // With the option enabled, the local pointer becomes a contributor and gets + // its own entity summary describing the same edge that was previously only + // observable through `foo`. + const auto *LocalSum = getEntitySummary<VarDecl>("local_ptr"); + ASSERT_TRUE(LocalSum); + EXPECT_EQ(*LocalSum, + makeEdges(__LINE__, {{{"local_ptr", 1U}, {"param", 1U}}})); + + EXPECT_TRUE(getEntitySummary("foo")); +} } // namespace diff --git a/clang/unittests/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp index c2f4cb97c0fae..6d47bff85a059 100644 --- a/clang/unittests/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp @@ -47,7 +47,8 @@ class UnsafeBufferUsageTest : public TestFixture { BuildNamespace(BuildNamespaceKind::CompilationUnit, "Mock.cpp")), Builder(TUSum, Opts) {} - bool setUpTest(StringRef Code) { + bool setUpTest(StringRef Code, const SSAFOptions &Opts = {}) { + this->Opts = Opts; // Override the options. AST = tooling::buildASTFromCodeWithArgs( Code, {"-Wno-unused-value", "-Wno-int-to-pointer-cast"}); @@ -779,5 +780,49 @@ TEST_F(UnsafeBufferUsageTest, StmtExprArrayAccess) { .contains("attempt to translate StmtExpr to EntityPointerLevels")); } #endif +////////////////////////////////////////////////////////////// +// Local-entity inclusion option tests // +////////////////////////////////////////////////////////////// + +TEST_F(UnsafeBufferUsageTest, LocalVarSkippedByDefault) { + // The unsafe subscript p[5] sits inside a local-variable initializer. + // Without IncludeLocalEntities, only `use` (the enclosing function) is a + // contributor. The initializer is still walked as part of `use`'s body, so + // `use` gets a summary attributing the unsafe usage to its parameter. + ASSERT_TRUE(setUpTest(R"cpp( + int use(int *param) { + int x = param[5]; + return x; + } + )cpp")); + + EXPECT_TRUE(getEntitySummary("use")); + // `x` is not a contributor and therefore has no entity summary of its own. + EXPECT_FALSE(getEntitySummary<VarDecl>("x")); +} + +TEST_F(UnsafeBufferUsageTest, LocalVarReportedWhenIncluded) { + // With IncludeLocalEntities, the local var `x` becomes its own contributor. + // The matcher then walks `x`'s scope (the initializer) and reports the + // unsafe subscript on `param` against `x` as well. + SSAFOptions Opts; + Opts.IncludeLocalEntities = true; + ASSERT_TRUE(setUpTest(R"cpp( + int use(int *param) { + int x = param[5]; + return x; + } + )cpp", + Opts)); + + // Pre-existing per-function summary is still produced. + EXPECT_TRUE(getEntitySummary("use")); + + // The new local-entity summary describes the same unsafe-pointer usage, + // but is attributed to the local variable's own scope. + const auto *LocalSum = getEntitySummary<VarDecl>("x"); + ASSERT_TRUE(LocalSum); + EXPECT_EQ(*LocalSum, makeSet(__LINE__, {{"param", 1U}})); +} } // namespace _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
