[llvm-branch-commits] [clang] [UnsafeBufferUsage][SSAF] Change -Wunsafe-buffer-usage API for SSAF-based analysis (PR #191934)

Ziqing Luo via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Apr 16 13:53:54 PDT 2026


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

>From d116672ae4a7f894e0989902b1e4412016b75345 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Mon, 13 Apr 2026 20:04:26 -0700
Subject: [PATCH 1/3] [UnsafeBufferUsage][SSAF] Change -Wunsafe-buffer-usage
 API for SSAF-based analysis

Change -Wunsafe-buffer-usage API to match `Stmt`s instead of `Decl`s.
It is up to clients of the API to determine how to traversal a
`Decl`. In this change, the client is SSAF-based
UnsafeBufferUsageExtractor.
---
 .../Analysis/Analyses/UnsafeBufferUsage.h     |  12 +-
 clang/lib/Analysis/UnsafeBufferUsage.cpp      | 123 ++++++++++--------
 .../UnsafeBufferUsageExtractor.cpp            |  24 +---
 3 files changed, 72 insertions(+), 87 deletions(-)

diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index e0d583c735e61..65b79cfc1c2ff 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -201,14 +201,10 @@ bool anyConflict(const llvm::SmallVectorImpl<FixItHint> &FixIts,
                  const SourceManager &SM);
 } // namespace internal
 
-/// Find unsafe pointers in body/initializer of `D`, if `D` is one of the
-/// followings:
-///   VarDecl
-///   FieldDecl
-///   FunctionDecl
-///   BlockDecl
-///   ObjCMethodDecl
-std::set<const Expr *> findUnsafePointers(const Decl *D);
+/// \return true iff `N` is an unsafe buffer usage and populates the unsafe
+/// pointers in `UnsafePointers`
+bool matchUnsafePointers(const DynTypedNode &N, ASTContext &Ctx,
+                         std::set<const Expr *> &UnsafePointers);
 } // end namespace clang
 
 #endif /* LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H */
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 3dba15cff3b52..e80dfc82e60ba 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -2975,63 +2975,6 @@ static void populateStmtsForFindingGadgets(SmallVector<const Stmt *> &Stmts,
   }
 }
 
-std::set<const Expr *> clang::findUnsafePointers(const Decl *D) {
-  class MockReporter : public UnsafeBufferUsageHandler {
-  public:
-    MockReporter() {}
-    void handleUnsafeOperation(const Stmt *, bool, ASTContext &) override {}
-    void handleUnsafeLibcCall(const CallExpr *, unsigned, ASTContext &,
-                              const Expr *UnsafeArg = nullptr) override {}
-    void handleUnsafeOperationInContainer(const Stmt *, bool,
-                                          ASTContext &) override {}
-    void handleUnsafeVariableGroup(const VarDecl *,
-                                   const VariableGroupsManager &, FixItList &&,
-                                   const Decl *,
-                                   const FixitStrategy &) override {}
-    void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node,
-                                          bool IsRelatedToDecl,
-                                          ASTContext &Ctx) override {}
-    bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override {
-      return false;
-    }
-    bool isSafeBufferOptOut(const SourceLocation &) const override {
-      return false;
-    }
-    bool ignoreUnsafeBufferInLibcCall(const SourceLocation &) const override {
-      return false;
-    }
-    bool ignoreUnsafeBufferInStaticSizedArray(
-        const SourceLocation &Loc) const override {
-      return false;
-    }
-    std::string getUnsafeBufferUsageAttributeTextAt(
-        SourceLocation, StringRef WSSuffix = "") const override {
-      return "";
-    }
-  };
-
-  FixableGadgetList FixableGadgets;
-  WarningGadgetList WarningGadgets;
-  DeclUseTracker Tracker;
-  MockReporter IgnoreHandler;
-  ASTContext &Ctx = D->getASTContext();
-  SmallVector<const Stmt *> Stmts;
-
-  populateStmtsForFindingGadgets(Stmts, D);
-  for (auto *Stmt : Stmts)
-    findGadgets(Stmt, Ctx, IgnoreHandler, false, FixableGadgets, WarningGadgets,
-                Tracker);
-
-  std::set<const Expr *> Result;
-  for (auto &G : WarningGadgets) {
-    for (const Expr *E : G->getUnsafePtrs()) {
-      Result.insert(E);
-    }
-  }
-
-  return Result;
-}
-
 struct WarningGadgetSets {
   std::map<const VarDecl *, std::set<const WarningGadget *>,
            // To keep keys sorted by their locations in the map so that the
@@ -4749,3 +4692,69 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
   applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
                std::move(Tracker), Handler, EmitSuggestions);
 }
+
+bool clang::matchUnsafePointers(const DynTypedNode &N, ASTContext &Ctx,
+                                std::set<const Expr *> &UnsafePointers) {
+  class MockReporter : public UnsafeBufferUsageHandler {
+  public:
+    MockReporter() {}
+    void handleUnsafeOperation(const Stmt *, bool, ASTContext &) override {}
+    void handleUnsafeLibcCall(const CallExpr *, unsigned, ASTContext &,
+                              const Expr *UnsafeArg = nullptr) override {}
+    void handleUnsafeOperationInContainer(const Stmt *, bool,
+                                          ASTContext &) override {}
+    void handleUnsafeVariableGroup(const VarDecl *,
+                                   const VariableGroupsManager &, FixItList &&,
+                                   const Decl *,
+                                   const FixitStrategy &) override {}
+    void handleUnsafeUniquePtrArrayAccess(const DynTypedNode &Node,
+                                          bool IsRelatedToDecl,
+                                          ASTContext &Ctx) override {}
+    bool ignoreUnsafeBufferInContainer(const SourceLocation &) const override {
+      return false;
+    }
+    bool isSafeBufferOptOut(const SourceLocation &) const override {
+      return false;
+    }
+    bool ignoreUnsafeBufferInLibcCall(const SourceLocation &) const override {
+      return false;
+    }
+    bool ignoreUnsafeBufferInStaticSizedArray(
+        const SourceLocation &Loc) const override {
+      return false;
+    }
+    std::string getUnsafeBufferUsageAttributeTextAt(
+        SourceLocation, StringRef WSSuffix = "") const override {
+      return "";
+    }
+  } Handler;
+
+  const Stmt *S = N.get<Stmt>();
+  if (!S)
+    return false;
+
+  MatchResult Result;
+  WarningGadgetList WarningGadgets;
+  bool Matched = false;
+
+  // FIXME: By design, we don't need MockReporter, and we are supposed to
+  // only define WARNING_GADGET when we want to treat WARNING_OPTIONAL_GADGET
+  // the same as WARNING_GADGET. The reason we have to do it this way now is
+  // that some WARNING_OPTIONAL_GADGETs do not have the 3-argument `matches`
+  // overload. We need to fix this problem in a separate patch.
+
+#define WARNING_GADGET(name)                                                   \
+  if (name##Gadget::matches(S, Ctx, Result))                                   \
+    WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));
+#define WARNING_OPTIONAL_GADGET(name)                                          \
+  if (name##Gadget::matches(S, Ctx, &Handler, Result))                         \
+    WarningGadgets.push_back(std::make_unique<name##Gadget>(Result));
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+
+  for (auto &WG : WarningGadgets)
+    for (auto *E : WG->getUnsafePtrs()) {
+      UnsafePointers.insert(E);
+      Matched = true;
+    }
+  return Matched;
+}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
index d8b8829a19106..53e47ffde7310 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
@@ -26,25 +26,6 @@
 using namespace clang;
 using namespace ssaf;
 
-static std::set<const Expr *>
-findUnsafePointersInContributor(const DynTypedNode &Node) {
-  const Decl *D = Node.get<Decl>();
-
-  if (!D)
-    return {};
-  if (isa<FunctionDecl>(D) || isa<VarDecl>(D))
-    return findUnsafePointers(D);
-  if (auto *RD = dyn_cast<RecordDecl>(D)) {
-    std::set<const Expr *> Result;
-
-    for (const FieldDecl *FD : RD->fields()) {
-      Result.merge(findUnsafePointers(FD));
-    }
-    return Result;
-  }
-  return {};
-}
-
 class clang::ssaf::UnsafeBufferUsageTUSummaryExtractor
     : public TUSummaryExtractor {
 public:
@@ -57,9 +38,8 @@ class clang::ssaf::UnsafeBufferUsageTUSummaryExtractor
   extractEntitySummary(const NamedDecl *Contributor, ASTContext &Ctx) {
     std::set<const Expr *> UnsafePointers;
 
-    auto MatchAction = [&UnsafePointers](const DynTypedNode &Node) {
-      auto Result = findUnsafePointersInContributor(Node);
-      UnsafePointers.insert(Result.begin(), Result.end());
+    auto MatchAction = [&Ctx, &UnsafePointers](const DynTypedNode &Node) {
+      return matchUnsafePointers(Node, Ctx, UnsafePointers);
     };
     findMatchesIn(Contributor, MatchAction);
 

>From 3cd2f6f8ed861eb52dde10bcc0f0492ac7e1924d Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Thu, 16 Apr 2026 13:49:40 -0700
Subject: [PATCH 2/3] fix linux build fail

---
 .../Analyses/SSAFAnalysesCommon.cpp                              | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
index a00e7933165ef..8e611742b74de 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SSAFAnalysesCommon.h"
+#include "clang/AST/ASTContext.h"
 
 using namespace clang;
 

>From 51c6b68abefa5fd02d0192c9039672eafbbfd015 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Thu, 16 Apr 2026 13:53:31 -0700
Subject: [PATCH 3/3] move ASTContext include to the header

---
 .../Analyses/SSAFAnalysesCommon.cpp                              | 1 -
 .../Analyses/SSAFAnalysesCommon.h                                | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
index 8e611742b74de..a00e7933165ef 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "SSAFAnalysesCommon.h"
-#include "clang/AST/ASTContext.h"
 
 using namespace clang;
 
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
index e6759c1fb6e39..d2854f7fbae45 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/SSAFAnalysesCommon.h
@@ -12,6 +12,7 @@
 #ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_SSAFANALYSESCOMMON_H
 #define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_SSAFANALYSESCOMMON_H
 
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "llvm/Support/JSON.h"



More information about the llvm-branch-commits mailing list