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)
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
26template <class IntT>
27std::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(dest: &tmp, src: data, n: sizeof(IntT));
32 size -= sizeof(IntT);
33 data += sizeof(IntT);
34 result.push_back(tmp);
35 }
36 return result;
37}
38
39template <class Dist>
40struct 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(dest: &input, src: data, n: sizeof(ParamT));
88 return input;
89 }
90};
91
92template <class IntT>
93struct 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(x: vals[0]) || std::isnan(x: std::abs(x: vals[0])) || vals[0] < 0)
102 return ParamT{};
103 OK = true;
104 return ParamT{vals[0]};
105 }
106};
107
108template <class IntT>
109struct 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(x: vals[0]) || vals[0] < 0 )
118 return ParamT{};
119 OK = true;
120 return ParamT{vals[0]};
121 }
122};
123
124template <class IntT>
125struct 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
140template <>
141struct 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
156template <class Distribution>
157int 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
177extern "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

source code of libcxx/test/libcxx/fuzzing/random.pass.cpp