spv: reject invalid SPIR-V

Use the SPIRV-Tools validator, with the WebGPU0 environment.

Bug: tint:3
Change-Id: Id1132d209fd939ed68587034761e97da9b35b21d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/16821
Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
David Neto 2020-03-13 20:18:06 +00:00
parent 1ae7c7dba9
commit e5dc367a7e
5 changed files with 109 additions and 4 deletions

View File

@ -319,6 +319,7 @@ endif()
if(${TINT_BUILD_SPV_PARSER})
list (APPEND TINT_TEST_SRCS
reader/spv/fail_stream_test.cc
reader/spv/parser_impl_test.cc
reader/spv/parser_test.cc
)
endif()

View File

@ -14,6 +14,7 @@
#include <cstring>
#include "spirv-tools/libspirv.hpp"
#include "src/reader/spv/parser_impl.h"
namespace tint {
@ -26,9 +27,33 @@ ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
ParserImpl::~ParserImpl() = default;
bool ParserImpl::Parse() {
// Exit early if we've already failed.
if (!success_) {
return false;
}
// Set up use of SPIRV-Tools utilities.
// TODO(dneto): Add option to handle other environments.
spvtools::SpirvTools spv_tools(SPV_ENV_WEBGPU_0);
// Error messages from SPIRV-Tools are forwarded as failures.
auto message_consumer =
[this](spv_message_level_t level, const char* /*source*/,
const spv_position_t& position, const char* message) {
switch (level) {
// Drop info and warning message.
case SPV_MSG_WARNING:
case SPV_MSG_INFO:
default:
// For binary validation errors, we only have the instruction
// number. It's not text, so there is no column number.
this->Fail() << "line:" << position.index << ": " << message;
}
};
spv_tools.SetMessageConsumer(message_consumer);
// Only consider valid modules.
if (success_) {
Fail() << "SPIR-V parsing is not supported yet";
success_ = spv_tools.Validate(spv_binary_);
}
return success_;

View File

@ -33,6 +33,7 @@ class ParserImpl : Reader {
/// Creates a new parser
/// @param input the input data to parse
explicit ParserImpl(const std::vector<uint32_t>& input);
/// Destructor
~ParserImpl() override;
/// Run the parser

View File

@ -0,0 +1,79 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/reader/spv/parser_impl.h"
#include <cstdint>
#include <vector>
#include "gmock/gmock.h"
#include "spirv-tools/libspirv.hpp"
namespace tint {
namespace reader {
namespace spv {
namespace {
using ::testing::HasSubstr;
using SpvParserImplTest = testing::Test;
TEST_F(SpvParserImplTest, Uint32VecEmpty) {
std::vector<uint32_t> data;
ParserImpl p{data};
EXPECT_FALSE(p.Parse());
// TODO(dneto): What message?
}
/// @returns the SPIR-V module assembled from the given text. Numeric IDs
/// are preserved.
std::vector<uint32_t> Assemble(const std::string& spirv_assembly) {
// TODO(dneto): Use ScopedTrace?
// (The target environment doesn't affect assembly.
spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
std::stringstream errors;
std::vector<uint32_t> result;
tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
const spv_position_t& position,
const char* message) {
errors << "assembly error:" << position.line << ":" << position.column
<< ": " << message;
});
const auto success = tools.Assemble(
spirv_assembly, &result, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_TRUE(success) << errors.str();
return result;
}
TEST_F(SpvParserImplTest, InvalidModuleFails) {
auto invalid_spv = Assemble("%ty = OpTypeInt 3 0");
ParserImpl p{invalid_spv};
EXPECT_FALSE(p.Parse());
EXPECT_THAT(
p.error(),
HasSubstr("TypeInt cannot appear before the memory model instruction"));
EXPECT_THAT(p.error(), HasSubstr("OpTypeInt 3 0"));
}
// TODO(dneto): uint32 vec, valid SPIR-V
} // namespace
} // namespace spv
} // namespace reader
} // namespace tint

View File

@ -14,8 +14,7 @@
#include "src/reader/spv/parser.h"
#include <stdint.h>
#include <cstdint>
#include <vector>
#include "gtest/gtest.h"