Refactor fuzzer transform generation

Also splits out various utility classes from tint_common_fuzzer and
uses consistent naming for utility classes.

BUG=tint:1106

Change-Id: Ic343741eea799366850c46834865d50885554a84
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/65301
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ryan Harrison 2021-09-30 18:58:32 +00:00 committed by Tint LUCI CQ
parent 0e193ac03e
commit c57642cbd5
30 changed files with 436 additions and 251 deletions

View File

@ -66,10 +66,12 @@ if (build_with_chromium) {
]
sources = [
"data_builder.h",
"random_generator.cc",
"random_generator.h",
"tint_common_fuzzer.cc",
"tint_common_fuzzer.h",
"transform_builder.h",
]
}
@ -79,8 +81,8 @@ if (build_with_chromium) {
sources = [
"cli.cc",
"cli.h",
"tint_init_fuzzer.cc",
"tint_init_fuzzer.h",
"fuzzer_init.cc",
"fuzzer_init.h",
]
}
if (tint_build_wgsl_reader) {

View File

@ -17,12 +17,14 @@ function(add_tint_fuzzer NAME)
${NAME}.cc
cli.cc
cli.h
data_builder.h
fuzzer_init.cc
fuzzer_init.h
random_generator.cc
random_generator.h
tint_common_fuzzer.cc
tint_common_fuzzer.h
tint_init_fuzzer.cc
tint_init_fuzzer.h
transform_builder.h
)
target_link_libraries(${NAME} libtint-fuzz)
tint_default_compile_options(${NAME})

142
fuzzers/data_builder.h Normal file
View File

@ -0,0 +1,142 @@
// Copyright 2021 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.
#ifndef FUZZERS_DATA_BUILDER_H_
#define FUZZERS_DATA_BUILDER_H_
#include <cassert>
#include <functional>
#include <string>
#include <vector>
#include "fuzzers/random_generator.h"
namespace tint {
namespace fuzzers {
/// Builder for generic pseudo-random data using a data buffer as seed
class DataBuilder {
public:
/// @brief Initialize random number generations
/// @param data - pointer to a data buffer to use as a seed
/// @param size - size of data buffer
explicit DataBuilder(const uint8_t* data, size_t size)
: generator_(data, size) {}
~DataBuilder() {}
/// Generate pseudo-random data of a specific type
/// @tparam T - type of data to produce
/// @returns pseudo-random data of type T
template <typename T>
T build() {
return BuildImpl<T>::impl(this);
}
/// Generate pseudo-random data of a specific type in a vector
/// @tparam T - data type held vector
/// @returns pseudo-random data of type std::vector<T>
template <typename T>
std::vector<T> vector() {
auto count = build<uint8_t>();
std::vector<T> out(count);
for (uint8_t i = 0; i < count; i++) {
out[i] = build<T>();
}
return out;
}
/// Generate complex pseudo-random data of a specific type in a vector
/// @tparam T - data type held vector
/// @tparam Callback - callback that takes in a DataBuilder* and returns a T
/// @param generate - callback for generating each instance of T
/// @returns pseudo-random data of type std::vector<T>
template <typename T, typename Callback>
std::vector<T> vector(Callback generate) {
auto count = build<uint8_t>();
std::vector<T> out(count);
for (size_t i = 0; i < count; i++) {
out[i] = generate(this);
}
return out;
}
/// Generate an pseudo-random entry to a enum class.
/// Assumes enum is tightly packed starting at 0.
/// @tparam T - type of enum class
/// @param count - number of entries in enum class
/// @returns a random enum class entry
template <typename T>
T enum_class(uint32_t count) {
return static_cast<T>(generator_.Get4Bytes() % count);
}
private:
RandomGenerator generator_;
/// Get N bytes of pseudo-random data
/// @param out - pointer to location to save data
/// @param n - number of bytes to get
void build(void* out, size_t n) {
assert(out != nullptr && "|out| cannot be nullptr");
assert(n > 0 && "|n| must be > 0");
generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
}
/// Implementation of ::build<T>()
/// @tparam T - type of data to produce
template <typename T>
struct BuildImpl {
/// Generate a pseudo-random variable of type T
/// @param b - data builder to use
/// @returns a variable of type T filled with pseudo-random data
static T impl(DataBuilder* b) {
T out{};
b->build(&out, sizeof(T));
return out;
}
};
/// Specialization for std::string
template <>
struct BuildImpl<std::string> {
/// Generate a pseudo-random string
/// @param b - data builder to use
/// @returns a string filled with pseudo-random data
static std::string impl(DataBuilder* b) {
auto count = b->build<uint8_t>();
if (count == 0) {
return "";
}
std::vector<uint8_t> source(count);
b->build(source.data(), count);
return std::string(source.begin(), source.end());
}
};
/// Specialization for bool
template <>
struct BuildImpl<bool> {
/// Generate a pseudo-random bool
/// @param b - data builder to use
/// @returns a boolean with even odds of being true or false
static bool impl(DataBuilder* b) { return b->generator_.GetBool(); }
};
};
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_DATA_BUILDER_H_

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/cli.h"
namespace tint {

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FUZZERS_TINT_INIT_FUZZER_H_
#define FUZZERS_TINT_INIT_FUZZER_H_
#ifndef FUZZERS_FUZZER_INIT_H_
#define FUZZERS_FUZZER_INIT_H_
#include "fuzzers/cli.h"
@ -26,4 +26,4 @@ const CliParams& GetCliParams();
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_TINT_INIT_FUZZER_H_
#endif // FUZZERS_FUZZER_INIT_H_

View File

@ -58,6 +58,9 @@ size_t HashBuffer(const uint8_t* data, const size_t size) {
RandomGenerator::RandomGenerator(uint64_t seed) : engine_(seed) {}
RandomGenerator::RandomGenerator(const uint8_t* data, size_t size)
: engine_(RandomGenerator::CalculateSeed(data, size)) {}
uint32_t RandomGenerator::GetUInt32(uint32_t lower, uint32_t upper) {
return RandomUInt(&engine_, lower, upper);
}

View File

@ -27,6 +27,12 @@ class RandomGenerator {
/// @brief Initializes the internal engine
/// @param seed - seed value passed to engine
explicit RandomGenerator(uint64_t seed);
/// @brief Wrapper that invokes CalculateSeed for caller
/// @param data - data fuzzer to calculate seed from
/// @param size - size of data buffer
explicit RandomGenerator(const uint8_t* data, size_t size);
~RandomGenerator() {}
/// Get uint32_t value from uniform distribution.

View File

@ -12,41 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
struct Config {
Config(const uint8_t* data, size_t size) : builder(data, size) {}
DataBuilder builder;
transform::Manager manager;
transform::DataMap inputs;
};
void AddPlatformIndependentPasses(Config* config) {
GenerateFirstIndexOffsetInputs(&config->builder, &config->inputs);
GenerateBindingRemapperInputs(&config->builder, &config->inputs);
GenerateSingleEntryPointInputs(&config->builder, &config->inputs);
GenerateVertexPullingInputs(&config->builder, &config->inputs);
config->manager.Add<transform::Robustness>();
config->manager.Add<transform::FirstIndexOffset>();
config->manager.Add<transform::BindingRemapper>();
config->manager.Add<transform::Renamer>();
config->manager.Add<tint::transform::SingleEntryPoint>();
config->manager.Add<tint::transform::VertexPulling>();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
{
Config config(data, size);
AddPlatformIndependentPasses(&config);
TransformBuilder tb(data, size);
tb.AddPlatformIndependentPasses();
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
fuzzer.SetTransformManager(&(config.manager), std::move(config.inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
fuzzer.Run(data, size);
@ -54,11 +34,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
#if TINT_BUILD_HLSL_WRITER
{
Config config(data, size);
AddPlatformIndependentPasses(&config);
TransformBuilder tb(data, size);
tb.AddPlatformIndependentPasses();
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kHLSL);
fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
fuzzer.Run(data, size);
@ -67,11 +47,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
#if TINT_BUILD_MSL_WRITER
{
Config config(data, size);
AddPlatformIndependentPasses(&config);
TransformBuilder tb(data, size);
tb.AddPlatformIndependentPasses();
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
fuzzer.Run(data, size);
@ -79,11 +59,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
#endif // TINT_BUILD_MSL_WRITER
#if TINT_BUILD_SPV_WRITER
{
Config config(data, size);
AddPlatformIndependentPasses(&config);
TransformBuilder tb(data, size);
tb.AddPlatformIndependentPasses();
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
fuzzer.SetTransformManager(&config.manager, std::move(config.inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
fuzzer.Run(data, size);

View File

@ -115,7 +115,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
fuzzer.EnableInspector();
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzer.SetTransformManager(&transform_manager, &transform_inputs);
fuzzer.Run(data, size);
if (fuzzer.HasErrors()) {

View File

@ -12,23 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
transform::Manager transform_manager;
transform::DataMap transform_inputs;
DataBuilder b(data, size);
GenerateBindingRemapperInputs(&b, &transform_inputs);
transform_manager.Add<tint::transform::BindingRemapper>();
TransformBuilder tb(data, size);
tb.AddTransform<transform::BindingRemapper>();
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
return fuzzer.Run(data, size);

View File

@ -52,26 +52,6 @@ namespace {
FatalError(diagnostics);
}
transform::VertexAttributeDescriptor GenerateVertexAttributeDescriptor(
DataBuilder* b) {
transform::VertexAttributeDescriptor desc{};
desc.format = b->enum_class<transform::VertexFormat>(
static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
desc.offset = b->build<uint32_t>();
desc.shader_location = b->build<uint32_t>();
return desc;
}
transform::VertexBufferLayoutDescriptor GenerateVertexBufferLayoutDescriptor(
DataBuilder* b) {
transform::VertexBufferLayoutDescriptor desc;
desc.array_stride = b->build<uint32_t>();
desc.step_mode = b->enum_class<transform::VertexStepMode>(
static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
desc.attributes = b->vector(GenerateVertexAttributeDescriptor);
return desc;
}
bool SPIRVToolsValidationCheck(const tint::Program& program,
const std::vector<uint32_t>& spirv) {
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
@ -94,76 +74,6 @@ bool SPIRVToolsValidationCheck(const tint::Program& program,
} // namespace
DataBuilder::DataBuilder(const uint8_t* data, size_t size)
: generator_(RandomGenerator::CalculateSeed(data, size)) {}
std::string DataBuilder::string() {
auto count = build<uint8_t>();
if (count == 0) {
return "";
}
std::vector<uint8_t> source(count);
build(source.data(), count);
return std::string(source.begin(), source.end());
}
void DataBuilder::build(void* out, size_t n) {
assert(out != nullptr && "|out| cannot be nullptr");
assert(n > 0 && "|n| must be > 0");
generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
}
void GenerateBindingRemapperInputs(DataBuilder* b,
tint::transform::DataMap* inputs) {
struct Config {
uint8_t old_group;
uint8_t old_binding;
uint8_t new_group;
uint8_t new_binding;
ast::Access new_access;
};
std::vector<Config> configs = b->vector<Config>();
transform::BindingRemapper::BindingPoints binding_points;
transform::BindingRemapper::AccessControls accesses;
for (const auto& config : configs) {
binding_points[{config.old_binding, config.old_group}] = {
config.new_binding, config.new_group};
accesses[{config.old_binding, config.old_group}] = config.new_access;
}
inputs->Add<transform::BindingRemapper::Remappings>(binding_points, accesses);
}
void GenerateFirstIndexOffsetInputs(DataBuilder* b,
tint::transform::DataMap* inputs) {
struct Config {
uint32_t group;
uint32_t binding;
};
Config config = b->build<Config>();
inputs->Add<tint::transform::FirstIndexOffset::BindingPoint>(config.binding,
config.group);
}
void GenerateSingleEntryPointInputs(DataBuilder* b,
tint::transform::DataMap* inputs) {
std::string input = b->string();
transform::SingleEntryPoint::Config cfg(input);
inputs->Add<transform::SingleEntryPoint::Config>(cfg);
}
void GenerateVertexPullingInputs(DataBuilder* b,
tint::transform::DataMap* inputs) {
transform::VertexPulling::Config cfg;
cfg.entry_point_name = b->string();
cfg.vertex_state = b->vector(GenerateVertexBufferLayoutDescriptor);
cfg.pulling_group = b->build<uint32_t>();
inputs->Add<transform::VertexPulling::Config>(cfg);
}
void GenerateSpirvOptions(DataBuilder* b, writer::spirv::Options* options) {
*options = b->build<writer::spirv::Options>();
}
@ -181,10 +91,7 @@ void GenerateMslOptions(DataBuilder* b, writer::msl::Options* options) {
}
CommonFuzzer::CommonFuzzer(InputFormat input, OutputFormat output)
: input_(input),
output_(output),
transform_manager_(nullptr),
inspector_enabled_(false) {}
: input_(input), output_(output) {}
CommonFuzzer::~CommonFuzzer() = default;
@ -345,7 +252,7 @@ int CommonFuzzer::Run(const uint8_t* data, size_t size) {
}
if (transform_manager_) {
auto out = transform_manager_->Run(&program, transform_inputs_);
auto out = transform_manager_->Run(&program, *transform_inputs_);
if (!out.program.IsValid()) {
// Transforms can produce error messages for bad input.
// Catch ICEs and errors from non transform systems.

View File

@ -15,71 +15,20 @@
#ifndef FUZZERS_TINT_COMMON_FUZZER_H_
#define FUZZERS_TINT_COMMON_FUZZER_H_
#include <cassert>
#include <cstring>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "fuzzers/random_generator.h"
#include "include/tint/tint.h"
#include "fuzzers/data_builder.h"
namespace tint {
namespace fuzzers {
class DataBuilder {
public:
DataBuilder(const uint8_t* data, size_t size);
template <typename T>
T build() {
T out{};
build(&out, sizeof(T));
return out;
}
std::string string();
template <typename T>
std::vector<T> vector() {
auto count = build<uint8_t>();
std::vector<T> out(count);
for (uint8_t i = 0; i < count; i++) {
out[i] = build<T>();
}
return out;
}
template <typename T>
std::vector<T> vector(T (*generate)(DataBuilder*)) {
auto count = build<uint8_t>();
std::vector<T> out(count);
for (uint8_t i = 0; i < count; i++) {
out[i] = generate(this);
}
return out;
}
template <typename T>
T enum_class(uint8_t count) {
auto val = build<uint8_t>();
return static_cast<T>(val % count);
}
private:
void build(void* out, size_t n);
RandomGenerator generator_;
};
void GenerateBindingRemapperInputs(DataBuilder* b,
tint::transform::DataMap* inputs);
void GenerateFirstIndexOffsetInputs(DataBuilder* b,
tint::transform::DataMap* inputs);
void GenerateSingleEntryPointInputs(DataBuilder* b,
tint::transform::DataMap* inputs);
void GenerateVertexPullingInputs(DataBuilder* b,
tint::transform::DataMap* inputs);
void GenerateSpirvOptions(DataBuilder* b, writer::spirv::Options* options);
void GenerateWgslOptions(DataBuilder* b, writer::wgsl::Options* options);
void GenerateHlslOptions(DataBuilder* b, writer::hlsl::Options* options);
@ -94,9 +43,10 @@ class CommonFuzzer {
explicit CommonFuzzer(InputFormat input, OutputFormat output);
~CommonFuzzer();
void SetTransformManager(transform::Manager* tm, transform::DataMap inputs) {
void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
assert((!tm || inputs) && "DataMap must be !nullptr if Manager !nullptr");
transform_manager_ = tm;
transform_inputs_ = std::move(inputs);
transform_inputs_ = inputs;
}
void EnableInspector() { inspector_enabled_ = true; }
@ -137,9 +87,9 @@ class CommonFuzzer {
private:
InputFormat input_;
OutputFormat output_;
transform::Manager* transform_manager_;
transform::DataMap transform_inputs_;
bool inspector_enabled_;
transform::Manager* transform_manager_ = nullptr;
transform::DataMap* transform_inputs_ = nullptr;
bool inspector_enabled_ = false;
bool dump_input_ = false;
tint::diag::List diagnostics_;

View File

@ -12,22 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
tint::transform::Manager transform_manager;
tint::transform::DataMap transform_inputs;
DataBuilder b(data, size);
TransformBuilder tb(data, size);
tb.AddTransform<transform::FirstIndexOffset>();
GenerateFirstIndexOffsetInputs(&b, &transform_inputs);
transform_manager.Add<tint::transform::FirstIndexOffset>();
tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
return fuzzer.Run(data, size);

View File

@ -12,21 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
transform::Manager transform_manager;
transform::DataMap transform_inputs;
transform_manager.Add<transform::Robustness>();
TransformBuilder tb(data, size);
tb.AddTransform<transform::Robustness>();
tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.EnableInspector();
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
return fuzzer.Run(data, size);
}

View File

@ -143,7 +143,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
fuzzer.EnableInspector();
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzer.SetTransformManager(&transform_manager, &transform_inputs);
fuzzer.Run(data, size);
}

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -12,22 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
tint::transform::Manager transform_manager;
tint::transform::DataMap transform_inputs;
DataBuilder b(data, size);
TransformBuilder tb(data, size);
tb.AddTransform<transform::SingleEntryPoint>();
GenerateSingleEntryPointInputs(&b, &transform_inputs);
transform_manager.Add<tint::transform::SingleEntryPoint>();
tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
return fuzzer.Run(data, size);

View File

@ -14,8 +14,8 @@
#include <vector>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <vector>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <vector>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <vector>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <vector>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -12,22 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
#include "fuzzers/transform_builder.h"
namespace tint {
namespace fuzzers {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
tint::transform::Manager transform_manager;
tint::transform::DataMap transform_inputs;
DataBuilder b(data, size);
GenerateVertexPullingInputs(&b, &transform_inputs);
transform_manager.Add<tint::transform::VertexPulling>();
TransformBuilder tb(data, size);
tb.AddTransform<transform::VertexPulling>();
tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
fuzzer.SetTransformManager(&transform_manager, std::move(transform_inputs));
fuzzer.SetTransformManager(tb.manager(), tb.data_map());
fuzzer.SetDumpInput(GetCliParams().dump_input);
return fuzzer.Run(data, size);

View File

@ -14,8 +14,8 @@
#include <string>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <string>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <string>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <string>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

View File

@ -14,8 +14,8 @@
#include <string>
#include "fuzzers/fuzzer_init.h"
#include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_init_fuzzer.h"
namespace tint {
namespace fuzzers {

206
fuzzers/transform_builder.h Normal file
View File

@ -0,0 +1,206 @@
// Copyright 2021 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.
#ifndef FUZZERS_TRANSFORM_BUILDER_H_
#define FUZZERS_TRANSFORM_BUILDER_H_
#include <string>
#include <vector>
#include "include/tint/tint.h"
#include "fuzzers/data_builder.h"
namespace tint {
namespace fuzzers {
/// Fuzzer utility class to build inputs for transforms and setup the transform
/// manager.
class TransformBuilder {
public:
/// @brief Initialize the data source using a data buffer as a seed
/// @param data - pointer to a data buffer to use as a seed
/// @param size - size of data buffer
explicit TransformBuilder(const uint8_t* data, size_t size)
: builder_(data, size) {}
~TransformBuilder() {}
transform::Manager* manager() { return &manager_; }
transform::DataMap* data_map() { return &data_map_; }
DataBuilder* builder() { return &builder_; }
/// Adds a transform and needed data to |manager_| and |data_map_|.
/// @tparam T - A class that inherits from transform::Transform and has an
/// explicit specialization in AddTransformImpl.
template <typename T>
void AddTransform() {
static_assert(std::is_base_of<transform::Transform, T>::value,
"T is not a transform::Transform");
AddTransformImpl<T>::impl(this);
}
/// Helper that invokes Add*Transform for all of the platform independent
/// passes.
void AddPlatformIndependentPasses() {
AddTransform<transform::Robustness>();
AddTransform<transform::FirstIndexOffset>();
AddTransform<transform::BindingRemapper>();
AddTransform<transform::Renamer>();
AddTransform<transform::SingleEntryPoint>();
AddTransform<transform::VertexPulling>();
}
private:
DataBuilder builder_;
transform::Manager manager_;
transform::DataMap data_map_;
/// Implementation of AddTransform, specialized for each transform that is
/// implemented. Default implementation intentionally deleted to cause compile
/// error if unimplemented type passed in.
/// @tparam T - A fuzzer transform
template <typename T>
struct AddTransformImpl;
/// Implementation of AddTransform for transform::Robustness
template <>
struct AddTransformImpl<transform::Robustness> {
/// Add instance of transform::Robustness to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
tb->manager()->Add<transform::Robustness>();
}
};
/// Implementation of AddTransform for transform::FirstIndexOffset
template <>
struct AddTransformImpl<transform::FirstIndexOffset> {
/// Add instance of transform::FirstIndexOffset to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
struct Config {
uint32_t group;
uint32_t binding;
};
Config config = tb->builder()->build<Config>();
tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(
config.binding, config.group);
tb->manager()->Add<transform::FirstIndexOffset>();
}
};
/// Implementation of AddTransform for transform::BindingRemapper
template <>
struct AddTransformImpl<transform::BindingRemapper> {
/// Add instance of transform::BindingRemapper to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
struct Config {
uint8_t old_group;
uint8_t old_binding;
uint8_t new_group;
uint8_t new_binding;
ast::Access new_access;
};
std::vector<Config> configs = tb->builder()->vector<Config>();
transform::BindingRemapper::BindingPoints binding_points;
transform::BindingRemapper::AccessControls accesses;
for (const auto& config : configs) {
binding_points[{config.old_binding, config.old_group}] = {
config.new_binding, config.new_group};
accesses[{config.old_binding, config.old_group}] = config.new_access;
}
tb->data_map()->Add<transform::BindingRemapper::Remappings>(
binding_points, accesses, tb->builder()->build<bool>());
tb->manager()->Add<transform::BindingRemapper>();
}
};
/// Implementation of AddTransform for transform::Renamer
template <>
struct AddTransformImpl<transform::Renamer> {
/// Add instance of transform::Renamer to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
tb->manager()->Add<transform::Renamer>();
}
};
/// Implementation of AddTransform for transform::SingleEntryPoint
template <>
struct AddTransformImpl<transform::SingleEntryPoint> {
/// Add instance of transform::SingleEntryPoint to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
auto input = tb->builder()->build<std::string>();
transform::SingleEntryPoint::Config cfg(input);
tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
tb->manager()->Add<transform::SingleEntryPoint>();
}
}; // struct AddTransformImpl<transform::SingleEntryPoint>
/// Implementation of AddTransform for transform::VertexPulling
template <>
struct AddTransformImpl<transform::VertexPulling> {
/// Add instance of transform::VertexPulling to TransformBuilder
/// @param tb - TransformBuilder to add transform to
static void impl(TransformBuilder* tb) {
transform::VertexPulling::Config cfg;
cfg.entry_point_name = tb->builder()->build<std::string>();
cfg.vertex_state =
tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
GenerateVertexBufferLayoutDescriptor);
cfg.pulling_group = tb->builder()->build<uint32_t>();
tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
tb->manager()->Add<transform::VertexPulling>();
}
private:
/// Generate an instance of transform::VertexAttributeDescriptor
/// @param b - DataBuilder to use
static transform::VertexAttributeDescriptor
GenerateVertexAttributeDescriptor(DataBuilder* b) {
transform::VertexAttributeDescriptor desc{};
desc.format = b->enum_class<transform::VertexFormat>(
static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
desc.offset = b->build<uint32_t>();
desc.shader_location = b->build<uint32_t>();
return desc;
}
/// Generate an instance of VertexBufferLayoutDescriptor
/// @param b - DataBuilder to use
static transform::VertexBufferLayoutDescriptor
GenerateVertexBufferLayoutDescriptor(DataBuilder* b) {
transform::VertexBufferLayoutDescriptor desc;
desc.array_stride = b->build<uint32_t>();
desc.step_mode = b->enum_class<transform::VertexStepMode>(
static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
desc.attributes = b->vector<transform::VertexAttributeDescriptor>(
GenerateVertexAttributeDescriptor);
return desc;
}
};
}; // class TransformBuilder
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_TRANSFORM_BUILDER_H_