https://github.com/ziqingluo-90 updated 
https://github.com/llvm/llvm-project/pull/197568

>From c096a1004ca0f78c10895c3fd0e26959c9d2ea68 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <[email protected]>
Date: Wed, 13 May 2026 14:36:46 -0700
Subject: [PATCH 1/2] [SSAF] Increase Expr kind coverage in
 EntityPointerLevelTranslator

Add support for more kinds of Expr that can be translated to
EntityPointerLevel(s).

Additionally, fix bugs in PointerFlowExtractor discovered by tests
added for the new Expr kinds.
---
 .../EntityPointerLevel/EntityPointerLevel.cpp | 109 +++++++++++++++--
 .../PointerFlow/PointerFlowExtractor.cpp      |  15 ++-
 .../Analyses/PointerFlow/PointerFlowTest.cpp  |  67 ++++++++++
 .../UnsafeBufferUsageTest.cpp                 | 114 ++++++++++++++++++
 4 files changed, 291 insertions(+), 14 deletions(-)

diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
index da6084f4d41a8..d1aa41bd03d47 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
@@ -10,6 +10,8 @@
 #include "SSAFAnalysesCommon.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtVisitor.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h"
 #include <optional>
@@ -43,10 +45,17 @@ class EntityPointerLevelTranslator
   friend class StmtVisitorBase;
 
   // Fallback method for all unsupported expression kind:
-  llvm::Error fallback(const Stmt *E) {
-    return makeErrAtNode(Ctx, E,
-                         "attempt to translate %s to EntityPointerLevels",
-                         E->getStmtClassName());
+  Expected<EntityPointerLevelSet> fallback(const Stmt *S) {
+    // Report an error/warning (at least in debug mode) for any unsupported 
kind
+    // of pointer/array typed expression, because we want to understand every
+    // pointer/array expression. But for non-pointer/array typed expressions, 
we
+    // could silently ignore unsupported kinds. This translator visits
+    // non-pointer/array typed expressions because of address-of expressions.
+    if (const Expr *E = dyn_cast<Expr>(S); E && hasPtrOrArrType(E))
+      return makeErrAtNode(Ctx, E,
+                           "attempt to translate %s to EntityPointerLevels",
+                           E->getStmtClassName());
+    return EntityPointerLevelSet{};
   }
 
   Expected<EntityPointerLevel>
@@ -142,6 +151,7 @@ class EntityPointerLevelTranslator
   // Translate(*base)          -> Translate(base) with .pointerLevel += 1
   // Translate(&base)          -> {}, if Translate(base) is {}
   //                           -> Translate(base) with .pointerLevel -= 1
+  // Translate(+base)          -> Translate(base)
   Expected<EntityPointerLevelSet> VisitUnaryOperator(const UnaryOperator *E) {
     switch (E->getOpcode()) {
     case clang::UO_PostInc:
@@ -159,6 +169,8 @@ class EntityPointerLevelTranslator
     }
     case clang::UO_Deref:
       return translateDereferencePointer(E->getSubExpr());
+    case clang::UO_Plus:
+      return Visit(E->getSubExpr());
     default:
       return fallback(E);
     }
@@ -209,13 +221,21 @@ class EntityPointerLevelTranslator
     return Visit(E->getSubExpr());
   }
 
-  // Translate("string-literal") -> {}
-  // Buffer accesses on string literals are unsafe, but string literals are not
-  // entities so there is no EntityPointerLevel associated with it.
+  // Translate("string-literal") -> {} // no entity involved
   Expected<EntityPointerLevelSet> VisitStringLiteral(const StringLiteral *E) {
     return EntityPointerLevelSet{};
   }
 
+  // Translate(predefined-expr) -> {} // treated the same as string literals
+  Expected<EntityPointerLevelSet> VisitPredefinedExpr(const PredefinedExpr *E) 
{
+    return EntityPointerLevelSet{};
+  }
+
+  // Translate(integer-literal) -> {} // no entity involved
+  Expected<EntityPointerLevelSet> VisitIntegerLiteral(const IntegerLiteral *E) 
{
+    return EntityPointerLevelSet{};
+  }
+
   // Translate(DRE) -> {(Decl, 1)}
   Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
     auto Res = createEntityPointerLevelFor(E->getDecl());
@@ -232,16 +252,89 @@ class EntityPointerLevelTranslator
     return EntityPointerLevelSet{*Res};
   }
 
-  // Translate(`DefaultArg`) -> Translate(`DefaultArg->getExpr()`)
+  // Unwrap CXXDefaultArgExpr
   Expected<EntityPointerLevelSet>
   VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
     return Visit(E->getExpr());
   }
 
+  // Unwrap OpaqueValueExpr
   Expected<EntityPointerLevelSet>
   VisitOpaqueValueExpr(const OpaqueValueExpr *S) {
     return Visit(S->getSourceExpr());
   }
+
+  // Unwrap ExprWithCleanups
+  Expected<EntityPointerLevelSet>
+  VisitExprWithCleanups(const ExprWithCleanups *S) {
+    return Visit(S->getSubExpr());
+  }
+
+  // Unwrap MaterializeTemporaryExpr
+  Expected<EntityPointerLevelSet>
+  VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
+    return Visit(S->getSubExpr());
+  }
+
+  // Unwrap CXXDefaultInitExpr
+  Expected<EntityPointerLevelSet>
+  VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+    return Visit(E->getExpr());
+  }
+
+  // Translate(`nullptr`) -> {}
+  Expected<EntityPointerLevelSet>
+  VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
+    return EntityPointerLevelSet{};
+  }
+
+  // Translate(`this`) -> {}
+  Expected<EntityPointerLevelSet> VisitCXXThisExpr(const CXXThisExpr *S) {
+    return EntityPointerLevelSet{};
+  }
+
+  // Translate(`new`/`new [*]`) -> {}
+  Expected<EntityPointerLevelSet> VisitCXXNewExpr(const CXXNewExpr *S) {
+    return EntityPointerLevelSet{};
+  }
+
+  // ImplicitValueInitExpr, for raw pointer type,
+  // evaluates to a compile-time constant zero (or null). So no EPL in the
+  // result.
+  Expected<EntityPointerLevelSet>
+  VisitImplicitValueInitExpr(const ImplicitValueInitExpr *S) {
+    return EntityPointerLevelSet{};
+  }
+
+  // Fall back if the InitListExpr is not an empty or singleton list that
+  // initializes a pointer scalar. EntityPointerLevelTranslator does not
+  // expect to visit an InitListExpr in any other case.
+  Expected<EntityPointerLevelSet> VisitInitListExpr(const InitListExpr *E) {
+    if (E->getNumInits() < 1)
+      return EntityPointerLevelSet{};
+    if (E->getType()->isPointerType())
+      return Visit(E->getInit(0));
+    return fallback(E);
+  }
+
+  // Clang may default initializes an array with a CXXConstructExpr. Fallback 
on
+  // other cases, if they exist.
+  // When a CXXConstructExpr has an array type, clang is initializing an array
+  // of class-type objects with default values.  In this case, no entity is
+  // associated with the initializer.
+  Expected<EntityPointerLevelSet>
+  VisitCXXConstructExpr(const CXXConstructExpr *E) {
+    if (E->getType()->isArrayType()) {
+      return EntityPointerLevelSet{};
+    }
+    return fallback(E);
+  }
+
+  // No entity is associated with a CXXScalarValueInitExpr:
+  Expected<EntityPointerLevelSet>
+  VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
+    return EntityPointerLevelSet{};
+  }
 };
 } // namespace clang::ssaf
 
diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
index e1130a2c52e4c..3bd088284249c 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowExtractor.cpp
@@ -107,8 +107,9 @@ 
PointerFlowMatcher::addEdges(Expected<EntityPointerLevelSet> &&LHS,
     return LHS.takeError();
   if (!RHS)
     return RHS.takeError();
-  for (auto L : *LHS)
-    Results[L].insert(RHS->begin(), RHS->end());
+  if (!RHS->empty())
+    for (auto L : *LHS)
+      Results[L].insert(RHS->begin(), RHS->end());
   return llvm::Error::success();
 }
 
@@ -222,9 +223,8 @@ llvm::Error 
matchInitializerListForRecordDecl(PointerFlowMatcher &Matcher,
   if (RecordTy->isUnion()) {
     auto *InitField = ILE->getInitializedFieldInUnion();
 
-    if (!InitField)
+    if (!InitField || ILE->getNumInits() == 0)
       return llvm::Error::success();
-    assert(!ILE->inits().empty());
     return Matcher.matchesInitializerList(InitField, ILE->getInit(0));
   }
   // Handle struct/class:
@@ -299,8 +299,11 @@ PointerFlowMatcher::matchesInitializerList(const ValueDecl 
*Base,
   if (Type->isArrayType())
     return matchInitializerListForArray(*this, Base, ILE,
                                         ArrayElementIndirectLevel);
-  // Must be the case of using a initializer-list for a scalar:
-  return matchesInitializerList(Base, ILE->getInit(0));
+
+  // Must be the case of using an initializer-list for a scalar:
+  if (ILE->getNumInits() > 0)
+    return matchesInitializerList(Base, ILE->getInit(0));
+  return llvm::Error::success();
 }
 
 class PointerFlowTUSummaryExtractor : public TUSummaryExtractor {
diff --git 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
index 9f7a508ea35fd..bff9dc10bfc1f 100644
--- 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/PointerFlow/PointerFlowTest.cpp
@@ -1126,4 +1126,71 @@ TEST_F(PointerFlowTest, NestedLambdaAssign) {
   ASSERT_NE(Sum, nullptr);
   EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"y", 1U}, {"x", 1U}}}));
 }
+
+TEST_F(PointerFlowTest, ImplicitValueInit) {
+  ASSERT_EQ(setUpTest(R"cpp(
+    struct S { int *a; int *b; };
+    void foo(int *p) {
+      S s = {p};  // ImplicitValueInit inits 'b'
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"a", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, InitListExpr) {
+  ASSERT_EQ(setUpTest(R"cpp(
+    void foo(int *p) {
+      int *q = {p};
+      int *r = {};
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"q", 1U}, {"p", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, CXXDefaultInitExpr) {
+  ASSERT_EQ(setUpTest(R"cpp(
+    int *g;
+    struct S {
+      int *field = g;
+    };
+    void foo(int *p) {
+      S s;
+      s.field = p;
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary<RecordDecl>("S");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"field", 1U}, {"g", 1U}}}));
+}
+
+TEST_F(PointerFlowTest, CXXConstructExprArrayInit) {
+  ASSERT_EQ(setUpTest(
+                R"cpp(
+    struct S {};
+    void foo(S *q) {
+      S arr[3]; // -VarDecl <...> arr 'S[3]' callinit
+                //   `-CXXConstructExpr <...> 'S[3]' 'void () noexcept'
+      q = arr;
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeEdges(__LINE__, {{{"q", 1U}, {"arr", 1U}}}));
+}
 } // namespace
diff --git 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
index 6b75ed3f1a1fe..1ef2c5e7337bf 100644
--- 
a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
+++ 
b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
@@ -570,4 +570,118 @@ TEST_F(UnsafeBufferUsageTest, NestedDefinitions2) {
   EXPECT_EQ(Sum, nullptr);
 }
 
+TEST_F(UnsafeBufferUsageTest, UnaryPlusSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo(int *p) {
+      (+p)[5];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U}}));
+}
+
+TEST_F(UnsafeBufferUsageTest, PredefinedExprSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo() {
+      __func__[100];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_EQ(Sum, nullptr);
+}
+
+TEST_F(UnsafeBufferUsageTest, IntegerLiteralCastSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo() {
+      ((int *)0)[5];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_EQ(Sum, nullptr);
+}
+
+TEST_F(UnsafeBufferUsageTest, CXXNewArraySubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo() {
+      (new int[10])[5];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_EQ(Sum, nullptr);
+}
+
+TEST_F(UnsafeBufferUsageTest, CXXNullPtrSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    void foo() {
+      ((int*)nullptr)[5];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_EQ(Sum, nullptr);
+}
+
+TEST_F(UnsafeBufferUsageTest, CXXThisSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    struct S {
+      void foo() {
+        this[5];
+      }
+    };
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_EQ(Sum, nullptr);
+}
+
+TEST_F(UnsafeBufferUsageTest, ExprWithCleanupsSubscript) {
+  ASSERT_TRUE(setUpTest(R"cpp(
+    struct Guard { ~Guard(); };
+    int *getPtr(Guard);
+    void foo() {
+      getPtr(Guard{})[5];
+    }
+  )cpp"));
+  const auto *Sum = getEntitySummary("foo");
+
+  EXPECT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeSet(__LINE__, {{"getPtr", 1U, true}}));
+}
+
+TEST_F(UnsafeBufferUsageTest, MaterializeTemporaryExpr) {
+  ASSERT_EQ(setUpTest(R"cpp(
+    struct S { int *get(); };
+    void foo(int *p) {
+      S{}.get()[5];
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeSet(__LINE__, {{"get", 1U, true}}));
+}
+
+TEST_F(UnsafeBufferUsageTest, CXXScalarValueInitExpr) {
+  ASSERT_EQ(setUpTest(R"cpp(
+    using IntPtr = int*;
+
+    void foo(int *q) {
+      int p = IntPtr()[5]; // no EPL created for CXXScalarValueInitExpr
+      q[5];
+    }
+  )cpp"),
+            true);
+
+  auto *Sum = getEntitySummary("foo");
+
+  ASSERT_NE(Sum, nullptr);
+  EXPECT_EQ(*Sum, makeSet(__LINE__, {{"q", 1U}}));
+}
 } // namespace

>From 5549c1bee7e8ae121c07281eebe216a0cb5de7d2 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <[email protected]>
Date: Wed, 13 May 2026 18:03:27 -0700
Subject: [PATCH 2/2] address comments

---
 .../Analyses/EntityPointerLevel/EntityPointerLevel.cpp   | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
index d1aa41bd03d47..758009be1f49b 100644
--- 
a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
+++ 
b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
@@ -306,15 +306,16 @@ class EntityPointerLevelTranslator
     return EntityPointerLevelSet{};
   }
 
-  // Fall back if the InitListExpr is not an empty or singleton list that
-  // initializes a pointer scalar. EntityPointerLevelTranslator does not
-  // expect to visit an InitListExpr in any other case.
+  // The InitListExpr must be an empty or singleton list that
+  // initializes a pointer scalar.  Other cases are unexpected thus an error.
   Expected<EntityPointerLevelSet> VisitInitListExpr(const InitListExpr *E) {
     if (E->getNumInits() < 1)
       return EntityPointerLevelSet{};
     if (E->getType()->isPointerType())
       return Visit(E->getInit(0));
-    return fallback(E);
+    return llvm::createStringError(
+        "Cannot translate an InitListExpr to EntityPointerLevels if it is not "
+        "an empty or singleton list that initializes a pointer scalar");
   }
 
   // Clang may default initializes an array with a CXXConstructExpr. Fallback 
on

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

Reply via email to