1b4bd1943SLouis Dionne //===----------------------------------------------------------------------===// 2b4bd1943SLouis Dionne // 3b4bd1943SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b4bd1943SLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5b4bd1943SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b4bd1943SLouis Dionne // 7b4bd1943SLouis Dionne //===----------------------------------------------------------------------===// 8b4bd1943SLouis Dionne 9a5403a3aSPetr Hosek // This test fails because Clang no longer enables -fdelayed-template-parsing 10a5403a3aSPetr Hosek // by default on Windows with C++20 (#69431). 11*1c3a99c7Sgulfemsavrun // XFAIL: msvc && (clang-18 || clang-19 || clang-20) 12a5403a3aSPetr Hosek 13b4bd1943SLouis Dionne // UNSUPPORTED: c++03, c++11 14b4bd1943SLouis Dionne 15b4bd1943SLouis Dionne #include <cassert> 16b4bd1943SLouis Dionne #include <cmath> 17b4bd1943SLouis Dionne #include <cstddef> 18b4bd1943SLouis Dionne #include <cstdint> 19b4bd1943SLouis Dionne #include <cstring> 20b4bd1943SLouis Dionne #include <random> 21b4bd1943SLouis Dionne #include <type_traits> 22b4bd1943SLouis Dionne #include <vector> 23b4bd1943SLouis Dionne 24b4bd1943SLouis Dionne #include "fuzz.h" 25b4bd1943SLouis Dionne 26b4bd1943SLouis Dionne template <class IntT> 27b4bd1943SLouis Dionne std::vector<IntT> GetValues(const std::uint8_t *data, std::size_t size) { 28b4bd1943SLouis Dionne std::vector<IntT> result; 29b4bd1943SLouis Dionne while (size >= sizeof(IntT)) { 30b4bd1943SLouis Dionne IntT tmp; 31b4bd1943SLouis Dionne std::memcpy(&tmp, data, sizeof(IntT)); 32b4bd1943SLouis Dionne size -= sizeof(IntT); 33b4bd1943SLouis Dionne data += sizeof(IntT); 34b4bd1943SLouis Dionne result.push_back(tmp); 35b4bd1943SLouis Dionne } 36b4bd1943SLouis Dionne return result; 37b4bd1943SLouis Dionne } 38b4bd1943SLouis Dionne 39b4bd1943SLouis Dionne template <class Dist> 40b4bd1943SLouis Dionne struct ParamTypeHelper { 41b4bd1943SLouis Dionne using ParamT = typename Dist::param_type; 42b4bd1943SLouis Dionne using ResultT = typename Dist::result_type; 43b4bd1943SLouis Dionne static_assert(std::is_same<ResultT, typename ParamT::distribution_type::result_type>::value, ""); 44b4bd1943SLouis Dionne 45bd5d0feeSMark de Wever static ParamT Create(const std::uint8_t* data, std::size_t size, bool &OK) { 46b4bd1943SLouis Dionne constexpr bool select_vector_result = std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value; 47b4bd1943SLouis Dionne constexpr bool select_vector_double = std::is_constructible<ParamT, double*, double*>::value; 48b4bd1943SLouis Dionne constexpr int selector = select_vector_result ? 0 : (select_vector_double ? 1 : 2); 49b4bd1943SLouis Dionne return DispatchAndCreate(std::integral_constant<int, selector>{}, data, size, OK); 50b4bd1943SLouis Dionne } 51b4bd1943SLouis Dionne 52b4bd1943SLouis Dionne // Vector result 53b4bd1943SLouis Dionne static ParamT DispatchAndCreate(std::integral_constant<int, 0>, const std::uint8_t *data, std::size_t size, bool &OK) { 54b4bd1943SLouis Dionne auto Input = GetValues<ResultT>(data, size); 55b4bd1943SLouis Dionne OK = false; 56b4bd1943SLouis Dionne if (Input.size() < 10) 57b4bd1943SLouis Dionne return ParamT{}; 58b4bd1943SLouis Dionne OK = true; 59b4bd1943SLouis Dionne auto Beg = Input.begin(); 60b4bd1943SLouis Dionne auto End = Input.end(); 61b4bd1943SLouis Dionne auto Mid = Beg + ((End - Beg) / 2); 62b4bd1943SLouis Dionne 63b4bd1943SLouis Dionne assert(Mid - Beg <= (End - Mid)); 64b4bd1943SLouis Dionne ParamT p(Beg, Mid, Mid); 65b4bd1943SLouis Dionne return p; 66b4bd1943SLouis Dionne } 67b4bd1943SLouis Dionne 68b4bd1943SLouis Dionne // Vector double 69b4bd1943SLouis Dionne static ParamT DispatchAndCreate(std::integral_constant<int, 1>, const std::uint8_t *data, std::size_t size, bool &OK) { 70b4bd1943SLouis Dionne auto Input = GetValues<double>(data, size); 71b4bd1943SLouis Dionne 72b4bd1943SLouis Dionne OK = true; 73b4bd1943SLouis Dionne auto Beg = Input.begin(); 74b4bd1943SLouis Dionne auto End = Input.end(); 75b4bd1943SLouis Dionne 76b4bd1943SLouis Dionne ParamT p(Beg, End); 77b4bd1943SLouis Dionne return p; 78b4bd1943SLouis Dionne } 79b4bd1943SLouis Dionne 80b4bd1943SLouis Dionne // Default 81b4bd1943SLouis Dionne static ParamT DispatchAndCreate(std::integral_constant<int, 2>, const std::uint8_t *data, std::size_t size, bool &OK) { 82b4bd1943SLouis Dionne OK = false; 83b4bd1943SLouis Dionne if (size < sizeof(ParamT)) 84b4bd1943SLouis Dionne return ParamT{}; 85b4bd1943SLouis Dionne OK = true; 86b4bd1943SLouis Dionne ParamT input; 87b4bd1943SLouis Dionne std::memcpy(&input, data, sizeof(ParamT)); 88b4bd1943SLouis Dionne return input; 89b4bd1943SLouis Dionne } 90b4bd1943SLouis Dionne }; 91b4bd1943SLouis Dionne 92b4bd1943SLouis Dionne template <class IntT> 93b4bd1943SLouis Dionne struct ParamTypeHelper<std::poisson_distribution<IntT>> { 94b4bd1943SLouis Dionne using Dist = std::poisson_distribution<IntT>; 95b4bd1943SLouis Dionne using ParamT = typename Dist::param_type; 96b4bd1943SLouis Dionne using ResultT = typename Dist::result_type; 97b4bd1943SLouis Dionne 98b4bd1943SLouis Dionne static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) { 99b4bd1943SLouis Dionne OK = false; 100b4bd1943SLouis Dionne auto vals = GetValues<double>(data, size); 101b4bd1943SLouis Dionne if (vals.empty() || std::isnan(vals[0]) || std::isnan(std::abs(vals[0])) || vals[0] < 0) 102b4bd1943SLouis Dionne return ParamT{}; 103b4bd1943SLouis Dionne OK = true; 104b4bd1943SLouis Dionne return ParamT{vals[0]}; 105b4bd1943SLouis Dionne } 106b4bd1943SLouis Dionne }; 107b4bd1943SLouis Dionne 108b4bd1943SLouis Dionne template <class IntT> 109b4bd1943SLouis Dionne struct ParamTypeHelper<std::geometric_distribution<IntT>> { 110b4bd1943SLouis Dionne using Dist = std::geometric_distribution<IntT>; 111b4bd1943SLouis Dionne using ParamT = typename Dist::param_type; 112b4bd1943SLouis Dionne using ResultT = typename Dist::result_type; 113b4bd1943SLouis Dionne 114b4bd1943SLouis Dionne static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) { 115b4bd1943SLouis Dionne OK = false; 116b4bd1943SLouis Dionne auto vals = GetValues<double>(data, size); 117b4bd1943SLouis Dionne if (vals.empty() || std::isnan(vals[0]) || vals[0] < 0 ) 118b4bd1943SLouis Dionne return ParamT{}; 119b4bd1943SLouis Dionne OK = true; 120b4bd1943SLouis Dionne return ParamT{vals[0]}; 121b4bd1943SLouis Dionne } 122b4bd1943SLouis Dionne }; 123b4bd1943SLouis Dionne 124b4bd1943SLouis Dionne template <class IntT> 125b4bd1943SLouis Dionne struct ParamTypeHelper<std::lognormal_distribution<IntT>> { 126b4bd1943SLouis Dionne using Dist = std::lognormal_distribution<IntT>; 127b4bd1943SLouis Dionne using ParamT = typename Dist::param_type; 128b4bd1943SLouis Dionne using ResultT = typename Dist::result_type; 129b4bd1943SLouis Dionne 130b4bd1943SLouis Dionne static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) { 131b4bd1943SLouis Dionne OK = false; 132b4bd1943SLouis Dionne auto vals = GetValues<ResultT>(data, size); 133b4bd1943SLouis Dionne if (vals.size() < 2 ) 134b4bd1943SLouis Dionne return ParamT{}; 135b4bd1943SLouis Dionne OK = true; 136b4bd1943SLouis Dionne return ParamT{vals[0], vals[1]}; 137b4bd1943SLouis Dionne } 138b4bd1943SLouis Dionne }; 139b4bd1943SLouis Dionne 140b4bd1943SLouis Dionne template <> 141b4bd1943SLouis Dionne struct ParamTypeHelper<std::bernoulli_distribution> { 142b4bd1943SLouis Dionne using Dist = std::bernoulli_distribution; 143b4bd1943SLouis Dionne using ParamT = Dist::param_type; 144b4bd1943SLouis Dionne using ResultT = Dist::result_type; 145b4bd1943SLouis Dionne 146b4bd1943SLouis Dionne static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) { 147b4bd1943SLouis Dionne OK = false; 148b4bd1943SLouis Dionne auto vals = GetValues<double>(data, size); 149b4bd1943SLouis Dionne if (vals.empty()) 150b4bd1943SLouis Dionne return ParamT{}; 151b4bd1943SLouis Dionne OK = true; 152b4bd1943SLouis Dionne return ParamT{vals[0]}; 153b4bd1943SLouis Dionne } 154b4bd1943SLouis Dionne }; 155b4bd1943SLouis Dionne 156b4bd1943SLouis Dionne template <class Distribution> 157b4bd1943SLouis Dionne int helper(const std::uint8_t *data, std::size_t size) { 158b4bd1943SLouis Dionne std::mt19937 engine; 159b4bd1943SLouis Dionne using ParamT = typename Distribution::param_type; 160b4bd1943SLouis Dionne bool OK; 161b4bd1943SLouis Dionne ParamT p = ParamTypeHelper<Distribution>::Create(data, size, OK); 162b4bd1943SLouis Dionne if (!OK) 163b4bd1943SLouis Dionne return 0; 164b4bd1943SLouis Dionne Distribution d(p); 165b4bd1943SLouis Dionne volatile auto res = d(engine); 166b4bd1943SLouis Dionne if (std::isnan(res)) { 167b4bd1943SLouis Dionne // FIXME(llvm.org/PR44289): 168b4bd1943SLouis Dionne // Investigate why these distributions are returning NaN and decide 169b4bd1943SLouis Dionne // if that's what we want them to be doing. 170b4bd1943SLouis Dionne // 171b4bd1943SLouis Dionne // Make this assert false (or return non-zero). 172b4bd1943SLouis Dionne return 0; 173b4bd1943SLouis Dionne } 174b4bd1943SLouis Dionne return 0; 175b4bd1943SLouis Dionne } 176b4bd1943SLouis Dionne 177b4bd1943SLouis Dionne extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) { 178b4bd1943SLouis Dionne return helper<std::uniform_int_distribution<std::int16_t>>(data, size) || 179b4bd1943SLouis Dionne helper<std::uniform_real_distribution<float>>(data, size) || 180b4bd1943SLouis Dionne helper<std::bernoulli_distribution>(data, size) || 181b4bd1943SLouis Dionne helper<std::poisson_distribution<std::int16_t>>(data, size) || 182b4bd1943SLouis Dionne helper<std::geometric_distribution<std::int16_t>>(data, size) || 183b4bd1943SLouis Dionne helper<std::binomial_distribution<std::int16_t>>(data, size) || 184b4bd1943SLouis Dionne helper<std::negative_binomial_distribution<std::int16_t>>(data, size) || 185b4bd1943SLouis Dionne helper<std::exponential_distribution<float>>(data, size) || 186b4bd1943SLouis Dionne helper<std::gamma_distribution<float>>(data, size) || 187b4bd1943SLouis Dionne helper<std::weibull_distribution<float>>(data, size) || 188b4bd1943SLouis Dionne helper<std::extreme_value_distribution<float>>(data, size) || 189b4bd1943SLouis Dionne helper<std::normal_distribution<float>>(data, size) || 190b4bd1943SLouis Dionne helper<std::lognormal_distribution<float>>(data, size) || 191b4bd1943SLouis Dionne helper<std::chi_squared_distribution<float>>(data, size) || 192b4bd1943SLouis Dionne helper<std::cauchy_distribution<float>>(data, size) || 193b4bd1943SLouis Dionne helper<std::fisher_f_distribution<float>>(data, size) || 194b4bd1943SLouis Dionne helper<std::student_t_distribution<float>>(data, size) || 195b4bd1943SLouis Dionne helper<std::discrete_distribution<std::int16_t>>(data, size) || 196b4bd1943SLouis Dionne helper<std::piecewise_constant_distribution<float>>(data, size) || 197b4bd1943SLouis Dionne helper<std::piecewise_linear_distribution<float>>(data, size); 198b4bd1943SLouis Dionne } 199