Skip to content

[SSAF][PointerFlow] Recognize reference-to-pointer/array Decls - #203633

Merged
ziqingluo-90 merged 3 commits into
mainfrom
users/ziqingluo/PR-179173940
Jun 15, 2026
Merged

[SSAF][PointerFlow] Recognize reference-to-pointer/array Decls#203633
ziqingluo-90 merged 3 commits into
mainfrom
users/ziqingluo/PR-179173940

Conversation

@ziqingluo-90

Copy link
Copy Markdown
Contributor

Decls of reference-to-pointer/array types are now treated the same as those of pointer/array type.

rdar://179173940

Decls of reference-to-pointer/array types are now treated the same as
those of pointer/array type.

rdar://179173940
@llvmorg-github-actions llvmorg-github-actions Bot added clang Clang issues not falling into any other category clang:static analyzer clang:ssaf Scalable Static Analysis Framework labels Jun 12, 2026
@llvmorg-github-actions

llvmorg-github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-clang-static-analyzer-1

@llvm/pr-subscribers-clang-ssaf

Author: Ziqing Luo (ziqingluo-90)

Changes

Decls of reference-to-pointer/array types are now treated the same as those of pointer/array type.

rdar://179173940


Full diff: https://github.com/llvm/llvm-project/pull/203633.diff

3 Files Affected:

  • (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h (+8-1)
  • (added) clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test (+40)
  • (modified) clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp (+62-2)
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
index 63755304ea3c9..144bab532d4bf 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
@@ -42,11 +42,18 @@ llvm::Error makeSawButExpectedError(const JSONTy &Saw, llvm::StringRef Expected,
   return llvm::createStringError(Fmt.c_str(), SawStr.c_str(), ExpectedArgs...);
 }
 
-template <typename DeclOrExpr> bool hasPtrOrArrType(const DeclOrExpr *E) {
+///\return true iff expression `E` has pointer or array type.
+inline bool hasPtrOrArrType(const Expr *E) {
   return llvm::isa<clang::PointerType, clang::ArrayType>(
       E->getType().getCanonicalType());
 }
 
+///\return true iff Decl `D` has (reference-to) pointer or array type.
+inline bool hasPtrOrArrType(const ValueDecl *D) {
+  return llvm::isa<clang::PointerType, clang::ArrayType>(
+      D->getType().getNonReferenceType().getCanonicalType());
+}
+
 llvm::Error makeEntityNameErr(clang::ASTContext &Ctx,
                               const clang::NamedDecl *D);
 
diff --git a/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
new file mode 100644
index 0000000000000..195a4d47ae54a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
@@ -0,0 +1,40 @@
+// Test that entities representing references-to-pointers are
+// connected through 'fake_move' (my fake 'std::move').
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// Extract per-TU PointerFlow + UnsafeBufferUsage summaries.
+// RUN: %clang_cc1 -fsyntax-only %t/tu.cpp \
+// RUN:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
+// RUN:   --ssaf-tu-summary-file=%t/tu.summary.json
+
+// Link into a single LU summary.
+// RUN: clang-ssaf-linker %t/tu.summary.json -o %t/lu.json
+
+// RUN: clang-ssaf-analyzer %t/lu.json -o %t/wpa.json \
+// RUN:   -a UnsafeBufferReachableAnalysisResult
+
+//--- tu.cpp
+constexpr int* &&fake_move(int* &arg) noexcept { //FIXME: after #198927, we can use template
+  return static_cast<int* &&>(arg);
+}
+
+void foo(int *p) {
+  int *&&rp = fake_move(p);
+  rp[5] = 0;
+}
+
+// Check that unsafe buffer propagates from 'rp' to 'p' by ensuring
+// that both 'rp' and 'p' are in the reachable set.
+
+// RUN: FileCheck %s --input-file=%t/wpa.json
+
+// CHECK-DAG: "id": [[RP_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": "",[[:space:]]+"usr": "[^"]*}}@rp"
+// CHECK-DAG: "id": [[P_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": "1",[[:space:]]+"usr": }}"c:@F@foo#*I#"
+
+// CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
+// CHECK-DAG: {{\{[[:space:]]+}}"@": [[RP_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK-DAG: {{\{[[:space:]]+}}"@": [[P_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK: "analysis_name"
+
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
index bff9dc10bfc1f..c1f5416718c4c 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
@@ -13,9 +13,7 @@
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Frontend/ASTUnit.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
@@ -1193,4 +1191,66 @@ TEST_F(PointerFlowTest, CXXConstructExprArrayInit) {
   ASSERT_NE(Sum, nullptr);
   EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"q", 1U}, {"arr", 1U}}}));
 }
+
+//////////////////////////////////////////////////////////////
+//          Reference-to-pointer Tests                      //
+//////////////////////////////////////////////////////////////
+
+TEST_F(PointerFlowTest, ArgToRefParam) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int *&rp);
+    void caller(int *p) {
+      callee(p);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ArgToRefParamLevel2) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int **&rp);
+    void caller(int **pp) {
+      callee(pp);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"pp", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, InitRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo(int *p) {
+      int *&rp = p;
+      int * const & crp = p;
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}},
+                                       {{"crp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ReturnRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    int *& f();
+    int *& foo() {
+      return f();
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"foo", 1U, true}, {"f", 1U, true}}}));
+}
+
 } // namespace

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-clang

Author: Ziqing Luo (ziqingluo-90)

Changes

Decls of reference-to-pointer/array types are now treated the same as those of pointer/array type.

rdar://179173940


Full diff: https://github.com/llvm/llvm-project/pull/203633.diff

3 Files Affected:

  • (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h (+8-1)
  • (added) clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test (+40)
  • (modified) clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp (+62-2)
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
index 63755304ea3c9..144bab532d4bf 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
@@ -42,11 +42,18 @@ llvm::Error makeSawButExpectedError(const JSONTy &Saw, llvm::StringRef Expected,
   return llvm::createStringError(Fmt.c_str(), SawStr.c_str(), ExpectedArgs...);
 }
 
-template <typename DeclOrExpr> bool hasPtrOrArrType(const DeclOrExpr *E) {
+///\return true iff expression `E` has pointer or array type.
+inline bool hasPtrOrArrType(const Expr *E) {
   return llvm::isa<clang::PointerType, clang::ArrayType>(
       E->getType().getCanonicalType());
 }
 
+///\return true iff Decl `D` has (reference-to) pointer or array type.
+inline bool hasPtrOrArrType(const ValueDecl *D) {
+  return llvm::isa<clang::PointerType, clang::ArrayType>(
+      D->getType().getNonReferenceType().getCanonicalType());
+}
+
 llvm::Error makeEntityNameErr(clang::ASTContext &Ctx,
                               const clang::NamedDecl *D);
 
diff --git a/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
new file mode 100644
index 0000000000000..195a4d47ae54a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/PointerFlow/lref-to-rref-cast.test
@@ -0,0 +1,40 @@
+// Test that entities representing references-to-pointers are
+// connected through 'fake_move' (my fake 'std::move').
+
+// RUN: rm -rf %t && mkdir -p %t
+// RUN: split-file %s %t
+
+// Extract per-TU PointerFlow + UnsafeBufferUsage summaries.
+// RUN: %clang_cc1 -fsyntax-only %t/tu.cpp \
+// RUN:   --ssaf-extract-summaries=PointerFlow,UnsafeBufferUsage \
+// RUN:   --ssaf-tu-summary-file=%t/tu.summary.json
+
+// Link into a single LU summary.
+// RUN: clang-ssaf-linker %t/tu.summary.json -o %t/lu.json
+
+// RUN: clang-ssaf-analyzer %t/lu.json -o %t/wpa.json \
+// RUN:   -a UnsafeBufferReachableAnalysisResult
+
+//--- tu.cpp
+constexpr int* &&fake_move(int* &arg) noexcept { //FIXME: after #198927, we can use template
+  return static_cast<int* &&>(arg);
+}
+
+void foo(int *p) {
+  int *&&rp = fake_move(p);
+  rp[5] = 0;
+}
+
+// Check that unsafe buffer propagates from 'rp' to 'p' by ensuring
+// that both 'rp' and 'p' are in the reachable set.
+
+// RUN: FileCheck %s --input-file=%t/wpa.json
+
+// CHECK-DAG: "id": [[RP_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": "",[[:space:]]+"usr": "[^"]*}}@rp"
+// CHECK-DAG: "id": [[P_ID:[0-9]+]],{{([^]]|[[:space:]])+\],[[:space:]]+"suffix": "1",[[:space:]]+"usr": }}"c:@F@foo#*I#"
+
+// CHECK: "analysis_name": "UnsafeBufferReachableAnalysisResult"
+// CHECK-DAG: {{\{[[:space:]]+}}"@": [[RP_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK-DAG: {{\{[[:space:]]+}}"@": [[P_ID]]{{[[:space:]]+\},[[:space:]]+1[[:space:]]+\]}}
+// CHECK: "analysis_name"
+
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
index bff9dc10bfc1f..c1f5416718c4c 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
@@ -13,9 +13,7 @@
 #include "clang/AST/DynamicRecursiveASTVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Frontend/ASTUnit.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
@@ -1193,4 +1191,66 @@ TEST_F(PointerFlowTest, CXXConstructExprArrayInit) {
   ASSERT_NE(Sum, nullptr);
   EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"q", 1U}, {"arr", 1U}}}));
 }
+
+//////////////////////////////////////////////////////////////
+//          Reference-to-pointer Tests                      //
+//////////////////////////////////////////////////////////////
+
+TEST_F(PointerFlowTest, ArgToRefParam) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int *&rp);
+    void caller(int *p) {
+      callee(p);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ArgToRefParamLevel2) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void callee(int **&rp);
+    void caller(int **pp) {
+      callee(pp);
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("caller");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"pp", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, InitRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo(int *p) {
+      int *&rp = p;
+      int * const & crp = p;
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"rp", 1U}, {"p", 1U}},
+                                       {{"crp", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, ReturnRefPtr) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    int *& f();
+    int *& foo() {
+      return f();
+    }
+  )cpp"));
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_TRUE(Sum);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"foo", 1U, true}, {"f", 1U, true}}}));
+}
+
 } // namespace

…luo/PR-179173940

 Conflicts:
	clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 118254 tests passed
  • 4826 tests skipped

✅ The build succeeded and all tests passed.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

🪟 Windows x64 Test Results

  • 55682 tests passed
  • 2657 tests skipped

✅ The build succeeded and all tests passed.

@jkorous-apple jkorous-apple left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ziqingluo-90

Copy link
Copy Markdown
Contributor Author

Thanks for the review

@ziqingluo-90
ziqingluo-90 merged commit e2015b1 into main Jun 15, 2026
11 checks passed
@ziqingluo-90
ziqingluo-90 deleted the users/ziqingluo/PR-179173940 branch June 15, 2026 19:42
ziqingluo-90 added a commit that referenced this pull request Jun 25, 2026
The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
#203633.  Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
ziqingluo-90 added a commit that referenced this pull request Jun 26, 2026
)

The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
#203633. Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
llvm-upstreamsync Bot pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request Jun 26, 2026
…tests (#205937)

The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
llvm/llvm-project#203633. Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request Jun 26, 2026
…tests (#205937)

The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
llvm/llvm-project#203633. Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
LouisLu060211 pushed a commit to LouisLu060211/llvm-project that referenced this pull request Jun 30, 2026
…#205937)

The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
llvm#203633. Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
maarcosrmz pushed a commit to maarcosrmz/llvm-project that referenced this pull request Jul 1, 2026
…#205937)

The majority of the content of rdar://179151476 duplicates the
PointerFlow analysis after
llvm#203633. Therefore, we only
need to upstream the tests for better test coverage and proving the
duplication.

rdar://179151476
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:ssaf Scalable Static Analysis Framework clang:static analyzer clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants