[llvm-branch-commits] [clang] [ssaf][UnsafeBufferUsage] Add JSON serialization for UnsafeBufferUsage (PR #187156)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Mar 17 16:47:59 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Ziqing Luo (ziqingluo-90)

<details>
<summary>Changes</summary>

Implemented and registered a JSONFormat::FormatInfo for UnsafeBufferUsage analysis

rdar://171920065

---

Patch is 59.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/187156.diff


17 Files Affected:

- (modified) clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h (+8-1) 
- (renamed) clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h (+40-32) 
- (added) clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h (+40) 
- (removed) clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsageBuilder.h (-32) 
- (modified) clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h (+4) 
- (modified) clang/lib/Analysis/UnsafeBufferUsage.cpp (+43-16) 
- (added) clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt (+16) 
- (added) clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp (+89) 
- (added) clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp (+369) 
- (modified) clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt (+2) 
- (modified) clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt (+1) 
- (added) clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test (+4) 
- (added) clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary.json (+108) 
- (modified) clang/test/Analysis/Scalable/ssaf-format/list.test (+2-1) 
- (modified) clang/tools/clang-ssaf-format/CMakeLists.txt (+2-1) 
- (modified) clang/tools/clang-ssaf-linker/CMakeLists.txt (+1) 
- (modified) clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp (+638-39) 


``````````diff
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 876682ad779d4..e0d583c735e61 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -201,7 +201,14 @@ bool anyConflict(const llvm::SmallVectorImpl<FixItHint> &FixIts,
                  const SourceManager &SM);
 } // namespace internal
 
-std::set<const Expr *> findUnsafePointers(const FunctionDecl *FD);
+/// 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);
 } // end namespace clang
 
 #endif /* LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H */
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
similarity index 56%
rename from clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
rename to clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
index 5b58ed0684333..2b36c47fe67a5 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
@@ -6,13 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
-#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
 
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
-#include "llvm/ADT/iterator_range.h"
 #include <set>
 
 namespace clang::ssaf {
@@ -26,22 +26,19 @@ namespace clang::ssaf {
 /// *' of 'p'.
 ///
 /// An EntityPointerLevel can be identified by an EntityId and an unsigned
-/// integer indicating the pointer level: '(EntityId, PointerLevel)'.  An
-/// EntityPointerLevel 'P' is valid iff
-///   - 'P.EntityId' has a pointer type with at least 'P.PointerLevel' levels
-///     (This implies 'P.PointerLevel > 0');
-///   - 'P.EntityId' identifies an lvalue object and 'P.PointerLevel == 0'.
-/// The latter case represents address-of expressions.
+/// integer indicating the pointer level: '(EntityId, PointerLevel)'.
+/// An EntityPointerLevel 'P' is valid iff 'P.EntityId' has a pointer type with
+/// at least 'P.PointerLevel' levels (This implies 'P.PointerLevel > 0').
 ///
 /// For the same example 'int *p[10];', the EntityPointerLevels below are valid:
-/// '(p, 1)' is associated with 'int *[10]' of 'p';
-/// '(p, 2)' is associated with 'int *' of 'p';
-/// '(p, 0)' represents '&p'.
+/// - '(p, 2)' is associated with the 'int *' part of the declared type of 'p';
+/// - '(p, 1)' is associated with the 'int *[10]' part of the declared type of
+/// 'p'.
 class EntityPointerLevel {
   EntityId Entity;
   unsigned PointerLevel;
 
-  friend class UnsafeBufferUsageTUSummaryBuilder;
+  friend class UnsafeBufferUsageTUSummaryExtractor;
   friend class UnsafeBufferUsageEntitySummary;
 
   EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
@@ -52,7 +49,8 @@ class EntityPointerLevel {
   unsigned getPointerLevel() const { return PointerLevel; }
 
   bool operator==(const EntityPointerLevel &Other) const {
-    return Entity == Other.Entity && PointerLevel == Other.PointerLevel;
+    return std::tie(Entity, PointerLevel) ==
+           std::tie(Other.Entity, Other.PointerLevel);
   }
 
   bool operator!=(const EntityPointerLevel &Other) const {
@@ -64,7 +62,8 @@ class EntityPointerLevel {
            std::tie(Other.Entity, Other.PointerLevel);
   }
 
-  // Comparator supporting partial comparison against EntityId:
+  /// Compares `EntityPointerLevel`s; additionally, partially compares
+  /// `EntityPointerLevel` with `EntityId`.
   struct Comparator {
     using is_transparent = void;
     bool operator()(const EntityPointerLevel &L,
@@ -88,33 +87,42 @@ using EntityPointerLevelSet =
 class UnsafeBufferUsageEntitySummary final : public EntitySummary {
   const EntityPointerLevelSet UnsafeBuffers;
 
-  friend class UnsafeBufferUsageTUSummaryBuilder;
+  friend class UnsafeBufferUsageTUSummaryExtractor;
 
-  UnsafeBufferUsageEntitySummary(EntityPointerLevelSet &&UnsafeBuffers)
+  UnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers)
       : EntitySummary(), UnsafeBuffers(std::move(UnsafeBuffers)) {}
 
 public:
-  using const_iterator = EntityPointerLevelSet::const_iterator;
-
-  const_iterator begin() const { return UnsafeBuffers.begin(); }
-  const_iterator end() const { return UnsafeBuffers.end(); }
+  SummaryName getSummaryName() const override { return summaryName(); };
 
-  const_iterator find(const EntityPointerLevel &V) const {
-    return UnsafeBuffers.find(V);
+  bool operator==(const EntityPointerLevelSet &Other) const {
+    return UnsafeBuffers == Other;
   }
 
-  llvm::iterator_range<const_iterator> getSubsetOf(EntityId Entity) const {
-    return llvm::make_range(UnsafeBuffers.equal_range(Entity));
+  bool operator==(const UnsafeBufferUsageEntitySummary &Other) const {
+    return UnsafeBuffers == Other.UnsafeBuffers;
   }
 
-  /// \return the size of the set of EntityLevelPointers, which represents the
-  /// set of unsafe buffers
-  size_t getNumUnsafeBuffers() { return UnsafeBuffers.size(); }
+  bool empty() const { return UnsafeBuffers.empty(); }
 
-  SummaryName getSummaryName() const override {
-    return SummaryName{"UnsafeBufferUsage"};
-  };
+  static llvm::json::Object
+  jsonSerializeFn(const EntitySummary &ES,
+                  JSONFormat::EntityIdToJSONFn EntityId2JSON);
+
+  static llvm::Expected<std::unique_ptr<EntitySummary>>
+  jsonDeserializeFn(const llvm::json::Object &Data, EntityIdTable &,
+                    JSONFormat::EntityIdFromJSONFn EntityIdFromJSON);
+
+  static SummaryName summaryName() { return SummaryName{"UnsafeBufferUsage"}; }
+};
+
+struct UnsafeBufferUsageJSONFormatInfo : JSONFormat::FormatInfo {
+  UnsafeBufferUsageJSONFormatInfo()
+      : JSONFormat::FormatInfo(
+            UnsafeBufferUsageEntitySummary::summaryName(),
+            UnsafeBufferUsageEntitySummary::jsonSerializeFn,
+            UnsafeBufferUsageEntitySummary::jsonDeserializeFn) {}
 };
 } // namespace clang::ssaf
 
-#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGE_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
new file mode 100644
index 0000000000000..765b2c37562ce
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h
@@ -0,0 +1,40 @@
+//===- UnsafeBufferUsageExtractor.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
+
+#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+
+namespace clang::ssaf {
+class UnsafeBufferUsageTUSummaryExtractor : public TUSummaryExtractor {
+public:
+  UnsafeBufferUsageTUSummaryExtractor(TUSummaryBuilder &Builder)
+      : TUSummaryExtractor(Builder) {}
+
+  static EntityPointerLevel buildEntityPointerLevel(EntityId Entity,
+                                                    unsigned PointerLevel) {
+    return {Entity, PointerLevel};
+  }
+
+  EntityId addEntity(EntityName EN) { return SummaryBuilder.addEntity(EN); }
+
+  std::unique_ptr<UnsafeBufferUsageEntitySummary>
+  extractEntitySummary(const Decl *Contributor, ASTContext &Ctx,
+                       llvm::Error &Error);
+
+  void HandleTranslationUnit(ASTContext &Ctx) override;
+};
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsageBuilder.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsageBuilder.h
deleted file mode 100644
index db6c097510a57..0000000000000
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsageBuilder.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//===- UnsafeBufferUsageBuilder.h -------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
-#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
-
-#include "clang/ScalableStaticAnalysisFramework/Core/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
-#include <memory>
-
-namespace clang::ssaf {
-class UnsafeBufferUsageTUSummaryBuilder : public TUSummaryBuilder {
-public:
-  static EntityPointerLevel buildEntityPointerLevel(EntityId Entity,
-                                                    unsigned PointerLevel) {
-    return {Entity, PointerLevel};
-  }
-
-  static std::unique_ptr<UnsafeBufferUsageEntitySummary>
-  buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet &&UnsafeBuffers) {
-    return std::make_unique<UnsafeBufferUsageEntitySummary>(
-        UnsafeBufferUsageEntitySummary(std::move(UnsafeBuffers)));
-  }
-};
-} // namespace clang::ssaf
-
-#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGEBUILDER_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
index 5f201487ca1fe..e0a394da1a921 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
@@ -25,4 +25,8 @@ extern volatile int SSAFJSONFormatAnchorSource;
 [[maybe_unused]] static int SSAFJSONFormatAnchorDestination =
     SSAFJSONFormatAnchorSource;
 
+extern volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+[[maybe_unused]] static int UnsafeBufferUsageSSAFJSONFormatAnchorDestination =
+    UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+
 #endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_SSAFBUILTINFORCELINKER_H
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 133e39b8fac2b..5a9241acbee36 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -28,6 +28,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -36,6 +37,7 @@
 #include <queue>
 #include <set>
 #include <sstream>
+#include <vector>
 
 using namespace clang;
 
@@ -2942,7 +2944,37 @@ template <typename NodeTy> struct CompareNode {
   }
 };
 
-std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) {
+// Populate `Stmts` with the body/initializer Stmt of `D`, if `D` is one of the
+// followings:
+//   VarDecl
+//   FieldDecl
+//   FunctionDecl
+//   BlockDecl
+//   ObjCMethodDecl
+static void populateStmtsForFindingGadgets(SmallVector<const Stmt *> &Stmts,
+                                           const Decl *D) {
+  auto AddStmt = [&Stmts](const Stmt *S) {
+    if (S)
+      Stmts.push_back(S);
+  };
+  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+    AddStmt(FD->getBody());
+    for (const auto *PD : FD->parameters())
+      AddStmt(PD->getDefaultArg());
+    if (const auto *CtorD = dyn_cast<CXXConstructorDecl>(FD))
+      llvm::append_range(
+          Stmts, llvm::map_range(CtorD->inits(),
+                                 std::mem_fn(&CXXCtorInitializer::getInit)));
+  } else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
+    AddStmt(D->getBody());
+  } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
+    AddStmt(VD->getInit()); // FIXME: default arg for ParmVarDecl?
+  } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
+    AddStmt(FD->getInClassInitializer());
+  }
+}
+
+std::set<const Expr *> clang::findUnsafePointers(const Decl *D) {
   class MockReporter : public UnsafeBufferUsageHandler {
   public:
     MockReporter() {}
@@ -2981,9 +3013,13 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) {
   WarningGadgetList WarningGadgets;
   DeclUseTracker Tracker;
   MockReporter IgnoreHandler;
+  ASTContext &Ctx = D->getASTContext();
+  SmallVector<const Stmt *> Stmts;
 
-  findGadgets(FD->getBody(), FD->getASTContext(), IgnoreHandler, false,
-              FixableGadgets, WarningGadgets, Tracker);
+  populateStmtsForFindingGadgets(Stmts, D);
+  for (auto *Stmt : Stmts)
+    findGadgets(Stmt, Ctx, IgnoreHandler, false, FixableGadgets, WarningGadgets,
+                Tracker);
 
   std::set<const Expr *> Result;
   for (auto &G : WarningGadgets) {
@@ -4673,9 +4709,6 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
 #endif
 
   assert(D);
-
-  SmallVector<Stmt *> Stmts;
-
   if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
     // Consteval functions are free of UB by the spec, so we don't need to
     // visit them or produce diagnostics.
@@ -4697,24 +4730,18 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
         break;
       }
     }
+  }
 
-    Stmts.push_back(FD->getBody());
+  SmallVector<const Stmt *> Stmts;
 
-    if (const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
-      for (const CXXCtorInitializer *CI : ID->inits()) {
-        Stmts.push_back(CI->getInit());
-      }
-    }
-  } else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
-    Stmts.push_back(D->getBody());
-  }
+  populateStmtsForFindingGadgets(Stmts, D);
 
   assert(!Stmts.empty());
 
   FixableGadgetList FixableGadgets;
   WarningGadgetList WarningGadgets;
   DeclUseTracker Tracker;
-  for (Stmt *S : Stmts) {
+  for (const Stmt *S : Stmts) {
     findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
                 WarningGadgets, Tracker);
   }
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
new file mode 100644
index 0000000000000..c85fa044c1e9f
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
+  UnsafeBufferUsage/UnsafeBufferUsage.cpp
+  UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp  
+
+  LINK_LIBS
+  clangAST
+  clangAnalysis
+  clangBasic
+  clangScalableStaticAnalysisFrameworkCore
+
+  DEPENDS
+  )
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
new file mode 100644
index 0000000000000..44eaa20c74236
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
@@ -0,0 +1,89 @@
+//===---------- UnsafeBufferUsage.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "clang/ScalableStaticAnalysisFramework/SSAFForceLinker.h" // IWYU pragma: keep
+
+namespace {
+constexpr const char *const UnsafeBuffersKey = "UnsafeBuffers";
+} // namespace
+
+namespace clang::ssaf {
+using Object = llvm::json::Object;
+using Array = llvm::json::Array;
+using Value = llvm::json::Value;
+
+llvm::json::Object UnsafeBufferUsageEntitySummary::jsonSerializeFn(
+    const EntitySummary &ES, JSONFormat::EntityIdToJSONFn EntityId2JSON) {
+  // Writes a EntityPointerLevel as
+  // Array {
+  //   Object {
+  //     "@" : [entity-id]
+  //   },
+  //   [pointer-level]
+  // }
+  Array UnsafeBuffersData;
+
+  for (const auto &EPL :
+       static_cast<const UnsafeBufferUsageEntitySummary &>(ES).UnsafeBuffers)
+    UnsafeBuffersData.push_back(
+        Value(Array{// EntityId:
+                    Value(EntityId2JSON(EPL.getEntity())),
+                    // PointerLevel:
+                    Value(EPL.getPointerLevel())}));
+
+  Object Data;
+
+  Data[UnsafeBuffersKey] = Value(std::move(UnsafeBuffersData));
+  return Data;
+}
+
+llvm::Expected<std::unique_ptr<EntitySummary>>
+UnsafeBufferUsageEntitySummary::jsonDeserializeFn(
+    const llvm::json::Object &Data, EntityIdTable &,
+    JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
+  const Array *UnsafeBuffersData = Data.getArray(UnsafeBuffersKey);
+  constexpr const char *const ErrMsg = "unrecognized UnsafeBufferUsageEntitySummary data";
+
+  if (!UnsafeBuffersData)
+    return llvm::createStringError(ErrMsg);
+
+  EntityPointerLevelSet UnsafeBuffers;
+
+  for (auto &EltData : *UnsafeBuffersData) {
+    const Array *EltDataAsArr = EltData.getAsArray();
+
+    if (!EltDataAsArr || EltDataAsArr->size() != 2)
+      return llvm::createStringError(ErrMsg);
+
+    const Object *IdData = (*EltDataAsArr)[0].getAsObject();
+    std::optional<uint64_t> PtrLvData = (*EltDataAsArr)[1].getAsInteger();
+
+    if (!IdData || !PtrLvData)
+      return llvm::createStringError(ErrMsg);
+
+    llvm::Expected<EntityId> Id = EntityIdFromJSON(*IdData);
+
+    if (!Id)
+      return Id.takeError();
+    UnsafeBuffers.insert(EntityPointerLevel(Id.get(), *PtrLvData));
+  }
+  return std::make_unique<UnsafeBufferUsageEntitySummary>(
+      UnsafeBufferUsageEntitySummary(std::move(UnsafeBuffers)));
+}
+
+static llvm::Registry<JSONFormat::FormatInfo>::Add<
+    UnsafeBufferUsageJSONFormatInfo>
+    RegisterUnsafeBufferUsageJSONFormatInfo(
+        "UnsafeBufferUsage",
+        "JSON Format info for UnsafeBufferUsageEntitySummary");
+
+} // namespace clang::ssaf
+
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource = 0;
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/Unsaf...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/187156


More information about the llvm-branch-commits mailing list