[clang] 4913bd5 - [ssaf][UnsafeBufferUsage] Add JSON serialization for UnsafeBufferUsage (#187156)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 7 11:20:04 PDT 2026
Author: Ziqing Luo
Date: 2026-04-07T11:19:59-07:00
New Revision: 4913bd5588ada1dfd0e5a822b016d99b8196ca43
URL: https://github.com/llvm/llvm-project/commit/4913bd5588ada1dfd0e5a822b016d99b8196ca43
DIFF: https://github.com/llvm/llvm-project/commit/4913bd5588ada1dfd0e5a822b016d99b8196ca43.diff
LOG: [ssaf][UnsafeBufferUsage] Add JSON serialization for UnsafeBufferUsage (#187156)
Implemented and registered a JSONFormat::FormatInfo for
UnsafeBufferUsage analysis
rdar://171920065
---------
Co-authored-by: Balázs Benics <benicsbalazs at gmail.com>
Added:
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test
Modified:
clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
clang/test/Analysis/Scalable/ssaf-format/list.test
clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
index c0a4c2f76ab48..4e217c2eb87ef 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h
@@ -12,6 +12,8 @@
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
#include <set>
namespace clang::ssaf {
@@ -37,7 +39,9 @@ class EntityPointerLevel {
EntityId Entity;
unsigned PointerLevel;
+ friend class UnsafeBufferUsageEntitySummary;
friend class UnsafeBufferUsageTUSummaryExtractor;
+ friend EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
EntityPointerLevel(EntityId Entity, unsigned PointerLevel)
: Entity(Entity), PointerLevel(PointerLevel) {}
@@ -86,20 +90,30 @@ class UnsafeBufferUsageEntitySummary final : public EntitySummary {
const EntityPointerLevelSet UnsafeBuffers;
friend class UnsafeBufferUsageTUSummaryExtractor;
+ friend UnsafeBufferUsageEntitySummary
+ buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet);
+ friend llvm::iterator_range<EntityPointerLevelSet::const_iterator>
+ getUnsafeBuffers(const UnsafeBufferUsageEntitySummary &);
UnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers)
: EntitySummary(), UnsafeBuffers(std::move(UnsafeBuffers)) {}
public:
- SummaryName getSummaryName() const override {
- return SummaryName{"UnsafeBufferUsage"};
- };
+ static constexpr llvm::StringLiteral Name = "UnsafeBufferUsage";
+
+ SummaryName getSummaryName() const override { return summaryName(); };
bool operator==(const EntityPointerLevelSet &Other) const {
return UnsafeBuffers == Other;
}
+ bool operator==(const UnsafeBufferUsageEntitySummary &Other) const {
+ return UnsafeBuffers == Other.UnsafeBuffers;
+ }
+
bool empty() const { return UnsafeBuffers.empty(); }
+
+ static SummaryName summaryName() { return SummaryName{Name.str()}; }
};
} // namespace clang::ssaf
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
new file mode 100644
index 0000000000000..6a2d1161246f2
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h
@@ -0,0 +1,29 @@
+//===- UnsafeBufferUsageTest.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions and data structures that help UnsafeBufferUsage unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H
+
+#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
+#include "llvm/Support/Error.h"
+
+namespace clang::ssaf {
+
+llvm::Expected<std::unique_ptr<EntitySummary>> serializeDeserializeRoundTrip(
+ const UnsafeBufferUsageEntitySummary &S,
+ std::function<uint64_t(EntityId)> IdToIntFn,
+ std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn);
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_ANALYSES_UNSAFEBUFFERUSAGE_UNSAFEBUFFERUSAGETEST_H
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
index 1dc50c9c58dd8..2030dc8a12030 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/SSAFBuiltinForceLinker.h
@@ -32,6 +32,10 @@ extern volatile int SSAFAnalysisRegistryAnchorSource;
[[maybe_unused]] static int SSAFAnalysisRegistryAnchorDestination =
SSAFAnalysisRegistryAnchorSource;
+extern volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+[[maybe_unused]] static int UnsafeBufferUsageSSAFJSONFormatAnchorDestination =
+ UnsafeBufferUsageSSAFJSONFormatAnchorSource;
+
// This anchor is used to force the linker to link the CallGraphExtractor.
extern volatile int CallGraphExtractorAnchorSource;
[[maybe_unused]] static int CallGraphExtractorAnchorDestination =
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
index df8079a7d375d..926b610aa8dee 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CMakeLists.txt
@@ -2,9 +2,10 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
+add_clang_library(clangScalableStaticAnalysisFrameworkAnalyses
CallGraph/CallGraphExtractor.cpp
CallGraph/CallGraphJSONFormat.cpp
+ UnsafeBufferUsage/UnsafeBufferUsage.cpp
UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
LINK_LIBS
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
new file mode 100644
index 0000000000000..d325e8df79c20
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.cpp
@@ -0,0 +1,123 @@
+//===- 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/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/JSON.h"
+#include <cstdint>
+
+using namespace clang;
+using namespace ssaf;
+using Array = llvm::json::Array;
+using Object = llvm::json::Object;
+
+static constexpr llvm::StringLiteral SummarySerializationKey = "UnsafeBuffers";
+
+EntityPointerLevel ssaf::buildEntityPointerLevel(EntityId Id, unsigned PtrLv) {
+ return EntityPointerLevel(Id, PtrLv);
+}
+
+UnsafeBufferUsageEntitySummary
+ssaf::buildUnsafeBufferUsageEntitySummary(EntityPointerLevelSet UnsafeBuffers) {
+ return UnsafeBufferUsageEntitySummary(std::move(UnsafeBuffers));
+}
+
+llvm::iterator_range<EntityPointerLevelSet::const_iterator>
+ssaf::getUnsafeBuffers(const UnsafeBufferUsageEntitySummary &S) {
+ return llvm::make_range(S.UnsafeBuffers.begin(), S.UnsafeBuffers.end());
+}
+
+static Object serialize(const EntitySummary &S,
+ JSONFormat::EntityIdToJSONFn Fn) {
+ const auto &SS = static_cast<const UnsafeBufferUsageEntitySummary &>(S);
+ Array UnsafeBuffersData;
+
+ for (const auto &EPL : getUnsafeBuffers(SS))
+ UnsafeBuffersData.push_back(
+ Array{Fn(EPL.getEntity()), EPL.getPointerLevel()});
+ return Object{{SummarySerializationKey.data(), std::move(UnsafeBuffersData)}};
+}
+
+static llvm::Expected<std::unique_ptr<EntitySummary>>
+deserializeImpl(const Object &Data, JSONFormat::EntityIdFromJSONFn Fn) {
+ const Array *UnsafeBuffersData =
+ Data.getArray(SummarySerializationKey.data());
+
+ if (!UnsafeBuffersData)
+ return llvm::createStringError("expected a json::Object with a key %s",
+ SummarySerializationKey.data());
+
+ EntityPointerLevelSet EPLs;
+
+ for (const auto &EltData : *UnsafeBuffersData) {
+ const Array *EltDataAsArr = EltData.getAsArray();
+
+ if (!EltDataAsArr || EltDataAsArr->size() != 2)
+ return llvm::createStringError("expected a json::Array of size 2");
+
+ const Object *IdData = (*EltDataAsArr)[0].getAsObject();
+ std::optional<uint64_t> PtrLvData = (*EltDataAsArr)[1].getAsInteger();
+
+ if (!IdData || !PtrLvData)
+ return llvm::createStringError("expected a json::Value of integer type");
+
+ llvm::Expected<EntityId> Id = Fn(*IdData);
+
+ if (!Id)
+ return Id.takeError();
+ EPLs.insert(buildEntityPointerLevel(Id.get(), *PtrLvData));
+ }
+ return std::make_unique<UnsafeBufferUsageEntitySummary>(
+ buildUnsafeBufferUsageEntitySummary(std::move(EPLs)));
+}
+
+static llvm::Expected<std::unique_ptr<EntitySummary>>
+deserialize(const Object &Data, EntityIdTable &,
+ JSONFormat::EntityIdFromJSONFn Fn) {
+ return deserializeImpl(Data, Fn);
+}
+
+struct UnsafeBufferUsageJSONFormatInfo : JSONFormat::FormatInfo {
+ UnsafeBufferUsageJSONFormatInfo()
+ : JSONFormat::FormatInfo(UnsafeBufferUsageEntitySummary::summaryName(),
+ serialize, deserialize) {}
+};
+
+static llvm::Registry<JSONFormat::FormatInfo>::Add<
+ UnsafeBufferUsageJSONFormatInfo>
+ RegisterUnsafeBufferUsageJSONFormatInfo(
+ UnsafeBufferUsageEntitySummary::Name,
+ "JSON Format info for UnsafeBufferUsageEntitySummary");
+
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int UnsafeBufferUsageSSAFJSONFormatAnchorSource = 0;
+
+// For unit test:
+llvm::Expected<std::unique_ptr<EntitySummary>>
+ssaf::serializeDeserializeRoundTrip(
+ const UnsafeBufferUsageEntitySummary &S,
+ std::function<uint64_t(EntityId)> IdToIntFn,
+ std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn) {
+
+ auto IdToJson = [&IdToIntFn](EntityId Id) -> Object {
+ return Object({{"@", IdToIntFn(Id)}});
+ };
+ auto IdFromJson =
+ [&IdFromIntFn](const Object &O) -> llvm::Expected<EntityId> {
+ const auto *Int = O.get("@");
+
+ if (Int && Int->getAsUINT64())
+ return IdFromIntFn(*Int->getAsUINT64());
+ return llvm::createStringError("failed to get EntityId from Object");
+ };
+
+ return deserializeImpl(serialize(S, IdToJson), IdFromJson);
+}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
index b90d9c0ded1a9..3da1558810572 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/Frontend/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangScalableStaticAnalysisFrameworkFrontend
clangAST
clangBasic
clangFrontend
+ clangScalableStaticAnalysisFrameworkAnalyses
clangScalableStaticAnalysisFrameworkCore
clangSema
)
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
new file mode 100644
index 0000000000000..10d8c9457aaeb
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-element.json
@@ -0,0 +1,53 @@
+{
+ "data": [
+ {
+ "summary_data": [
+ {
+ "entity_id": 2,
+ "entity_summary": {
+ "UnsafeBuffers": [
+ 42
+ ]
+ }
+ }
+ ],
+ "summary_name": "UnsafeBufferUsage"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 2,
+ "name": {
+ "namespace": [],
+ "suffix": "",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ },
+ {
+ "id": 0,
+ "name": {
+ "namespace": [],
+ "suffix": "1",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {
+ "type": "External"
+ }
+ },
+ {
+ "id": 2,
+ "linkage": {
+ "type": "Internal"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "Mock.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
new file mode 100644
index 0000000000000..6b59ff39e6913
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-bad-ptr-level.json
@@ -0,0 +1,58 @@
+{
+ "data": [
+ {
+ "summary_data": [
+ {
+ "entity_id": 2,
+ "entity_summary": {
+ "UnsafeBuffers": [
+ [
+ {
+ "@": 0
+ },
+ "not-an-integer"
+ ]
+ ]
+ }
+ }
+ ],
+ "summary_name": "UnsafeBufferUsage"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 2,
+ "name": {
+ "namespace": [],
+ "suffix": "",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ },
+ {
+ "id": 0,
+ "name": {
+ "namespace": [],
+ "suffix": "1",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {
+ "type": "External"
+ }
+ },
+ {
+ "id": 2,
+ "linkage": {
+ "type": "Internal"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "Mock.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
new file mode 100644
index 0000000000000..555070ce3e660
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary-no-key.json
@@ -0,0 +1,58 @@
+{
+ "data": [
+ {
+ "summary_data": [
+ {
+ "entity_id": 2,
+ "entity_summary": {
+ "NotUnsafeBuffers": [
+ [
+ {
+ "@": 0
+ },
+ 1
+ ]
+ ]
+ }
+ }
+ ],
+ "summary_name": "UnsafeBufferUsage"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 2,
+ "name": {
+ "namespace": [],
+ "suffix": "",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ },
+ {
+ "id": 0,
+ "name": {
+ "namespace": [],
+ "suffix": "1",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {
+ "type": "External"
+ }
+ },
+ {
+ "id": 2,
+ "linkage": {
+ "type": "Internal"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "Mock.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
new file mode 100644
index 0000000000000..382b294ccc7bd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/Inputs/tu-summary.json
@@ -0,0 +1,108 @@
+{
+ "data": [
+ {
+ "summary_data": [
+ {
+ "entity_id": 2,
+ "entity_summary": {
+ "UnsafeBuffers": [
+ [
+ {
+ "@": 0
+ },
+ 1
+ ],
+ [
+ {
+ "@": 0
+ },
+ 2
+ ],
+ [
+ {
+ "@": 0
+ },
+ 3
+ ],
+ [
+ {
+ "@": 1
+ },
+ 1
+ ],
+ [
+ {
+ "@": 1
+ },
+ 2
+ ],
+ [
+ {
+ "@": 1
+ },
+ 3
+ ],
+ [
+ {
+ "@": 1
+ },
+ 4
+ ]
+ ]
+ }
+ }
+ ],
+ "summary_name": "UnsafeBufferUsage"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 2,
+ "name": {
+ "namespace": [],
+ "suffix": "",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ },
+ {
+ "id": 0,
+ "name": {
+ "namespace": [],
+ "suffix": "1",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ },
+ {
+ "id": 1,
+ "name": {
+ "namespace": [],
+ "suffix": "2",
+ "usr": "c:@F at foo#***I#*S0_#I#"
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {
+ "type": "External"
+ }
+ },
+ {
+ "id": 1,
+ "linkage": {
+ "type": "Internal"
+ }
+ },
+ {
+ "id": 2,
+ "linkage": {
+ "type": "Internal"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "Mock.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test b/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test
new file mode 100644
index 0000000000000..6a12949f3bbb4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/UnsafeBufferUsage/tu-summary-serialization.test
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t.json
+// RUN: clang-ssaf-format -type=tu %S/Inputs/tu-summary.json -o %t.json
+// RUN:
diff %S/Inputs/tu-summary.json %t.json
+
+// Negative tests:
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-no-key.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-KEY
+// CHECK-NO-KEY: expected a json::Object with a key UnsafeBuffers
+
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-bad-element.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-BAD-ELEMENT
+// CHECK-BAD-ELEMENT: expected a json::Array of size 2
+
+// RUN: not clang-ssaf-format -type=tu %S/Inputs/tu-summary-bad-ptr-level.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-BAD-PTR-LEVEL
+// CHECK-BAD-PTR-LEVEL: expected a json::Value of integer type
diff --git a/clang/test/Analysis/Scalable/ssaf-format/list.test b/clang/test/Analysis/Scalable/ssaf-format/list.test
index ffc1624c5872a..82811a97c40c5 100644
--- a/clang/test/Analysis/Scalable/ssaf-format/list.test
+++ b/clang/test/Analysis/Scalable/ssaf-format/list.test
@@ -7,4 +7,5 @@
// CHECK-EMPTY:
// CHECK-DAG: [[NthFormat:[0-9]+]]. json - JSON serialization format
// CHECK-DAG: Analyses:
-// CHECK-DAG: [[NthFormat]].[[MthSummary:[0-9]+]]. CallGraph - JSON Format info for CallGraph summary
+// CHECK-DAG: [[NthFormat]].{{[0-9]+}}. CallGraph - JSON Format info for CallGraph summary
+// CHECK-DAG: [[NthFormat]].{{[0-9]+}}. UnsafeBufferUsage - JSON Format info for UnsafeBufferUsageEntitySummary
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
index 3555f5196a7b9..51d422c1921af 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
@@ -7,17 +7,25 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "TestFixture.h"
#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.h"
+#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h"
#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <memory>
+#include <optional>
using namespace clang;
using namespace ssaf;
@@ -58,7 +66,7 @@ const FunctionDecl *findFnByName(StringRef Name, ASTContext &Ctx) {
constexpr inline auto buildEntityPointerLevel =
UnsafeBufferUsageTUSummaryExtractor::buildEntityPointerLevel;
-class UnsafeBufferUsageTest : public testing::Test {
+class UnsafeBufferUsageTest : public TestFixture {
protected:
TUSummary TUSum;
TUSummaryBuilder Builder;
@@ -184,6 +192,52 @@ TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageEntityPointerLevelSetTest) {
EXPECT_THAT(getSubsetOf(Set, E3), UnorderedElementsAre(P5));
}
+//////////////////////////////////////////////////////////////
+// (De-)Serialization Tests //
+//////////////////////////////////////////////////////////////
+
+TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageSerializeTest) {
+ auto Sum = setUpTest(R"cpp(
+ void foo(int ***p, int ****q, int x) {
+ p[5][5][5];
+ q[5][5][5][5];
+ }
+ )cpp",
+ "foo");
+ ASSERT_NE(Sum, nullptr);
+ EXPECT_EQ(*Sum, makeSet(__LINE__, {{"p", 1U},
+ {"p", 2U},
+ {"p", 3U},
+ {"q", 1U},
+ {"q", 2U},
+ {"q", 3U},
+ {"q", 4U}}));
+
+ std::function<uint64_t(EntityId)> IdToIntFn = [](EntityId Id) -> uint64_t {
+ return getIndex(Id);
+ };
+ std::function<llvm::Expected<EntityId>(uint64_t)> IdFromIntFn =
+ [this](uint64_t Int) -> llvm::Expected<EntityId> {
+ std::optional<EntityId> Result = std::nullopt;
+
+ getIdTable(TUSum).forEach([&Int, &Result](const EntityName &, EntityId Id) {
+ if (getIndex(Id) == Int)
+ Result = Id;
+ });
+ if (Result)
+ return *Result;
+ return llvm::createStringError("failed to convert %d to an EntityId", Int);
+ };
+
+ auto RoundTripResult =
+ serializeDeserializeRoundTrip(*Sum, IdToIntFn, IdFromIntFn);
+
+ EXPECT_THAT_ERROR(RoundTripResult.takeError(), llvm::Succeeded());
+ ASSERT_NE(*RoundTripResult, nullptr);
+ EXPECT_EQ(*Sum, *static_cast<const UnsafeBufferUsageEntitySummary *>(
+ RoundTripResult->get()));
+}
+
//////////////////////////////////////////////////////////////
// Extractor Tests //
//////////////////////////////////////////////////////////////
More information about the cfe-commits
mailing list