From 979a0b4446cc7fb0b734f328c2feafa3811ab942 Mon Sep 17 00:00:00 2001 From: Vasyl Teliman Date: Fri, 16 Jul 2021 10:26:34 +0000 Subject: [PATCH] Fix CLI parameters in fuzzers This CL changes the prefix of CLI parameters in AST and SPIRV-Tools fuzzers from `--` to `-` to make these fuzzers compatible with ClusterFuzz. Additionally, a `tint_` prefix was added to all CLI arguments to prevent their name collisions with LibFuzzer arguments. Change-Id: Id2e087e59f04b495d5a7edb3b62d55de652c1acd Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58226 Kokoro: Kokoro Reviewed-by: Alastair Donaldson Commit-Queue: Alastair Donaldson --- fuzzers/tint_ast_fuzzer/cli.cc | 48 ++++++--- fuzzers/tint_ast_fuzzer/cli.h | 7 +- fuzzers/tint_ast_fuzzer/fuzzer.cc | 2 +- fuzzers/tint_spirv_tools_fuzzer/cli.cc | 113 +++++++++++++--------- fuzzers/tint_spirv_tools_fuzzer/cli.h | 9 +- fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc | 2 +- 6 files changed, 109 insertions(+), 72 deletions(-) diff --git a/fuzzers/tint_ast_fuzzer/cli.cc b/fuzzers/tint_ast_fuzzer/cli.cc index 5e3f07355f..a1ace139a4 100644 --- a/fuzzers/tint_ast_fuzzer/cli.cc +++ b/fuzzers/tint_ast_fuzzer/cli.cc @@ -19,6 +19,7 @@ #include #include #include +#include namespace tint { namespace fuzzers { @@ -31,28 +32,28 @@ This is a fuzzer for the Tint compiler that works by mutating the AST. Below is a list of all supported parameters for this fuzzer. You may want to run it with -help=1 to check out libfuzzer parameters. - --enable_all_mutations= + -tint_enable_all_mutations= If `false`, the fuzzer will only apply mutations from a randomly selected subset of mutation types. Otherwise, all mutation types will be considered. This must be one of `true` or `false` (without `). By default it's `false`. - --fuzzing_target= + -tint_fuzzing_target= Specifies the shading language to target during fuzzing. This must be one or a combination of `wgsl`, `spv`, `hlsl`, `msl` (without `) separated by commas. By default it's `wgsl,msl,hlsl,spv`. - --help + -tint_help Show this message. Note that there is also a -help=1 parameter that will display libfuzzer's help message. - --mutation_batch_size= + -tint_mutation_batch_size= The number of mutations to apply in a single libfuzzer mutation session. This must be a numeric value that fits in type `uint32_t`. By default it's 5. - --record_mutations= + -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 @@ -106,31 +107,33 @@ bool ParseFuzzingTarget(const char* value, FuzzingTarget* out) { } // namespace -CliParams ParseCliParams(int argc, const char* const* argv) { +CliParams ParseCliParams(int* argc, char** argv) { CliParams cli_params; auto help = false; - for (int i = 1; i < argc; ++i) { + for (int i = *argc - 1; i > 0; --i) { auto param = argv[i]; - if (HasPrefix(param, "--record_mutations=")) { - if (!ParseBool(param + sizeof("--record_mutations=") - 1, + auto recognized_parameter = true; + + if (HasPrefix(param, "-tint_record_mutations=")) { + if (!ParseBool(param + sizeof("-tint_record_mutations=") - 1, &cli_params.record_mutations)) { InvalidParam(param); } - } else if (HasPrefix(param, "--enable_all_mutations=")) { - if (!ParseBool(param + sizeof("--enable_all_mutations=") - 1, + } else if (HasPrefix(param, "-tint_enable_all_mutations=")) { + if (!ParseBool(param + sizeof("-tint_enable_all_mutations=") - 1, &cli_params.enable_all_mutations)) { InvalidParam(param); } - } else if (HasPrefix(param, "--mutation_batch_size=")) { - if (!ParseUint32(param + sizeof("--mutation_batch_size=") - 1, + } else if (HasPrefix(param, "-tint_mutation_batch_size=")) { + if (!ParseUint32(param + sizeof("-tint_mutation_batch_size=") - 1, &cli_params.mutation_batch_size)) { InvalidParam(param); } - } else if (HasPrefix(param, "--fuzzing_target=")) { + } else if (HasPrefix(param, "-tint_fuzzing_target=")) { auto result = FuzzingTarget::kNone; - std::stringstream ss(param + sizeof("--fuzzing_target=") - 1); + std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1); for (std::string value; std::getline(ss, value, ',');) { auto tmp = FuzzingTarget::kNone; if (!ParseFuzzingTarget(value.c_str(), &tmp)) { @@ -144,8 +147,21 @@ CliParams ParseCliParams(int argc, const char* const* argv) { } cli_params.fuzzing_target = result; - } else if (!strcmp(param, "--help")) { + } else if (!strcmp(param, "-tint_help")) { help = true; + } else { + recognized_parameter = false; + } + + if (recognized_parameter) { + // Remove the recognized parameter from the list of all parameters by + // swapping it with the last one. This will suppress warnings in the + // libFuzzer about unrecognized parameters. By default, libFuzzer thinks + // that all user-defined parameters start with two dashes. However, we are + // forced to use a single one to make the fuzzer compatible with the + // ClusterFuzz. + std::swap(argv[i], argv[*argc - 1]); + *argc -= 1; } } diff --git a/fuzzers/tint_ast_fuzzer/cli.h b/fuzzers/tint_ast_fuzzer/cli.h index dd94fbb3b6..077b662ce3 100644 --- a/fuzzers/tint_ast_fuzzer/cli.h +++ b/fuzzers/tint_ast_fuzzer/cli.h @@ -39,7 +39,7 @@ inline FuzzingTarget operator&(FuzzingTarget a, FuzzingTarget b) { return static_cast(static_cast(a) & static_cast(b)); } -/// CLI parameters accepted by the fuzzer. Type --help in the CLI to see the +/// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the /// help message struct CliParams { /// Whether to record applied mutations. @@ -60,12 +60,13 @@ struct CliParams { /// @brief Parses CLI parameters. /// /// This function will exit the process with non-zero return code if some -/// parameters are invalid. +/// parameters are invalid. This function will remove recognized parameters from +/// `argv` and adjust `argc` accordingly. /// /// @param argc - the total number of parameters. /// @param argv - array of all CLI parameters. /// @return parsed parameters. -CliParams ParseCliParams(int argc, const char* const* argv); +CliParams ParseCliParams(int* argc, char** argv); } // namespace ast_fuzzer } // namespace fuzzers diff --git a/fuzzers/tint_ast_fuzzer/fuzzer.cc b/fuzzers/tint_ast_fuzzer/fuzzer.cc index a431cb2e93..5e58fb4540 100644 --- a/fuzzers/tint_ast_fuzzer/fuzzer.cc +++ b/fuzzers/tint_ast_fuzzer/fuzzer.cc @@ -34,7 +34,7 @@ CliParams cli_params{}; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter // is invalid. - cli_params = ParseCliParams(*argc, *argv); + cli_params = ParseCliParams(argc, *argv); return 0; } diff --git a/fuzzers/tint_spirv_tools_fuzzer/cli.cc b/fuzzers/tint_spirv_tools_fuzzer/cli.cc index cfb6633280..f304ed743b 100644 --- a/fuzzers/tint_spirv_tools_fuzzer/cli.cc +++ b/fuzzers/tint_spirv_tools_fuzzer/cli.cc @@ -32,59 +32,59 @@ namespace { const char* const kMutatorParameters = R"( Mutators' parameters: - --donors= + -tint_donors= A path to the text file with a list of paths to the SPIR-V donor files. Check out the doc for the spirv-fuzz to learn more about donor binaries. Donors are not used by default. - --enable_all_fuzzer_passes= + -tint_enable_all_fuzzer_passes= Whether to use all fuzzer passes or a randomly selected subset of them. This must be one of `true` or `false` (without `). By default it's `false`. - --enable_all_reduce_passes= + -tint_enable_all_reduce_passes= Whether to use all reduction passes or a randomly selected subset of them. This must be one of `true` or `false` (without `). By default it's `false`. - --opt_batch_size= + -tint_opt_batch_size= The maximum number of spirv-opt optimizations that will be applied in a single mutation session (i.e. a call to LLVMFuzzerCustomMutator). This must fit in uint32_t. By default it's 6. - --reduction_batch_size= + -tint_reduction_batch_size= The maximum number of spirv-reduce reductions that will be applied in a single mutation session (i.e. a call to LLVMFuzzerCustomMutator). This must fit in uint32_t. By default it's 3. - --repeated_pass_strategy= + -tint_repeated_pass_strategy= The strategy that will be used to recommend the next fuzzer pass. This must be one of `simple`, `looped` or `random` (without `). By default it's `simple`. Check out the doc for spirv-fuzz to learn more. - --transformation_batch_size= + -tint_transformation_batch_size= The maximum number of spirv-fuzz transformations that will be applied during a single mutation session (i.e. a call to LLVMFuzzerCustomMutator). This must fit in uint32_t. By default it's 3. - --validate_after_each_fuzzer_pass= + -tint_validate_after_each_fuzzer_pass= Whether to validate SPIR-V binary after each fuzzer pass. This must be one of `true` or `false` (without `). By default it's `true`. Switch this to `false` if you experience bad performance. - --validate_after_each_opt_pass= + -tint_validate_after_each_opt_pass= Whether to validate SPIR-V binary after each optimization pass. This must be one of `true` or `false` (without `). By default it's `true`. Switch this to `false` if you experience bad performance. - --validate_after_each_reduce_pass= + -tint_validate_after_each_reduce_pass= Whether to validate SPIR-V binary after each reduction pass. This must be one of `true` or `false` (without `). By default it's `true`. Switch this to `false` if you experience @@ -105,7 +105,7 @@ run it with -help=1 to check out libfuzzer parameters. Fuzzer parameters: - --error_dir + -tint_error_dir The directory that will be used to output invalid SPIR-V binaries to. This is especially useful during debugging mutators. The directory must have the following subdirectories: @@ -117,22 +117,22 @@ Fuzzer parameters: the mutators. By default invalid files are not printed out. - --fuzzing_target + -tint_fuzzing_target The type of backend to target during fuzzing. This must be one or a combination of `wgsl`, `spv`, `msl` or `hlsl` (without `) separated by commas. By default it's `wgsl,spv,msl,hlsl`. - --help + -tint_help Show this message. Note that there is also a -help=1 parameter that will display libfuzzer's help message. - --mutator_cache_size= + -tint_mutator_cache_size= The maximum size of the cache that stores mutation sessions. This must fit in uint32_t. By default it's 20. - --mutator_type= + -tint_mutator_type= Determines types of the mutators to run. This must be one or a combination of `fuzz`, `opt`, `reduce` (without `) separated by comma. If a combination is specified, each element in the @@ -287,80 +287,83 @@ bool HasPrefix(const char* str, const char* prefix) { return strncmp(str, prefix, strlen(prefix)) == 0; } -void ParseMutatorCliParam(const char* param, +bool ParseMutatorCliParam(const char* param, const char* help_message, MutatorCliParams* out) { - if (HasPrefix(param, "--transformation_batch_size=")) { - if (!ParseUint32(param + sizeof("--transformation_batch_size=") - 1, + if (HasPrefix(param, "-tint_transformation_batch_size=")) { + if (!ParseUint32(param + sizeof("-tint_transformation_batch_size=") - 1, &out->transformation_batch_size)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--reduction_batch_size=")) { - if (!ParseUint32(param + sizeof("--reduction_batch_size=") - 1, + } else if (HasPrefix(param, "-tint_reduction_batch_size=")) { + if (!ParseUint32(param + sizeof("-tint_reduction_batch_size=") - 1, &out->reduction_batch_size)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--opt_batch_size=")) { - if (!ParseUint32(param + sizeof("--opt_batch_size=") - 1, + } else if (HasPrefix(param, "-tint_opt_batch_size=")) { + if (!ParseUint32(param + sizeof("-tint_opt_batch_size=") - 1, &out->opt_batch_size)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--donors=")) { - out->donors = ParseDonors(param + sizeof("--donors=") - 1); - } else if (HasPrefix(param, "--repeated_pass_strategy=")) { + } else if (HasPrefix(param, "-tint_donors=")) { + out->donors = ParseDonors(param + sizeof("-tint_donors=") - 1); + } else if (HasPrefix(param, "-tint_repeated_pass_strategy=")) { if (!ParseRepeatedPassStrategy( - param + sizeof("--repeated_pass_strategy=") - 1, + param + sizeof("-tint_repeated_pass_strategy=") - 1, &out->repeated_pass_strategy)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--enable_all_fuzzer_passes=")) { - if (!ParseBool(param + sizeof("--enable_all_fuzzer_passes=") - 1, + } else if (HasPrefix(param, "-tint_enable_all_fuzzer_passes=")) { + if (!ParseBool(param + sizeof("-tint_enable_all_fuzzer_passes=") - 1, &out->enable_all_fuzzer_passes)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--enable_all_reduce_passes=")) { - if (!ParseBool(param + sizeof("--enable_all_reduce_passes=") - 1, + } else if (HasPrefix(param, "-tint_enable_all_reduce_passes=")) { + if (!ParseBool(param + sizeof("-tint_enable_all_reduce_passes=") - 1, &out->enable_all_reduce_passes)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--validate_after_each_opt_pass=")) { - if (!ParseBool(param + sizeof("--validate_after_each_opt_pass=") - 1, + } else if (HasPrefix(param, "-tint_validate_after_each_opt_pass=")) { + if (!ParseBool(param + sizeof("-tint_validate_after_each_opt_pass=") - 1, &out->validate_after_each_opt_pass)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--validate_after_each_fuzzer_pass=")) { - if (!ParseBool(param + sizeof("--validate_after_each_fuzzer_pass=") - 1, + } else if (HasPrefix(param, "-tint_validate_after_each_fuzzer_pass=")) { + if (!ParseBool(param + sizeof("-tint_validate_after_each_fuzzer_pass=") - 1, &out->validate_after_each_fuzzer_pass)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--validate_after_each_reduce_pass=")) { - if (!ParseBool(param + sizeof("--validate_after_each_reduce_pass=") - 1, + } else if (HasPrefix(param, "-tint_validate_after_each_reduce_pass=")) { + if (!ParseBool(param + sizeof("-tint_validate_after_each_reduce_pass=") - 1, &out->validate_after_each_reduce_pass)) { InvalidParameter(help_message, param); } + } else { + return false; } + return true; } } // namespace -FuzzerCliParams ParseFuzzerCliParams(int argc, const char* const* argv) { +FuzzerCliParams ParseFuzzerCliParams(int* argc, char** argv) { FuzzerCliParams cli_params; const auto* help_message = kFuzzerHelpMessage; auto help = false; - for (int i = 0; i < argc; ++i) { + for (int i = *argc - 1; i > 0; --i) { auto param = argv[i]; - ParseMutatorCliParam(param, help_message, &cli_params.mutator_params); + auto recognized_param = true; - if (HasPrefix(param, "--mutator_cache_size=")) { - if (!ParseUint32(param + sizeof("--mutator_cache_size=") - 1, + if (HasPrefix(param, "-tint_mutator_cache_size=")) { + if (!ParseUint32(param + sizeof("-tint_mutator_cache_size=") - 1, &cli_params.mutator_cache_size)) { InvalidParameter(help_message, param); } - } else if (HasPrefix(param, "--mutator_type=")) { + } else if (HasPrefix(param, "-tint_mutator_type=")) { auto result = MutatorType::kNone; - std::stringstream ss(param + sizeof("--mutator_type=") - 1); + std::stringstream ss(param + sizeof("-tint_mutator_type=") - 1); for (std::string value; std::getline(ss, value, ',');) { auto out = MutatorType::kNone; if (!ParseMutatorType(value.c_str(), &out)) { @@ -374,10 +377,10 @@ FuzzerCliParams ParseFuzzerCliParams(int argc, const char* const* argv) { } cli_params.mutator_type = result; - } else if (HasPrefix(param, "--fuzzing_target=")) { + } else if (HasPrefix(param, "-tint_fuzzing_target=")) { auto result = FuzzingTarget::kNone; - std::stringstream ss(param + sizeof("--fuzzing_target=") - 1); + std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1); for (std::string value; std::getline(ss, value, ',');) { auto tmp = FuzzingTarget::kNone; if (!ParseFuzzingTarget(value.c_str(), &tmp)) { @@ -391,10 +394,24 @@ FuzzerCliParams ParseFuzzerCliParams(int argc, const char* const* argv) { } cli_params.fuzzing_target = result; - } else if (HasPrefix(param, "--error_dir=")) { - cli_params.error_dir = param + sizeof("--error_dir=") - 1; - } else if (!strcmp(param, "--help")) { + } else if (HasPrefix(param, "-tint_error_dir=")) { + cli_params.error_dir = param + sizeof("-tint_error_dir=") - 1; + } else if (!strcmp(param, "-tint_help")) { help = true; + } else { + recognized_param = ParseMutatorCliParam(param, help_message, + &cli_params.mutator_params); + } + + if (recognized_param) { + // Remove the recognized parameter from the list of all parameters by + // swapping it with the last one. This will suppress warnings in the + // libFuzzer about unrecognized parameters. By default, libFuzzer thinks + // that all user-defined parameters start with two dashes. However, we are + // forced to use a single one to make the fuzzer compatible with the + // ClusterFuzz. + std::swap(argv[i], argv[*argc - 1]); + *argc -= 1; } } diff --git a/fuzzers/tint_spirv_tools_fuzzer/cli.h b/fuzzers/tint_spirv_tools_fuzzer/cli.h index 1076066c71..3d54a5dc9a 100644 --- a/fuzzers/tint_spirv_tools_fuzzer/cli.h +++ b/fuzzers/tint_spirv_tools_fuzzer/cli.h @@ -102,7 +102,8 @@ struct MutatorCliParams { bool validate_after_each_reduce_pass = true; }; -/// Parameters specific to the fuzzer. Type `--help` in the CLI to learn more. +/// Parameters specific to the fuzzer. Type `-tint_help` in the CLI to learn +/// more. struct FuzzerCliParams { /// The size of the cache that records ongoing mutation sessions. uint32_t mutator_cache_size = 20; @@ -138,13 +139,15 @@ struct MutatorDebuggerCliParams { /// Parses CLI parameters for the fuzzer. This function exits with an error code /// and a message is printed to the console if some parameter has invalid -/// format. You can pass `--help` to check out all available parameters. +/// format. You can pass `-tint_help` to check out all available parameters. +/// This function will remove recognized parameters from the `argv` and adjust +/// the `argc` accordingly. /// /// @param argc - the number of parameters (identical to the `argc` in `main` /// function). /// @param argv - array of C strings of parameters. /// @return the parsed parameters. -FuzzerCliParams ParseFuzzerCliParams(int argc, const char* const* argv); +FuzzerCliParams ParseFuzzerCliParams(int* argc, char** argv); /// Parses CLI parameters for the mutator debugger. This function exits with an /// error code and a message is printed to the console if some parameter has diff --git a/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc b/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc index 7f67e75822..c1b3d64017 100644 --- a/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc +++ b/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc @@ -38,7 +38,7 @@ struct Context { Context* context = nullptr; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { - auto params = ParseFuzzerCliParams(*argc, *argv); + auto params = ParseFuzzerCliParams(argc, *argv); auto mutator_cache = params.mutator_cache_size ? std::make_unique(params.mutator_cache_size)