
AIX's system header provides these C++ overloads for compatibility with older XL C++ implementations, but they can be disabled by defining __LIBC_NO_CPP_MATH_OVERLOADS__ since AIX 7.2 TL 5 SP 3. Since D109078 landed clang will define this macro when using libc++ on AIX and we already run the lit tests with it too. This change will enable the overloads in libc++'s math.h and we'll continue to require the compiler to define the macro going forward. Reviewed By: ldionne, jsji, EricWF Differential Revision: https://reviews.llvm.org/D102172 co-authored-by: Jason Liu <jasonliu.development@gmail.com>
195 lines
6.7 KiB
C++
195 lines
6.7 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// UNSUPPORTED: c++03, c++11
|
|
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <random>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "fuzz.h"
|
|
|
|
template <class IntT>
|
|
std::vector<IntT> GetValues(const std::uint8_t *data, std::size_t size) {
|
|
std::vector<IntT> result;
|
|
while (size >= sizeof(IntT)) {
|
|
IntT tmp;
|
|
std::memcpy(&tmp, data, sizeof(IntT));
|
|
size -= sizeof(IntT);
|
|
data += sizeof(IntT);
|
|
result.push_back(tmp);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
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, std::size_t size, bool &OK) {
|
|
constexpr bool select_vector_result = std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value;
|
|
constexpr bool select_vector_double = std::is_constructible<ParamT, double*, double*>::value;
|
|
constexpr int selector = select_vector_result ? 0 : (select_vector_double ? 1 : 2);
|
|
return DispatchAndCreate(std::integral_constant<int, selector>{}, data, size, OK);
|
|
}
|
|
|
|
// Vector result
|
|
static ParamT DispatchAndCreate(std::integral_constant<int, 0>, const std::uint8_t *data, std::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;
|
|
}
|
|
|
|
// Vector double
|
|
static ParamT DispatchAndCreate(std::integral_constant<int, 1>, const std::uint8_t *data, std::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;
|
|
}
|
|
|
|
// Default
|
|
static ParamT DispatchAndCreate(std::integral_constant<int, 2>, const std::uint8_t *data, std::size_t size, bool &OK) {
|
|
OK = false;
|
|
if (size < sizeof(ParamT))
|
|
return ParamT{};
|
|
OK = true;
|
|
ParamT input;
|
|
std::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 std::uint8_t *data, std::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;
|
|
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 std::uint8_t *data, std::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;
|
|
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 std::uint8_t *data, std::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 = Dist::param_type;
|
|
using ResultT = Dist::result_type;
|
|
|
|
static ParamT Create(const std::uint8_t *data, std::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 helper(const std::uint8_t *data, std::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)) {
|
|
// FIXME(llvm.org/PR44289):
|
|
// Investigate why these distributions are returning NaN and decide
|
|
// if that's what we want them to be doing.
|
|
//
|
|
// Make this assert false (or return non-zero).
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
|
|
return helper<std::uniform_int_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::uniform_real_distribution<float>>(data, size) ||
|
|
helper<std::bernoulli_distribution>(data, size) ||
|
|
helper<std::poisson_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::geometric_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::binomial_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::negative_binomial_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::exponential_distribution<float>>(data, size) ||
|
|
helper<std::gamma_distribution<float>>(data, size) ||
|
|
helper<std::weibull_distribution<float>>(data, size) ||
|
|
helper<std::extreme_value_distribution<float>>(data, size) ||
|
|
helper<std::normal_distribution<float>>(data, size) ||
|
|
helper<std::lognormal_distribution<float>>(data, size) ||
|
|
helper<std::chi_squared_distribution<float>>(data, size) ||
|
|
helper<std::cauchy_distribution<float>>(data, size) ||
|
|
helper<std::fisher_f_distribution<float>>(data, size) ||
|
|
helper<std::student_t_distribution<float>>(data, size) ||
|
|
helper<std::discrete_distribution<std::int16_t>>(data, size) ||
|
|
helper<std::piecewise_constant_distribution<float>>(data, size) ||
|
|
helper<std::piecewise_linear_distribution<float>>(data, size);
|
|
}
|