[libc++] Add fuzzing tests for parts of <random>.
This patch also re-names the existing fuzzing unit tests so they
actually run.
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: daacf57032450079b44b8a7f9b976700d3bc38f8
diff --git a/fuzzing/fuzzing.cpp b/fuzzing/fuzzing.cpp
index 5c32f28..2849939 100644
--- a/fuzzing/fuzzing.cpp
+++ b/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 @@
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 @@
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