feat(fuzzer): Adds fuzz tests (#386)
This commit is contained in:
parent
e1f8c16702
commit
58daccc945
6
.github/workflows/cmake.yml
vendored
6
.github/workflows/cmake.yml
vendored
@ -20,11 +20,9 @@ jobs:
|
||||
build-ubuntu:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ]
|
||||
os: [ ubuntu-20.04, ubuntu-22.04 ]
|
||||
compiler: [ g++-9, g++-10, clang++ ]
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
compiler: g++-7
|
||||
|
||||
name: Build and Test on Ubuntu
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
|
@ -6,3 +6,11 @@ cc_library(
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
|
||||
|
||||
cc_fuzz_test(
|
||||
name = "cxxopts_fuzz_test",
|
||||
srcs = ["test/fuzz.cpp"],
|
||||
deps = [":cxxopts"],
|
||||
)
|
16
WORKSPACE
16
WORKSPACE
@ -0,0 +1,16 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "rules_fuzzing",
|
||||
sha256 = "23bb074064c6f488d12044934ab1b0631e8e6898d5cf2f6bde087adb01111573",
|
||||
strip_prefix = "rules_fuzzing-0.3.1",
|
||||
urls = ["https://github.com/bazelbuild/rules_fuzzing/archive/v0.3.1.zip"],
|
||||
)
|
||||
|
||||
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
|
||||
|
||||
rules_fuzzing_dependencies()
|
||||
|
||||
load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
|
||||
|
||||
rules_fuzzing_init()
|
@ -51,3 +51,10 @@ add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
||||
|
||||
add_executable(link_test link_a.cpp link_b.cpp)
|
||||
target_link_libraries(link_test cxxopts)
|
||||
|
||||
if(("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND ("${CMAKE_SYSTEM}" MATCHES "Linux"))
|
||||
add_executable(fuzzer fuzz.cpp)
|
||||
target_link_libraries(fuzzer PRIVATE cxxopts)
|
||||
target_compile_options(fuzzer PRIVATE -fsanitize=fuzzer)
|
||||
target_link_options(fuzzer PRIVATE -fsanitize=fuzzer)
|
||||
endif()
|
||||
|
107
test/fuzz.cpp
Normal file
107
test/fuzz.cpp
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user