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 <[email protected]> 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@foo#***I#*S0_#I#" + } + }, + { + "id": 0, + "name": { + "namespace": [], + "suffix": "1", + "usr": "c:@F@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@foo#***I#*S0_#I#" + } + }, + { + "id": 0, + "name": { + "namespace": [], + "suffix": "1", + "usr": "c:@F@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@foo#***I#*S0_#I#" + } + }, + { + "id": 0, + "name": { + "namespace": [], + "suffix": "1", + "usr": "c:@F@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@foo#***I#*S0_#I#" + } + }, + { + "id": 0, + "name": { + "namespace": [], + "suffix": "1", + "usr": "c:@F@foo#***I#*S0_#I#" + } + }, + { + "id": 1, + "name": { + "namespace": [], + "suffix": "2", + "usr": "c:@F@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 // ////////////////////////////////////////////////////////////// _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
