Files
swift-mirror/include/swift/Serialization/Validation.h
Alexis Laferrière c38d1773d2 [Serialization] Restrict loading swiftmodule files to the builder's SDK
Serialize the canonical name of the SDK used when building a swiftmodule
file and use it to ensure that the swiftmodule file is loaded only with
the same SDK. The SDK name must be passed down from the frontend.

This will report unsupported configurations like:

- Installing roots between incompatible SDKs without deleting the
swiftmodule files.
- Having multiple targets in the same project using different SDKs.
- Loading a swiftmodule created with a newer SDK (and stdlib) with an
older SDK.

All of these lead to hard to investigate deserialization failures and
this change should detect them early, before reaching a deserialization
failure.

rdar://78048939
2021-09-13 16:44:08 -07:00

217 lines
7.3 KiB
C++

//===--- Validation.h - Validation / errors for serialization ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SERIALIZATION_VALIDATION_H
#define SWIFT_SERIALIZATION_VALIDATION_H
#include "swift/Basic/LLVM.h"
#include "swift/Serialization/SerializationOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
namespace swift {
class ModuleFile;
enum class ResilienceStrategy : unsigned;
namespace serialization {
/// Describes whether a serialized module can be used by this compiler.
enum class Status {
/// The module is valid.
Valid,
/// The module file format is too old to be used by this version of the
/// compiler.
FormatTooOld,
/// The module file format is too new to be used by this version of the
/// compiler.
FormatTooNew,
/// The module file depends on another module that can't be loaded.
MissingDependency,
/// The module file is an overlay for a Clang module, which can't be found.
MissingUnderlyingModule,
/// The module file depends on a module that is still being loaded, i.e.
/// there is a circular dependency.
CircularDependency,
/// The module file depends on a bridging header that can't be loaded.
FailedToLoadBridgingHeader,
/// The module file is malformed in some way.
Malformed,
/// The module documentation file is malformed in some way.
MalformedDocumentation,
/// The module file's name does not match the module it is being loaded
/// into.
NameMismatch,
/// The module file was built for a different target platform.
TargetIncompatible,
/// The module file was built for a target newer than the current target.
TargetTooNew,
/// The module file was built with a different SDK than the one in use
/// to build the client.
SDKMismatch
};
/// Returns true if the data looks like it contains a serialized AST.
bool isSerializedAST(StringRef data);
/// \see validateSerializedAST()
struct ValidationInfo {
StringRef name = {};
StringRef targetTriple = {};
StringRef shortVersion = {};
StringRef miscVersion = {};
version::Version compatibilityVersion = {};
llvm::VersionTuple userModuleVersion;
StringRef sdkName = {};
size_t bytes = 0;
Status status = Status::Malformed;
};
/// A collection of options that can be used to set up a new AST context
/// before it has been created.
///
/// Note that this is intended to be a transient data structure; as such,
/// <strong>none of the string values added to it are copied</strong>.
///
/// \sa validateSerializedAST()
class ExtendedValidationInfo {
SmallVector<StringRef, 4> ExtraClangImporterOpts;
StringRef SDKPath;
StringRef ModuleABIName;
struct {
unsigned ArePrivateImportsEnabled : 1;
unsigned IsSIB : 1;
unsigned IsStaticLibrary: 1;
unsigned IsTestable : 1;
unsigned ResilienceStrategy : 2;
unsigned IsImplicitDynamicEnabled : 1;
unsigned IsAllowModuleWithCompilerErrorsEnabled : 1;
unsigned IsConcurrencyChecked : 1;
} Bits;
public:
ExtendedValidationInfo() : Bits() {}
StringRef getSDKPath() const { return SDKPath; }
void setSDKPath(StringRef path) {
assert(SDKPath.empty());
SDKPath = path;
}
ArrayRef<StringRef> getExtraClangImporterOptions() const {
return ExtraClangImporterOpts;
}
void addExtraClangImporterOption(StringRef option) {
ExtraClangImporterOpts.push_back(option);
}
bool isSIB() const { return Bits.IsSIB; }
void setIsSIB(bool val) {
Bits.IsSIB = val;
}
bool arePrivateImportsEnabled() { return Bits.ArePrivateImportsEnabled; }
void setPrivateImportsEnabled(bool enabled) {
Bits.ArePrivateImportsEnabled = enabled;
}
bool isImplicitDynamicEnabled() { return Bits.IsImplicitDynamicEnabled; }
void setImplicitDynamicEnabled(bool val) {
Bits.IsImplicitDynamicEnabled = val;
}
bool isStaticLibrary() const { return Bits.IsStaticLibrary; }
void setIsStaticLibrary(bool val) {
Bits.IsStaticLibrary = val;
}
bool isTestable() const { return Bits.IsTestable; }
void setIsTestable(bool val) {
Bits.IsTestable = val;
}
ResilienceStrategy getResilienceStrategy() const {
return ResilienceStrategy(Bits.ResilienceStrategy);
}
void setResilienceStrategy(ResilienceStrategy resilience) {
Bits.ResilienceStrategy = unsigned(resilience);
}
bool isAllowModuleWithCompilerErrorsEnabled() {
return Bits.IsAllowModuleWithCompilerErrorsEnabled;
}
void setAllowModuleWithCompilerErrorsEnabled(bool val) {
Bits.IsAllowModuleWithCompilerErrorsEnabled = val;
}
StringRef getModuleABIName() const { return ModuleABIName; }
void setModuleABIName(StringRef name) { ModuleABIName = name; }
bool isConcurrencyChecked() const {
return Bits.IsConcurrencyChecked;
}
void setIsConcurrencyChecked(bool val = true) {
Bits.IsConcurrencyChecked = val;
}
};
/// Returns info about the serialized AST in the given data.
///
/// If the returned status is anything but Status::Valid, the serialized data
/// cannot be loaded by this version of the compiler. If the returned size is
/// non-zero, it's possible to skip over this module's data, in case there is
/// more data in the buffer. The returned name, which may be empty, directly
/// points into the given data buffer.
///
/// Note that this does not actually try to load the module or validate any
/// of its dependencies; it only checks that it /can/ be loaded.
///
/// \param data A buffer containing the serialized AST. Result information
/// refers directly into this buffer.
/// \param[out] extendedInfo If present, will be populated with additional
/// compilation options serialized into the AST at build time that may be
/// necessary to load it properly.
/// \param[out] dependencies If present, will be populated with list of
/// input files the module depends on, if present in INPUT_BLOCK.
ValidationInfo validateSerializedAST(
StringRef data, ExtendedValidationInfo *extendedInfo = nullptr,
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies =
nullptr);
/// Emit diagnostics explaining a failure to load a serialized AST.
///
/// - \p Ctx is an AST context through which any diagnostics are surfaced.
/// - \p diagLoc is the (possibly invalid) location used in the diagnostics.
/// - \p loadInfo and \p extendedInfo describe the attempt to load an AST
/// (\ref validateSerializedAST). Note that loadInfo.Status must not be
/// Status::Valid.
/// - \p moduleBufferID and \p moduleDocBufferID are the buffer identifiers
/// of the module input and doc input buffers respectively (\ref
/// SerializedModuleLoaderBase::loadAST, \ref ModuleFile::load).
/// - \p loadedModuleFile is an invalid loaded module.
/// - \p ModuleName is the name used to refer to the module in diagnostics.
void diagnoseSerializedASTLoadFailure(
ASTContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo,
StringRef moduleBufferID, StringRef moduleDocBufferID,
ModuleFile *loadedModuleFile, Identifier ModuleName);
} // end namespace serialization
} // end namespace swift
#endif