Author: Aviral Goel Date: 2026-07-02T20:11:37-07:00 New Revision: e69038f9c2b1c47dd7beebb5531129514fab36e7
URL: https://github.com/llvm/llvm-project/commit/e69038f9c2b1c47dd7beebb5531129514fab36e7 DIFF: https://github.com/llvm/llvm-project/commit/e69038f9c2b1c47dd7beebb5531129514fab36e7.diff LOG: [clang][ssaf] Add `MultiArchSharedLibrary` data structure (#206854) This change introduces `MultiArchSharedLibrary` data structure that wraps per-architecture `LUSummaryEncoding` members. This is the SSAF analogue of a fat shared library. The overall design mirrors the existing `MultiArchStaticLibrary` design: each member identifies the same logical library built for a different target triple. Support for constructing and consuming this object will be added in a future PR. rdar://181164537 Added: clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/MultiArchSharedLibrary.cpp clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-empty.json clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-nonempty.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/duplicate-target-triple.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/invalid-syntax.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-empty-lu-namespace.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-inner-error.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-mismatched-type.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-missing-type.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-namespace-mismatch.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-not-object.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/members-not-array.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/mismatched-type.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-members.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-namespace.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-type.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/namespace-not-array.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-json-extension.txt clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-object.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-empty-members.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-multiple-members.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-nonempty-members.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-single-member.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-three-members.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-members-input.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-three-members-input.json clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/io.test clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/permissions.test clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/round-trip.test clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/top-level.test Modified: clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test clang/tools/clang-ssaf-format/SSAFFormat.cpp clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h clang/unittests/ScalableStaticAnalysis/TestFixture.h Removed: ################################################################################ diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h index 663697cdb88b3..308196d38a84a 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h @@ -33,6 +33,7 @@ namespace clang::ssaf { /// entity linker and contains deduplicated and patched entity summaries. class LUSummaryEncoding { friend class EntityLinker; + friend class MultiArchSharedLibrary; friend class SerializationFormat; friend class TestFixture; diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h new file mode 100644 index 0000000000000..8c3f4345ee5f8 --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h @@ -0,0 +1,74 @@ +//===- MultiArchSharedLibrary.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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the MultiArchSharedLibrary class, which represents a +// multi-architecture wrapper around per-architecture LUSummaryEncoding +// instances (the SSAF analogue of a Mach-O fat shared library/dylib, e.g. +// one produced by `lipo -create` over per-arch `.dylib` files). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_MULTIARCHSHAREDLIBRARY_H +#define LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_MULTIARCHSHAREDLIBRARY_H + +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/Model/BuildNamespace.h" +#include <memory> +#include <set> +#include <tuple> + +namespace clang::ssaf { + +/// Represents a multi-architecture shared library. +/// +/// A MultiArchSharedLibrary bundles per-architecture LUSummaryEncoding +/// members, mirroring the role of a Mach-O fat shared library (the result +/// of `lipo -create` over per-architecture `.dylib` files). All members +/// represent the same logical shared library built for diff erent +/// architectures; the wrapper's \c Namespace is the nested build +/// namespace identifying that shared library, and every member's +/// \c LUNamespace must equal it exactly. +class MultiArchSharedLibrary { + friend class SerializationFormat; + friend class TestFixture; + + /// Orders members by their TargetTriple's canonical enum components. + /// llvm::Triple's parser maps alias spellings to the same enum values + /// (e.g. "aarch64" and "arm64" both become Triple::aarch64), so a + /// tuple-of-enums compare is equivalent to comparing normalized triples + /// for identity, but without the per-call string allocation. + struct MemberByTargetTriple { + static auto key(const llvm::Triple &T) { + return std::make_tuple(T.getArch(), T.getSubArch(), T.getVendor(), + T.getOS(), T.getEnvironment(), + T.getObjectFormat()); + } + bool operator()(const std::unique_ptr<LUSummaryEncoding> &A, + const std::unique_ptr<LUSummaryEncoding> &B) const { + return key(A->TargetTriple) < key(B->TargetTriple); + } + }; + + // The nested namespace identifying this multi-architecture shared + // library. It matches the LUNamespace of every member exactly (same + // path, same kinds, same names): the shared library's identity is the + // same across all its architecture slices. + NestedBuildNamespace Namespace; + + // LUSummaryEncoding objects ordered by TargetTriple enum components. + // Two members with the same TargetTriple are not permitted. + std::set<std::unique_ptr<LUSummaryEncoding>, MemberByTargetTriple> Members; + +public: + explicit MultiArchSharedLibrary(NestedBuildNamespace Namespace) + : Namespace(std::move(Namespace)) {} +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_CORE_ENTITYLINKER_MULTIARCHSHAREDLIBRARY_H diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h index 37147c98243c3..6ff7ed347a791 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h @@ -8,8 +8,7 @@ // // This file defines the MultiArchStaticLibrary class, which represents a // multi-architecture wrapper around per-architecture StaticLibrary -// instances (the SSAF analogue of a Mach-O fat static library, e.g. one -// produced by `lipo -create` over per-arch `.a` files). +// instances. // //===----------------------------------------------------------------------===// @@ -26,21 +25,15 @@ namespace clang::ssaf { /// Represents a multi-architecture static library. /// -/// A MultiArchStaticLibrary bundles per-architecture StaticLibrary -/// members, mirroring the role of a Mach-O fat static library (the result -/// of `lipo -create` over per-architecture `.a` files). All members -/// represent the same logical library built for diff erent architectures; -/// the wrapper's \c Namespace identifies that shared library and every -/// member's namespace must agree on its name. +/// A MultiArchStaticLibrary bundles per-architecture StaticLibrary members. All +/// members represent the same logical library built for diff erent +/// architectures; the wrapper's \c Namespace identifies that shared library and +/// every member's namespace must agree on its name. class MultiArchStaticLibrary { friend class SerializationFormat; friend class TestFixture; /// Orders members by their TargetTriple's canonical enum components. - /// llvm::Triple's parser maps alias spellings to the same enum values - /// (e.g. "aarch64" and "arm64" both become Triple::aarch64), so a - /// tuple-of-enums compare is equivalent to comparing normalized triples - /// for identity, but without the per-call string allocation. struct MemberByTargetTriple { static auto key(const llvm::Triple &T) { return std::make_tuple(T.getArch(), T.getSubArch(), T.getVendor(), diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def b/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def index e43ff93140674..33f47f8f9151c 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def +++ b/clang/include/clang/ScalableStaticAnalysis/Core/Model/PrivateFieldNames.def @@ -37,6 +37,8 @@ FIELD(LUSummaryEncoding, LinkageTable) FIELD(LUSummaryEncoding, LUNamespace) FIELD(MultiArchStaticLibrary, Members) FIELD(MultiArchStaticLibrary, Namespace) +FIELD(MultiArchSharedLibrary, Members) +FIELD(MultiArchSharedLibrary, Namespace) FIELD(NestedBuildNamespace, Namespaces) FIELD(StaticLibrary, Members) FIELD(StaticLibrary, Namespace) diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h index f95f3f490da81..aa4d3d6e3a3cd 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h @@ -80,6 +80,12 @@ class JSONFormat final : public SerializationFormat { llvm::Error writeMultiArchStaticLibrary(const MultiArchStaticLibrary &M, llvm::StringRef Path) override; + llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibrary(llvm::StringRef Path) override; + + llvm::Error writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, + llvm::StringRef Path) override; + llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) override; llvm::Error writeWPASuite(const WPASuite &Suite, @@ -143,6 +149,11 @@ class JSONFormat final : public SerializationFormat { llvm::Expected<MultiArchStaticLibrary> readMultiArchStaticLibraryFromObject(const Object &Root); + /// Parses a MultiArchSharedLibrary from an already-validated root JSON + /// object. See \c readTUSummaryFromObject for caller responsibilities. + llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibraryFromObject(const Object &Root); + /// Serializes a TUSummaryEncoding to a JSON object including its /// self-describing \c type field. Used both by \c writeTUSummaryEncoding /// and by the StaticLibrary writer to emit member entries. @@ -153,6 +164,11 @@ class JSONFormat final : public SerializationFormat { /// and by the MultiArchStaticLibrary writer to emit per-arch slices. Object staticLibraryToJSON(const StaticLibrary &S) const; + /// Serializes an LUSummaryEncoding to a JSON object including its + /// self-describing \c type field. Used both by \c writeLUSummaryEncoding + /// and by the MultiArchSharedLibrary writer to emit per-arch slices. + Object luSummaryEncodingToJSON(const LUSummaryEncoding &E) const; + /// Parses a WPASuite from an already-validated root JSON object. See /// \c readTUSummaryFromObject for caller responsibilities. llvm::Expected<WPASuite> readWPASuiteFromObject(const Object &Root); diff --git a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h index a9c25de95a598..ddd52718ab4ee 100644 --- a/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h +++ b/clang/include/clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h @@ -16,6 +16,7 @@ #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h" @@ -43,12 +44,13 @@ using Artifact = std::variant<TUSummary, LUSummary, WPASuite>; /// artifacts but with their per-entity summary payloads left as opaque /// format-specific encodings rather than fully resolved analysis results. /// -/// \c StaticLibrary and \c MultiArchStaticLibrary appear only in this -/// variant: the archiver/arch tools and the linker pass member payloads -/// through without decoding them, so fully decoded shapes would have no -/// consumer. -using ArtifactEncoding = std::variant<TUSummaryEncoding, LUSummaryEncoding, - StaticLibrary, MultiArchStaticLibrary>; +/// \c StaticLibrary, \c MultiArchStaticLibrary, and +/// \c MultiArchSharedLibrary appear only in this variant: the +/// archiver/arch tools and the linker pass member payloads through +/// without decoding them, so fully decoded shapes would have no consumer. +using ArtifactEncoding = + std::variant<TUSummaryEncoding, LUSummaryEncoding, StaticLibrary, + MultiArchStaticLibrary, MultiArchSharedLibrary>; /// Abstract base class for serialization formats. class SerializationFormat { @@ -115,6 +117,13 @@ class SerializationFormat { writeMultiArchStaticLibrary(const MultiArchStaticLibrary &M, llvm::StringRef Path) = 0; + virtual llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibrary(llvm::StringRef Path) = 0; + + virtual llvm::Error + writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, + llvm::StringRef Path) = 0; + virtual llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) = 0; virtual llvm::Error writeWPASuite(const WPASuite &Suite, diff --git a/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt b/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt index 47f018f61becf..28c4ac9f6911b 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt +++ b/clang/lib/ScalableStaticAnalysis/Core/CMakeLists.txt @@ -18,6 +18,7 @@ add_clang_library(clangScalableStaticAnalysisCore Serialization/JSONFormat/LUSummary.cpp Serialization/JSONFormat/LUSummaryEncoding.cpp Serialization/JSONFormat/MultiArchStaticLibrary.cpp + Serialization/JSONFormat/MultiArchSharedLibrary.cpp Serialization/JSONFormat/StaticLibrary.cpp Serialization/JSONFormat/TUSummary.cpp Serialization/JSONFormat/TUSummaryEncoding.cpp diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp index a34f5cb718ab2..15248ce92ae88 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/Artifact.cpp @@ -165,11 +165,22 @@ JSONFormat::readArtifactEncoding(llvm::StringRef Path) { return ArtifactEncoding{std::move(*ExpectedM)}; } + if (*ExpectedType == JSONTypeValueMultiArchSharedLibrary) { + auto ExpectedM = readMultiArchSharedLibraryFromObject(*RootObjectPtr); + if (!ExpectedM) { + return ErrorBuilder::wrap(ExpectedM.takeError()) + .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path) + .build(); + } + return ArtifactEncoding{std::move(*ExpectedM)}; + } + return ErrorBuilder::create( std::errc::invalid_argument, ErrorMessages::UnknownArtifactEncodingType, *ExpectedType, JSONTypeKey, JSONTypeValueTUSummary, JSONTypeValueLUSummary, - JSONTypeValueStaticLibrary, JSONTypeValueMultiArchStaticLibrary) + JSONTypeValueStaticLibrary, JSONTypeValueMultiArchStaticLibrary, + JSONTypeValueMultiArchSharedLibrary) .context(ErrorMessages::ReadingFromFile, "ArtifactEncoding", Path) .build(); } @@ -185,11 +196,13 @@ llvm::Error JSONFormat::writeArtifactEncoding(const ArtifactEncoding &E, return writeLUSummaryEncoding(Enc, Path); } else if constexpr (std::is_same_v<T, StaticLibrary>) { return writeStaticLibrary(Enc, Path); + } else if constexpr (std::is_same_v<T, MultiArchStaticLibrary>) { + return writeMultiArchStaticLibrary(Enc, Path); } else { static_assert( - std::is_same_v<T, MultiArchStaticLibrary>, + std::is_same_v<T, MultiArchSharedLibrary>, "ArtifactEncoding visitor must cover all variant alternatives"); - return writeMultiArchStaticLibrary(Enc, Path); + return writeMultiArchSharedLibrary(Enc, Path); } }, E); diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h index 9cfe67e20d1d7..b17f296eda1b4 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h +++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/JSONFormatImpl.h @@ -82,11 +82,13 @@ inline constexpr const char *FailedToReadObjectAtIndex = inline constexpr const char *MismatchedSummaryType = "expected '{0}' for field '{1}' but got '{2}'"; +inline constexpr const char *MismatchedNestedNamespace = + "field '{0}' does not equal the enclosing artifact's namespace"; inline constexpr const char *UnknownArtifactType = "unknown value '{0}' for field '{1}': expected '{2}', '{3}', or '{4}'"; inline constexpr const char *UnknownArtifactEncodingType = - "unknown value '{0}' for field '{1}': expected '{2}', '{3}', '{4}', or " - "'{5}'"; + "unknown value '{0}' for field '{1}': expected '{2}', '{3}', '{4}', '{5}', " + "or '{6}'"; inline constexpr const char *FailedToDeserializeEntitySummaryNoFormatInfo = "failed to deserialize EntitySummary: no FormatInfo registered for '{0}'"; @@ -158,6 +160,11 @@ inline constexpr const char *JSONTypeValueStaticLibrary = "StaticLibrary"; inline constexpr const char *JSONTypeValueMultiArchStaticLibrary = "MultiArchStaticLibrary"; +/// Value written to \c JSONTypeKey for serialized \c MultiArchSharedLibrary +/// files. +inline constexpr const char *JSONTypeValueMultiArchSharedLibrary = + "MultiArchSharedLibrary"; + /// Value written to \c JSONTypeKey for serialized \c WPASuite files. inline constexpr const char *JSONTypeValueWPASuite = "WPASuite"; diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp index b1f78c5309dfb..8961ce95e059b 100644 --- a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp +++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/LUSummaryEncoding.cpp @@ -164,6 +164,17 @@ JSONFormat::readLUSummaryEncodingFromObject(const Object &RootObject) { llvm::Error JSONFormat::writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path) { + if (auto Error = writeJSON(luSummaryEncodingToJSON(SummaryEncoding), Path)) { + return ErrorBuilder::wrap(std::move(Error)) + .context(ErrorMessages::WritingToFile, "LUSummary", Path) + .build(); + } + + return llvm::Error::success(); +} + +Object JSONFormat::luSummaryEncodingToJSON( + const LUSummaryEncoding &SummaryEncoding) const { Object RootObject; RootObject[JSONTypeKey] = JSONTypeValueLUSummary; @@ -181,13 +192,7 @@ JSONFormat::writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, RootObject["data"] = encodingSummaryDataMapToJSON(getData(SummaryEncoding)); - if (auto Error = writeJSON(std::move(RootObject), Path)) { - return ErrorBuilder::wrap(std::move(Error)) - .context(ErrorMessages::WritingToFile, "LUSummary", Path) - .build(); - } - - return llvm::Error::success(); + return RootObject; } } // namespace clang::ssaf diff --git a/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/MultiArchSharedLibrary.cpp b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/MultiArchSharedLibrary.cpp new file mode 100644 index 0000000000000..d23eef1ff9fe9 --- /dev/null +++ b/clang/lib/ScalableStaticAnalysis/Core/Serialization/JSONFormat/MultiArchSharedLibrary.cpp @@ -0,0 +1,163 @@ +//===- MultiArchSharedLibrary.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 "JSONFormatImpl.h" + +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h" +#include "llvm/TargetParser/Triple.h" + +namespace clang::ssaf { + +//---------------------------------------------------------------------------- +// MultiArchSharedLibrary +//---------------------------------------------------------------------------- + +llvm::Expected<MultiArchSharedLibrary> +JSONFormat::readMultiArchSharedLibrary(llvm::StringRef Path) { + auto ExpectedJSON = readJSON(Path); + if (!ExpectedJSON) { + return ErrorBuilder::wrap(ExpectedJSON.takeError()) + .context(ErrorMessages::ReadingFromFile, "MultiArchSharedLibrary", Path) + .build(); + } + + Object *RootObjectPtr = ExpectedJSON->getAsObject(); + if (!RootObjectPtr) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::FailedToReadObject, + "MultiArchSharedLibrary", "object") + .context(ErrorMessages::ReadingFromFile, "MultiArchSharedLibrary", Path) + .build(); + } + + if (auto Err = checkSummaryType(*RootObjectPtr, + JSONTypeValueMultiArchSharedLibrary)) { + return ErrorBuilder::wrap(std::move(Err)) + .context(ErrorMessages::ReadingFromFile, "MultiArchSharedLibrary", Path) + .build(); + } + + auto ExpectedM = readMultiArchSharedLibraryFromObject(*RootObjectPtr); + if (!ExpectedM) { + return ErrorBuilder::wrap(ExpectedM.takeError()) + .context(ErrorMessages::ReadingFromFile, "MultiArchSharedLibrary", Path) + .build(); + } + + return std::move(*ExpectedM); +} + +llvm::Expected<MultiArchSharedLibrary> +JSONFormat::readMultiArchSharedLibraryFromObject(const Object &RootObject) { + const Array *NamespaceArray = RootObject.getArray("namespace"); + if (!NamespaceArray) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::FailedToReadObjectAtField, + "NestedBuildNamespace", "namespace", "array") + .build(); + } + + auto ExpectedNamespace = nestedBuildNamespaceFromJSON(*NamespaceArray); + if (!ExpectedNamespace) { + return ErrorBuilder::wrap(ExpectedNamespace.takeError()) + .context(ErrorMessages::ReadingFromField, "NestedBuildNamespace", + "namespace") + .build(); + } + + const Array *MembersArray = RootObject.getArray("members"); + if (!MembersArray) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::FailedToReadObjectAtField, + "MultiArchSharedLibrary members", "members", + "array") + .build(); + } + + MultiArchSharedLibrary M(std::move(*ExpectedNamespace)); + auto &Members = getMembers(M); + const auto &WrapperNamespace = getNamespace(M); + + for (const auto &[Index, MemberValue] : llvm::enumerate(*MembersArray)) { + const Object *MemberObject = MemberValue.getAsObject(); + if (!MemberObject) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::FailedToReadObjectAtIndex, + "MultiArchSharedLibrary member", Index, + "object") + .build(); + } + + if (auto Err = checkSummaryType(*MemberObject, JSONTypeValueLUSummary)) { + return ErrorBuilder::wrap(std::move(Err)) + .context(ErrorMessages::ReadingFromIndex, + "MultiArchSharedLibrary member", Index) + .build(); + } + + auto ExpectedMember = readLUSummaryEncodingFromObject(*MemberObject); + if (!ExpectedMember) { + return ErrorBuilder::wrap(ExpectedMember.takeError()) + .context(ErrorMessages::ReadingFromIndex, + "MultiArchSharedLibrary member", Index) + .build(); + } + + // Every per-arch slice must resolve to the same shared-library identity, + // so the member's LUNamespace must equal the wrapper's Namespace. + if (WrapperNamespace != getLUNamespace(*ExpectedMember)) { + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::MismatchedNestedNamespace, + "lu_namespace") + .context(ErrorMessages::ReadingFromIndex, + "MultiArchSharedLibrary member", Index) + .build(); + } + + auto [It, Inserted] = Members.insert( + std::make_unique<LUSummaryEncoding>(std::move(*ExpectedMember))); + if (!Inserted) { + auto MemberTriple = llvm::Triple::normalize(getTargetTriple(**It).str()); + return ErrorBuilder::create(std::errc::invalid_argument, + ErrorMessages::FailedInsertionOnDuplication, + "MultiArchSharedLibrary member", Index, + MemberTriple) + .build(); + } + } + + return std::move(M); +} + +llvm::Error +JSONFormat::writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, + llvm::StringRef Path) { + Object RootObject; + + RootObject[JSONTypeKey] = JSONTypeValueMultiArchSharedLibrary; + + RootObject["namespace"] = nestedBuildNamespaceToJSON(getNamespace(M)); + + Array MembersArray; + MembersArray.reserve(getMembers(M).size()); + for (const auto &Member : getMembers(M)) { + MembersArray.push_back(luSummaryEncodingToJSON(*Member)); + } + RootObject["members"] = std::move(MembersArray); + + if (auto Error = writeJSON(std::move(RootObject), Path)) { + return ErrorBuilder::wrap(std::move(Error)) + .context(ErrorMessages::WritingToFile, "MultiArchSharedLibrary", Path) + .build(); + } + + return llvm::Error::success(); +} + +} // namespace clang::ssaf diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-empty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-empty.json new file mode 100644 index 0000000000000..1cd693b2fc8ce --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-empty.json @@ -0,0 +1,10 @@ +{ + "members": [], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-nonempty.json b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-nonempty.json new file mode 100644 index 0000000000000..dc00a24f0eaf0 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/Inputs/rt-multi-arch-shared-library-nonempty.json @@ -0,0 +1,79 @@ +{ + "members": [ + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "suffix": "", + "usr": "c:@F@foo" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "suffix": "", + "usr": "c:@F@foo" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test index 32214cabbc36b..19d162f46261b 100644 --- a/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test +++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/round-trip.test @@ -60,3 +60,16 @@ // RUN: diff %S/Inputs/rt-multi-arch-static-library-nonempty.json %t/rt-multi-arch-static-library-nonempty-enc.json // RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-multi-arch-static-library-nonempty.json -o %t/rt-multi-arch-static-library-nonempty-enc-explicit.json // RUN: diff %S/Inputs/rt-multi-arch-static-library-nonempty.json %t/rt-multi-arch-static-library-nonempty-enc-explicit.json + +// MultiArchSharedLibrary, like its sibling, appears only in the +// ArtifactEncoding variant; round-trip both empty and non-empty fixtures. + +// RUN: clang-ssaf-format --encoding %S/Inputs/rt-multi-arch-shared-library-empty.json -o %t/rt-multi-arch-shared-library-empty-enc.json +// RUN: diff %S/Inputs/rt-multi-arch-shared-library-empty.json %t/rt-multi-arch-shared-library-empty-enc.json +// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-multi-arch-shared-library-empty.json -o %t/rt-multi-arch-shared-library-empty-enc-explicit.json +// RUN: diff %S/Inputs/rt-multi-arch-shared-library-empty.json %t/rt-multi-arch-shared-library-empty-enc-explicit.json + +// RUN: clang-ssaf-format --encoding %S/Inputs/rt-multi-arch-shared-library-nonempty.json -o %t/rt-multi-arch-shared-library-nonempty-enc.json +// RUN: diff %S/Inputs/rt-multi-arch-shared-library-nonempty.json %t/rt-multi-arch-shared-library-nonempty-enc.json +// RUN: clang-ssaf-format --type auto --encoding %S/Inputs/rt-multi-arch-shared-library-nonempty.json -o %t/rt-multi-arch-shared-library-nonempty-enc-explicit.json +// RUN: diff %S/Inputs/rt-multi-arch-shared-library-nonempty.json %t/rt-multi-arch-shared-library-nonempty-enc-explicit.json diff --git a/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test index 5f8333ca52b37..f5b4f3106d7f9 100644 --- a/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test +++ b/clang/test/Analysis/Scalable/ssaf-format/Artifact/top-level.test @@ -40,4 +40,4 @@ // RUN: not clang-ssaf-format --type auto --encoding %S/Inputs/unknown-type.json 2>&1 \ // RUN: | FileCheck %s --match-full-lines --check-prefix=ENCODING-UNKNOWN-TYPE // ENCODING-UNKNOWN-TYPE: clang-ssaf-format: error: reading ArtifactEncoding from file '{{.*}}unknown-type.json' -// ENCODING-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', 'LUSummary', 'StaticLibrary', or 'MultiArchStaticLibrary' +// ENCODING-UNKNOWN-TYPE-NEXT: unknown value 'Mystery' for field 'type': expected 'TUSummary', 'LUSummary', 'StaticLibrary', 'MultiArchStaticLibrary', or 'MultiArchSharedLibrary' diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/duplicate-target-triple.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/duplicate-target-triple.json new file mode 100644 index 0000000000000..f3142832581fb --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/duplicate-target-triple.json @@ -0,0 +1,37 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/invalid-syntax.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/invalid-syntax.json new file mode 100644 index 0000000000000..20d082b967157 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/invalid-syntax.json @@ -0,0 +1 @@ +{ broken \ No newline at end of file diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-empty-lu-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-empty-lu-namespace.json new file mode 100644 index 0000000000000..a8bdc5e79da9b --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-empty-lu-namespace.json @@ -0,0 +1,19 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-inner-error.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-inner-error.json new file mode 100644 index 0000000000000..5b6b7413b1738 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-inner-error.json @@ -0,0 +1,18 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-mismatched-type.json new file mode 100644 index 0000000000000..c48d5a5cc3eb4 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-mismatched-type.json @@ -0,0 +1,24 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "TUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-missing-type.json new file mode 100644 index 0000000000000..3630d1843e243 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-missing-type.json @@ -0,0 +1,23 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-namespace-mismatch.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-namespace-mismatch.json new file mode 100644 index 0000000000000..ab779950af56d --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-namespace-mismatch.json @@ -0,0 +1,24 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libbar" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-not-object.json new file mode 100644 index 0000000000000..8269b374cb602 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/member-not-object.json @@ -0,0 +1,12 @@ +{ + "members": [ + "not an object" + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/members-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/members-not-array.json new file mode 100644 index 0000000000000..7b84c5635327a --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/members-not-array.json @@ -0,0 +1,10 @@ +{ + "members": {}, + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/mismatched-type.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/mismatched-type.json new file mode 100644 index 0000000000000..3d7f01538bee1 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/mismatched-type.json @@ -0,0 +1,10 @@ +{ + "members": [], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchStaticLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-members.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-members.json new file mode 100644 index 0000000000000..5191a4f092f2d --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-members.json @@ -0,0 +1,9 @@ +{ + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-namespace.json new file mode 100644 index 0000000000000..66fb6bc008515 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-namespace.json @@ -0,0 +1,4 @@ +{ + "members": [], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-type.json new file mode 100644 index 0000000000000..79794ae546e1e --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/missing-type.json @@ -0,0 +1,9 @@ +{ + "members": [], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ] +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/namespace-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/namespace-not-array.json new file mode 100644 index 0000000000000..3dc32039cb74a --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/namespace-not-array.json @@ -0,0 +1,5 @@ +{ + "members": [], + "namespace": "libfoo", + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-json-extension.txt b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-json-extension.txt new file mode 100644 index 0000000000000..0967ef424bce6 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-json-extension.txt @@ -0,0 +1 @@ +{} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-object.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-object.json new file mode 100644 index 0000000000000..fe51488c7066f --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/not-object.json @@ -0,0 +1 @@ +[] diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-empty-members.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-empty-members.json new file mode 100644 index 0000000000000..1cd693b2fc8ce --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-empty-members.json @@ -0,0 +1,10 @@ +{ + "members": [], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-multiple-members.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-multiple-members.json new file mode 100644 index 0000000000000..d1de17900eb84 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-multiple-members.json @@ -0,0 +1,37 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-nonempty-members.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-nonempty-members.json new file mode 100644 index 0000000000000..dc00a24f0eaf0 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-nonempty-members.json @@ -0,0 +1,79 @@ +{ + "members": [ + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "suffix": "", + "usr": "c:@F@foo" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [ + { + "id": 0, + "name": { + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "suffix": "", + "usr": "c:@F@foo" + } + } + ], + "linkage_table": [ + { + "id": 0, + "linkage": { + "type": "External" + } + } + ], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-single-member.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-single-member.json new file mode 100644 index 0000000000000..bf7e570e21bf5 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-single-member.json @@ -0,0 +1,24 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-three-members.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-three-members.json new file mode 100644 index 0000000000000..ce123fe904dda --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/rt-three-members.json @@ -0,0 +1,50 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64_32-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-members-input.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-members-input.json new file mode 100644 index 0000000000000..3c47d9167107e --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-members-input.json @@ -0,0 +1,37 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-three-members-input.json b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-three-members-input.json new file mode 100644 index 0000000000000..ff5f5f88e134d --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/Inputs/unsorted-three-members-input.json @@ -0,0 +1,50 @@ +{ + "members": [ + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "x86_64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64-apple-macosx", + "type": "LUSummary" + }, + { + "data": [], + "id_table": [], + "linkage_table": [], + "lu_namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "target_triple": "arm64_32-apple-macosx", + "type": "LUSummary" + } + ], + "namespace": [ + { + "kind": "LinkUnit", + "name": "libfoo" + } + ], + "type": "MultiArchSharedLibrary" +} diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/io.test b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/io.test new file mode 100644 index 0000000000000..351149a6c8145 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/io.test @@ -0,0 +1,49 @@ +// File-I/O error tests: readJSON() input validation and writeJSON() output +// validation for clang-ssaf-format --type multi-arch-shared-library. + +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// ============================================================================ +// readJSON() errors +// ============================================================================ + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/nonexistent.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=NONEXISTENT-FILE +// NONEXISTENT-FILE: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent.json': Path does not exist + +// RUN: mkdir -p %t/test-directory.json +// RUN: not clang-ssaf-format --type multi-arch-shared-library %t/test-directory.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=PATH-IS-DIRECTORY +// PATH-IS-DIRECTORY: clang-ssaf-format: error: failed to validate path '{{.*}}test-directory.json': Path is not a file + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/not-json-extension.txt 2>&1 \ +// RUN: | FileCheck %s --check-prefix=NOT-JSON-EXTENSION +// NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}not-json-extension.txt': No format registered for extension 'txt' + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/invalid-syntax.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=INVALID-SYNTAX +// INVALID-SYNTAX: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}invalid-syntax.json' +// INVALID-SYNTAX-NEXT: {{.*}}Expected object key + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/not-object.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=NOT-OBJECT +// NOT-OBJECT: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}not-object.json' +// NOT-OBJECT-NEXT: failed to read MultiArchSharedLibrary: expected JSON object + +// ============================================================================ +// writeJSON() errors +// ============================================================================ + +// RUN: echo '{}' > %t/existing.json +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-single-member.json -o %t/existing.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=WRITE-FILE-ALREADY-EXISTS +// WRITE-FILE-ALREADY-EXISTS: clang-ssaf-format: error: failed to validate path '{{.*}}existing.json': File already exists + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-single-member.json -o %t/nonexistent-dir/test.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=WRITE-PARENT-DIRECTORY-NOT-FOUND +// WRITE-PARENT-DIRECTORY-NOT-FOUND: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent-dir{{.}}test.json': Parent directory does not exist + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-single-member.json -o %t/test.txt 2>&1 \ +// RUN: | FileCheck %s --check-prefix=WRITE-NOT-JSON-EXTENSION +// WRITE-NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}test.txt': No format registered for extension 'txt' diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/permissions.test b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/permissions.test new file mode 100644 index 0000000000000..bf873b5916440 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/permissions.test @@ -0,0 +1,40 @@ +// Tests for clang-ssaf-format --type multi-arch-shared-library that +// require filesystem permission support (symlinks, chmod). + +// UNSUPPORTED: system-windows +// REQUIRES: non-root-user + +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// ============================================================================ +// Broken symlink +// ============================================================================ + +// RUN: ln -sf %t/nonexistent-target.json %t/broken-symlink.json +// RUN: not clang-ssaf-format --type multi-arch-shared-library %t/broken-symlink.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=BROKEN-SYMLINK +// BROKEN-SYMLINK: clang-ssaf-format: error: failed to validate path '{{.*}}broken-symlink.json': Path does not exist + +// ============================================================================ +// No read permission +// ============================================================================ + +// RUN: cp %S/Inputs/rt-single-member.json %t/no-read-permission.json +// RUN: chmod -r %t/no-read-permission.json +// RUN: not clang-ssaf-format --type multi-arch-shared-library %t/no-read-permission.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=NO-READ-PERMISSION +// RUN: chmod +r %t/no-read-permission.json +// NO-READ-PERMISSION: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}no-read-permission.json' +// NO-READ-PERMISSION-NEXT: failed to read file '{{.*}}no-read-permission.json': {{.*}} + +// ============================================================================ +// Write to directory without write permission +// ============================================================================ + +// RUN: mkdir -p %t/write-protected-dir +// RUN: chmod -w %t/write-protected-dir +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-single-member.json -o %t/write-protected-dir/test.json 2>&1 \ +// RUN: | FileCheck %s --check-prefix=WRITE-STREAM-OPEN-FAILURE +// RUN: chmod +w %t/write-protected-dir +// WRITE-STREAM-OPEN-FAILURE: clang-ssaf-format: error: failed to validate path '{{.*}}write-protected-dir{{.}}test.json': Parent directory is not writable diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/round-trip.test new file mode 100644 index 0000000000000..9beb9068d4302 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/round-trip.test @@ -0,0 +1,55 @@ +// Round-trip tests: read a MultiArchSharedLibrary JSON input, write it +// back out, and diff the result against the original. +// +// MultiArchSharedLibrary has only an encoding representation, so +// --encoding is a no-op for --type multi-arch-shared-library and both +// invocations must produce the same output. + +// RUN: rm -rf %t +// RUN: mkdir -p %t + +// An empty members array is a valid (if degenerate) MultiArchSharedLibrary. +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-empty-members.json -o %t/rt-empty-members.json +// RUN: diff %S/Inputs/rt-empty-members.json %t/rt-empty-members.json +// RUN: clang-ssaf-format --type multi-arch-shared-library --encoding %S/Inputs/rt-empty-members.json -o %t/rt-empty-members-enc.json +// RUN: diff %S/Inputs/rt-empty-members.json %t/rt-empty-members-enc.json + +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-single-member.json -o %t/rt-single-member.json +// RUN: diff %S/Inputs/rt-single-member.json %t/rt-single-member.json +// RUN: clang-ssaf-format --type multi-arch-shared-library --encoding %S/Inputs/rt-single-member.json -o %t/rt-single-member-enc.json +// RUN: diff %S/Inputs/rt-single-member.json %t/rt-single-member-enc.json + +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-multiple-members.json -o %t/rt-multiple-members.json +// RUN: diff %S/Inputs/rt-multiple-members.json %t/rt-multiple-members.json +// RUN: clang-ssaf-format --type multi-arch-shared-library --encoding %S/Inputs/rt-multiple-members.json -o %t/rt-multiple-members-enc.json +// RUN: diff %S/Inputs/rt-multiple-members.json %t/rt-multiple-members-enc.json + +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-nonempty-members.json -o %t/rt-nonempty-members.json +// RUN: diff %S/Inputs/rt-nonempty-members.json %t/rt-nonempty-members.json +// RUN: clang-ssaf-format --type multi-arch-shared-library --encoding %S/Inputs/rt-nonempty-members.json -o %t/rt-nonempty-members-enc.json +// RUN: diff %S/Inputs/rt-nonempty-members.json %t/rt-nonempty-members-enc.json + +// ============================================================================ +// Member sort order +// ============================================================================ +// +// Members are stored in a std::set keyed by TargetTriple enum components, +// so the writer emits them in enum-tuple order regardless of input order. +// unsorted-members-input.json lists the members as x86_64, then arm64; +// the writer must produce the canonical (arm64, x86_64) ordering, byte +// identical to rt-multiple-members.json. + +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/unsorted-members-input.json -o %t/unsorted-members-output.json +// RUN: diff %S/Inputs/rt-multiple-members.json %t/unsorted-members-output.json +// RUN: clang-ssaf-format --type multi-arch-shared-library --encoding %S/Inputs/unsorted-members-input.json -o %t/unsorted-members-output-enc.json +// RUN: diff %S/Inputs/rt-multiple-members.json %t/unsorted-members-output-enc.json + +// 3-member ordering: confirms the sort isn't an accidental two-element +// swap. The unsorted input lists x86_64, arm64, arm64_32; the writer +// must produce (arm64, arm64_32, x86_64) — byte identical to +// rt-three-members.json. + +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/rt-three-members.json -o %t/rt-three-members.json +// RUN: diff %S/Inputs/rt-three-members.json %t/rt-three-members.json +// RUN: clang-ssaf-format --type multi-arch-shared-library %S/Inputs/unsorted-three-members-input.json -o %t/unsorted-three-members-output.json +// RUN: diff %S/Inputs/rt-three-members.json %t/unsorted-three-members-output.json diff --git a/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/top-level.test new file mode 100644 index 0000000000000..c0f9aa2bef153 --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/MultiArchSharedLibrary/top-level.test @@ -0,0 +1,105 @@ +// Top-level MultiArchSharedLibrary structure tests: type discriminator, +// namespace identity, members array, and per-member validation including +// duplicate-target-triple and namespace-mismatch rejection. + +// ============================================================================ +// readMultiArchSharedLibrary() / writeMultiArchSharedLibrary() type-field +// errors +// ============================================================================ + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/missing-type.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-TYPE +// MISSING-TYPE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}missing-type.json' +// MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/mismatched-type.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MISMATCHED-TYPE +// MISMATCHED-TYPE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}mismatched-type.json' +// MISMATCHED-TYPE-NEXT: expected 'MultiArchSharedLibrary' for field 'type' but got 'MultiArchStaticLibrary' + +// ============================================================================ +// namespace field errors +// ============================================================================ + +// The top-level namespace is required and must be a JSON array of +// BuildNamespace steps. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/missing-namespace.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-NAMESPACE +// MISSING-NAMESPACE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}missing-namespace.json' +// MISSING-NAMESPACE-NEXT: failed to read NestedBuildNamespace from field 'namespace': expected JSON array + +// The namespace field must be a JSON array, not a string. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/namespace-not-array.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-NOT-ARRAY +// NAMESPACE-NOT-ARRAY: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}namespace-not-array.json' +// NAMESPACE-NOT-ARRAY-NEXT: failed to read NestedBuildNamespace from field 'namespace': expected JSON array + +// ============================================================================ +// members field errors +// ============================================================================ + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/missing-members.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-MEMBERS +// MISSING-MEMBERS: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}missing-members.json' +// MISSING-MEMBERS-NEXT: failed to read MultiArchSharedLibrary members from field 'members': expected JSON array + +// The members field must be a JSON array, not an object. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/members-not-array.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBERS-NOT-ARRAY +// MEMBERS-NOT-ARRAY: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}members-not-array.json' +// MEMBERS-NOT-ARRAY-NEXT: failed to read MultiArchSharedLibrary members from field 'members': expected JSON array + +// ============================================================================ +// per-member errors +// ============================================================================ + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-not-object.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-NOT-OBJECT +// MEMBER-NOT-OBJECT: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-not-object.json' +// MEMBER-NOT-OBJECT-NEXT: failed to read MultiArchSharedLibrary member from index '0': expected JSON object + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-missing-type.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-MISSING-TYPE +// MEMBER-MISSING-TYPE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-missing-type.json' +// MEMBER-MISSING-TYPE-NEXT: reading MultiArchSharedLibrary member from index '0' +// MEMBER-MISSING-TYPE-NEXT: failed to read summary type from field 'type': expected JSON string + +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-mismatched-type.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-MISMATCHED-TYPE +// MEMBER-MISMATCHED-TYPE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-mismatched-type.json' +// MEMBER-MISMATCHED-TYPE-NEXT: reading MultiArchSharedLibrary member from index '0' +// MEMBER-MISMATCHED-TYPE-NEXT: expected 'LUSummary' for field 'type' but got 'TUSummary' + +// Each member is a per-arch slice of the same shared library, so its +// lu_namespace must equal the wrapper's namespace exactly. A member +// whose leaf-step name diff ers from the wrapper's is rejected. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-namespace-mismatch.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-NAMESPACE-MISMATCH +// MEMBER-NAMESPACE-MISMATCH: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-namespace-mismatch.json' +// MEMBER-NAMESPACE-MISMATCH-NEXT: reading MultiArchSharedLibrary member from index '0' +// MEMBER-NAMESPACE-MISMATCH-NEXT: field 'lu_namespace' does not equal the enclosing artifact's namespace + +// A member with an empty lu_namespace array cannot equal the wrapper's +// (non-empty) namespace, so the equality check also fires. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-empty-lu-namespace.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-EMPTY-LU-NAMESPACE +// MEMBER-EMPTY-LU-NAMESPACE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-empty-lu-namespace.json' +// MEMBER-EMPTY-LU-NAMESPACE-NEXT: reading MultiArchSharedLibrary member from index '0' +// MEMBER-EMPTY-LU-NAMESPACE-NEXT: field 'lu_namespace' does not equal the enclosing artifact's namespace + +// Members are identified by their full target_triple. Two members sharing +// the same target_triple are rejected. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/duplicate-target-triple.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-TARGET-TRIPLE +// DUPLICATE-TARGET-TRIPLE: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}duplicate-target-triple.json' +// DUPLICATE-TARGET-TRIPLE-NEXT: failed to insert MultiArchSharedLibrary member at index '1': encountered duplicate 'arm64-apple-macosx' + +// Verifies that errors raised inside readLUSummaryEncodingFromObject (here, a +// missing lu_namespace on the member) are properly wrapped with the +// "reading MultiArchSharedLibrary member from index 'N'" context, then +// with the outer "reading MultiArchSharedLibrary from file '...'" context. +// RUN: not clang-ssaf-format --type multi-arch-shared-library %S/Inputs/member-inner-error.json 2>&1 \ +// RUN: | FileCheck %s --match-full-lines --check-prefix=MEMBER-INNER-ERROR +// MEMBER-INNER-ERROR: clang-ssaf-format: error: reading MultiArchSharedLibrary from file '{{.*}}member-inner-error.json' +// MEMBER-INNER-ERROR-NEXT: reading MultiArchSharedLibrary member from index '0' +// MEMBER-INNER-ERROR-NEXT: failed to read NestedBuildNamespace from field 'lu_namespace': expected JSON array diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp b/clang/tools/clang-ssaf-format/SSAFFormat.cpp index b0f123f75be2a..7317424d2ca42 100644 --- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp +++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h" @@ -47,6 +48,7 @@ enum class SummaryType { LU, StaticLibrary, MultiArchStaticLibrary, + MultiArchSharedLibrary, WPA }; @@ -77,6 +79,9 @@ cl::opt<SummaryType> Type( clEnumValN(SummaryType::MultiArchStaticLibrary, "multi-arch-static-library", "Multi-architecture static library"), + clEnumValN(SummaryType::MultiArchSharedLibrary, + "multi-arch-shared-library", + "Multi-architecture shared library"), clEnumValN(SummaryType::WPA, "wpa", "Whole-program analysis suite")), cl::init(SummaryType::Auto), cl::cat(SsafFormatCategory)); @@ -322,6 +327,13 @@ void convert(const FormatInput &FI) { run(FI, &SerializationFormat::readMultiArchStaticLibrary, &SerializationFormat::writeMultiArchStaticLibrary); return; + case SummaryType::MultiArchSharedLibrary: + // MultiArchSharedLibrary has only an encoded representation, so + // --encoding is a no-op here: both paths route to + // readMultiArchSharedLibrary / writeMultiArchSharedLibrary. + run(FI, &SerializationFormat::readMultiArchSharedLibrary, + &SerializationFormat::writeMultiArchSharedLibrary); + return; case SummaryType::WPA: run(FI, &SerializationFormat::readWPASuite, &SerializationFormat::writeWPASuite); diff --git a/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp b/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp index 79504a4f9754f..ab2b406850489 100644 --- a/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp +++ b/clang/unittests/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendActionTest.cpp @@ -118,6 +118,16 @@ class FailingSerializationFormat final : public SerializationFormat { return failing("writeMultiArchStaticLibrary"); } + llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibrary(llvm::StringRef Path) override { + return failing("readMultiArchSharedLibrary"); + } + + llvm::Error writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, + llvm::StringRef Path) override { + return failing("writeMultiArchSharedLibrary"); + } + llvm::Expected<WPASuite> readWPASuite(llvm::StringRef Path) override { return failing("readWPASuite"); } @@ -214,6 +224,14 @@ class CapturingSerializationFormat final : public SerializationFormat { llvm::StringRef) override { return llvm::Error::success(); } + llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibrary(llvm::StringRef) override { + return llvm::createStringError("not implemented"); + } + llvm::Error writeMultiArchSharedLibrary(const MultiArchSharedLibrary &, + llvm::StringRef) override { + return llvm::Error::success(); + } llvm::Expected<WPASuite> readWPASuite(llvm::StringRef) override { return llvm::createStringError("not implemented"); } diff --git a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp index 92d6d0abc8936..236e81a16b56e 100644 --- a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp +++ b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.cpp @@ -9,6 +9,7 @@ #include "Registries/MockSerializationFormat.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h" @@ -222,6 +223,18 @@ llvm::Error MockSerializationFormat::writeMultiArchStaticLibrary( "MockSerializationFormat does not support MultiArchStaticLibrary"); } +llvm::Expected<MultiArchSharedLibrary> +MockSerializationFormat::readMultiArchSharedLibrary(llvm::StringRef Path) { + llvm_unreachable( + "MockSerializationFormat does not support MultiArchSharedLibrary"); +} + +llvm::Error MockSerializationFormat::writeMultiArchSharedLibrary( + const MultiArchSharedLibrary &M, llvm::StringRef Path) { + llvm_unreachable( + "MockSerializationFormat does not support MultiArchSharedLibrary"); +} + llvm::Expected<WPASuite> MockSerializationFormat::readWPASuite(llvm::StringRef Path) { llvm_unreachable("MockSerializationFormat does not support WPASuite"); diff --git a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h index e03e5092589fe..f5f44c51d3e97 100644 --- a/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h +++ b/clang/unittests/ScalableStaticAnalysis/Registries/MockSerializationFormat.h @@ -56,6 +56,12 @@ class MockSerializationFormat final : public SerializationFormat { llvm::Error writeMultiArchStaticLibrary(const MultiArchStaticLibrary &M, llvm::StringRef Path) override; + llvm::Expected<MultiArchSharedLibrary> + readMultiArchSharedLibrary(llvm::StringRef Path) override; + + llvm::Error writeMultiArchSharedLibrary(const MultiArchSharedLibrary &M, + llvm::StringRef Path) override; + llvm::Expected<Artifact> readArtifact(llvm::StringRef Path) override; llvm::Error writeArtifact(const Artifact &A, llvm::StringRef Path) override; diff --git a/clang/unittests/ScalableStaticAnalysis/TestFixture.h b/clang/unittests/ScalableStaticAnalysis/TestFixture.h index c2b7005bd4b0c..cb33dd57a31a9 100644 --- a/clang/unittests/ScalableStaticAnalysis/TestFixture.h +++ b/clang/unittests/ScalableStaticAnalysis/TestFixture.h @@ -11,6 +11,7 @@ #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/LUSummaryEncoding.h" +#include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchSharedLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/MultiArchStaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/StaticLibrary.h" #include "clang/ScalableStaticAnalysis/Core/EntityLinker/TUSummaryEncoding.h" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
