[clang] [SSAF][PointerFlow] Recognize reference-to-pointer/array Decls (PR #203633)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 12 14:05:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-ssaf
Author: Ziqing Luo (ziqingluo-90)
<details>
<summary>Changes</summary>
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
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 at 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
``````````
</details>
https://github.com/llvm/llvm-project/pull/203633
More information about the cfe-commits
mailing list