blob: 5c32f28a3addc2be0a1837f181a708db148be181 [file] [log] [blame]
Marshall Clowbaa6fb32017-10-04 22:23:03 +00001// -*- C++ -*-
2//===------------------------- fuzzing.cpp -------------------------------===//
3//
Chandler Carruthd2012102019-01-19 10:56:40 +00004// 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
Marshall Clowbaa6fb32017-10-04 22:23:03 +00007//
8//===----------------------------------------------------------------------===//
9
Marshall Clow43ff7d92018-11-04 17:57:25 +000010// A set of routines to use when fuzzing the algorithms in libc++
11// Each one tests a single algorithm.
Marshall Clowbaa6fb32017-10-04 22:23:03 +000012//
Marshall Clow43ff7d92018-11-04 17:57:25 +000013// They all have the form of:
14// int `algorithm`(const uint8_t *data, size_t size);
Marshall Clowbaa6fb32017-10-04 22:23:03 +000015//
Marshall Clow43ff7d92018-11-04 17:57:25 +000016// They perform the operation, and then check to see if the results are correct.
17// If so, they return zero, and non-zero otherwise.
Marshall Clowbaa6fb32017-10-04 22:23:03 +000018//
Marshall Clow43ff7d92018-11-04 17:57:25 +000019// For example, sort calls std::sort, then checks two things:
20// (1) The resulting vector is sorted
21// (2) The resulting vector contains the same elements as the original data.
Marshall Clowbaa6fb32017-10-04 22:23:03 +000022
23
24
25#include "fuzzing.h"
26#include <vector>
27#include <algorithm>
Marshall Clowa97ab842017-10-23 23:19:30 +000028#include <functional>
Marshall Clowd84736b2017-10-12 14:48:09 +000029#include <regex>
Marshall Clow294dd862017-11-08 20:25:47 +000030#include <cassert>
Marshall Clowbaa6fb32017-10-04 22:23:03 +000031
Marshall Clowa97ab842017-10-23 23:19:30 +000032#include <iostream>
33
Marshall Clow43ff7d92018-11-04 17:57:25 +000034// If we had C++14, we could use the four iterator version of is_permutation and equal
Marshall Clowbaa6fb32017-10-04 22:23:03 +000035
36namespace fuzzing {
37
Marshall Clow43ff7d92018-11-04 17:57:25 +000038// This is a struct we can use to test the stable_XXX algorithms.
39// perform the operation on the key, then check the order of the payload.
Marshall Clowbaa6fb32017-10-04 22:23:03 +000040
41struct stable_test {
Marshall Clow43ff7d92018-11-04 17:57:25 +000042 uint8_t key;
43 size_t payload;
44
45 stable_test(uint8_t k) : key(k), payload(0) {}
46 stable_test(uint8_t k, size_t p) : key(k), payload(p) {}
47 };
Marshall Clowbaa6fb32017-10-04 22:23:03 +000048
49void swap(stable_test &lhs, stable_test &rhs)
50{
Marshall Clow43ff7d92018-11-04 17:57:25 +000051 using std::swap;
52 swap(lhs.key, rhs.key);
53 swap(lhs.payload, rhs.payload);
Marshall Clowbaa6fb32017-10-04 22:23:03 +000054}
55
56struct key_less
57{
Marshall Clow43ff7d92018-11-04 17:57:25 +000058 bool operator () (const stable_test &lhs, const stable_test &rhs) const
59 {
60 return lhs.key < rhs.key;
61 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +000062};
63
64struct payload_less
65{
Marshall Clow43ff7d92018-11-04 17:57:25 +000066 bool operator () (const stable_test &lhs, const stable_test &rhs) const
67 {
68 return lhs.payload < rhs.payload;
69 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +000070};
71
72struct total_less
73{
Marshall Clow43ff7d92018-11-04 17:57:25 +000074 bool operator () (const stable_test &lhs, const stable_test &rhs) const
75 {
76 return lhs.key == rhs.key ? lhs.payload < rhs.payload : lhs.key < rhs.key;
77 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +000078};
79
80bool operator==(const stable_test &lhs, const stable_test &rhs)
Marshall Clow43ff7d92018-11-04 17:57:25 +000081{
82 return lhs.key == rhs.key && lhs.payload == rhs.payload;
Marshall Clowbaa6fb32017-10-04 22:23:03 +000083}
84
85
86template<typename T>
87struct is_even
88{
Marshall Clow43ff7d92018-11-04 17:57:25 +000089 bool operator () (const T &t) const
90 {
91 return t % 2 == 0;
92 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +000093};
94
95
96template<>
97struct is_even<stable_test>
98{
Marshall Clow43ff7d92018-11-04 17:57:25 +000099 bool operator () (const stable_test &t) const
100 {
101 return t.key % 2 == 0;
102 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000103};
104
Marshall Clow974677c2017-10-30 19:51:58 +0000105typedef std::vector<uint8_t> Vec;
106typedef std::vector<stable_test> StableVec;
Marshall Clow161681a2018-01-19 03:17:45 +0000107typedef StableVec::const_iterator SVIter;
108
Marshall Clow43ff7d92018-11-04 17:57:25 +0000109// Cheap version of is_permutation
110// Builds a set of buckets for each of the key values.
111// Sums all the payloads.
112// Not 100% perfect, but _way_ faster
Marshall Clow161681a2018-01-19 03:17:45 +0000113bool is_permutation(SVIter first1, SVIter last1, SVIter first2)
114{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000115 size_t xBuckets[256] = {0};
116 size_t xPayloads[256] = {0};
117 size_t yBuckets[256] = {0};
118 size_t yPayloads[256] = {0};
Marshall Clow161681a2018-01-19 03:17:45 +0000119
Marshall Clow43ff7d92018-11-04 17:57:25 +0000120 for (; first1 != last1; ++first1, ++first2)
121 {
122 xBuckets [first1->key]++;
123 xPayloads[first1->key] += first1->payload;
Marshall Clow161681a2018-01-19 03:17:45 +0000124
Marshall Clow43ff7d92018-11-04 17:57:25 +0000125 yBuckets [first2->key]++;
126 yPayloads[first2->key] += first2->payload;
127 }
128
129 for (size_t i = 0; i < 256; ++i)
130 {
131 if (xBuckets[i] != yBuckets[i])
132 return false;
133 if (xPayloads[i] != yPayloads[i])
134 return false;
135 }
136
137 return true;
Marshall Clow161681a2018-01-19 03:17:45 +0000138}
139
140template <typename Iter1, typename Iter2>
141bool is_permutation(Iter1 first1, Iter1 last1, Iter2 first2)
142{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000143 static_assert((std::is_same<typename std::iterator_traits<Iter1>::value_type, uint8_t>::value), "");
144 static_assert((std::is_same<typename std::iterator_traits<Iter2>::value_type, uint8_t>::value), "");
Marshall Clow161681a2018-01-19 03:17:45 +0000145
Marshall Clow43ff7d92018-11-04 17:57:25 +0000146 size_t xBuckets[256] = {0};
147 size_t yBuckets[256] = {0};
148
149 for (; first1 != last1; ++first1, ++first2)
150 {
151 xBuckets [*first1]++;
152 yBuckets [*first2]++;
153 }
154
155 for (size_t i = 0; i < 256; ++i)
156 if (xBuckets[i] != yBuckets[i])
157 return false;
158
159 return true;
Marshall Clow161681a2018-01-19 03:17:45 +0000160}
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000161
Marshall Clow43ff7d92018-11-04 17:57:25 +0000162// == sort ==
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000163int sort(const uint8_t *data, size_t size)
164{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000165 Vec working(data, data + size);
166 std::sort(working.begin(), working.end());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000167
Marshall Clow43ff7d92018-11-04 17:57:25 +0000168 if (!std::is_sorted(working.begin(), working.end())) return 1;
169 if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
170 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000171}
172
173
Marshall Clow43ff7d92018-11-04 17:57:25 +0000174// == stable_sort ==
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000175int stable_sort(const uint8_t *data, size_t size)
176{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000177 StableVec input;
178 for (size_t i = 0; i < size; ++i)
179 input.push_back(stable_test(data[i], i));
180 StableVec working = input;
181 std::stable_sort(working.begin(), working.end(), key_less());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000182
Marshall Clow43ff7d92018-11-04 17:57:25 +0000183 if (!std::is_sorted(working.begin(), working.end(), key_less())) return 1;
184 auto iter = working.begin();
185 while (iter != working.end())
186 {
187 auto range = std::equal_range(iter, working.end(), *iter, key_less());
188 if (!std::is_sorted(range.first, range.second, total_less())) return 2;
189 iter = range.second;
190 }
191 if (!fuzzing::is_permutation(input.cbegin(), input.cend(), working.cbegin())) return 99;
192 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000193}
194
Marshall Clow43ff7d92018-11-04 17:57:25 +0000195// == partition ==
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000196int partition(const uint8_t *data, size_t size)
197{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000198 Vec working(data, data + size);
199 auto iter = std::partition(working.begin(), working.end(), is_even<uint8_t>());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000200
Marshall Clow43ff7d92018-11-04 17:57:25 +0000201 if (!std::all_of (working.begin(), iter, is_even<uint8_t>())) return 1;
202 if (!std::none_of(iter, working.end(), is_even<uint8_t>())) return 2;
203 if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
204 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000205}
206
207
Marshall Clow43ff7d92018-11-04 17:57:25 +0000208// == partition_copy ==
Marshall Clow974677c2017-10-30 19:51:58 +0000209int partition_copy(const uint8_t *data, size_t size)
210{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000211 Vec v1, v2;
212 auto iter = std::partition_copy(data, data + size,
213 std::back_inserter<Vec>(v1), std::back_inserter<Vec>(v2),
214 is_even<uint8_t>());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000215
Marshall Clow43ff7d92018-11-04 17:57:25 +0000216// The two vectors should add up to the original size
217 if (v1.size() + v2.size() != size) return 1;
Marshall Clow974677c2017-10-30 19:51:58 +0000218
Marshall Clow43ff7d92018-11-04 17:57:25 +0000219// All of the even values should be in the first vector, and none in the second
220 if (!std::all_of (v1.begin(), v1.end(), is_even<uint8_t>())) return 2;
221 if (!std::none_of(v2.begin(), v2.end(), is_even<uint8_t>())) return 3;
Marshall Clow974677c2017-10-30 19:51:58 +0000222
Marshall Clow43ff7d92018-11-04 17:57:25 +0000223// Every value in both vectors has to be in the original
224
225// Make a copy of the input, and sort it
226 Vec v0{data, data + size};
227 std::sort(v0.begin(), v0.end());
228
229// Sort each vector and ensure that all of the elements appear in the original input
230 std::sort(v1.begin(), v1.end());
231 if (!std::includes(v0.begin(), v0.end(), v1.begin(), v1.end())) return 4;
232
233 std::sort(v2.begin(), v2.end());
234 if (!std::includes(v0.begin(), v0.end(), v2.begin(), v2.end())) return 5;
235
236// This, while simple, is really slow - 20 seconds on a 500K element input.
237// for (auto v: v1)
238// if (std::find(data, data + size, v) == data + size) return 4;
239//
240// for (auto v: v2)
241// if (std::find(data, data + size, v) == data + size) return 5;
242
243 return 0;
Marshall Clow974677c2017-10-30 19:51:58 +0000244}
245
Marshall Clow43ff7d92018-11-04 17:57:25 +0000246// == stable_partition ==
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000247int stable_partition (const uint8_t *data, size_t size)
248{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000249 StableVec input;
250 for (size_t i = 0; i < size; ++i)
251 input.push_back(stable_test(data[i], i));
252 StableVec working = input;
253 auto iter = std::stable_partition(working.begin(), working.end(), is_even<stable_test>());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000254
Marshall Clow43ff7d92018-11-04 17:57:25 +0000255 if (!std::all_of (working.begin(), iter, is_even<stable_test>())) return 1;
256 if (!std::none_of(iter, working.end(), is_even<stable_test>())) return 2;
257 if (!std::is_sorted(working.begin(), iter, payload_less())) return 3;
258 if (!std::is_sorted(iter, working.end(), payload_less())) return 4;
259 if (!fuzzing::is_permutation(input.cbegin(), input.cend(), working.cbegin())) return 99;
260 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000261}
262
Marshall Clow43ff7d92018-11-04 17:57:25 +0000263// == nth_element ==
264// use the first element as a position into the data
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000265int nth_element (const uint8_t *data, size_t size)
266{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000267 if (size <= 1) return 0;
268 const size_t partition_point = data[0] % size;
269 Vec working(data + 1, data + size);
270 const auto partition_iter = working.begin() + partition_point;
271 std::nth_element(working.begin(), partition_iter, working.end());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000272
Marshall Clow43ff7d92018-11-04 17:57:25 +0000273// nth may be the end iterator, in this case nth_element has no effect.
274 if (partition_iter == working.end())
275 {
276 if (!std::equal(data + 1, data + size, working.begin())) return 98;
277 }
278 else
279 {
280 const uint8_t nth = *partition_iter;
281 if (!std::all_of(working.begin(), partition_iter, [=](uint8_t v) { return v <= nth; }))
282 return 1;
283 if (!std::all_of(partition_iter, working.end(), [=](uint8_t v) { return v >= nth; }))
284 return 2;
285 if (!fuzzing::is_permutation(data + 1, data + size, working.cbegin())) return 99;
286 }
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000287
Marshall Clow43ff7d92018-11-04 17:57:25 +0000288 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000289}
290
Marshall Clow43ff7d92018-11-04 17:57:25 +0000291// == partial_sort ==
292// use the first element as a position into the data
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000293int partial_sort (const uint8_t *data, size_t size)
294{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000295 if (size <= 1) return 0;
296 const size_t sort_point = data[0] % size;
297 Vec working(data + 1, data + size);
298 const auto sort_iter = working.begin() + sort_point;
299 std::partial_sort(working.begin(), sort_iter, working.end());
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000300
Marshall Clow43ff7d92018-11-04 17:57:25 +0000301 if (sort_iter != working.end())
302 {
303 const uint8_t nth = *std::min_element(sort_iter, working.end());
304 if (!std::all_of(working.begin(), sort_iter, [=](uint8_t v) { return v <= nth; }))
305 return 1;
306 if (!std::all_of(sort_iter, working.end(), [=](uint8_t v) { return v >= nth; }))
307 return 2;
308 }
309 if (!std::is_sorted(working.begin(), sort_iter)) return 3;
310 if (!fuzzing::is_permutation(data + 1, data + size, working.cbegin())) return 99;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000311
Marshall Clow43ff7d92018-11-04 17:57:25 +0000312 return 0;
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000313}
314
Marshall Clowd84736b2017-10-12 14:48:09 +0000315
Marshall Clow43ff7d92018-11-04 17:57:25 +0000316// == partial_sort_copy ==
317// use the first element as a count
Marshall Clow974677c2017-10-30 19:51:58 +0000318int partial_sort_copy (const uint8_t *data, size_t size)
319{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000320 if (size <= 1) return 0;
321 const size_t num_results = data[0] % size;
322 Vec results(num_results);
323 (void) std::partial_sort_copy(data + 1, data + size, results.begin(), results.end());
Marshall Clowd84736b2017-10-12 14:48:09 +0000324
Marshall Clow43ff7d92018-11-04 17:57:25 +0000325// The results have to be sorted
326 if (!std::is_sorted(results.begin(), results.end())) return 1;
327// All the values in results have to be in the original data
328 for (auto v: results)
329 if (std::find(data + 1, data + size, v) == data + size) return 2;
Marshall Clow974677c2017-10-30 19:51:58 +0000330
Marshall Clow43ff7d92018-11-04 17:57:25 +0000331// The things in results have to be the smallest N in the original data
332 Vec sorted(data + 1, data + size);
333 std::sort(sorted.begin(), sorted.end());
334 if (!std::equal(results.begin(), results.end(), sorted.begin())) return 3;
335 return 0;
Marshall Clow974677c2017-10-30 19:51:58 +0000336}
337
Marshall Clow43ff7d92018-11-04 17:57:25 +0000338// The second sequence has been "uniqued"
Marshall Clow974677c2017-10-30 19:51:58 +0000339template <typename Iter1, typename Iter2>
340static bool compare_unique(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
341{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000342 assert(first1 != last1 && first2 != last2);
343 if (*first1 != *first2) return false;
Marshall Clow974677c2017-10-30 19:51:58 +0000344
Marshall Clow43ff7d92018-11-04 17:57:25 +0000345 uint8_t last_value = *first1;
346 ++first1; ++first2;
347 while(first1 != last1 && first2 != last2)
348 {
349 // Skip over dups in the first sequence
350 while (*first1 == last_value)
351 if (++first1 == last1) return false;
352 if (*first1 != *first2) return false;
353 last_value = *first1;
354 ++first1; ++first2;
355 }
Marshall Clow974677c2017-10-30 19:51:58 +0000356
Marshall Clow43ff7d92018-11-04 17:57:25 +0000357// Still stuff left in the 'uniqued' sequence - oops
358 if (first1 == last1 && first2 != last2) return false;
Marshall Clow974677c2017-10-30 19:51:58 +0000359
Marshall Clow43ff7d92018-11-04 17:57:25 +0000360// Still stuff left in the original sequence - better be all the same
361 while (first1 != last1)
362 {
363 if (*first1 != last_value) return false;
364 ++first1;
365 }
366 return true;
Marshall Clow974677c2017-10-30 19:51:58 +0000367}
368
Marshall Clow43ff7d92018-11-04 17:57:25 +0000369// == unique ==
Marshall Clow974677c2017-10-30 19:51:58 +0000370int unique (const uint8_t *data, size_t size)
371{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000372 Vec working(data, data + size);
373 std::sort(working.begin(), working.end());
374 Vec results = working;
375 Vec::iterator new_end = std::unique(results.begin(), results.end());
376 Vec::iterator it; // scratch iterator
Marshall Clow974677c2017-10-30 19:51:58 +0000377
Marshall Clow43ff7d92018-11-04 17:57:25 +0000378// Check the size of the unique'd sequence.
379// it should only be zero if the input sequence was empty.
380 if (results.begin() == new_end)
381 return working.size() == 0 ? 0 : 1;
382
383// 'results' is sorted
384 if (!std::is_sorted(results.begin(), new_end)) return 2;
385
386// All the elements in 'results' must be different
387 it = results.begin();
388 uint8_t prev_value = *it++;
389 for (; it != new_end; ++it)
390 {
391 if (*it == prev_value) return 3;
392 prev_value = *it;
393 }
394
395// Every element in 'results' must be in 'working'
396 for (it = results.begin(); it != new_end; ++it)
397 if (std::find(working.begin(), working.end(), *it) == working.end())
398 return 4;
399
400// Every element in 'working' must be in 'results'
401 for (auto v : working)
402 if (std::find(results.begin(), new_end, v) == new_end)
403 return 5;
404
405 return 0;
Marshall Clow974677c2017-10-30 19:51:58 +0000406}
407
Marshall Clow43ff7d92018-11-04 17:57:25 +0000408// == unique_copy ==
Marshall Clow974677c2017-10-30 19:51:58 +0000409int unique_copy (const uint8_t *data, size_t size)
410{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000411 Vec working(data, data + size);
412 std::sort(working.begin(), working.end());
413 Vec results;
414 (void) std::unique_copy(working.begin(), working.end(),
415 std::back_inserter<Vec>(results));
416 Vec::iterator it; // scratch iterator
Marshall Clow974677c2017-10-30 19:51:58 +0000417
Marshall Clow43ff7d92018-11-04 17:57:25 +0000418// Check the size of the unique'd sequence.
419// it should only be zero if the input sequence was empty.
420 if (results.size() == 0)
421 return working.size() == 0 ? 0 : 1;
422
423// 'results' is sorted
424 if (!std::is_sorted(results.begin(), results.end())) return 2;
425
426// All the elements in 'results' must be different
427 it = results.begin();
428 uint8_t prev_value = *it++;
429 for (; it != results.end(); ++it)
430 {
431 if (*it == prev_value) return 3;
432 prev_value = *it;
433 }
434
435// Every element in 'results' must be in 'working'
436 for (auto v : results)
437 if (std::find(working.begin(), working.end(), v) == working.end())
438 return 4;
439
440// Every element in 'working' must be in 'results'
441 for (auto v : working)
442 if (std::find(results.begin(), results.end(), v) == results.end())
443 return 5;
444
445 return 0;
Marshall Clow974677c2017-10-30 19:51:58 +0000446}
447
448
Marshall Clow43ff7d92018-11-04 17:57:25 +0000449// -- regex fuzzers
Marshall Clowd84736b2017-10-12 14:48:09 +0000450static int regex_helper(const uint8_t *data, size_t size, std::regex::flag_type flag)
451{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000452 if (size > 0)
453 {
454 try
455 {
456 std::string s((const char *)data, size);
457 std::regex re(s, flag);
458 return std::regex_match(s, re) ? 1 : 0;
459 }
460 catch (std::regex_error &ex) {}
461 }
462 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000463}
464
465
466int regex_ECMAScript (const uint8_t *data, size_t size)
467{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000468 (void) regex_helper(data, size, std::regex_constants::ECMAScript);
469 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000470}
471
472int regex_POSIX (const uint8_t *data, size_t size)
473{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000474 (void) regex_helper(data, size, std::regex_constants::basic);
475 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000476}
477
478int regex_extended (const uint8_t *data, size_t size)
479{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000480 (void) regex_helper(data, size, std::regex_constants::extended);
481 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000482}
483
484int regex_awk (const uint8_t *data, size_t size)
485{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000486 (void) regex_helper(data, size, std::regex_constants::awk);
487 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000488}
489
490int regex_grep (const uint8_t *data, size_t size)
491{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000492 (void) regex_helper(data, size, std::regex_constants::grep);
493 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000494}
495
496int regex_egrep (const uint8_t *data, size_t size)
497{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000498 (void) regex_helper(data, size, std::regex_constants::egrep);
499 return 0;
Marshall Clowd84736b2017-10-12 14:48:09 +0000500}
501
Marshall Clow43ff7d92018-11-04 17:57:25 +0000502// -- heap fuzzers
Marshall Clowa97ab842017-10-23 23:19:30 +0000503int make_heap (const uint8_t *data, size_t size)
504{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000505 Vec working(data, data + size);
506 std::make_heap(working.begin(), working.end());
Marshall Clowa97ab842017-10-23 23:19:30 +0000507
Marshall Clow43ff7d92018-11-04 17:57:25 +0000508 if (!std::is_heap(working.begin(), working.end())) return 1;
509 if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
510 return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000511}
512
513int push_heap (const uint8_t *data, size_t size)
514{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000515 if (size < 2) return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000516
Marshall Clow43ff7d92018-11-04 17:57:25 +0000517// Make a heap from the first half of the data
518 Vec working(data, data + size);
519 auto iter = working.begin() + (size / 2);
520 std::make_heap(working.begin(), iter);
521 if (!std::is_heap(working.begin(), iter)) return 1;
Marshall Clowa97ab842017-10-23 23:19:30 +0000522
Marshall Clow43ff7d92018-11-04 17:57:25 +0000523// Now push the rest onto the heap, one at a time
524 ++iter;
525 for (; iter != working.end(); ++iter) {
526 std::push_heap(working.begin(), iter);
527 if (!std::is_heap(working.begin(), iter)) return 2;
528 }
Marshall Clowa97ab842017-10-23 23:19:30 +0000529
Marshall Clow43ff7d92018-11-04 17:57:25 +0000530 if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
531 return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000532}
533
534int pop_heap (const uint8_t *data, size_t size)
535{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000536 if (size < 2) return 0;
537 Vec working(data, data + size);
538 std::make_heap(working.begin(), working.end());
Marshall Clowa97ab842017-10-23 23:19:30 +0000539
Marshall Clow43ff7d92018-11-04 17:57:25 +0000540// Pop things off, one at a time
541 auto iter = --working.end();
542 while (iter != working.begin()) {
543 std::pop_heap(working.begin(), iter);
544 if (!std::is_heap(working.begin(), --iter)) return 2;
545 }
Marshall Clowa97ab842017-10-23 23:19:30 +0000546
Marshall Clow43ff7d92018-11-04 17:57:25 +0000547 return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000548}
549
550
Marshall Clow43ff7d92018-11-04 17:57:25 +0000551// -- search fuzzers
Marshall Clowa97ab842017-10-23 23:19:30 +0000552int search (const uint8_t *data, size_t size)
553{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000554 if (size < 2) return 0;
555
556 const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
557 assert(pat_size <= size - 1);
558 const uint8_t *pat_begin = data + 1;
559 const uint8_t *pat_end = pat_begin + pat_size;
560 const uint8_t *data_end = data + size;
561 assert(pat_end <= data_end);
562// std::cerr << "data[0] = " << size_t(data[0]) << " ";
563// std::cerr << "Pattern size = " << pat_size << "; corpus is " << size - 1 << std::endl;
564 auto it = std::search(pat_end, data_end, pat_begin, pat_end);
565 if (it != data_end) // not found
566 if (!std::equal(pat_begin, pat_end, it))
567 return 1;
568 return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000569}
570
571template <typename S>
572static int search_helper (const uint8_t *data, size_t size)
573{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000574 if (size < 2) return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000575
Marshall Clow43ff7d92018-11-04 17:57:25 +0000576 const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
577 const uint8_t *pat_begin = data + 1;
578 const uint8_t *pat_end = pat_begin + pat_size;
579 const uint8_t *data_end = data + size;
580
581 auto it = std::search(pat_end, data_end, S(pat_begin, pat_end));
582 if (it != data_end) // not found
583 if (!std::equal(pat_begin, pat_end, it))
584 return 1;
585 return 0;
Marshall Clowa97ab842017-10-23 23:19:30 +0000586}
587
Marshall Clow43ff7d92018-11-04 17:57:25 +0000588// These are still in std::experimental
Marshall Clowa97ab842017-10-23 23:19:30 +0000589// int search_boyer_moore (const uint8_t *data, size_t size)
590// {
Marshall Clow43ff7d92018-11-04 17:57:25 +0000591// return search_helper<std::boyer_moore_searcher<const uint8_t *>>(data, size);
Marshall Clowa97ab842017-10-23 23:19:30 +0000592// }
Marshall Clow43ff7d92018-11-04 17:57:25 +0000593//
Marshall Clowa97ab842017-10-23 23:19:30 +0000594// int search_boyer_moore_horspool (const uint8_t *data, size_t size)
595// {
Marshall Clow43ff7d92018-11-04 17:57:25 +0000596// return search_helper<std::boyer_moore_horspool_searcher<const uint8_t *>>(data, size);
Marshall Clowa97ab842017-10-23 23:19:30 +0000597// }
598
Marshall Clow974677c2017-10-30 19:51:58 +0000599
Marshall Clow43ff7d92018-11-04 17:57:25 +0000600// -- set operation fuzzers
Marshall Clow974677c2017-10-30 19:51:58 +0000601template <typename S>
602static void set_helper (const uint8_t *data, size_t size, Vec &v1, Vec &v2)
603{
Marshall Clow43ff7d92018-11-04 17:57:25 +0000604 assert(size > 1);
Marshall Clow974677c2017-10-30 19:51:58 +0000605
Marshall Clow43ff7d92018-11-04 17:57:25 +0000606 const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
607 const uint8_t *pat_begin = data + 1;
608 const uint8_t *pat_end = pat_begin + pat_size;
609 const uint8_t *data_end = data + size;
610 v1.assign(pat_begin, pat_end);
611 v2.assign(pat_end, data_end);
612
613 std::sort(v1.begin(), v1.end());
614 std::sort(v2.begin(), v2.end());
Marshall Clow974677c2017-10-30 19:51:58 +0000615}
616
Marshall Clowbaa6fb32017-10-04 22:23:03 +0000617} // namespace fuzzing