[Serialization] Preparation for giving swiftdoc its own version

The functionality change in this commit is that the control block in a
swiftdoc file is validated rather than just being ignored. Tests in
following commit.
This commit is contained in:
Jordan Rose
2018-09-20 15:59:24 -07:00
parent 81c24cded6
commit f3ea8bdd55
9 changed files with 201 additions and 133 deletions

View File

@@ -12,6 +12,7 @@
#include "swift/Serialization/ModuleFile.h"
#include "DeserializationErrors.h"
#include "DocFormat.h"
#include "swift/Serialization/ModuleFormat.h"
#include "swift/Subsystems.h"
#include "swift/AST/ASTContext.h"
@@ -36,15 +37,9 @@ using namespace swift::serialization;
using namespace llvm::support;
using llvm::Expected;
static bool checkModuleSignature(llvm::BitstreamCursor &cursor) {
for (unsigned char byte : MODULE_SIGNATURE)
if (cursor.AtEndOfStream() || cursor.Read(8) != byte)
return false;
return true;
}
static bool checkModuleDocSignature(llvm::BitstreamCursor &cursor) {
for (unsigned char byte : MODULE_DOC_SIGNATURE)
static bool checkModuleSignature(llvm::BitstreamCursor &cursor,
ArrayRef<unsigned char> signature) {
for (unsigned char byte : signature)
if (cursor.AtEndOfStream() || cursor.Read(8) != byte)
return false;
return true;
@@ -179,9 +174,9 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
}
uint16_t versionMajor = scratch[0];
if (versionMajor > VERSION_MAJOR)
if (versionMajor > SWIFTMODULE_VERSION_MAJOR)
result.status = Status::FormatTooNew;
else if (versionMajor < VERSION_MAJOR)
else if (versionMajor < SWIFTMODULE_VERSION_MAJOR)
result.status = Status::FormatTooOld;
else
result.status = Status::Valid;
@@ -189,8 +184,8 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
// Major version 0 does not have stable minor versions.
if (versionMajor == 0) {
uint16_t versionMinor = scratch[1];
if (versionMinor != VERSION_MINOR) {
if (versionMinor < VERSION_MINOR)
if (versionMinor != SWIFTMODULE_VERSION_MINOR) {
if (versionMinor < SWIFTMODULE_VERSION_MINOR)
result.status = Status::FormatTooOld;
else
result.status = Status::FormatTooNew;
@@ -202,9 +197,11 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
default:
// Add new cases here, in descending order.
case 4:
result.compatibilityVersion =
version::Version(blobData.substr(scratch[2]+1, scratch[3]),
SourceLoc(), nullptr);
if (scratch[3] != 0) {
result.compatibilityVersion =
version::Version(blobData.substr(scratch[2]+1, scratch[3]),
SourceLoc(), nullptr);
}
LLVM_FALLTHROUGH;
case 3:
result.shortVersion = blobData.slice(0, scratch[2]);
@@ -235,8 +232,8 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
}
bool serialization::isSerializedAST(StringRef data) {
StringRef signatureStr(reinterpret_cast<const char *>(MODULE_SIGNATURE),
llvm::array_lengthof(MODULE_SIGNATURE));
StringRef signatureStr(reinterpret_cast<const char *>(SWIFTMODULE_SIGNATURE),
llvm::array_lengthof(SWIFTMODULE_SIGNATURE));
return data.startswith(signatureStr);
}
@@ -253,7 +250,7 @@ ValidationInfo serialization::validateSerializedAST(
llvm::BitstreamCursor cursor(data);
SmallVector<uint64_t, 32> scratch;
if (!checkModuleSignature(cursor) ||
if (!checkModuleSignature(cursor, SWIFTMODULE_SIGNATURE) ||
!enterTopLevelModuleBlock(cursor, MODULE_BLOCK_ID, false))
return result;
@@ -1084,6 +1081,62 @@ static bool isTargetTooNew(const llvm::Triple &moduleTarget,
return ctxTarget.isOSVersionLT(major, minor, micro);
}
bool ModuleFile::readModuleDocIfPresent() {
if (!this->ModuleDocInputBuffer)
return true;
llvm::BitstreamCursor docCursor{ModuleDocInputBuffer->getMemBufferRef()};
if (!checkModuleSignature(docCursor, SWIFTDOC_SIGNATURE) ||
!enterTopLevelModuleBlock(docCursor, MODULE_DOC_BLOCK_ID)) {
return false;
}
SmallVector<uint64_t, 64> scratch;
llvm::BitstreamEntry topLevelEntry;
bool hasValidControlBlock = false;
ValidationInfo info;
while (!docCursor.AtEndOfStream()) {
topLevelEntry = docCursor.advance(AF_DontPopBlockAtEnd);
if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock)
break;
switch (topLevelEntry.ID) {
case CONTROL_BLOCK_ID: {
docCursor.EnterSubBlock(CONTROL_BLOCK_ID);
info = validateControlBlock(docCursor, scratch, /*extendedInfo*/nullptr);
if (info.status != Status::Valid)
return false;
// Check that the swiftdoc is actually for this module.
if (info.name != Name)
return false;
hasValidControlBlock = true;
break;
}
case COMMENT_BLOCK_ID: {
if (!hasValidControlBlock || !readCommentBlock(docCursor))
return false;
break;
}
default:
// Unknown top-level block, possibly for use by a future version of the
// module format.
if (docCursor.SkipBlock())
return false;
break;
}
}
if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock)
return false;
return true;
}
ModuleFile::ModuleFile(
std::unique_ptr<llvm::MemoryBuffer> moduleInputBuffer,
std::unique_ptr<llvm::MemoryBuffer> moduleDocInputBuffer,
@@ -1099,7 +1152,7 @@ ModuleFile::ModuleFile(
llvm::BitstreamCursor cursor{ModuleInputBuffer->getMemBufferRef()};
if (!checkModuleSignature(cursor) ||
if (!checkModuleSignature(cursor, SWIFTMODULE_SIGNATURE) ||
!enterTopLevelModuleBlock(cursor, MODULE_BLOCK_ID)) {
error();
return;
@@ -1313,42 +1366,7 @@ ModuleFile::ModuleFile(
return;
}
if (!this->ModuleDocInputBuffer)
return;
llvm::BitstreamCursor docCursor{ModuleDocInputBuffer->getMemBufferRef()};
if (!checkModuleDocSignature(docCursor) ||
!enterTopLevelModuleBlock(docCursor, MODULE_DOC_BLOCK_ID)) {
error(Status::MalformedDocumentation);
return;
}
while (!docCursor.AtEndOfStream()) {
topLevelEntry = docCursor.advance(AF_DontPopBlockAtEnd);
if (topLevelEntry.Kind != llvm::BitstreamEntry::SubBlock)
break;
switch (topLevelEntry.ID) {
case COMMENT_BLOCK_ID: {
if (!hasValidControlBlock || !readCommentBlock(docCursor)) {
error(Status::MalformedDocumentation);
return;
}
break;
}
default:
// Unknown top-level block, possibly for use by a future version of the
// module format.
if (docCursor.SkipBlock()) {
error(Status::MalformedDocumentation);
return;
}
break;
}
}
if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock) {
if (!readModuleDocIfPresent()) {
error(Status::MalformedDocumentation);
return;
}