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 <noreply+kokoro@google.com>
Reviewed-by: Alastair Donaldson <afdx@google.com>
Commit-Queue: Alastair Donaldson <afdx@google.com>
diff --git a/fuzzers/tint_ast_fuzzer/cli.cc b/fuzzers/tint_ast_fuzzer/cli.cc
index 5e3f073..a1ace13 100644
--- a/fuzzers/tint_ast_fuzzer/cli.cc
+++ b/fuzzers/tint_ast_fuzzer/cli.cc
@@ -19,6 +19,7 @@
#include <limits>
#include <sstream>
#include <string>
+#include <utility>
namespace tint {
namespace fuzzers {
@@ -31,28 +32,28 @@
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 @@
} // 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 @@
}
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 dd94fbb..077b662 100644
--- a/fuzzers/tint_ast_fuzzer/cli.h
+++ b/fuzzers/tint_ast_fuzzer/cli.h
@@ -39,7 +39,7 @@
return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(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 @@
/// @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 a431cb2..5e58fb4 100644
--- a/fuzzers/tint_ast_fuzzer/fuzzer.cc
+++ b/fuzzers/tint_ast_fuzzer/fuzzer.cc
@@ -34,7 +34,7 @@
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 cfb6633..f304ed7 100644
--- a/fuzzers/tint_spirv_tools_fuzzer/cli.cc
+++ b/fuzzers/tint_spirv_tools_fuzzer/cli.cc
@@ -32,59 +32,59 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 1076066..3d54a5d 100644
--- a/fuzzers/tint_spirv_tools_fuzzer/cli.h
+++ b/fuzzers/tint_spirv_tools_fuzzer/cli.h
@@ -102,7 +102,8 @@
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 @@
/// 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 7f67e75..c1b3d64 100644
--- a/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc
+++ b/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc
@@ -38,7 +38,7 @@
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<MutatorCache>(params.mutator_cache_size)