Validate that SPIR-V binary is encoded as little endian for WebGPU (#2523)

Fixes #2522
This commit is contained in:
Ryan Harrison 2019-04-17 12:44:54 -04:00 committed by GitHub
parent 3aad3e9228
commit 21712068fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 0 deletions

View File

@ -281,6 +281,12 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
<< "Invalid SPIR-V magic number.";
}
if (spvIsWebGPUEnv(context.target_env) && endian != SPV_ENDIANNESS_LITTLE) {
return DiagnosticStream(position, context.consumer, "",
SPV_ERROR_INVALID_BINARY)
<< "WebGPU requires SPIR-V to be little endian.";
}
spv_header_t header;
if (spvBinaryHeaderGet(binary.get(), endian, &header)) {
return DiagnosticStream(position, context.consumer, "",

View File

@ -276,6 +276,63 @@ TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelExtensionBad) {
"\"SPV_KHR_8bit_storage\"\n"));
}
spv_binary GenerateTrivialBinary(bool need_little_endian) {
// Smallest possible valid WebGPU SPIR-V binary in little endian. Contains all
// the required boilerplate and a trivial entry point function.
static const uint8_t binary_bytes[] = {
// clang-format off
0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0xE1, 0x14, 0x00, 0x00,
0x0A, 0x00, 0x08, 0x00, 0x53, 0x50, 0x56, 0x5F, 0x4B, 0x48, 0x52, 0x5F,
0x76, 0x75, 0x6C, 0x6B, 0x61, 0x6E, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72,
0x79, 0x5F, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x00, 0x0E, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x64,
0x65, 0x72, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x04, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00
// clang-format on
};
static const size_t word_count = sizeof(binary_bytes) / sizeof(uint32_t);
std::unique_ptr<spv_binary_t> result(new spv_binary_t);
if (!result) return nullptr;
result->wordCount = word_count;
result->code = new uint32_t[word_count];
if (!result->code) return nullptr;
if (need_little_endian) {
memcpy(result->code, binary_bytes, sizeof(binary_bytes));
} else {
uint8_t* code_bytes = reinterpret_cast<uint8_t*>(result->code);
for (size_t word = 0; word < word_count; ++word) {
code_bytes[4 * word] = binary_bytes[4 * word + 3];
code_bytes[4 * word + 1] = binary_bytes[4 * word + 2];
code_bytes[4 * word + 2] = binary_bytes[4 * word + 1];
code_bytes[4 * word + 3] = binary_bytes[4 * word];
}
}
return result.release();
}
TEST_F(ValidateWebGPU, LittleEndianGood) {
DestroyBinary();
binary_ = GenerateTrivialBinary(true);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
}
TEST_F(ValidateWebGPU, BigEndianBad) {
DestroyBinary();
binary_ = GenerateTrivialBinary(false);
EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("WebGPU requires SPIR-V to be little endian."));
}
} // namespace
} // namespace val
} // namespace spvtools