mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-04 12:16:10 +00:00
Fix AST fuzzer message serialization
Currently, AST fuzzer requires that all fuzzed binaries are serialized protobuf messages. In principle, we don't need this when we don't record mutations (which is the case right now). Hence, this CL removes that requirement. Change-Id: Ibe677d1ac7d34d640d6e3a368af50df5b4fe474a Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58225 Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Vasyl Teliman <vasniktel@gmail.com> Reviewed-by: Alastair Donaldson <afdx@google.com>
This commit is contained in:
parent
e087a95706
commit
fa4d4341f4
@ -52,12 +52,6 @@ run it with -help=1 to check out libfuzzer parameters.
|
|||||||
The number of mutations to apply in a single libfuzzer
|
The number of mutations to apply in a single libfuzzer
|
||||||
mutation session. This must be a numeric value that fits
|
mutation session. This must be a numeric value that fits
|
||||||
in type `uint32_t`. By default it's 5.
|
in type `uint32_t`. By default it's 5.
|
||||||
|
|
||||||
-tint_record_mutations=
|
|
||||||
Whether to record applied mutations in the protobuf
|
|
||||||
message. This is useful to debug the fuzzer and during
|
|
||||||
metamorphic fuzzing. The value must be one of `true` or
|
|
||||||
`false` (without `). By default it's `false`.
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
bool HasPrefix(const char* str, const char* prefix) {
|
bool HasPrefix(const char* str, const char* prefix) {
|
||||||
@ -115,12 +109,7 @@ CliParams ParseCliParams(int* argc, char** argv) {
|
|||||||
auto param = argv[i];
|
auto param = argv[i];
|
||||||
auto recognized_parameter = true;
|
auto recognized_parameter = true;
|
||||||
|
|
||||||
if (HasPrefix(param, "-tint_record_mutations=")) {
|
if (HasPrefix(param, "-tint_enable_all_mutations=")) {
|
||||||
if (!ParseBool(param + sizeof("-tint_record_mutations=") - 1,
|
|
||||||
&cli_params.record_mutations)) {
|
|
||||||
InvalidParam(param);
|
|
||||||
}
|
|
||||||
} else if (HasPrefix(param, "-tint_enable_all_mutations=")) {
|
|
||||||
if (!ParseBool(param + sizeof("-tint_enable_all_mutations=") - 1,
|
if (!ParseBool(param + sizeof("-tint_enable_all_mutations=") - 1,
|
||||||
&cli_params.enable_all_mutations)) {
|
&cli_params.enable_all_mutations)) {
|
||||||
InvalidParam(param);
|
InvalidParam(param);
|
||||||
|
@ -42,9 +42,6 @@ inline FuzzingTarget operator&(FuzzingTarget a, FuzzingTarget b) {
|
|||||||
/// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the
|
/// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the
|
||||||
/// help message
|
/// help message
|
||||||
struct CliParams {
|
struct CliParams {
|
||||||
/// Whether to record applied mutations.
|
|
||||||
bool record_mutations = false;
|
|
||||||
|
|
||||||
/// Whether to use all mutation finders or only a randomly selected subset of
|
/// Whether to use all mutation finders or only a randomly selected subset of
|
||||||
/// them.
|
/// them.
|
||||||
bool enable_all_mutations = false;
|
bool enable_all_mutations = false;
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include "fuzzers/tint_ast_fuzzer/cli.h"
|
#include "fuzzers/tint_ast_fuzzer/cli.h"
|
||||||
#include "fuzzers/tint_ast_fuzzer/mt_rng.h"
|
#include "fuzzers/tint_ast_fuzzer/mt_rng.h"
|
||||||
#include "fuzzers/tint_ast_fuzzer/mutator.h"
|
#include "fuzzers/tint_ast_fuzzer/mutator.h"
|
||||||
#include "fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.h"
|
|
||||||
#include "fuzzers/tint_common_fuzzer.h"
|
#include "fuzzers/tint_common_fuzzer.h"
|
||||||
|
|
||||||
#include "src/reader/wgsl/parser.h"
|
#include "src/reader/wgsl/parser.h"
|
||||||
@ -42,27 +41,12 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
|
|||||||
size_t size,
|
size_t size,
|
||||||
size_t max_size,
|
size_t max_size,
|
||||||
unsigned seed) {
|
unsigned seed) {
|
||||||
protobufs::MutatorState mutator_state;
|
Source::File file("test.wgsl", {reinterpret_cast<char*>(data), size});
|
||||||
auto success = mutator_state.ParseFromArray(data, static_cast<int>(size));
|
|
||||||
(void)success; // This variable will be unused in release mode.
|
|
||||||
assert(success && "Can't parse protobuf message");
|
|
||||||
|
|
||||||
tint::Source::File file("test.wgsl", mutator_state.program());
|
|
||||||
auto program = reader::wgsl::Parse(&file);
|
auto program = reader::wgsl::Parse(&file);
|
||||||
protobufs::MutationSequence* mutation_sequence = nullptr;
|
if (!program.IsValid()) {
|
||||||
|
std::cout << "Trying to mutate an invalid program:" << std::endl
|
||||||
if (cli_params.record_mutations) {
|
<< program.Diagnostics().str() << std::endl;
|
||||||
// If mutations are being recorded, then `mutator_state.program` is the
|
return 0;
|
||||||
// original (unmodified) program and it is necessary to replay all
|
|
||||||
// mutations.
|
|
||||||
mutation_sequence = mutator_state.mutable_mutation_sequence();
|
|
||||||
program = Replay(std::move(program), *mutation_sequence);
|
|
||||||
if (!program.IsValid()) {
|
|
||||||
std::cout << "Replayer produced invalid WGSL:" << std::endl
|
|
||||||
<< " seed: " << seed << std::endl
|
|
||||||
<< program.Diagnostics().str() << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the mutator.
|
// Run the mutator.
|
||||||
@ -70,7 +54,7 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
|
|||||||
ProbabilityContext probability_context(&mt_rng);
|
ProbabilityContext probability_context(&mt_rng);
|
||||||
program = Mutate(std::move(program), &probability_context,
|
program = Mutate(std::move(program), &probability_context,
|
||||||
cli_params.enable_all_mutations,
|
cli_params.enable_all_mutations,
|
||||||
cli_params.mutation_batch_size, mutation_sequence);
|
cli_params.mutation_batch_size, nullptr);
|
||||||
|
|
||||||
if (!program.IsValid()) {
|
if (!program.IsValid()) {
|
||||||
std::cout << "Mutator produced invalid WGSL:" << std::endl
|
std::cout << "Mutator produced invalid WGSL:" << std::endl
|
||||||
@ -79,27 +63,21 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cli_params.record_mutations) {
|
auto result = writer::wgsl::Generate(&program, writer::wgsl::Options());
|
||||||
// If mutations are not being recorded, then the mutated `program` must be
|
if (!result.success) {
|
||||||
// stored into the `mutator_state`.
|
std::cout << "Can't generate WGSL for a valid tint::Program:" << std::endl
|
||||||
writer::wgsl::Options options;
|
<< result.error << std::endl;
|
||||||
auto result = writer::wgsl::Generate(&program, options);
|
|
||||||
if (!result.success) {
|
|
||||||
std::cout << "Can't generate WGSL for valid tint::Program:" << std::endl
|
|
||||||
<< " seed: " << seed << std::endl
|
|
||||||
<< result.error << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*mutator_state.mutable_program() = std::move(result.wgsl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mutator_state.ByteSizeLong() > max_size) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = mutator_state.SerializeToArray(data, static_cast<int>(max_size));
|
// +1 to account for \0 at the end of a string.
|
||||||
assert(success && "Can't serialize a protobuf message");
|
auto mutated_size = result.wgsl.size() + 1;
|
||||||
return mutator_state.ByteSizeLong();
|
if (mutated_size > max_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(data, result.wgsl.data(), mutated_size);
|
||||||
|
return mutated_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
@ -107,44 +85,31 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufs::MutatorState mutator_state;
|
struct Target {
|
||||||
auto success = mutator_state.ParseFromArray(data, static_cast<int>(size));
|
FuzzingTarget fuzzing_target;
|
||||||
(void)success; // This variable will be unused in release mode.
|
OutputFormat output_format;
|
||||||
assert(success && "Can't parse a protobuf message");
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
std::string program_text;
|
Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
|
||||||
if (cli_params.record_mutations) {
|
{FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
|
||||||
// If mutations are being recorded, then it's necessary to replay them
|
{FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
|
||||||
// before invoking the system under test.
|
{FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
|
||||||
Source::File file("test.wgsl", mutator_state.program());
|
|
||||||
auto program =
|
|
||||||
Replay(reader::wgsl::Parse(&file), mutator_state.mutation_sequence());
|
|
||||||
assert(program.IsValid() && "Replayed program is invalid");
|
|
||||||
|
|
||||||
writer::wgsl::Options options;
|
|
||||||
auto result = writer::wgsl::Generate(&program, options);
|
|
||||||
assert(result.success &&
|
|
||||||
"Can't generate a shader for the valid tint::Program");
|
|
||||||
program_text = std::move(result.wgsl);
|
|
||||||
} else {
|
|
||||||
program_text.assign(data, data + size);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<FuzzingTarget, OutputFormat> targets[] = {
|
|
||||||
{FuzzingTarget::kWgsl, OutputFormat::kWGSL},
|
|
||||||
{FuzzingTarget::kHlsl, OutputFormat::kHLSL},
|
|
||||||
{FuzzingTarget::kMsl, OutputFormat::kMSL},
|
|
||||||
{FuzzingTarget::kSpv, OutputFormat::kSpv}};
|
|
||||||
|
|
||||||
for (auto target : targets) {
|
for (auto target : targets) {
|
||||||
if ((target.first & cli_params.fuzzing_target) != target.first) {
|
if ((target.fuzzing_target & cli_params.fuzzing_target) !=
|
||||||
|
target.fuzzing_target) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonFuzzer fuzzer(InputFormat::kWGSL, target.second);
|
CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
|
||||||
fuzzer.EnableInspector();
|
fuzzer.EnableInspector();
|
||||||
fuzzer.Run(reinterpret_cast<const uint8_t*>(program_text.data()),
|
fuzzer.Run(data, size);
|
||||||
program_text.size());
|
if (fuzzer.HasErrors()) {
|
||||||
|
std::cout << "Fuzzing " << target.name
|
||||||
|
<< " produced an error:" << std::endl
|
||||||
|
<< fuzzer.GetErrors() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user