[libcxx-commits] [libcxx] b4bd194 - [libc++] Refactor the fuzzing tests
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Oct 19 09:12:11 PDT 2020
Author: Louis Dionne
Date: 2020-10-19T12:11:50-04:00
New Revision: b4bd194378851c2f421477d4147019d10f2420ac
URL: https://github.com/llvm/llvm-project/commit/b4bd194378851c2f421477d4147019d10f2420ac
DIFF: https://github.com/llvm/llvm-project/commit/b4bd194378851c2f421477d4147019d10f2420ac.diff
LOG: [libc++] Refactor the fuzzing tests
Define all the fuzzing tests in libcxx/test/libcxx/fuzzing, and get
rid of the ad-hoc libcxx/fuzzing directory, which wasn't properly
integrated with the build system or test suite.
As a fly-by change, this also reduces the dependencies of fuzzing tests
on large library components like <iostream>, to make them work on more
platforms.
Added:
libcxx/test/libcxx/fuzzing/fuzz.h
libcxx/test/libcxx/fuzzing/make_heap.pass.cpp
libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp
libcxx/test/libcxx/fuzzing/push_heap.pass.cpp
libcxx/test/libcxx/fuzzing/random.pass.cpp
libcxx/test/libcxx/fuzzing/regex.pass.cpp
libcxx/test/libcxx/fuzzing/search.pass.cpp
Modified:
libcxx/test/libcxx/fuzzing/nth_element.pass.cpp
libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp
libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp
libcxx/test/libcxx/fuzzing/partition.pass.cpp
libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp
libcxx/test/libcxx/fuzzing/sort.pass.cpp
libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp
libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp
libcxx/test/libcxx/fuzzing/unique.pass.cpp
libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp
libcxx/utils/ci/oss-fuzz.sh
Removed:
libcxx/fuzzing/RoutineNames.txt
libcxx/fuzzing/fuzz_test.cpp
libcxx/fuzzing/fuzz_test_template.cpp
libcxx/fuzzing/fuzzing.cpp
libcxx/fuzzing/fuzzing.h
libcxx/test/libcxx/fuzzing/fuzzer_test.h
libcxx/test/libcxx/fuzzing/geometric_distribution.pass.cpp
libcxx/test/libcxx/fuzzing/regex_ECMAScript.pass.cpp
libcxx/test/libcxx/fuzzing/regex_POSIX.pass.cpp
libcxx/test/libcxx/fuzzing/regex_awk.pass.cpp
libcxx/test/libcxx/fuzzing/regex_egrep.pass.cpp
libcxx/test/libcxx/fuzzing/regex_extended.pass.cpp
libcxx/test/libcxx/fuzzing/regex_grep.pass.cpp
################################################################################
diff --git a/libcxx/fuzzing/RoutineNames.txt b/libcxx/fuzzing/RoutineNames.txt
deleted file mode 100644
index a853c87e1f73..000000000000
--- a/libcxx/fuzzing/RoutineNames.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-sort
-stable_sort
-partition
-partition_copy
-stable_partition
-unique
-unique_copy
-nth_element
-partial_sort
-partial_sort_copy
-make_heap
-push_heap
-pop_heap
-regex_ECMAScript
-regex_POSIX
-regex_extended
-regex_awk
-regex_grep
-regex_egrep
-search
-uniform_int_distribution
-uniform_real_distribution
-bernoulli_distribution
-poisson_distribution
-geometric_distribution
-binomial_distribution
-negative_binomial_distribution
-exponential_distribution
-gamma_distribution
-weibull_distribution
-extreme_value_distribution
-normal_distribution
-lognormal_distribution
-chi_squared_distribution
-cauchy_distribution
-fisher_f_distribution
-student_t_distribution
-discrete_distribution
-piecewise_constant_distribution
-piecewise_linear_distribution
diff --git a/libcxx/fuzzing/fuzz_test.cpp b/libcxx/fuzzing/fuzz_test.cpp
deleted file mode 100644
index 508c3b65f2df..000000000000
--- a/libcxx/fuzzing/fuzz_test.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-// -*- C++ -*-
-//===------------------------- fuzz_test.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// A simple program for running regressions on the fuzzing routines.
-// This code is not part of any shipping product.
-//
-// To build:
-// clang++ -std=c++11 fuzz_test.cpp fuzzing.cpp
-//
-// To use:
-// fuzz_test -r partial_sort [-v] files...
-//
-// Each file should contain a test case.
-
-// TODO: should add some memory tracking, too.
-
-
-#include <iostream>
-#include <fstream>
-#include <iterator>
-#include <vector>
-#include <map>
-#include <chrono>
-
-#include "fuzzing.h"
-
-// ==== Count memory allocations ====
-
-struct MemoryCounters {
- size_t totalAllocationCount;
- size_t netAllocationCount;
- size_t totalBytesAllocated;
- };
-
-MemoryCounters gMemoryCounters;
-
-void ZeroMemoryCounters() {
- gMemoryCounters.totalAllocationCount = 0;
- gMemoryCounters.netAllocationCount = 0;
- gMemoryCounters.totalBytesAllocated = 0;
-}
-
-void* operator new(std::size_t size)
-{
- if (size == 0) size = 1;
- void *p = ::malloc(size);
- if (p == NULL)
- throw std::bad_alloc();
- gMemoryCounters.totalAllocationCount += 1;
- gMemoryCounters.netAllocationCount += 1;
- gMemoryCounters.totalBytesAllocated += size;
- return p;
-}
-
-void* operator new(std::size_t size, const std::nothrow_t&) noexcept
-{
- try { return operator new(size); }
- catch (const std::bad_alloc &) {}
- return nullptr;
-}
-
-void* operator new[](std::size_t size)
-{
- return ::operator new(size);
-}
-
-void* operator new[](std::size_t size, const std::nothrow_t&) noexcept
-{
- try { return operator new(size); }
- catch (const std::bad_alloc &) {}
- return nullptr;
-}
-
-void operator delete(void* ptr) noexcept
-{
- if (ptr)
- ::free(ptr);
- gMemoryCounters.netAllocationCount -= 1;
-}
-
-void operator delete(void* ptr, const std::nothrow_t&) noexcept
-{
- ::operator delete(ptr);
-}
-
-void operator delete[](void* ptr) noexcept
-{
- ::operator delete(ptr);
-}
-
-void operator delete[](void* ptr, const std::nothrow_t&) noexcept
-{
- ::operator delete(ptr);
-}
-
-// ==== End count memory allocations ====
-
-
-typedef int (*FuzzProc) (const uint8_t *data, size_t size);
-
-const std::map<std::string, FuzzProc> procs = {
- {"sort", fuzzing::sort},
- {"stable_sort", fuzzing::stable_sort},
- {"partition", fuzzing::partition},
- {"partition_copy", fuzzing::partition_copy},
- {"stable_partition", fuzzing::stable_partition},
- {"unique", fuzzing::unique},
- {"unique_copy", fuzzing::unique_copy},
- {"nth_element", fuzzing::nth_element},
- {"partial_sort", fuzzing::partial_sort},
- {"partial_sort_copy", fuzzing::partial_sort_copy},
- {"make_heap", fuzzing::make_heap},
- {"push_heap", fuzzing::push_heap},
- {"pop_heap", fuzzing::pop_heap},
- {"regex_ECMAScript", fuzzing::regex_ECMAScript},
- {"regex_POSIX", fuzzing::regex_POSIX},
- {"regex_extended", fuzzing::regex_extended},
- {"regex_awk", fuzzing::regex_awk},
- {"regex_grep", fuzzing::regex_grep},
- {"regex_egrep", fuzzing::regex_egrep},
- {"search", fuzzing::search}
-};
-
-
-
-bool verbose = false;
-
-void test_one(const char *filename, FuzzProc fp)
-{
- std::vector<uint8_t> v;
- std::ifstream f (filename, std::ios::binary);
- if (!f.is_open())
- std::cerr << "## Can't open '" << filename << "'" << std::endl;
- else
- {
- typedef std::istream_iterator<uint8_t> Iter;
- std::copy(Iter(f), Iter(), std::back_inserter(v));
- if (verbose)
- std::cout << "File '" << filename << "' contains " << v.size() << " entries" << std::endl;
- ZeroMemoryCounters();
- const auto start_time = std::chrono::high_resolution_clock::now();
- int ret = fp (v.data(), v.size());
- const auto finish_time = std::chrono::high_resolution_clock::now();
- MemoryCounters mc = gMemoryCounters;
- if (ret != 0)
- std::cerr << "## Failure code: " << ret << std::endl;
- if (verbose)
- {
- std::cout << "Execution time: "
- << std::chrono::duration_cast<std::chrono::milliseconds>(finish_time - start_time).count()
- << " milliseconds" << std::endl;
- std::cout << "Memory: "
- << mc.totalBytesAllocated << " bytes allocated ("
- << mc.totalAllocationCount << " allocations); "
- << mc.netAllocationCount << " allocations remain" << std::endl;
- }
- }
-}
-
-void usage (const char *name)
-{
- std::cout << "Usage: " << name << " -r proc [-v] files..." << std::endl;
- std::cout << "Supported routines:" << std::endl;
- for (const auto &p : procs)
- std::cout << " " << p.first << std::endl;
- std::cout << std::endl;
-}
-
-// Poor man's command-line options
-const std::string dashR("-r");
-const std::string dashV("-v");
-
-int main(int argc, char *argv[])
-{
- if (argc < 4 || dashR != argv[1] || procs.find(argv[2]) == procs.end())
- usage(argv[0]);
- else {
- FuzzProc fp = procs.find(argv[2])->second;
- int firstFile = 3;
- if (dashV == argv[firstFile])
- {
- verbose = true;
- ++firstFile;
- }
- for (int i = firstFile; i < argc; ++i)
- test_one(argv[i], fp);
- }
-}
diff --git a/libcxx/fuzzing/fuzz_test_template.cpp b/libcxx/fuzzing/fuzz_test_template.cpp
deleted file mode 100644
index ba44eef7891d..000000000000
--- a/libcxx/fuzzing/fuzz_test_template.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===------------------------- fuzz_test.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "fuzzing/fuzzing.h"
-#ifdef NDEBUG
-#undef NDEBUG
-#endif
-#include <cassert>
-
-#ifndef TEST_FUNCTION
-#error TEST_FUNCTION must be defined
-#endif
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- int result = fuzzing::TEST_FUNCTION(data, size);
- assert(result == 0); return 0;
-}
diff --git a/libcxx/fuzzing/fuzzing.cpp b/libcxx/fuzzing/fuzzing.cpp
deleted file mode 100644
index 1840c26d4b95..000000000000
--- a/libcxx/fuzzing/fuzzing.cpp
+++ /dev/null
@@ -1,846 +0,0 @@
-// -*- C++ -*-
-//===------------------------- fuzzing.cpp -------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// A set of routines to use when fuzzing the algorithms in libc++
-// Each one tests a single algorithm.
-//
-// They all have the form of:
-// int `algorithm`(const uint8_t *data, size_t size);
-//
-// They perform the operation, and then check to see if the results are correct.
-// If so, they return zero, and non-zero otherwise.
-//
-// For example, sort calls std::sort, then checks two things:
-// (1) The resulting vector is sorted
-// (2) The resulting vector contains the same elements as the original data.
-
-
-
-#include "fuzzing.h"
-#include <vector>
-#include <algorithm>
-#include <functional>
-#include <regex>
-#include <random>
-#include <cassert>
-#include <cmath>
-
-#include <iostream>
-
-#ifdef NDEBUG
-#undef NDEBUG
-#endif
-#include <cassert>
-// If we had C++14, we could use the four iterator version of is_permutation and equal
-
-#ifndef _LIBCPP_VERSION
-#error These test should be built with libc++ only.
-#endif
-
-namespace fuzzing {
-
-// This is a struct we can use to test the stable_XXX algorithms.
-// perform the operation on the key, then check the order of the payload.
-
-struct stable_test {
- uint8_t key;
- size_t payload;
-
- stable_test(uint8_t k) : key(k), payload(0) {}
- stable_test(uint8_t k, size_t p) : key(k), payload(p) {}
- };
-
-void swap(stable_test &lhs, stable_test &rhs)
-{
- using std::swap;
- swap(lhs.key, rhs.key);
- swap(lhs.payload, rhs.payload);
-}
-
-struct key_less
-{
- bool operator () (const stable_test &lhs, const stable_test &rhs) const
- {
- return lhs.key < rhs.key;
- }
-};
-
-struct payload_less
-{
- bool operator () (const stable_test &lhs, const stable_test &rhs) const
- {
- return lhs.payload < rhs.payload;
- }
-};
-
-struct total_less
-{
- bool operator () (const stable_test &lhs, const stable_test &rhs) const
- {
- return lhs.key == rhs.key ? lhs.payload < rhs.payload : lhs.key < rhs.key;
- }
-};
-
-bool operator==(const stable_test &lhs, const stable_test &rhs)
-{
- return lhs.key == rhs.key && lhs.payload == rhs.payload;
-}
-
-
-template<typename T>
-struct is_even
-{
- bool operator () (const T &t) const
- {
- return t % 2 == 0;
- }
-};
-
-
-template<>
-struct is_even<stable_test>
-{
- bool operator () (const stable_test &t) const
- {
- return t.key % 2 == 0;
- }
-};
-
-typedef std::vector<uint8_t> Vec;
-typedef std::vector<stable_test> StableVec;
-typedef StableVec::const_iterator SVIter;
-
-// Cheap version of is_permutation
-// Builds a set of buckets for each of the key values.
-// Sums all the payloads.
-// Not 100% perfect, but _way_ faster
-bool is_permutation(SVIter first1, SVIter last1, SVIter first2)
-{
- size_t xBuckets[256] = {0};
- size_t xPayloads[256] = {0};
- size_t yBuckets[256] = {0};
- size_t yPayloads[256] = {0};
-
- for (; first1 != last1; ++first1, ++first2)
- {
- xBuckets [first1->key]++;
- xPayloads[first1->key] += first1->payload;
-
- yBuckets [first2->key]++;
- yPayloads[first2->key] += first2->payload;
- }
-
- for (size_t i = 0; i < 256; ++i)
- {
- if (xBuckets[i] != yBuckets[i])
- return false;
- if (xPayloads[i] != yPayloads[i])
- return false;
- }
-
- return true;
-}
-
-template <typename Iter1, typename Iter2>
-bool is_permutation(Iter1 first1, Iter1 last1, Iter2 first2)
-{
- static_assert((std::is_same<typename std::iterator_traits<Iter1>::value_type, uint8_t>::value), "");
- static_assert((std::is_same<typename std::iterator_traits<Iter2>::value_type, uint8_t>::value), "");
-
- size_t xBuckets[256] = {0};
- size_t yBuckets[256] = {0};
-
- for (; first1 != last1; ++first1, ++first2)
- {
- xBuckets [*first1]++;
- yBuckets [*first2]++;
- }
-
- for (size_t i = 0; i < 256; ++i)
- if (xBuckets[i] != yBuckets[i])
- return false;
-
- return true;
-}
-
-// == sort ==
-int sort(const uint8_t *data, size_t size)
-{
- Vec working(data, data + size);
- std::sort(working.begin(), working.end());
-
- if (!std::is_sorted(working.begin(), working.end())) return 1;
- if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
- return 0;
-}
-
-
-// == stable_sort ==
-int stable_sort(const uint8_t *data, size_t size)
-{
- StableVec input;
- for (size_t i = 0; i < size; ++i)
- input.push_back(stable_test(data[i], i));
- StableVec working = input;
- std::stable_sort(working.begin(), working.end(), key_less());
-
- if (!std::is_sorted(working.begin(), working.end(), key_less())) return 1;
- auto iter = working.begin();
- while (iter != working.end())
- {
- auto range = std::equal_range(iter, working.end(), *iter, key_less());
- if (!std::is_sorted(range.first, range.second, total_less())) return 2;
- iter = range.second;
- }
- if (!fuzzing::is_permutation(input.cbegin(), input.cend(), working.cbegin())) return 99;
- return 0;
-}
-
-// == partition ==
-int partition(const uint8_t *data, size_t size)
-{
- Vec working(data, data + size);
- auto iter = std::partition(working.begin(), working.end(), is_even<uint8_t>());
-
- if (!std::all_of (working.begin(), iter, is_even<uint8_t>())) return 1;
- if (!std::none_of(iter, working.end(), is_even<uint8_t>())) return 2;
- if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
- return 0;
-}
-
-
-// == partition_copy ==
-int partition_copy(const uint8_t *data, size_t size)
-{
- Vec v1, v2;
- auto iter = std::partition_copy(data, data + size,
- std::back_inserter<Vec>(v1), std::back_inserter<Vec>(v2),
- is_even<uint8_t>());
- ((void)iter);
-// The two vectors should add up to the original size
- if (v1.size() + v2.size() != size) return 1;
-
-// All of the even values should be in the first vector, and none in the second
- if (!std::all_of (v1.begin(), v1.end(), is_even<uint8_t>())) return 2;
- if (!std::none_of(v2.begin(), v2.end(), is_even<uint8_t>())) return 3;
-
-// Every value in both vectors has to be in the original
-
-// Make a copy of the input, and sort it
- Vec v0{data, data + size};
- std::sort(v0.begin(), v0.end());
-
-// Sort each vector and ensure that all of the elements appear in the original input
- std::sort(v1.begin(), v1.end());
- if (!std::includes(v0.begin(), v0.end(), v1.begin(), v1.end())) return 4;
-
- std::sort(v2.begin(), v2.end());
- if (!std::includes(v0.begin(), v0.end(), v2.begin(), v2.end())) return 5;
-
-// This, while simple, is really slow - 20 seconds on a 500K element input.
-// for (auto v: v1)
-// if (std::find(data, data + size, v) == data + size) return 4;
-//
-// for (auto v: v2)
-// if (std::find(data, data + size, v) == data + size) return 5;
-
- return 0;
-}
-
-// == stable_partition ==
-int stable_partition (const uint8_t *data, size_t size)
-{
- StableVec input;
- for (size_t i = 0; i < size; ++i)
- input.push_back(stable_test(data[i], i));
- StableVec working = input;
- auto iter = std::stable_partition(working.begin(), working.end(), is_even<stable_test>());
-
- if (!std::all_of (working.begin(), iter, is_even<stable_test>())) return 1;
- if (!std::none_of(iter, working.end(), is_even<stable_test>())) return 2;
- if (!std::is_sorted(working.begin(), iter, payload_less())) return 3;
- if (!std::is_sorted(iter, working.end(), payload_less())) return 4;
- if (!fuzzing::is_permutation(input.cbegin(), input.cend(), working.cbegin())) return 99;
- return 0;
-}
-
-// == nth_element ==
-// use the first element as a position into the data
-int nth_element (const uint8_t *data, size_t size)
-{
- if (size <= 1) return 0;
- const size_t partition_point = data[0] % size;
- Vec working(data + 1, data + size);
- const auto partition_iter = working.begin() + partition_point;
- std::nth_element(working.begin(), partition_iter, working.end());
-
-// nth may be the end iterator, in this case nth_element has no effect.
- if (partition_iter == working.end())
- {
- if (!std::equal(data + 1, data + size, working.begin())) return 98;
- }
- else
- {
- const uint8_t nth = *partition_iter;
- if (!std::all_of(working.begin(), partition_iter, [=](uint8_t v) { return v <= nth; }))
- return 1;
- if (!std::all_of(partition_iter, working.end(), [=](uint8_t v) { return v >= nth; }))
- return 2;
- if (!fuzzing::is_permutation(data + 1, data + size, working.cbegin())) return 99;
- }
-
- return 0;
-}
-
-// == partial_sort ==
-// use the first element as a position into the data
-int partial_sort (const uint8_t *data, size_t size)
-{
- if (size <= 1) return 0;
- const size_t sort_point = data[0] % size;
- Vec working(data + 1, data + size);
- const auto sort_iter = working.begin() + sort_point;
- std::partial_sort(working.begin(), sort_iter, working.end());
-
- if (sort_iter != working.end())
- {
- const uint8_t nth = *std::min_element(sort_iter, working.end());
- if (!std::all_of(working.begin(), sort_iter, [=](uint8_t v) { return v <= nth; }))
- return 1;
- if (!std::all_of(sort_iter, working.end(), [=](uint8_t v) { return v >= nth; }))
- return 2;
- }
- if (!std::is_sorted(working.begin(), sort_iter)) return 3;
- if (!fuzzing::is_permutation(data + 1, data + size, working.cbegin())) return 99;
-
- return 0;
-}
-
-
-// == partial_sort_copy ==
-// use the first element as a count
-int partial_sort_copy (const uint8_t *data, size_t size)
-{
- if (size <= 1) return 0;
- const size_t num_results = data[0] % size;
- Vec results(num_results);
- (void) std::partial_sort_copy(data + 1, data + size, results.begin(), results.end());
-
-// The results have to be sorted
- if (!std::is_sorted(results.begin(), results.end())) return 1;
-// All the values in results have to be in the original data
- for (auto v: results)
- if (std::find(data + 1, data + size, v) == data + size) return 2;
-
-// The things in results have to be the smallest N in the original data
- Vec sorted(data + 1, data + size);
- std::sort(sorted.begin(), sorted.end());
- if (!std::equal(results.begin(), results.end(), sorted.begin())) return 3;
- return 0;
-}
-
-// The second sequence has been "uniqued"
-template <typename Iter1, typename Iter2>
-static bool compare_unique(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2)
-{
- assert(first1 != last1 && first2 != last2);
- if (*first1 != *first2) return false;
-
- uint8_t last_value = *first1;
- ++first1; ++first2;
- while(first1 != last1 && first2 != last2)
- {
- // Skip over dups in the first sequence
- while (*first1 == last_value)
- if (++first1 == last1) return false;
- if (*first1 != *first2) return false;
- last_value = *first1;
- ++first1; ++first2;
- }
-
-// Still stuff left in the 'uniqued' sequence - oops
- if (first1 == last1 && first2 != last2) return false;
-
-// Still stuff left in the original sequence - better be all the same
- while (first1 != last1)
- {
- if (*first1 != last_value) return false;
- ++first1;
- }
- return true;
-}
-
-// == unique ==
-int unique (const uint8_t *data, size_t size)
-{
- Vec working(data, data + size);
- std::sort(working.begin(), working.end());
- Vec results = working;
- Vec::iterator new_end = std::unique(results.begin(), results.end());
- Vec::iterator it; // scratch iterator
-
-// Check the size of the unique'd sequence.
-// it should only be zero if the input sequence was empty.
- if (results.begin() == new_end)
- return working.size() == 0 ? 0 : 1;
-
-// 'results' is sorted
- if (!std::is_sorted(results.begin(), new_end)) return 2;
-
-// All the elements in 'results' must be
diff erent
- it = results.begin();
- uint8_t prev_value = *it++;
- for (; it != new_end; ++it)
- {
- if (*it == prev_value) return 3;
- prev_value = *it;
- }
-
-// Every element in 'results' must be in 'working'
- for (it = results.begin(); it != new_end; ++it)
- if (std::find(working.begin(), working.end(), *it) == working.end())
- return 4;
-
-// Every element in 'working' must be in 'results'
- for (auto v : working)
- if (std::find(results.begin(), new_end, v) == new_end)
- return 5;
-
- return 0;
-}
-
-// == unique_copy ==
-int unique_copy (const uint8_t *data, size_t size)
-{
- Vec working(data, data + size);
- std::sort(working.begin(), working.end());
- Vec results;
- (void) std::unique_copy(working.begin(), working.end(),
- std::back_inserter<Vec>(results));
- Vec::iterator it; // scratch iterator
-
-// Check the size of the unique'd sequence.
-// it should only be zero if the input sequence was empty.
- if (results.size() == 0)
- return working.size() == 0 ? 0 : 1;
-
-// 'results' is sorted
- if (!std::is_sorted(results.begin(), results.end())) return 2;
-
-// All the elements in 'results' must be
diff erent
- it = results.begin();
- uint8_t prev_value = *it++;
- for (; it != results.end(); ++it)
- {
- if (*it == prev_value) return 3;
- prev_value = *it;
- }
-
-// Every element in 'results' must be in 'working'
- for (auto v : results)
- if (std::find(working.begin(), working.end(), v) == working.end())
- return 4;
-
-// Every element in 'working' must be in 'results'
- for (auto v : working)
- if (std::find(results.begin(), results.end(), v) == results.end())
- return 5;
-
- return 0;
-}
-
-
-// -- regex fuzzers
-static int regex_helper(const uint8_t *data, size_t size, std::regex::flag_type flag)
-{
- if (size > 0)
- {
-#ifndef _LIBCPP_NO_EXCEPTIONS
- try
- {
- std::string s((const char *)data, size);
- std::regex re(s, flag);
- return std::regex_match(s, re) ? 1 : 0;
- }
- catch (std::regex_error &ex) {}
-#else
- ((void)data);
- ((void)size);
- ((void)flag);
-#endif
- }
- return 0;
-}
-
-
-int regex_ECMAScript (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::ECMAScript);
- return 0;
-}
-
-int regex_POSIX (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::basic);
- return 0;
-}
-
-int regex_extended (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::extended);
- return 0;
-}
-
-int regex_awk (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::awk);
- return 0;
-}
-
-int regex_grep (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::grep);
- return 0;
-}
-
-int regex_egrep (const uint8_t *data, size_t size)
-{
- (void) regex_helper(data, size, std::regex_constants::egrep);
- return 0;
-}
-
-// -- heap fuzzers
-int make_heap (const uint8_t *data, size_t size)
-{
- Vec working(data, data + size);
- std::make_heap(working.begin(), working.end());
-
- if (!std::is_heap(working.begin(), working.end())) return 1;
- if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
- return 0;
-}
-
-int push_heap (const uint8_t *data, size_t size)
-{
- if (size < 2) return 0;
-
-// Make a heap from the first half of the data
- Vec working(data, data + size);
- auto iter = working.begin() + (size / 2);
- std::make_heap(working.begin(), iter);
- if (!std::is_heap(working.begin(), iter)) return 1;
-
-// Now push the rest onto the heap, one at a time
- ++iter;
- for (; iter != working.end(); ++iter) {
- std::push_heap(working.begin(), iter);
- if (!std::is_heap(working.begin(), iter)) return 2;
- }
-
- if (!fuzzing::is_permutation(data, data + size, working.cbegin())) return 99;
- return 0;
-}
-
-int pop_heap (const uint8_t *data, size_t size)
-{
- if (size < 2) return 0;
- Vec working(data, data + size);
- std::make_heap(working.begin(), working.end());
-
-// Pop things off, one at a time
- auto iter = --working.end();
- while (iter != working.begin()) {
- std::pop_heap(working.begin(), iter);
- if (!std::is_heap(working.begin(), --iter)) return 2;
- }
-
- return 0;
-}
-
-
-// -- search fuzzers
-int search (const uint8_t *data, size_t size)
-{
- if (size < 2) return 0;
-
- const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
- assert(pat_size <= size - 1);
- const uint8_t *pat_begin = data + 1;
- const uint8_t *pat_end = pat_begin + pat_size;
- const uint8_t *data_end = data + size;
- assert(pat_end <= data_end);
-// std::cerr << "data[0] = " << size_t(data[0]) << " ";
-// std::cerr << "Pattern size = " << pat_size << "; corpus is " << size - 1 << std::endl;
- auto it = std::search(pat_end, data_end, pat_begin, pat_end);
- if (it != data_end) // not found
- if (!std::equal(pat_begin, pat_end, it))
- return 1;
- return 0;
-}
-
-template <typename S>
-static int search_helper (const uint8_t *data, size_t size)
-{
- if (size < 2) return 0;
-
- const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
- const uint8_t *pat_begin = data + 1;
- const uint8_t *pat_end = pat_begin + pat_size;
- const uint8_t *data_end = data + size;
-
- auto it = std::search(pat_end, data_end, S(pat_begin, pat_end));
- if (it != data_end) // not found
- if (!std::equal(pat_begin, pat_end, it))
- return 1;
- return 0;
-}
-
-// These are still in std::experimental
-// int search_boyer_moore (const uint8_t *data, size_t size)
-// {
-// return search_helper<std::boyer_moore_searcher<const uint8_t *>>(data, size);
-// }
-//
-// int search_boyer_moore_horspool (const uint8_t *data, size_t size)
-// {
-// return search_helper<std::boyer_moore_horspool_searcher<const uint8_t *>>(data, size);
-// }
-
-
-// -- set operation fuzzers
-template <typename S>
-static void set_helper (const uint8_t *data, size_t size, Vec &v1, Vec &v2)
-{
- assert(size > 1);
-
- const size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
- const uint8_t *pat_begin = data + 1;
- const uint8_t *pat_end = pat_begin + pat_size;
- const uint8_t *data_end = data + size;
- v1.assign(pat_begin, pat_end);
- v2.assign(pat_end, data_end);
-
- std::sort(v1.begin(), v1.end());
- std::sort(v2.begin(), v2.end());
-}
-
-enum class ParamKind {
- OneValue,
- TwoValues,
- PointerRange
-};
-
-template <class IntT>
-std::vector<IntT> GetValues(const uint8_t *data, size_t size) {
- std::vector<IntT> result;
- while (size >= sizeof(IntT)) {
- IntT tmp;
- memcpy(&tmp, data, sizeof(IntT));
- size -= sizeof(IntT);
- data += sizeof(IntT);
- result.push_back(tmp);
- }
- return result;
-}
-
-enum InitKind {
- Default,
- DoubleOnly,
- VectorDouble,
- VectorResultType
-};
-
-
-
-template <class Dist>
-struct ParamTypeHelper {
- using ParamT = typename Dist::param_type;
- using ResultT = typename Dist::result_type;
- static_assert(std::is_same<ResultT, typename ParamT::distribution_type::result_type>::value, "");
- static ParamT Create(const uint8_t* data, size_t size, bool &OK) {
-
- constexpr bool select_vector_result = std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value;
- constexpr bool select_vector_double = std::is_constructible<ParamT, double*, double*>::value;
- constexpr int selector = select_vector_result ? 0 : (select_vector_double ? 1 : 2);
- return DispatchAndCreate(std::integral_constant<int, selector>{}, data, size, OK);
-
- }
-
- static ParamT DispatchAndCreate(std::integral_constant<int, 0>, const uint8_t *data, size_t size, bool &OK) {
- return CreateVectorResult(data, size, OK);
- }
- static ParamT DispatchAndCreate(std::integral_constant<int, 1>, const uint8_t *data, size_t size, bool &OK) {
- return CreateVectorDouble(data, size, OK);
- }
- static ParamT DispatchAndCreate(std::integral_constant<int, 2>, const uint8_t *data, size_t size, bool &OK) {
- return CreateDefault(data, size, OK);
- }
-
-static ParamT
-CreateVectorResult(const uint8_t *data, size_t size, bool &OK) {
- auto Input = GetValues<ResultT>(data, size);
- OK = false;
- if (Input.size() < 10)
- return ParamT{};
- OK = true;
- auto Beg = Input.begin();
- auto End = Input.end();
- auto Mid = Beg + ((End - Beg) / 2);
-
- assert(Mid - Beg <= (End - Mid));
- ParamT p(Beg, Mid, Mid);
- return p;
-}
-
- static ParamT
- CreateVectorDouble(const uint8_t *data, size_t size, bool &OK) {
- auto Input = GetValues<double>(data, size);
-
- OK = true;
- auto Beg = Input.begin();
- auto End = Input.end();
-
- ParamT p(Beg, End);
- return p;
- }
-
-
- static ParamT
- CreateDefault(const uint8_t *data, size_t size, bool &OK) {
- OK = false;
- if (size < sizeof(ParamT))
- return ParamT{};
- OK = true;
- ParamT input;
- memcpy(&input, data, sizeof(ParamT));
- return input;
- }
-
-};
-
-
-
-
-template <class IntT>
-struct ParamTypeHelper<std::poisson_distribution<IntT>> {
- using Dist = std::poisson_distribution<IntT>;
- using ParamT = typename Dist::param_type;
- using ResultT = typename Dist::result_type;
-
- static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
- OK = false;
- auto vals = GetValues<double>(data, size);
- if (vals.empty() || std::isnan(vals[0]) || std::isnan(std::abs(vals[0])) || vals[0] < 0 )
- return ParamT{};
- OK = true;
- //std::cerr << "Value: " << vals[0] << std::endl;
- return ParamT{vals[0]};
- }
-};
-
-
-template <class IntT>
-struct ParamTypeHelper<std::geometric_distribution<IntT>> {
- using Dist = std::geometric_distribution<IntT>;
- using ParamT = typename Dist::param_type;
- using ResultT = typename Dist::result_type;
-
- static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
- OK = false;
- auto vals = GetValues<double>(data, size);
- if (vals.empty() || std::isnan(vals[0]) || vals[0] < 0 )
- return ParamT{};
- OK = true;
- // std::cerr << "Value: " << vals[0] << std::endl;
- return ParamT{vals[0]};
- }
-};
-
-
-template <class IntT>
-struct ParamTypeHelper<std::lognormal_distribution<IntT>> {
- using Dist = std::lognormal_distribution<IntT>;
- using ParamT = typename Dist::param_type;
- using ResultT = typename Dist::result_type;
-
- static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
- OK = false;
- auto vals = GetValues<ResultT>(data, size);
- if (vals.size() < 2 )
- return ParamT{};
- OK = true;
- return ParamT{vals[0], vals[1]};
- }
-};
-
-
-template <>
-struct ParamTypeHelper<std::bernoulli_distribution> {
- using Dist = std::bernoulli_distribution;
- using ParamT = typename Dist::param_type;
- using ResultT = typename Dist::result_type;
-
- static ParamT Create(const uint8_t *data, size_t size, bool& OK) {
- OK = false;
- auto vals = GetValues<double>(data, size);
- if (vals.empty())
- return ParamT{};
- OK = true;
- return ParamT{vals[0]};
- }
-};
-
-template <class Distribution>
-int random_distribution_helper(const uint8_t *data, size_t size) {
-
- std::mt19937 engine;
- using ParamT = typename Distribution::param_type;
- bool OK;
- ParamT p = ParamTypeHelper<Distribution>::Create(data, size, OK);
- if (!OK)
- return 0;
- Distribution d(p);
- volatile auto res = d(engine);
- if (std::isnan(res)) {
- // FIXME(llvm.org/PR44289):
- // Investigate why these distributions are returning NaN and decide
- // if that's what we want them to be doing.
- //
- // Make this assert false (or return non-zero).
- return 0;
- }
- return 0;
-}
-
-#define DEFINE_RANDOM_TEST(name, ...) \
-int name(const uint8_t *data, size_t size) { \
- return random_distribution_helper< std::name __VA_ARGS__ >(data, size); \
-}
-DEFINE_RANDOM_TEST(uniform_int_distribution,<std::int16_t>)
-DEFINE_RANDOM_TEST(uniform_real_distribution,<float>)
-DEFINE_RANDOM_TEST(bernoulli_distribution)
-DEFINE_RANDOM_TEST(poisson_distribution,<std::int16_t>)
-DEFINE_RANDOM_TEST(geometric_distribution,<std::int16_t>)
-DEFINE_RANDOM_TEST(binomial_distribution, <std::int16_t>)
-DEFINE_RANDOM_TEST(negative_binomial_distribution, <std::int16_t>)
-DEFINE_RANDOM_TEST(exponential_distribution, <float>)
-DEFINE_RANDOM_TEST(gamma_distribution, <float>)
-DEFINE_RANDOM_TEST(weibull_distribution, <float>)
-DEFINE_RANDOM_TEST(extreme_value_distribution, <float>)
-DEFINE_RANDOM_TEST(normal_distribution, <float>)
-DEFINE_RANDOM_TEST(lognormal_distribution, <float>)
-DEFINE_RANDOM_TEST(chi_squared_distribution, <float>)
-DEFINE_RANDOM_TEST(cauchy_distribution, <float>)
-DEFINE_RANDOM_TEST(fisher_f_distribution, <float>)
-DEFINE_RANDOM_TEST(student_t_distribution, <float>)
-DEFINE_RANDOM_TEST(discrete_distribution, <std::int16_t>)
-DEFINE_RANDOM_TEST(piecewise_constant_distribution, <float>)
-DEFINE_RANDOM_TEST(piecewise_linear_distribution, <float>)
-
-} // namespace fuzzing
diff --git a/libcxx/fuzzing/fuzzing.h b/libcxx/fuzzing/fuzzing.h
deleted file mode 100644
index 99a3aa14a777..000000000000
--- a/libcxx/fuzzing/fuzzing.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// -*- C++ -*-
-//===-------------------------- fuzzing.h --------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP_FUZZING
-#define _LIBCPP_FUZZING
-
-#include <cstddef> // for size_t
-#include <cstdint> // for uint8_t
-
-namespace fuzzing {
-
-// These all return 0 on success; != 0 on failure
- int sort (const uint8_t *data, size_t size);
- int stable_sort (const uint8_t *data, size_t size);
- int partition (const uint8_t *data, size_t size);
- int partition_copy (const uint8_t *data, size_t size);
- int stable_partition (const uint8_t *data, size_t size);
- int unique (const uint8_t *data, size_t size);
- int unique_copy (const uint8_t *data, size_t size);
-
-// partition and stable_partition take Bi-Di iterators.
-// Should test those, too
- int nth_element (const uint8_t *data, size_t size);
- int partial_sort (const uint8_t *data, size_t size);
- int partial_sort_copy (const uint8_t *data, size_t size);
-
-// Heap operations
- int make_heap (const uint8_t *data, size_t size);
- int push_heap (const uint8_t *data, size_t size);
- int pop_heap (const uint8_t *data, size_t size);
-
-// Various flavors of regex
- int regex_ECMAScript (const uint8_t *data, size_t size);
- int regex_POSIX (const uint8_t *data, size_t size);
- int regex_extended (const uint8_t *data, size_t size);
- int regex_awk (const uint8_t *data, size_t size);
- int regex_grep (const uint8_t *data, size_t size);
- int regex_egrep (const uint8_t *data, size_t size);
-
-// Searching
- int search (const uint8_t *data, size_t size);
-// int search_boyer_moore (const uint8_t *data, size_t size);
-// int search_boyer_moore_horspool (const uint8_t *data, size_t size);
-
-// Set operations
-// int includes (const uint8_t *data, size_t size);
-// int set_union (const uint8_t *data, size_t size);
-// int set_intersection (const uint8_t *data, size_t size);
-// int set_
diff erence (const uint8_t *data, size_t size);
-// int set_symmetric_
diff erence (const uint8_t *data, size_t size);
-// int merge (const uint8_t *data, size_t size);
-
-// Random numbers
- int uniform_int_distribution(const uint8_t*, size_t);
- int uniform_real_distribution(const uint8_t*, size_t);
- int bernoulli_distribution(const uint8_t*, size_t);
- int poisson_distribution(const uint8_t*, size_t);
- int geometric_distribution(const uint8_t*, size_t);
- int binomial_distribution(const uint8_t*, size_t);
- int negative_binomial_distribution(const uint8_t*, size_t);
- int exponential_distribution(const uint8_t*, size_t);
- int gamma_distribution(const uint8_t*, size_t);
- int weibull_distribution(const uint8_t*, size_t);
- int extreme_value_distribution(const uint8_t*, size_t);
- int normal_distribution(const uint8_t*, size_t);
- int lognormal_distribution(const uint8_t*, size_t);
- int chi_squared_distribution(const uint8_t*, size_t);
- int cauchy_distribution(const uint8_t*, size_t);
- int fisher_f_distribution(const uint8_t*, size_t);
- int student_t_distribution(const uint8_t*, size_t);
- int discrete_distribution(const uint8_t*, size_t);
- int piecewise_constant_distribution(const uint8_t*, size_t);
- int piecewise_linear_distribution(const uint8_t*, size_t);
-
-} // namespace fuzzing
-
-#endif // _LIBCPP_FUZZING
diff --git a/libcxx/test/libcxx/fuzzing/fuzz.h b/libcxx/test/libcxx/fuzzing/fuzz.h
new file mode 100644
index 000000000000..1281879c536c
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/fuzz.h
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_LIBCXX_FUZZING_FUZZ_H
+#define TEST_LIBCXX_FUZZING_FUZZ_H
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring> // std::strlen
+#include <type_traits>
+#include <utility> // std::swap
+
+
+// This is a struct we can use to test the stable_XXX algorithms.
+// Perform the operation on the key, then check the order of the payload.
+struct ByteWithPayload {
+ std::uint8_t key;
+ std::size_t payload;
+
+ ByteWithPayload(std::uint8_t k) : key(k), payload(0) { }
+ ByteWithPayload(std::uint8_t k, std::size_t p) : key(k), payload(p) { }
+
+ friend bool operator==(ByteWithPayload const& x, ByteWithPayload const& y) {
+ return x.key == y.key && x.payload == y.payload;
+ }
+
+ friend bool operator!=(ByteWithPayload const& x, ByteWithPayload const& y) {
+ return !(x == y);
+ }
+
+ struct key_less {
+ bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const
+ { return x.key < y.key; }
+ };
+
+ struct payload_less {
+ bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const
+ { return x.payload < y.payload; }
+ };
+
+ struct total_less {
+ bool operator()(ByteWithPayload const& x, ByteWithPayload const& y) const {
+ return x.key == y.key ? x.payload < y.payload : x.key < y.key;
+ }
+ };
+
+ friend void swap(ByteWithPayload& lhs, ByteWithPayload& rhs) {
+ std::swap(lhs.key, rhs.key);
+ std::swap(lhs.payload, rhs.payload);
+ }
+};
+
+// Faster version of std::is_permutation
+//
+// Builds a set of buckets for each of the key values, and sums all the payloads.
+// Not 100% perfect, but _way_ faster.
+template <typename Iter1, typename Iter2, typename = typename std::enable_if<
+ std::is_same<typename std::iterator_traits<Iter1>::value_type, ByteWithPayload>::value &&
+ std::is_same<typename std::iterator_traits<Iter2>::value_type, ByteWithPayload>::value
+>::type>
+bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) {
+ std::size_t xBuckets[256] = {0};
+ std::size_t xPayloads[256] = {0};
+ std::size_t yBuckets[256] = {0};
+ std::size_t yPayloads[256] = {0};
+
+ for (; first1 != last1; ++first1, ++first2) {
+ xBuckets[first1->key]++;
+ xPayloads[first1->key] += first1->payload;
+
+ yBuckets[first2->key]++;
+ yPayloads[first2->key] += first2->payload;
+ }
+
+ for (std::size_t i = 0; i < 256; ++i) {
+ if (xBuckets[i] != yBuckets[i])
+ return false;
+ if (xPayloads[i] != yPayloads[i])
+ return false;
+ }
+
+ return true;
+}
+
+template <typename Iter1, typename Iter2, typename = void, typename = typename std::enable_if<
+ std::is_same<typename std::iterator_traits<Iter1>::value_type, std::uint8_t>::value &&
+ std::is_same<typename std::iterator_traits<Iter2>::value_type, std::uint8_t>::value
+>::type>
+bool fast_is_permutation(Iter1 first1, Iter1 last1, Iter2 first2) {
+ std::size_t xBuckets[256] = {0};
+ std::size_t yBuckets[256] = {0};
+
+ for (; first1 != last1; ++first1, ++first2) {
+ xBuckets[*first1]++;
+ yBuckets[*first2]++;
+ }
+
+ for (std::size_t i = 0; i < 256; ++i)
+ if (xBuckets[i] != yBuckets[i])
+ return false;
+
+ return true;
+}
+
+// When running inside OSS-Fuzz, we link against a fuzzing library that defines
+// main() and calls LLVMFuzzerTestOneInput.
+//
+// Otherwise, when e.g. running the Lit tests, we define main() to run fuzzing
+// tests on a few inputs.
+#if !defined(LIBCPP_OSS_FUZZ)
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t*, std::size_t);
+
+int main(int, char**) {
+ const char* test_cases[] = {
+ "",
+ "s",
+ "bac",
+ "bacasf",
+ "lkajseravea",
+ "adsfkajdsfjkas;lnc441324513,34535r34525234",
+ "b*c",
+ "ba?sf",
+ "lka*ea",
+ "adsf*kas;lnc441[0-9]1r34525234"
+ };
+
+ for (const char* tc : test_cases) {
+ const std::size_t size = std::strlen(tc);
+ const std::uint8_t* data = reinterpret_cast<const std::uint8_t*>(tc);
+ int result = LLVMFuzzerTestOneInput(data, size);
+ assert(result == 0);
+ }
+
+ return 0;
+}
+#endif // !LIBCPP_OSS_FUZZ
+
+#endif // TEST_LIBCXX_FUZZING_FUZZ_H
diff --git a/libcxx/test/libcxx/fuzzing/fuzzer_test.h b/libcxx/test/libcxx/fuzzing/fuzzer_test.h
deleted file mode 100644
index 1fafd2385a5c..000000000000
--- a/libcxx/test/libcxx/fuzzing/fuzzer_test.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef TEST_LIBCXX_FUZZER_TEST_H
-#define TEST_LIBCXX_FUZZER_TEST_H
-
-#include <cstddef>
-#include <cassert>
-
-#include "../../../fuzzing/fuzzing.h"
-#include "../../../fuzzing/fuzzing.cpp"
-
-const char* TestCaseSetOne[] = {"", "s", "bac",
- "bacasf",
- "lkajseravea",
- "adsfkajdsfjkas;lnc441324513,34535r34525234",
- "b*c",
- "ba?sf",
- "lka*ea",
- "adsf*kas;lnc441[0-9]1r34525234"};
-
-using FuzzerFuncType = int(const uint8_t*, size_t);
-
-template <size_t NumCases>
-inline void RunFuzzingTest(FuzzerFuncType *to_test, const char* (&test_cases)[NumCases]) {
- for (const char* TC : test_cases) {
- const size_t size = std::strlen(TC);
- const uint8_t* data = (const uint8_t*)TC;
- int result = to_test(data, size);
- assert(result == 0);
- }
-}
-
-#define FUZZER_TEST(FuncName) \
-int main() { \
- RunFuzzingTest(FuncName, TestCaseSetOne); \
-} \
-extern int require_semi
-
-#endif // TEST_LIBCXX_FUZZER_TEST_H
diff --git a/libcxx/test/libcxx/fuzzing/geometric_distribution.pass.cpp b/libcxx/test/libcxx/fuzzing/geometric_distribution.pass.cpp
deleted file mode 100644
index 5a5839a11a55..000000000000
--- a/libcxx/test/libcxx/fuzzing/geometric_distribution.pass.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// -*- C++ -*-
-//===------------------------ unique_copy.cpp -----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include <random>
-#include <cstdint>
-
-#include "fuzzer_test.h"
-
-template <class Distribution>
-int random_distribution_helper(const uint8_t *data, size_t size) {
- std::mt19937 engine;
- using ParamT = typename Distribution::param_type;
- if (size < sizeof(double))
- return 0;
- double Arg;
- memcpy(&Arg, data, sizeof(double));
- ParamT p(Arg);
- Distribution d(p);
- for (int I=0; I < 1000; ++I) {
- volatile auto res = d(engine);
- ((void)res);
- }
- return 0;
-}
-
-int FuzzRandom(const uint8_t *Data, size_t Size) {
- return random_distribution_helper<std::geometric_distribution<std::int16_t>>(Data, Size);
-}
-FUZZER_TEST(FuzzRandom);
-
-
diff --git a/libcxx/test/libcxx/fuzzing/make_heap.pass.cpp b/libcxx/test/libcxx/fuzzing/make_heap.pass.cpp
new file mode 100644
index 000000000000..ede82c288b06
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/make_heap.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ std::vector<std::uint8_t> working(data, data + size);
+ std::make_heap(working.begin(), working.end());
+
+ if (!std::is_heap(working.begin(), working.end()))
+ return 1;
+ if (!fast_is_permutation(data, data + size, working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp b/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp
index e3ad5bbf8d2b..5e491e76dfa2 100644
--- a/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/nth_element.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===----------------------- nth_element.cpp ------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,37 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+// Use the first element as a position into the data
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size <= 1) return 0;
+ const size_t partition_point = data[0] % size;
+ std::vector<std::uint8_t> working(data + 1, data + size);
+ const auto partition_iter = working.begin() + partition_point;
+ std::nth_element(working.begin(), partition_iter, working.end());
+
+ // nth may be the end iterator, in this case nth_element has no effect.
+ if (partition_iter == working.end()) {
+ if (!std::equal(data + 1, data + size, working.begin()))
+ return 98;
+ }
+ else {
+ const std::uint8_t nth = *partition_iter;
+ if (!std::all_of(working.begin(), partition_iter, [=](std::uint8_t v) { return v <= nth; }))
+ return 1;
+ if (!std::all_of(partition_iter, working.end(), [=](std::uint8_t v) { return v >= nth; }))
+ return 2;
+ if (!fast_is_permutation(data + 1, data + size, working.cbegin()))
+ return 99;
+ }
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::nth_element);
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp b/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp
index 3f6fef1de90d..c179846b6ff6 100644
--- a/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/partial_sort.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===-------------------------- partial_sort.cpp --------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,26 +6,35 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
-#include <cassert>
-#include <cstring> // for strlen
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
-#include "../../../fuzzing/fuzzing.h"
-#include "../../../fuzzing/fuzzing.cpp"
+#include "fuzz.h"
-const char* test_cases[] = {"", "s", "bac",
- "bacasf",
- "lkajseravea",
- "adsfkajdsfjkas;lnc441324513,34535r34525234"};
+// Use the first element as a position into the data
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size <= 1)
+ return 0;
+ const std::size_t sort_point = data[0] % size;
+ std::vector<std::uint8_t> working(data + 1, data + size);
+ const auto sort_iter = working.begin() + sort_point;
+ std::partial_sort(working.begin(), sort_iter, working.end());
-const size_t k_num_tests = sizeof(test_cases) / sizeof(test_cases[0]);
+ if (sort_iter != working.end()) {
+ const std::uint8_t nth = *std::min_element(sort_iter, working.end());
+ if (!std::all_of(working.begin(), sort_iter, [=](std::uint8_t v) { return v <= nth; }))
+ return 1;
+ if (!std::all_of(sort_iter, working.end(), [=](std::uint8_t v) { return v >= nth; }))
+ return 2;
+ }
+ if (!std::is_sorted(working.begin(), sort_iter))
+ return 3;
+ if (!fast_is_permutation(data + 1, data + size, working.cbegin()))
+ return 99;
-int main(int, char**) {
- for (size_t i = 0; i < k_num_tests; ++i) {
- const size_t size = std::strlen(test_cases[i]);
- const uint8_t* data = (const uint8_t*)test_cases[i];
- assert(0 == fuzzing::partial_sort(data, size));
- }
- return 0;
+ return 0;
}
diff --git a/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp b/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp
index b5d47c55b0db..530ab0d162c4 100644
--- a/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/partial_sort_copy.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===----------------------- partial_sort_copy.cpp ------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,36 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+// Use the first element as a count
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size <= 1)
+ return 0;
+ const std::size_t num_results = data[0] % size;
+ std::vector<std::uint8_t> results(num_results);
+ (void)std::partial_sort_copy(data + 1, data + size, results.begin(), results.end());
+
+ // The results have to be sorted
+ if (!std::is_sorted(results.begin(), results.end()))
+ return 1;
+ // All the values in results have to be in the original data
+ for (auto v: results)
+ if (std::find(data + 1, data + size, v) == data + size)
+ return 2;
+
+ // The things in results have to be the smallest N in the original data
+ std::vector<std::uint8_t> sorted(data + 1, data + size);
+ std::sort(sorted.begin(), sorted.end());
+ if (!std::equal(results.begin(), results.end(), sorted.begin()))
+ return 3;
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::partial_sort_copy);
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/partition.pass.cpp b/libcxx/test/libcxx/fuzzing/partition.pass.cpp
index dda506d82121..203e45bb8bdd 100644
--- a/libcxx/test/libcxx/fuzzing/partition.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/partition.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===--------------------------- partition.cpp ----------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,25 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ auto is_even = [](auto x) { return x % 2 == 0; };
+ std::vector<std::uint8_t> working(data, data + size);
+ auto iter = std::partition(working.begin(), working.end(), is_even);
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::partition);
+ if (!std::all_of(working.begin(), iter, is_even))
+ return 1;
+ if (!std::none_of(iter, working.end(), is_even))
+ return 2;
+ if (!fast_is_permutation(data, data + size, working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp b/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp
index 383b4cfc5c5d..ac37c2ef2427 100644
--- a/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/partition_copy.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===------------------------ partition_copy.cpp --------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,60 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ auto is_even = [](auto t) {
+ return t % 2 == 0;
+ };
+
+ std::vector<std::uint8_t> v1, v2;
+ auto iter = std::partition_copy(data, data + size,
+ std::back_inserter<std::vector<std::uint8_t>>(v1),
+ std::back_inserter<std::vector<std::uint8_t>>(v2),
+ is_even);
+ ((void)iter);
+ // The two vectors should add up to the original size
+ if (v1.size() + v2.size() != size)
+ return 1;
+
+ // All of the even values should be in the first vector, and none in the second
+ if (!std::all_of(v1.begin(), v1.end(), is_even))
+ return 2;
+ if (!std::none_of(v2.begin(), v2.end(), is_even))
+ return 3;
+
+ // Every value in both vectors has to be in the original
+
+ // Make a copy of the input, and sort it
+ std::vector<std::uint8_t> v0{data, data + size};
+ std::sort(v0.begin(), v0.end());
+
+ // Sort each vector and ensure that all of the elements appear in the original input
+ std::sort(v1.begin(), v1.end());
+ if (!std::includes(v0.begin(), v0.end(), v1.begin(), v1.end()))
+ return 4;
+
+ std::sort(v2.begin(), v2.end());
+ if (!std::includes(v0.begin(), v0.end(), v2.begin(), v2.end()))
+ return 5;
+
+ // This, while simple, is really slow - 20 seconds on a 500K element input.
+ // for (auto v: v1)
+ // if (std::find(data, data + size, v) == data + size)
+ // return 4;
+ //
+ // for (auto v: v2)
+ // if (std::find(data, data + size, v) == data + size)
+ // return 5;
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::partition_copy);
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp b/libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp
new file mode 100644
index 000000000000..e54eedec3644
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/pop_heap.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size < 2)
+ return 0;
+ std::vector<std::uint8_t> working(data, data + size);
+ std::make_heap(working.begin(), working.end());
+
+ // Pop things off, one at a time
+ auto iter = --working.end();
+ while (iter != working.begin()) {
+ std::pop_heap(working.begin(), iter);
+ if (!std::is_heap(working.begin(), --iter))
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/push_heap.pass.cpp b/libcxx/test/libcxx/fuzzing/push_heap.pass.cpp
new file mode 100644
index 000000000000..ce6717603975
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/push_heap.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size < 2)
+ return 0;
+
+ // Make a heap from the first half of the data
+ std::vector<std::uint8_t> working(data, data + size);
+ auto iter = working.begin() + (size / 2);
+ std::make_heap(working.begin(), iter);
+ if (!std::is_heap(working.begin(), iter))
+ return 1;
+
+ // Now push the rest onto the heap, one at a time
+ ++iter;
+ for (; iter != working.end(); ++iter) {
+ std::push_heap(working.begin(), iter);
+ if (!std::is_heap(working.begin(), iter))
+ return 2;
+ }
+
+ if (!fast_is_permutation(data, data + size, working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/random.pass.cpp b/libcxx/test/libcxx/fuzzing/random.pass.cpp
new file mode 100644
index 000000000000..e7545ffdf4da
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/random.pass.cpp
@@ -0,0 +1,194 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <random>
+#include <type_traits>
+#include <vector>
+
+#include "fuzz.h"
+
+template <class IntT>
+std::vector<IntT> GetValues(const std::uint8_t *data, std::size_t size) {
+ std::vector<IntT> result;
+ while (size >= sizeof(IntT)) {
+ IntT tmp;
+ std::memcpy(&tmp, data, sizeof(IntT));
+ size -= sizeof(IntT);
+ data += sizeof(IntT);
+ result.push_back(tmp);
+ }
+ return result;
+}
+
+template <class Dist>
+struct ParamTypeHelper {
+ using ParamT = typename Dist::param_type;
+ using ResultT = typename Dist::result_type;
+ static_assert(std::is_same<ResultT, typename ParamT::distribution_type::result_type>::value, "");
+
+ static ParamT Create(const uint8_t* data, std::size_t size, bool &OK) {
+ constexpr bool select_vector_result = std::is_constructible<ParamT, ResultT*, ResultT*, ResultT*>::value;
+ constexpr bool select_vector_double = std::is_constructible<ParamT, double*, double*>::value;
+ constexpr int selector = select_vector_result ? 0 : (select_vector_double ? 1 : 2);
+ return DispatchAndCreate(std::integral_constant<int, selector>{}, data, size, OK);
+ }
+
+ // Vector result
+ static ParamT DispatchAndCreate(std::integral_constant<int, 0>, const std::uint8_t *data, std::size_t size, bool &OK) {
+ auto Input = GetValues<ResultT>(data, size);
+ OK = false;
+ if (Input.size() < 10)
+ return ParamT{};
+ OK = true;
+ auto Beg = Input.begin();
+ auto End = Input.end();
+ auto Mid = Beg + ((End - Beg) / 2);
+
+ assert(Mid - Beg <= (End - Mid));
+ ParamT p(Beg, Mid, Mid);
+ return p;
+ }
+
+ // Vector double
+ static ParamT DispatchAndCreate(std::integral_constant<int, 1>, const std::uint8_t *data, std::size_t size, bool &OK) {
+ auto Input = GetValues<double>(data, size);
+
+ OK = true;
+ auto Beg = Input.begin();
+ auto End = Input.end();
+
+ ParamT p(Beg, End);
+ return p;
+ }
+
+ // Default
+ static ParamT DispatchAndCreate(std::integral_constant<int, 2>, const std::uint8_t *data, std::size_t size, bool &OK) {
+ OK = false;
+ if (size < sizeof(ParamT))
+ return ParamT{};
+ OK = true;
+ ParamT input;
+ std::memcpy(&input, data, sizeof(ParamT));
+ return input;
+ }
+};
+
+template <class IntT>
+struct ParamTypeHelper<std::poisson_distribution<IntT>> {
+ using Dist = std::poisson_distribution<IntT>;
+ using ParamT = typename Dist::param_type;
+ using ResultT = typename Dist::result_type;
+
+ static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) {
+ OK = false;
+ auto vals = GetValues<double>(data, size);
+ if (vals.empty() || std::isnan(vals[0]) || std::isnan(std::abs(vals[0])) || vals[0] < 0)
+ return ParamT{};
+ OK = true;
+ return ParamT{vals[0]};
+ }
+};
+
+template <class IntT>
+struct ParamTypeHelper<std::geometric_distribution<IntT>> {
+ using Dist = std::geometric_distribution<IntT>;
+ using ParamT = typename Dist::param_type;
+ using ResultT = typename Dist::result_type;
+
+ static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) {
+ OK = false;
+ auto vals = GetValues<double>(data, size);
+ if (vals.empty() || std::isnan(vals[0]) || vals[0] < 0 )
+ return ParamT{};
+ OK = true;
+ return ParamT{vals[0]};
+ }
+};
+
+template <class IntT>
+struct ParamTypeHelper<std::lognormal_distribution<IntT>> {
+ using Dist = std::lognormal_distribution<IntT>;
+ using ParamT = typename Dist::param_type;
+ using ResultT = typename Dist::result_type;
+
+ static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) {
+ OK = false;
+ auto vals = GetValues<ResultT>(data, size);
+ if (vals.size() < 2 )
+ return ParamT{};
+ OK = true;
+ return ParamT{vals[0], vals[1]};
+ }
+};
+
+template <>
+struct ParamTypeHelper<std::bernoulli_distribution> {
+ using Dist = std::bernoulli_distribution;
+ using ParamT = Dist::param_type;
+ using ResultT = Dist::result_type;
+
+ static ParamT Create(const std::uint8_t *data, std::size_t size, bool& OK) {
+ OK = false;
+ auto vals = GetValues<double>(data, size);
+ if (vals.empty())
+ return ParamT{};
+ OK = true;
+ return ParamT{vals[0]};
+ }
+};
+
+template <class Distribution>
+int helper(const std::uint8_t *data, std::size_t size) {
+ std::mt19937 engine;
+ using ParamT = typename Distribution::param_type;
+ bool OK;
+ ParamT p = ParamTypeHelper<Distribution>::Create(data, size, OK);
+ if (!OK)
+ return 0;
+ Distribution d(p);
+ volatile auto res = d(engine);
+ if (std::isnan(res)) {
+ // FIXME(llvm.org/PR44289):
+ // Investigate why these distributions are returning NaN and decide
+ // if that's what we want them to be doing.
+ //
+ // Make this assert false (or return non-zero).
+ return 0;
+ }
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ return helper<std::uniform_int_distribution<std::int16_t>>(data, size) ||
+ helper<std::uniform_real_distribution<float>>(data, size) ||
+ helper<std::bernoulli_distribution>(data, size) ||
+ helper<std::poisson_distribution<std::int16_t>>(data, size) ||
+ helper<std::geometric_distribution<std::int16_t>>(data, size) ||
+ helper<std::binomial_distribution<std::int16_t>>(data, size) ||
+ helper<std::negative_binomial_distribution<std::int16_t>>(data, size) ||
+ helper<std::exponential_distribution<float>>(data, size) ||
+ helper<std::gamma_distribution<float>>(data, size) ||
+ helper<std::weibull_distribution<float>>(data, size) ||
+ helper<std::extreme_value_distribution<float>>(data, size) ||
+ helper<std::normal_distribution<float>>(data, size) ||
+ helper<std::lognormal_distribution<float>>(data, size) ||
+ helper<std::chi_squared_distribution<float>>(data, size) ||
+ helper<std::cauchy_distribution<float>>(data, size) ||
+ helper<std::fisher_f_distribution<float>>(data, size) ||
+ helper<std::student_t_distribution<float>>(data, size) ||
+ helper<std::discrete_distribution<std::int16_t>>(data, size) ||
+ helper<std::piecewise_constant_distribution<float>>(data, size) ||
+ helper<std::piecewise_linear_distribution<float>>(data, size);
+}
diff --git a/libcxx/test/libcxx/fuzzing/regex.pass.cpp b/libcxx/test/libcxx/fuzzing/regex.pass.cpp
new file mode 100644
index 000000000000..b027dd0a0fa4
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/regex.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+// UNSUPPORTED: no-exceptions
+
+#include <cstddef>
+#include <cstdint>
+#include <regex>
+#include <string>
+
+#include "fuzz.h"
+
+template <std::regex_constants::syntax_option_type Syntax>
+static int regex_test(const std::uint8_t *data, std::size_t size) {
+ if (size == 0)
+ return 0;
+
+ std::string s((const char *)data, size);
+ std::regex re;
+ try {
+ re.assign(s, Syntax);
+ } catch (std::regex_error &) {
+ // the data represents an invalid regex, ignore this test case
+ return 0;
+ }
+
+ auto match = std::regex_match(s, re);
+ (void)match;
+ return 0; // always pretend we succeeded -- we're only looking for crashes
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ return regex_test<std::regex_constants::awk>(data, size) ||
+ regex_test<std::regex_constants::basic>(data, size) ||
+ regex_test<std::regex_constants::ECMAScript>(data, size) ||
+ regex_test<std::regex_constants::egrep>(data, size) ||
+ regex_test<std::regex_constants::extended>(data, size) ||
+ regex_test<std::regex_constants::grep>(data, size);
+}
diff --git a/libcxx/test/libcxx/fuzzing/regex_ECMAScript.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_ECMAScript.pass.cpp
deleted file mode 100644
index 79454948b4b5..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_ECMAScript.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===--------------------- regex_ECMAScript.cpp ---------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_ECMAScript);
diff --git a/libcxx/test/libcxx/fuzzing/regex_POSIX.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_POSIX.pass.cpp
deleted file mode 100644
index af94fb7afa65..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_POSIX.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===----------------------- regex_POSIX.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_POSIX);
diff --git a/libcxx/test/libcxx/fuzzing/regex_awk.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_awk.pass.cpp
deleted file mode 100644
index 8040d8b69182..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_awk.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===------------------------- regex_awk.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_awk);
diff --git a/libcxx/test/libcxx/fuzzing/regex_egrep.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_egrep.pass.cpp
deleted file mode 100644
index 1c7076b55651..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_egrep.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===------------------------ regex_egrep.cpp -----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_egrep);
diff --git a/libcxx/test/libcxx/fuzzing/regex_extended.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_extended.pass.cpp
deleted file mode 100644
index d981c8bd4a33..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_extended.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===---------------------- regex_extended.cpp ----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_extended);
diff --git a/libcxx/test/libcxx/fuzzing/regex_grep.pass.cpp b/libcxx/test/libcxx/fuzzing/regex_grep.pass.cpp
deleted file mode 100644
index 4c0ecebf2044..000000000000
--- a/libcxx/test/libcxx/fuzzing/regex_grep.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- C++ -*-
-//===------------------------ regex_grep.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::regex_grep);
diff --git a/libcxx/test/libcxx/fuzzing/search.pass.cpp b/libcxx/test/libcxx/fuzzing/search.pass.cpp
new file mode 100644
index 000000000000..e20fad2ea7e9
--- /dev/null
+++ b/libcxx/test/libcxx/fuzzing/search.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ if (size < 2)
+ return 0;
+
+ const std::size_t pat_size = data[0] * (size - 1) / std::numeric_limits<uint8_t>::max();
+ assert(pat_size <= size - 1);
+ const std::uint8_t *pat_begin = data + 1;
+ const std::uint8_t *pat_end = pat_begin + pat_size;
+ const std::uint8_t *data_end = data + size;
+ assert(pat_end <= data_end);
+
+ auto it = std::search(pat_end, data_end, pat_begin, pat_end);
+ if (it != data_end) // not found
+ if (!std::equal(pat_begin, pat_end, it))
+ return 1;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/sort.pass.cpp b/libcxx/test/libcxx/fuzzing/sort.pass.cpp
index c9fcf652d95b..e11889713a39 100644
--- a/libcxx/test/libcxx/fuzzing/sort.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/sort.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===--------------------------- sort.cpp ---------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,22 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ std::vector<std::uint8_t> working(data, data + size);
+ std::sort(working.begin(), working.end());
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::sort);
+ if (!std::is_sorted(working.begin(), working.end()))
+ return 1;
+ if (!fast_is_permutation(data, data + size, working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp b/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp
index d8eb359271b1..2a1799dc3b85 100644
--- a/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/stable_partition.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===--------------------- stable_partition.cpp ---------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,33 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ auto is_even = [](auto b) { return b.key % 2 == 0; };
+
+ std::vector<ByteWithPayload> input;
+ for (std::size_t i = 0; i < size; ++i)
+ input.push_back(ByteWithPayload(data[i], i));
+ std::vector<ByteWithPayload> working = input;
+ auto iter = std::stable_partition(working.begin(), working.end(), is_even);
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::stable_partition);
+ if (!std::all_of(working.begin(), iter, is_even))
+ return 1;
+ if (!std::none_of(iter, working.end(), is_even))
+ return 2;
+ if (!std::is_sorted(working.begin(), iter, ByteWithPayload::payload_less()))
+ return 3;
+ if (!std::is_sorted(iter, working.end(), ByteWithPayload::payload_less()))
+ return 4;
+ if (!fast_is_permutation(input.cbegin(), input.cend(), working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp b/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp
index 666e48bba53e..b493691035d7 100644
--- a/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/stable_sort.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===------------------------ stable_sort.cpp ----------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,34 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ std::vector<ByteWithPayload> input;
+ for (std::size_t i = 0; i < size; ++i)
+ input.push_back(ByteWithPayload(data[i], i));
+
+ std::vector<ByteWithPayload> working = input;
+ std::stable_sort(working.begin(), working.end(), ByteWithPayload::key_less());
+
+ if (!std::is_sorted(working.begin(), working.end(), ByteWithPayload::key_less()))
+ return 1;
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::stable_sort);
+ auto iter = working.begin();
+ while (iter != working.end()) {
+ auto range = std::equal_range(iter, working.end(), *iter, ByteWithPayload::key_less());
+ if (!std::is_sorted(range.first, range.second, ByteWithPayload::total_less()))
+ return 2;
+ iter = range.second;
+ }
+ if (!fast_is_permutation(input.cbegin(), input.cend(), working.cbegin()))
+ return 99;
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/unique.pass.cpp b/libcxx/test/libcxx/fuzzing/unique.pass.cpp
index 6ffbd5ce1075..e95c61711189 100644
--- a/libcxx/test/libcxx/fuzzing/unique.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/unique.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===--------------------------- unique.cpp -------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,49 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ std::vector<std::uint8_t> working(data, data + size);
+ std::sort(working.begin(), working.end());
+ std::vector<std::uint8_t> results = working;
+ std::vector<std::uint8_t>::iterator new_end = std::unique(results.begin(), results.end());
+ std::vector<std::uint8_t>::iterator it; // scratch iterator
+
+ // Check the size of the unique'd sequence.
+ // it should only be zero if the input sequence was empty.
+ if (results.begin() == new_end)
+ return working.size() == 0 ? 0 : 1;
+
+ // 'results' is sorted
+ if (!std::is_sorted(results.begin(), new_end))
+ return 2;
+
+ // All the elements in 'results' must be
diff erent
+ it = results.begin();
+ std::uint8_t prev_value = *it++;
+ for (; it != new_end; ++it) {
+ if (*it == prev_value)
+ return 3;
+ prev_value = *it;
+ }
+
+ // Every element in 'results' must be in 'working'
+ for (it = results.begin(); it != new_end; ++it)
+ if (std::find(working.begin(), working.end(), *it) == working.end())
+ return 4;
+
+ // Every element in 'working' must be in 'results'
+ for (auto v : working)
+ if (std::find(results.begin(), new_end, v) == new_end)
+ return 5;
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::unique);
+ return 0;
+}
diff --git a/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp b/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp
index 47a4f951cbe9..dfaaa19932f8 100644
--- a/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp
+++ b/libcxx/test/libcxx/fuzzing/unique_copy.pass.cpp
@@ -1,5 +1,4 @@
-// -*- C++ -*-
-//===------------------------ unique_copy.cpp -----------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,7 +6,51 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// UNSUPPORTED: c++03, c++11
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <vector>
+
+#include "fuzz.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size) {
+ std::vector<std::uint8_t> working(data, data + size);
+ std::sort(working.begin(), working.end());
+ std::vector<std::uint8_t> results;
+ (void)std::unique_copy(working.begin(), working.end(),
+ std::back_inserter<std::vector<std::uint8_t>>(results));
+ std::vector<std::uint8_t>::iterator it; // scratch iterator
+
+ // Check the size of the unique'd sequence.
+ // it should only be zero if the input sequence was empty.
+ if (results.size() == 0)
+ return working.size() == 0 ? 0 : 1;
+
+ // 'results' is sorted
+ if (!std::is_sorted(results.begin(), results.end()))
+ return 2;
+
+ // All the elements in 'results' must be
diff erent
+ it = results.begin();
+ std::uint8_t prev_value = *it++;
+ for (; it != results.end(); ++it) {
+ if (*it == prev_value)
+ return 3;
+ prev_value = *it;
+ }
+
+ // Every element in 'results' must be in 'working'
+ for (auto v : results)
+ if (std::find(working.begin(), working.end(), v) == working.end())
+ return 4;
+
+ // Every element in 'working' must be in 'results'
+ for (auto v : working)
+ if (std::find(results.begin(), results.end(), v) == results.end())
+ return 5;
-#include "fuzzer_test.h"
-FUZZER_TEST(fuzzing::unique_copy);
+ return 0;
+}
diff --git a/libcxx/utils/ci/oss-fuzz.sh b/libcxx/utils/ci/oss-fuzz.sh
index eac1a27c9465..8a9421a3ea2d 100755
--- a/libcxx/utils/ci/oss-fuzz.sh
+++ b/libcxx/utils/ci/oss-fuzz.sh
@@ -4,20 +4,16 @@
# This script runs the continuous fuzzing tests on OSS-Fuzz.
#
-if [[ $SANITIZER = *undefined* ]]; then
- CXXFLAGS="$CXXFLAGS -fsanitize=unsigned-integer-overflow -fsanitize-trap=unsigned-integer-overflow"
+if [[ ${SANITIZER} = *undefined* ]]; then
+ CXXFLAGS="${CXXFLAGS} -fsanitize=unsigned-integer-overflow -fsanitize-trap=unsigned-integer-overflow"
fi
-for f in $(grep -v "#" libcxx/fuzzing/RoutineNames.txt); do
- cat > ${f}_fuzzer.cc <<EOF
-#include "fuzzing/fuzzing.h"
-#include <cassert>
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- int result = fuzzing::$f(data, size);
- assert(result == 0); return 0;
-}
-EOF
- $CXX $CXXFLAGS -std=c++11 ${f}_fuzzer.cc ./libcxx/fuzzing/fuzzing.cpp \
- -nostdinc++ -cxx-isystem ./libcxx/include -iquote ./libcxx \
- -o $OUT/$f $LIB_FUZZING_ENGINE
+for test in libcxx/test/libcxx/fuzzing/*.pass.cpp; do
+ ${CXX} ${CXXFLAGS} \
+ -std=c++14 \
+ -DLIBCPP_OSS_FUZZ \
+ -nostdinc++ -cxx-isystem libcxx/include \
+ -o "${OUT}/$(basename ${test})" \
+ ${test} \
+ ${LIB_FUZZING_ENGINE}
done
More information about the libcxx-commits
mailing list