xref: /llvm-project/libcxx/test/libcxx/fuzzing/random.pass.cpp (revision 1c3a99c7397ea630949ab65a87fa6dd97609e4b3)
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