|  | // -*- 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); | 
|  | } | 
|  | } |