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