diff options
Diffstat (limited to 'libcxx/fuzzing')
-rw-r--r-- | libcxx/fuzzing/RoutineNames.txt | 20 | ||||
-rw-r--r-- | libcxx/fuzzing/fuzz_test_template.cpp | 22 | ||||
-rw-r--r-- | libcxx/fuzzing/fuzzing.cpp | 205 | ||||
-rw-r--r-- | libcxx/fuzzing/fuzzing.h | 22 |
4 files changed, 268 insertions, 1 deletions
diff --git a/libcxx/fuzzing/RoutineNames.txt b/libcxx/fuzzing/RoutineNames.txt index 06ef70ed649..a853c87e1f7 100644 --- a/libcxx/fuzzing/RoutineNames.txt +++ b/libcxx/fuzzing/RoutineNames.txt @@ -18,3 +18,23 @@ regex_awk regex_grep regex_egrep search +uniform_int_distribution +uniform_real_distribution +bernoulli_distribution +poisson_distribution +geometric_distribution +binomial_distribution +negative_binomial_distribution +exponential_distribution +gamma_distribution +weibull_distribution +extreme_value_distribution +normal_distribution +lognormal_distribution +chi_squared_distribution +cauchy_distribution +fisher_f_distribution +student_t_distribution +discrete_distribution +piecewise_constant_distribution +piecewise_linear_distribution diff --git a/libcxx/fuzzing/fuzz_test_template.cpp b/libcxx/fuzzing/fuzz_test_template.cpp new file mode 100644 index 00000000000..ba44eef7891 --- /dev/null +++ b/libcxx/fuzzing/fuzz_test_template.cpp @@ -0,0 +1,22 @@ +//===------------------------- fuzz_test.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "fuzzing/fuzzing.h" +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> + +#ifndef TEST_FUNCTION +#error TEST_FUNCTION must be defined +#endif + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + int result = fuzzing::TEST_FUNCTION(data, size); + assert(result == 0); return 0; +} diff --git a/libcxx/fuzzing/fuzzing.cpp b/libcxx/fuzzing/fuzzing.cpp index 5c32f28a3ad..284993918aa 100644 --- a/libcxx/fuzzing/fuzzing.cpp +++ b/libcxx/fuzzing/fuzzing.cpp @@ -27,10 +27,16 @@ #include <algorithm> #include <functional> #include <regex> +#include <random> #include <cassert> +#include <cmath> #include <iostream> +#ifdef NDEBUG +#undef NDEBUG +#endif +#include <cassert> // If we had C++14, we could use the four iterator version of is_permutation and equal namespace fuzzing { @@ -212,7 +218,7 @@ int partition_copy(const uint8_t *data, size_t size) auto iter = std::partition_copy(data, data + size, std::back_inserter<Vec>(v1), std::back_inserter<Vec>(v2), is_even<uint8_t>()); - + ((void)iter); // The two vectors should add up to the original size if (v1.size() + v2.size() != size) return 1; @@ -614,4 +620,201 @@ static void set_helper (const uint8_t *data, size_t size, Vec &v1, Vec &v2) std::sort(v2.begin(), v2.end()); } +enum class ParamKind { + OneValue, + TwoValues, + PointerRange +}; + +template <class IntT> +std::vector<IntT> GetValues(const uint8_t *data, size_t size) { + std::vector<IntT> result; + while (size >= sizeof(IntT)) { + IntT tmp; + memcpy(&tmp, data, sizeof(IntT)); + size -= sizeof(IntT); + data += sizeof(IntT); + result.push_back(tmp); + } + return result; +} + +enum InitKind { + Default, + DoubleOnly, + VectorDouble, + VectorResultType +}; + +template <class Dist> +struct ParamTypeHelper { + using ParamT = typename Dist::param_type; + using ResultT = typename Dist::result_type; + static_assert(std::is_same<ResultT, typename ParamT::distribution_type::result_type>::value, ""); + static ParamT Create(const uint8_t* data, size_t size, bool &OK) { + + if constexpr (std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value) + return CreateVectorResult(data, size, OK); + else if constexpr (std::is_constructible<ParamT, double*, double*>::value) + return CreateVectorDouble(data, size, OK); + else + return CreateDefault(data, size, OK); + } + + +static ParamT +CreateVectorResult(const uint8_t *data, size_t size, bool &OK) { + auto Input = GetValues<ResultT>(data, size); + OK = false; + if (Input.size() < 10) + return ParamT{}; + OK = true; + auto Beg = Input.begin(); + auto End = Input.end(); + auto Mid = Beg + ((End - Beg) / 2); + + assert(Mid - Beg <= (End - Mid)); + ParamT p(Beg, Mid, Mid); + return p; +} + + static ParamT + CreateVectorDouble(const uint8_t *data, size_t size, bool &OK) { + auto Input = GetValues<double>(data, size); + + OK = true; + auto Beg = Input.begin(); + auto End = Input.end(); + + ParamT p(Beg, End); + return p; + } + + + static ParamT + CreateDefault(const uint8_t *data, size_t size, bool &OK) { + OK = false; + if (size < sizeof(ParamT)) + return ParamT{}; + OK = true; + ParamT input; + memcpy(&input, data, sizeof(ParamT)); + return input; + } + +}; + + + + +template <class IntT> +struct ParamTypeHelper<std::poisson_distribution<IntT>> { + using Dist = std::poisson_distribution<IntT>; + using ParamT = typename Dist::param_type; + using ResultT = typename Dist::result_type; + + static ParamT Create(const uint8_t *data, size_t size, bool& OK) { + OK = false; + auto vals = GetValues<double>(data, size); + if (vals.empty() || std::isnan(vals[0]) || std::isnan(std::abs(vals[0])) || vals[0] < 0 ) + return ParamT{}; + OK = true; + //std::cerr << "Value: " << vals[0] << std::endl; + return ParamT{vals[0]}; + } +}; + + +template <class IntT> +struct ParamTypeHelper<std::geometric_distribution<IntT>> { + using Dist = std::geometric_distribution<IntT>; + using ParamT = typename Dist::param_type; + using ResultT = typename Dist::result_type; + + static ParamT Create(const uint8_t *data, size_t size, bool& OK) { + OK = false; + auto vals = GetValues<double>(data, size); + if (vals.empty() || std::isnan(vals[0]) || vals[0] < 0 ) + return ParamT{}; + OK = true; + // std::cerr << "Value: " << vals[0] << std::endl; + return ParamT{vals[0]}; + } +}; + + +template <class IntT> +struct ParamTypeHelper<std::lognormal_distribution<IntT>> { + using Dist = std::lognormal_distribution<IntT>; + using ParamT = typename Dist::param_type; + using ResultT = typename Dist::result_type; + + static ParamT Create(const uint8_t *data, size_t size, bool& OK) { + OK = false; + auto vals = GetValues<ResultT>(data, size); + if (vals.size() < 2 ) + return ParamT{}; + OK = true; + return ParamT{vals[0], vals[1]}; + } +}; + + +template <> +struct ParamTypeHelper<std::bernoulli_distribution> { + using Dist = std::bernoulli_distribution; + using ParamT = typename Dist::param_type; + using ResultT = typename Dist::result_type; + + static ParamT Create(const uint8_t *data, size_t size, bool& OK) { + OK = false; + auto vals = GetValues<double>(data, size); + if (vals.empty()) + return ParamT{}; + OK = true; + return ParamT{vals[0]}; + } +}; + +template <class Distribution> +int random_distribution_helper(const uint8_t *data, size_t size) { + + std::mt19937 engine; + using ParamT = typename Distribution::param_type; + bool OK; + ParamT p = ParamTypeHelper<Distribution>::Create(data, size, OK); + if (!OK) + return 0; + Distribution d(p); + volatile auto res = d(engine); + if (std::isnan(res)) + return 1; + return 0; +} + +#define DEFINE_RANDOM_TEST(name, ...) \ +int name(const uint8_t *data, size_t size) { \ + return random_distribution_helper< std::name __VA_ARGS__ >(data, size); \ +} +DEFINE_RANDOM_TEST(uniform_int_distribution,<std::int16_t>) +DEFINE_RANDOM_TEST(uniform_real_distribution,<float>) +DEFINE_RANDOM_TEST(bernoulli_distribution) +DEFINE_RANDOM_TEST(poisson_distribution,<std::int16_t>) +DEFINE_RANDOM_TEST(geometric_distribution,<std::int16_t>) +DEFINE_RANDOM_TEST(binomial_distribution, <std::int16_t>) +DEFINE_RANDOM_TEST(negative_binomial_distribution, <std::int16_t>) +DEFINE_RANDOM_TEST(exponential_distribution, <float>) +DEFINE_RANDOM_TEST(gamma_distribution, <float>) +DEFINE_RANDOM_TEST(weibull_distribution, <float>) +DEFINE_RANDOM_TEST(extreme_value_distribution, <float>) +DEFINE_RANDOM_TEST(normal_distribution, <float>) +DEFINE_RANDOM_TEST(lognormal_distribution, <float>) +DEFINE_RANDOM_TEST(chi_squared_distribution, <float>) +DEFINE_RANDOM_TEST(cauchy_distribution, <float>) +DEFINE_RANDOM_TEST(fisher_f_distribution, <float>) +DEFINE_RANDOM_TEST(student_t_distribution, <float>) +DEFINE_RANDOM_TEST(discrete_distribution, <std::int16_t>) +DEFINE_RANDOM_TEST(piecewise_constant_distribution, <float>) +DEFINE_RANDOM_TEST(piecewise_linear_distribution, <float>) + } // namespace fuzzing diff --git a/libcxx/fuzzing/fuzzing.h b/libcxx/fuzzing/fuzzing.h index 64103e59007..99a3aa14a77 100644 --- a/libcxx/fuzzing/fuzzing.h +++ b/libcxx/fuzzing/fuzzing.h @@ -56,6 +56,28 @@ namespace fuzzing { // int set_symmetric_difference (const uint8_t *data, size_t size); // int merge (const uint8_t *data, size_t size); +// Random numbers + int uniform_int_distribution(const uint8_t*, size_t); + int uniform_real_distribution(const uint8_t*, size_t); + int bernoulli_distribution(const uint8_t*, size_t); + int poisson_distribution(const uint8_t*, size_t); + int geometric_distribution(const uint8_t*, size_t); + int binomial_distribution(const uint8_t*, size_t); + int negative_binomial_distribution(const uint8_t*, size_t); + int exponential_distribution(const uint8_t*, size_t); + int gamma_distribution(const uint8_t*, size_t); + int weibull_distribution(const uint8_t*, size_t); + int extreme_value_distribution(const uint8_t*, size_t); + int normal_distribution(const uint8_t*, size_t); + int lognormal_distribution(const uint8_t*, size_t); + int chi_squared_distribution(const uint8_t*, size_t); + int cauchy_distribution(const uint8_t*, size_t); + int fisher_f_distribution(const uint8_t*, size_t); + int student_t_distribution(const uint8_t*, size_t); + int discrete_distribution(const uint8_t*, size_t); + int piecewise_constant_distribution(const uint8_t*, size_t); + int piecewise_linear_distribution(const uint8_t*, size_t); + } // namespace fuzzing #endif // _LIBCPP_FUZZING |