Skip to content

Commit daacf57

Browse files
committed
[libc++] Add fuzzing tests for parts of <random>.
This patch also re-names the existing fuzzing unit tests so they actually run.
1 parent fe593fe commit daacf57

38 files changed

+547
-587
lines changed

libcxx/fuzzing/RoutineNames.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,23 @@ regex_awk
1818
regex_grep
1919
regex_egrep
2020
search
21+
uniform_int_distribution
22+
uniform_real_distribution
23+
bernoulli_distribution
24+
poisson_distribution
25+
geometric_distribution
26+
binomial_distribution
27+
negative_binomial_distribution
28+
exponential_distribution
29+
gamma_distribution
30+
weibull_distribution
31+
extreme_value_distribution
32+
normal_distribution
33+
lognormal_distribution
34+
chi_squared_distribution
35+
cauchy_distribution
36+
fisher_f_distribution
37+
student_t_distribution
38+
discrete_distribution
39+
piecewise_constant_distribution
40+
piecewise_linear_distribution

libcxx/fuzzing/fuzz_test_template.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===------------------------- fuzz_test.cpp ------------------------------===//
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+
#include "fuzzing/fuzzing.h"
10+
#ifdef NDEBUG
11+
#undef NDEBUG
12+
#endif
13+
#include <cassert>
14+
15+
#ifndef TEST_FUNCTION
16+
#error TEST_FUNCTION must be defined
17+
#endif
18+
19+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
20+
int result = fuzzing::TEST_FUNCTION(data, size);
21+
assert(result == 0); return 0;
22+
}

libcxx/fuzzing/fuzzing.cpp

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@
2727
#include <algorithm>
2828
#include <functional>
2929
#include <regex>
30+
#include <random>
3031
#include <cassert>
32+
#include <cmath>
3133

3234
#include <iostream>
3335

36+
#ifdef NDEBUG
37+
#undef NDEBUG
38+
#endif
39+
#include <cassert>
3440
// If we had C++14, we could use the four iterator version of is_permutation and equal
3541

3642
namespace fuzzing {
@@ -212,7 +218,7 @@ int partition_copy(const uint8_t *data, size_t size)
212218
auto iter = std::partition_copy(data, data + size,
213219
std::back_inserter<Vec>(v1), std::back_inserter<Vec>(v2),
214220
is_even<uint8_t>());
215-
221+
((void)iter);
216222
// The two vectors should add up to the original size
217223
if (v1.size() + v2.size() != size) return 1;
218224

@@ -614,4 +620,201 @@ static void set_helper (const uint8_t *data, size_t size, Vec &v1, Vec &v2)
614620
std::sort(v2.begin(), v2.end());
615621
}
616622

623+
enum class ParamKind {
624+
OneValue,
625+
TwoValues,
626+
PointerRange
627+
};
628+
629+
template <class IntT>
630+
std::vector<IntT> GetValues(const uint8_t *data, size_t size) {
631+
std::vector<IntT> result;
632+
while (size >= sizeof(IntT)) {
633+
IntT tmp;
634+
memcpy(&tmp, data, sizeof(IntT));
635+
size -= sizeof(IntT);
636+
data += sizeof(IntT);
637+
result.push_back(tmp);
638+
}
639+
return result;
640+
}
641+
642+
enum InitKind {
643+
Default,
644+
DoubleOnly,
645+
VectorDouble,
646+
VectorResultType
647+
};
648+
649+
template <class Dist>
650+
struct ParamTypeHelper {
651+
using ParamT = typename Dist::param_type;
652+
using ResultT = typename Dist::result_type;
653+
static_assert(std::is_same<ResultT, typename ParamT::distribution_type::result_type>::value, "");
654+
static ParamT Create(const uint8_t* data, size_t size, bool &OK) {
655+
656+
if constexpr (std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value)
657+
return CreateVectorResult(data, size, OK);
658+
else if constexpr (std::is_constructible<ParamT, double*, double*>::value)
659+
return CreateVectorDouble(data, size, OK);
660+
else
661+
return CreateDefault(data, size, OK);
662+
}
663+
664+
665+
static ParamT
666+
CreateVectorResult(const uint8_t *data, size_t size, bool &OK) {
667+
auto Input = GetValues<ResultT>(data, size);
668+
OK = false;
669+
if (Input.size() < 10)
670+
return ParamT{};
671+
OK = true;
672+
auto Beg = Input.begin();
673+
auto End = Input.end();
674+
auto Mid = Beg + ((End - Beg) / 2);
675+
676+
assert(Mid - Beg <= (End - Mid));
677+
ParamT p(Beg, Mid, Mid);
678+
return p;
679+
}
680+
681+
static ParamT
682+
CreateVectorDouble(const uint8_t *data, size_t size, bool &OK) {
683+
auto Input = GetValues<double>(data, size);
684+
685+
OK = true;
686+
auto Beg = Input.begin();
687+
auto End = Input.end();
688+
689+
ParamT p(Beg, End);
690+
return p;
691+
}
692+
693+
694+
static ParamT
695+
CreateDefault(const uint8_t *data, size_t size, bool &OK) {
696+
OK = false;
697+
if (size < sizeof(ParamT))
698+
return ParamT{};
699+
OK = true;
700+
ParamT input;
701+
memcpy(&input, data, sizeof(ParamT));
702+
return input;
703+
}
704+
705+
};
706+
707+
708+
709+
710+
template <class IntT>
711+
struct ParamTypeHelper<std::poisson_distribution<IntT>> {
712+
using Dist = std::poisson_distribution<IntT>;
713+
using ParamT = typename Dist::param_type;
714+
using ResultT = typename Dist::result_type;
715+
716+
static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
717+
OK = false;
718+
auto vals = GetValues<double>(data, size);
719+
if (vals.empty() || std::isnan(vals[0]) || std::isnan(std::abs(vals[0])) || vals[0] < 0 )
720+
return ParamT{};
721+
OK = true;
722+
//std::cerr << "Value: " << vals[0] << std::endl;
723+
return ParamT{vals[0]};
724+
}
725+
};
726+
727+
728+
template <class IntT>
729+
struct ParamTypeHelper<std::geometric_distribution<IntT>> {
730+
using Dist = std::geometric_distribution<IntT>;
731+
using ParamT = typename Dist::param_type;
732+
using ResultT = typename Dist::result_type;
733+
734+
static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
735+
OK = false;
736+
auto vals = GetValues<double>(data, size);
737+
if (vals.empty() || std::isnan(vals[0]) || vals[0] < 0 )
738+
return ParamT{};
739+
OK = true;
740+
// std::cerr << "Value: " << vals[0] << std::endl;
741+
return ParamT{vals[0]};
742+
}
743+
};
744+
745+
746+
template <class IntT>
747+
struct ParamTypeHelper<std::lognormal_distribution<IntT>> {
748+
using Dist = std::lognormal_distribution<IntT>;
749+
using ParamT = typename Dist::param_type;
750+
using ResultT = typename Dist::result_type;
751+
752+
static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
753+
OK = false;
754+
auto vals = GetValues<ResultT>(data, size);
755+
if (vals.size() < 2 )
756+
return ParamT{};
757+
OK = true;
758+
return ParamT{vals[0], vals[1]};
759+
}
760+
};
761+
762+
763+
template <>
764+
struct ParamTypeHelper<std::bernoulli_distribution> {
765+
using Dist = std::bernoulli_distribution;
766+
using ParamT = typename Dist::param_type;
767+
using ResultT = typename Dist::result_type;
768+
769+
static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
770+
OK = false;
771+
auto vals = GetValues<double>(data, size);
772+
if (vals.empty())
773+
return ParamT{};
774+
OK = true;
775+
return ParamT{vals[0]};
776+
}
777+
};
778+
779+
template <class Distribution>
780+
int random_distribution_helper(const uint8_t *data, size_t size) {
781+
782+
std::mt19937 engine;
783+
using ParamT = typename Distribution::param_type;
784+
bool OK;
785+
ParamT p = ParamTypeHelper<Distribution>::Create(data, size, OK);
786+
if (!OK)
787+
return 0;
788+
Distribution d(p);
789+
volatile auto res = d(engine);
790+
if (std::isnan(res))
791+
return 1;
792+
return 0;
793+
}
794+
795+
#define DEFINE_RANDOM_TEST(name, ...) \
796+
int name(const uint8_t *data, size_t size) { \
797+
return random_distribution_helper< std::name __VA_ARGS__ >(data, size); \
798+
}
799+
DEFINE_RANDOM_TEST(uniform_int_distribution,<std::int16_t>)
800+
DEFINE_RANDOM_TEST(uniform_real_distribution,<float>)
801+
DEFINE_RANDOM_TEST(bernoulli_distribution)
802+
DEFINE_RANDOM_TEST(poisson_distribution,<std::int16_t>)
803+
DEFINE_RANDOM_TEST(geometric_distribution,<std::int16_t>)
804+
DEFINE_RANDOM_TEST(binomial_distribution, <std::int16_t>)
805+
DEFINE_RANDOM_TEST(negative_binomial_distribution, <std::int16_t>)
806+
DEFINE_RANDOM_TEST(exponential_distribution, <float>)
807+
DEFINE_RANDOM_TEST(gamma_distribution, <float>)
808+
DEFINE_RANDOM_TEST(weibull_distribution, <float>)
809+
DEFINE_RANDOM_TEST(extreme_value_distribution, <float>)
810+
DEFINE_RANDOM_TEST(normal_distribution, <float>)
811+
DEFINE_RANDOM_TEST(lognormal_distribution, <float>)
812+
DEFINE_RANDOM_TEST(chi_squared_distribution, <float>)
813+
DEFINE_RANDOM_TEST(cauchy_distribution, <float>)
814+
DEFINE_RANDOM_TEST(fisher_f_distribution, <float>)
815+
DEFINE_RANDOM_TEST(student_t_distribution, <float>)
816+
DEFINE_RANDOM_TEST(discrete_distribution, <std::int16_t>)
817+
DEFINE_RANDOM_TEST(piecewise_constant_distribution, <float>)
818+
DEFINE_RANDOM_TEST(piecewise_linear_distribution, <float>)
819+
617820
} // namespace fuzzing

libcxx/fuzzing/fuzzing.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,28 @@ namespace fuzzing {
5656
// int set_symmetric_difference (const uint8_t *data, size_t size);
5757
// int merge (const uint8_t *data, size_t size);
5858

59+
// Random numbers
60+
int uniform_int_distribution(const uint8_t*, size_t);
61+
int uniform_real_distribution(const uint8_t*, size_t);
62+
int bernoulli_distribution(const uint8_t*, size_t);
63+
int poisson_distribution(const uint8_t*, size_t);
64+
int geometric_distribution(const uint8_t*, size_t);
65+
int binomial_distribution(const uint8_t*, size_t);
66+
int negative_binomial_distribution(const uint8_t*, size_t);
67+
int exponential_distribution(const uint8_t*, size_t);
68+
int gamma_distribution(const uint8_t*, size_t);
69+
int weibull_distribution(const uint8_t*, size_t);
70+
int extreme_value_distribution(const uint8_t*, size_t);
71+
int normal_distribution(const uint8_t*, size_t);
72+
int lognormal_distribution(const uint8_t*, size_t);
73+
int chi_squared_distribution(const uint8_t*, size_t);
74+
int cauchy_distribution(const uint8_t*, size_t);
75+
int fisher_f_distribution(const uint8_t*, size_t);
76+
int student_t_distribution(const uint8_t*, size_t);
77+
int discrete_distribution(const uint8_t*, size_t);
78+
int piecewise_constant_distribution(const uint8_t*, size_t);
79+
int piecewise_linear_distribution(const uint8_t*, size_t);
80+
5981
} // namespace fuzzing
6082

6183
#endif // _LIBCPP_FUZZING
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef TEST_LIBCXX_FUZZER_TEST_H
11+
#define TEST_LIBCXX_FUZZER_TEST_H
12+
13+
#include <cstddef>
14+
#include <cassert>
15+
16+
#include "../../../fuzzing/fuzzing.h"
17+
#include "../../../fuzzing/fuzzing.cpp"
18+
19+
const char* TestCaseSetOne[] = {"", "s", "bac",
20+
"bacasf"
21+
"lkajseravea",
22+
"adsfkajdsfjkas;lnc441324513,34535r34525234",
23+
"b*c",
24+
"ba?sf"
25+
"lka*ea",
26+
"adsf*kas;lnc441[0-9]1r34525234"};
27+
28+
using FuzzerFuncType = int(const uint8_t*, size_t);
29+
30+
template <size_t NumCases>
31+
inline void RunFuzzingTest(FuzzerFuncType *to_test, const char* (&test_cases)[NumCases]) {
32+
for (const char* TC : test_cases) {
33+
const size_t size = std::strlen(TC);
34+
const uint8_t* data = (const uint8_t*)TC;
35+
int result = to_test(data, size);
36+
assert(result == 0);
37+
}
38+
}
39+
40+
#define FUZZER_TEST(FuncName) \
41+
int main() { \
42+
RunFuzzingTest(FuncName, TestCaseSetOne); \
43+
} \
44+
extern int require_semi
45+
46+
#endif // TEST_LIBCXX_FUZZER_TEST_H
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// -*- C++ -*-
2+
//===------------------------ unique_copy.cpp -----------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include <random>
11+
#include <cstdint>
12+
13+
#include "fuzzer_test.h"
14+
15+
template <class Distribution>
16+
int random_distribution_helper(const uint8_t *data, size_t size) {
17+
std::mt19937 engine;
18+
using ParamT = typename Distribution::param_type;
19+
if (size < sizeof(double))
20+
return 0;
21+
double Arg;
22+
memcpy(&Arg, data, sizeof(double));
23+
ParamT p(Arg);
24+
Distribution d(p);
25+
for (int I=0; I < 1000; ++I) {
26+
volatile auto res = d(engine);
27+
((void)res);
28+
}
29+
return 0;
30+
}
31+
32+
int FuzzRandom(const uint8_t *Data, size_t Size) {
33+
return random_distribution_helper<std::geometric_distribution<std::int16_t>>(Data, Size);
34+
}
35+
FUZZER_TEST(FuzzRandom);
36+
37+

0 commit comments

Comments
 (0)