Skip to content

[InstallAPI] Introduce Basic Verifier #85106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/AST/Availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ struct AvailabilityInfo {
/// Determine if this AvailabilityInfo represents the default availability.
bool isDefault() const { return *this == AvailabilityInfo(); }

/// Check if the symbol has been obsoleted.
bool isObsoleted() const { return !Obsoleted.empty(); }

/// Check if the symbol is unconditionally deprecated.
///
/// i.e. \code __attribute__((deprecated)) \endcode
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/InstallAPI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "clang/InstallAPI/MachO.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -45,6 +46,9 @@ struct InstallAPIContext {
/// DiagnosticsEngine for all error reporting.
DiagnosticsEngine *Diags = nullptr;

/// Verifier when binary dylib is passed as input.
std::unique_ptr<DylibVerifier> Verifier = nullptr;

/// File Path of output location.
llvm::StringRef OutputLoc{};

Expand Down
79 changes: 78 additions & 1 deletion clang/include/clang/InstallAPI/DylibVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
#ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
#define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H

#include "llvm/TextAPI/Target.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/InstallAPI/MachO.h"

namespace clang {
namespace installapi {
struct FrontendAttrs;

/// A list of InstallAPI verification modes.
enum class VerificationMode {
Expand All @@ -22,6 +24,81 @@ enum class VerificationMode {
Pedantic,
};

/// Service responsible to tracking state of verification across the
/// lifetime of InstallAPI.
/// As declarations are collected during AST traversal, they are
/// compared as symbols against what is available in the binary dylib.
class DylibVerifier {
private:
struct SymbolContext;

public:
enum class Result { NoVerify, Ignore, Valid, Invalid };
struct VerifierContext {
// Current target being verified against the AST.
llvm::MachO::Target Target;

// Query state of verification after AST has been traversed.
Result FrontendState;

// First error for AST traversal, which is tied to the target triple.
bool DiscoveredFirstError;
};

DylibVerifier() = default;

DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
VerificationMode Mode, bool Demangle)
: Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle),
Exports(std::make_unique<SymbolSet>()) {}

Result verify(GlobalRecord *R, const FrontendAttrs *FA);
Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
Result verify(ObjCIVarRecord *R, const FrontendAttrs *FA,
const StringRef SuperClass);

/// Initialize target for verification.
void setTarget(const Target &T);

/// Release ownership over exports.
std::unique_ptr<SymbolSet> getExports() { return std::move(Exports); }

/// Get result of verification.
Result getState() const { return Ctx.FrontendState; }

private:
/// Determine whether to compare declaration to symbol in binary.
bool canVerify();

/// Shared implementation for verifying exported symbols.
Result verifyImpl(Record *R, SymbolContext &SymCtx);

/// Update result state on each call to `verify`.
void updateState(Result State);

/// Add verified exported symbol.
void addSymbol(const Record *R, SymbolContext &SymCtx,
TargetList &&Targets = {});

// Symbols in dylib.
llvm::MachO::Records Dylib;

// Engine for reporting violations.
[[maybe_unused]] DiagnosticsEngine *Diag = nullptr;

// Controls what class of violations to report.
[[maybe_unused]] VerificationMode Mode = VerificationMode::Invalid;

// Attempt to demangle when reporting violations.
bool Demangle = false;

// Valid symbols in final text file.
std::unique_ptr<SymbolSet> Exports = std::make_unique<SymbolSet>();

// Track current state of verification while traversing AST.
VerifierContext Ctx;
};

} // namespace installapi
} // namespace clang
#endif // LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
1 change: 0 additions & 1 deletion clang/include/clang/InstallAPI/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#define LLVM_CLANG_INSTALLAPI_FRONTEND_H

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/Availability.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"
Expand Down
49 changes: 26 additions & 23 deletions clang/include/clang/InstallAPI/FrontendRecords.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param Flags The flags that describe attributes of the symbol.
/// \param Inlined Whether declaration is inlined, only applicable to
/// functions.
/// \return The non-owning pointer to added record in slice.
GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D,
const HeaderType Access,
SymbolFlags Flags = SymbolFlags::None,
bool Inlined = false);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<GlobalRecord *, FrontendAttrs *>
addGlobal(StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D,
const HeaderType Access, SymbolFlags Flags = SymbolFlags::None,
bool Inlined = false);

/// Add ObjC Class record with attributes from AST.
///
Expand All @@ -60,11 +60,12 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param IsEHType Whether declaration has an exception attribute.
/// \return The non-owning pointer to added record in slice.
ObjCInterfaceRecord *addObjCInterface(StringRef Name, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
bool IsEHType);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
addObjCInterface(StringRef Name, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D,
HeaderType Access, bool IsEHType);

/// Add ObjC Category record with attributes from AST.
///
Expand All @@ -75,11 +76,12 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// to the active target triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \return The non-owning pointer to added record in slice.
ObjCCategoryRecord *addObjCCategory(StringRef ClassToExtend,
StringRef CategoryName,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCCategoryRecord *, FrontendAttrs *>
addObjCCategory(StringRef ClassToExtend, StringRef CategoryName,
const clang::AvailabilityInfo Avail, const Decl *D,
HeaderType Access);

/// Add ObjC IVar record with attributes from AST.
///
Expand All @@ -91,12 +93,13 @@ class FrontendRecordsSlice : public llvm::MachO::RecordsSlice {
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param AC The access control tied to the ivar declaration.
/// \return The non-owning pointer to added record in slice.
ObjCIVarRecord *addObjCIVar(ObjCContainerRecord *Container,
StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);
/// \return The non-owning pointer to added record in slice with it's frontend
/// attributes.
std::pair<ObjCIVarRecord *, FrontendAttrs *>
addObjCIVar(ObjCContainerRecord *Container, StringRef IvarName,
RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC);

private:
/// Mapping of records stored in slice to their frontend attributes.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/InstallAPI/MachO.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/TextAPI/PackedVersion.h"
#include "llvm/TextAPI/Platform.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/Symbol.h"
#include "llvm/TextAPI/Target.h"
#include "llvm/TextAPI/TextAPIWriter.h"
#include "llvm/TextAPI/Utils.h"
Expand All @@ -33,8 +34,10 @@ using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
using Records = llvm::MachO::Records;
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
using SymbolSet = llvm::MachO::SymbolSet;
using SimpleSymbol = llvm::MachO::SimpleSymbol;
using FileType = llvm::MachO::FileType;
using PackedVersion = llvm::MachO::PackedVersion;
using Target = llvm::MachO::Target;
using TargetList = llvm::MachO::TargetList;

#endif // LLVM_CLANG_INSTALLAPI_MACHO_H
2 changes: 2 additions & 0 deletions clang/lib/InstallAPI/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
set(LLVM_LINK_COMPONENTS
Support
TextAPI
Demangle
Core
)

add_clang_library(clangInstallAPI
DylibVerifier.cpp
FileList.cpp
Frontend.cpp
HeaderFile.cpp
Expand Down
Loading