ZeroErr
fuzztest.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "zeroerr/unittest.h"
5 
11 #include "zeroerr/internal/rng.h"
12 
13 
14 #include <exception>
15 #include <functional>
16 #include <string>
17 #include <tuple>
18 #include <type_traits>
19 #include <vector>
20 
22 
23 #define ZEROERR_CREATE_FUZZ_TEST_FUNC(function, name) \
24  static void function(zeroerr::TestContext*); \
25  static zeroerr::detail::regTest ZEROERR_NAMEGEN(_zeroerr_reg)( \
26  {name, __FILE__, __LINE__, function}, zeroerr::TestType::fuzz_test); \
27  static void function(ZEROERR_UNUSED(zeroerr::TestContext* _ZEROERR_TEST_CONTEXT))
28 
29 #define FUZZ_TEST_CASE(name) ZEROERR_CREATE_FUZZ_TEST_FUNC(ZEROERR_NAMEGEN(_zeroerr_testcase), name)
30 
31 #define FUZZ_FUNC(func) zeroerr::FuzzFunction(func, _ZEROERR_TEST_CONTEXT)
32 
33 
34 namespace zeroerr {
35 
36 namespace detail {
37 
42 template <typename... Args>
44  static constexpr size_t numOfArgs = sizeof...(Args);
45  using ValueType = std::tuple<Args...>;
46 };
47 
48 template <typename... Args>
50  void (*)(Args...));
51 
52 template <typename... Args>
54  std::function<void(Args...)>);
55 
56 
57 template <typename T>
58 struct memfun_type {
59  using type = void;
60 };
61 
62 template <typename Ret, typename Class, typename... Args>
63 struct memfun_type<Ret (Class::*)(Args...) const> {
65 };
66 
67 template <typename F>
68 typename memfun_type<decltype(&F::operator())>::ret_type FunctionDecompositionImpl(F);
69 
70 
71 template <typename T>
72 using FunctionDecompositionT = decltype(FunctionDecompositionImpl(std::declval<T>()));
73 
74 } // namespace detail
75 
76 
82 template <typename TargetFunction,
84 struct FuzzTest;
85 
86 template <typename TargetFunction, typename FuncType, typename Domain,
87  typename Base = FuzzTest<TargetFunction, FuncType>>
88 struct FuzzTestWithDomain;
89 
90 struct IFuzzTest {
91  virtual void Run(int count = 1000, int seed = 0) = 0;
92  virtual void RunOneTime(const uint8_t* data, size_t size) = 0;
93  virtual std::string MutateData(const uint8_t* data, size_t size, size_t max_size,
94  unsigned int seed) = 0;
95 
96  int count = 0, max_count = 0;
97  bool should_stop() { return count == max_count; }
98 };
99 
100 class FuzzFinishedException : public std::exception {
101 public:
102  virtual const char* what() const throw() { return "Fuzzing finished"; }
103 };
104 
105 // The details are described in the declaration of the class.
106 template <typename TargetFunction, typename FuncType>
107 struct FuzzTest : IFuzzTest {
108  using ValueType = typename FuncType::ValueType;
110  FuzzTest(const FuzzTest& other)
111  : func(other.func), context(other.context), seeds(other.seeds) {}
112 
113  template <typename... T>
115  FuzzTestWithDomain<TargetFunction, FuncType,
116  AggregateOf<std::tuple<typename T::ValueType...>, T...>>;
117 
121  template <typename... T>
123  AggregateOf<std::tuple<typename T::ValueType...>, T...> domain) {
124  return FuzzTestWithDomainType<T...>(*this, domain);
125  }
126 
132  template <typename... T>
133  FuzzTestWithDomainType<T...> WithDomains(T&&... domains) {
134  return WithDomains(TupleOf(std::forward<T>(domains)...));
135  }
136 
137  FuzzTest& WithSeeds(std::vector<ValueType> _seeds) {
138  this->seeds.insert(this->seeds.end(), _seeds.begin(), _seeds.end());
139  return *this;
140  }
141 
142  // This should create default domains
143  virtual void Run(int = 1000, int = 0) {}
144  virtual void RunOneTime(const uint8_t*, size_t) {}
145  virtual std::string MutateData(const uint8_t*, size_t, size_t, unsigned int) { return ""; }
146 
147  TargetFunction func;
149  std::vector<ValueType> seeds;
150 };
151 
152 extern void RunFuzzTest(IFuzzTest& fuzz_test, int seed = 0, int runs = 1000, int max_len = 0,
153  int timeout = 1200, int len_control = 100);
154 
155 
163 template <typename TargetFunction, typename FuncType, typename Domain, typename Base>
164 struct FuzzTestWithDomain : public Base {
165  FuzzTestWithDomain(const Base& ft, const Domain& domain) : Base(ft), m_domain(domain) {}
166 
167  virtual void Run(int _count = 1000, int _seed = 0) override {
168  Base::count = 1;
169  Base::max_count = _count;
170  m_rng = new Rng(_seed);
171  RunFuzzTest(*this, _seed, _count, 500, 1200, 1);
172  delete m_rng;
173  m_rng = nullptr;
174  }
175 
176  typename Domain::CorpusType GetRandomCorpus() {
177  Rng& rng = *this->m_rng;
178  if (Base::seeds.size() > 0 && rng.bounded(2) == 0) {
179  return m_domain.FromValue(Base::seeds[rng() % Base::seeds.size()]);
180  }
181  return m_domain.GetRandomCorpus(rng);
182  }
183 
184  typename Domain::CorpusType TryParse(const std::string& input) {
185  try {
186  IRObject obj = IRObject::FromString(input);
187  if (obj.type == IRObject::Type::Undefined) return GetRandomCorpus();
188  return m_domain.ParseCorpus(obj);
189  } catch (...) {
190  return GetRandomCorpus();
191  }
192  }
193 
194  template <typename T, unsigned... I>
195  void apply(T args, detail::seq<I...>) {
196  this->func(std::get<I>(args)...);
197  }
198 
199  virtual void RunOneTime(const uint8_t* data, size_t size) override {
200  Base::count++;
201  std::string input = std::string((const char*)data, size);
202  typename Domain::CorpusType corpus = TryParse(input);
203  typename Domain::ValueType value = m_domain.GetValue(corpus);
204  apply(value, detail::gen_seq<std::tuple_size<typename Domain::ValueType>::value>{});
205  }
206 
207  virtual std::string MutateData(const uint8_t* data, size_t size, size_t max_size,
208  unsigned int seed) override {
209  Rng rng(seed);
210  std::string input = std::string((const char*)data, size);
211  typename Domain::CorpusType corpus = TryParse(input);
212  m_domain.Mutate(rng, corpus, false);
213  IRObject mutated_obj = m_domain.SerializeCorpus(corpus);
214  return IRObject::ToString(mutated_obj);
215  }
216 
219 };
220 
221 
222 template <typename T>
224  return FuzzTest<T>(func, context);
225 }
226 
227 template <typename T>
228 std::vector<T> ReadCorpusFromDir(std::string dir);
229 
230 
231 } // namespace zeroerr
232 
233 
Definition: aggregate_of.h:17
Domain class for generating random values of a specific type.
Definition: domain.h:22
virtual ValueType GetValue(const CorpusType &v) const =0
virtual void Mutate(Rng &rng, CorpusType &v, bool only_shrink=false) const =0
virtual CorpusType GetRandomCorpus(Rng &rng) const =0
virtual IRObject SerializeCorpus(const CorpusType &v) const
Definition: domain.h:33
virtual CorpusType FromValue(const ValueType &v) const =0
virtual CorpusType ParseCorpus(IRObject v) const
Definition: domain.h:32
Definition: fuzztest.h:100
virtual const char * what() const
Definition: fuzztest.h:102
Definition: rng.h:30
uint32_t bounded(uint32_t range) noexcept
Definition: rng.h:126
TestContext is a class that holds the test results and reporter context. There are 8 different matric...
Definition: unittest.h:67
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_POP
Definition: config.h:265
#define ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH
Definition: config.h:218
decltype(FunctionDecompositionImpl(std::declval< T >())) FunctionDecompositionT
Definition: fuzztest.h:72
FunctionDecomposition< typename std::decay< Args >::type... > FunctionDecompositionImpl(void(*)(Args...))
Definition: benchmark.cpp:17
void RunFuzzTest(IFuzzTest &fuzz_test, int seed, int runs, int max_len, int timeout, int len_control)
Definition: fuzztest.cpp:32
std::vector< T > ReadCorpusFromDir(std::string dir)
@ fuzz_test
Definition: unittest.h:254
AggregateOf< std::tuple< typename Inner::ValueType... >, Inner... > TupleOf(Inner &&... inner)
Definition: aggregate_of.h:83
FuzzTest< T > FuzzFunction(T func, TestContext *context)
Definition: fuzztest.h:223
FuzzTestWithDomain implements the Base class with the domain passed into.
Definition: fuzztest.h:164
Domain m_domain
Definition: fuzztest.h:217
FuzzTestWithDomain(const Base &ft, const Domain &domain)
Definition: fuzztest.h:165
Domain::CorpusType GetRandomCorpus()
Definition: fuzztest.h:176
virtual void RunOneTime(const uint8_t *data, size_t size) override
Definition: fuzztest.h:199
void apply(T args, detail::seq< I... >)
Definition: fuzztest.h:195
virtual std::string MutateData(const uint8_t *data, size_t size, size_t max_size, unsigned int seed) override
Definition: fuzztest.h:207
Rng * m_rng
Definition: fuzztest.h:218
virtual void Run(int _count=1000, int _seed=0) override
Definition: fuzztest.h:167
Domain::CorpusType TryParse(const std::string &input)
Definition: fuzztest.h:184
FuzzTest is a template class to create a fuzz test for the target function.
Definition: fuzztest.h:107
TargetFunction func
Definition: fuzztest.h:147
FuzzTest(TargetFunction func, TestContext *context)
Definition: fuzztest.h:109
FuzzTestWithDomainType< T... > WithDomains(T &&... domains)
Definition: fuzztest.h:133
std::vector< ValueType > seeds
Definition: fuzztest.h:149
TestContext * context
Definition: fuzztest.h:148
virtual void Run(int=1000, int=0)
Definition: fuzztest.h:143
virtual void RunOneTime(const uint8_t *, size_t)
Definition: fuzztest.h:144
typename FuncType::ValueType ValueType
Definition: fuzztest.h:108
FuzzTestWithDomainType< T... > WithDomains(AggregateOf< std::tuple< typename T::ValueType... >, T... > domain)
Definition: fuzztest.h:122
FuzzTest & WithSeeds(std::vector< ValueType > _seeds)
Definition: fuzztest.h:137
FuzzTest(const FuzzTest &other)
Definition: fuzztest.h:110
virtual std::string MutateData(const uint8_t *, size_t, size_t, unsigned int)
Definition: fuzztest.h:145
Definition: fuzztest.h:90
virtual void RunOneTime(const uint8_t *data, size_t size)=0
virtual std::string MutateData(const uint8_t *data, size_t size, size_t max_size, unsigned int seed)=0
virtual void Run(int count=1000, int seed=0)=0
bool should_stop()
Definition: fuzztest.h:97
int max_count
Definition: fuzztest.h:96
int count
Definition: fuzztest.h:96
Definition: serialization.h:17
static std::string ToString(IRObject obj)
Definition: serialization.cpp:133
static IRObject FromString(std::string str)
Definition: serialization.cpp:139
unsigned type
Definition: serialization.h:42
FunctionDecomposition is a meta function to decompose the function type. The ValueType and numOfArgs ...
Definition: fuzztest.h:43
std::tuple< Args... > ValueType
Definition: fuzztest.h:45
static constexpr size_t numOfArgs
Definition: fuzztest.h:44
Definition: typetraits.h:58
Definition: fuzztest.h:58
void type
Definition: fuzztest.h:59
Definition: typetraits.h:55