mirror of
https://github.com/jarro2783/cxxopts.git
synced 2026-09-07 05:10:51 +02:00
feat(fuzzer): Adds fuzz tests (#386)
This commit is contained in:
+107
@@ -0,0 +1,107 @@
|
||||
#include <cassert>
|
||||
#include <cxxopts.hpp>
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
|
||||
constexpr int kMaxOptions = 1024;
|
||||
constexpr int kMaxArgSize = 1024;
|
||||
|
||||
enum class ParseableTypes
|
||||
{
|
||||
kInt,
|
||||
kString,
|
||||
kVectorString,
|
||||
kFloat,
|
||||
kDouble,
|
||||
|
||||
// Marker for fuzzer.
|
||||
kMaxValue,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
add_fuzzed_option(cxxopts::Options* options, FuzzedDataProvider* provider)
|
||||
{
|
||||
assert(options);
|
||||
assert(provider);
|
||||
|
||||
options->add_options()(provider->ConsumeRandomLengthString(kMaxArgSize),
|
||||
provider->ConsumeRandomLengthString(kMaxArgSize),
|
||||
cxxopts::value<T>());
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
try
|
||||
{
|
||||
FuzzedDataProvider provider(data, size);
|
||||
|
||||
// Randomly generate a usage string.
|
||||
cxxopts::Options options(provider.ConsumeRandomLengthString(kMaxArgSize),
|
||||
provider.ConsumeRandomLengthString(kMaxArgSize));
|
||||
|
||||
// Randomly generate a set of flags configurations.
|
||||
for (int i = 0; i < provider.ConsumeIntegralInRange<int>(0, kMaxOptions);
|
||||
i++)
|
||||
{
|
||||
switch (provider.ConsumeEnum<ParseableTypes>())
|
||||
{
|
||||
case ParseableTypes::kInt:
|
||||
add_fuzzed_option<int>(&options, &provider);
|
||||
break;
|
||||
case ParseableTypes::kString:
|
||||
add_fuzzed_option<std::string>(&options, &provider);
|
||||
break;
|
||||
case ParseableTypes::kVectorString:
|
||||
add_fuzzed_option<std::vector<std::string>>(&options, &provider);
|
||||
break;
|
||||
case ParseableTypes::kFloat:
|
||||
add_fuzzed_option<float>(&options, &provider);
|
||||
break;
|
||||
case ParseableTypes::kDouble:
|
||||
add_fuzzed_option<double>(&options, &provider);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Sometimes allow unrecognised options.
|
||||
if (provider.ConsumeBool())
|
||||
{
|
||||
options.allow_unrecognised_options();
|
||||
}
|
||||
// Sometimes allow trailing positional arguments.
|
||||
if (provider.ConsumeBool())
|
||||
{
|
||||
std::string positional_option_name =
|
||||
provider.ConsumeRandomLengthString(kMaxArgSize);
|
||||
options.add_options()(positional_option_name,
|
||||
provider.ConsumeRandomLengthString(kMaxArgSize),
|
||||
cxxopts::value<std::vector<std::string>>());
|
||||
options.parse_positional({positional_option_name});
|
||||
}
|
||||
|
||||
// Build command line input.
|
||||
const int argc = provider.ConsumeIntegralInRange<int>(1, kMaxOptions);
|
||||
|
||||
std::vector<std::string> command_line_container;
|
||||
command_line_container.reserve(argc);
|
||||
|
||||
std::vector<const char*> argv;
|
||||
argv.reserve(argc);
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
command_line_container.push_back(
|
||||
provider.ConsumeRandomLengthString(kMaxArgSize));
|
||||
argv.push_back(command_line_container[i].c_str());
|
||||
}
|
||||
|
||||
// Parse command line;
|
||||
auto result = options.parse(argc, argv.data());
|
||||
} catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user