1 // -*- C++ -*- 2 //===------------------------- fuzz_test.cpp ------------------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is dual licensed under the MIT and the University of Illinois Open 7 // Source Licenses. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 // A simple program for running regressions on the fuzzing routines. 12 // This code is not part of any shipping product. 13 // 14 // To build: 15 // clang++ -std=c++11 fuzz_test.cpp fuzzing.cpp 16 // 17 // To use: 18 // fuzz_test -r partial_sort [-v] files... 19 // 20 // Each file should contain a test case. 21 22 // TODO: should add some memory tracking, too. 23 24 25 #include <iostream> 26 #include <fstream> 27 #include <iterator> 28 #include <vector> 29 #include <map> 30 #include <chrono> 31 32 #include "fuzzing.h" 33 34 // ==== Count memory allocations ==== 35 36 struct MemoryCounters { 37 size_t totalAllocationCount; 38 size_t netAllocationCount; 39 size_t totalBytesAllocated; 40 }; 41 42 MemoryCounters gMemoryCounters; 43 44 void ZeroMemoryCounters() { 45 gMemoryCounters.totalAllocationCount = 0; 46 gMemoryCounters.netAllocationCount = 0; 47 gMemoryCounters.totalBytesAllocated = 0; 48 } 49 50 void* operator new(std::size_t size) 51 { 52 if (size == 0) size = 1; 53 void *p = ::malloc(size); 54 if (p == NULL) 55 throw std::bad_alloc(); 56 gMemoryCounters.totalAllocationCount += 1; 57 gMemoryCounters.netAllocationCount += 1; 58 gMemoryCounters.totalBytesAllocated += size; 59 return p; 60 } 61 62 void* operator new(std::size_t size, const std::nothrow_t&) noexcept 63 { 64 try { return operator new(size); } 65 catch (const std::bad_alloc &) {} 66 return nullptr; 67 } 68 69 void* operator new[](std::size_t size) 70 { 71 return ::operator new(size); 72 } 73 74 void* operator new[](std::size_t size, const std::nothrow_t&) noexcept 75 { 76 try { return operator new(size); } 77 catch (const std::bad_alloc &) {} 78 return nullptr; 79 } 80 81 void operator delete(void* ptr) noexcept 82 { 83 if (ptr) 84 ::free(ptr); 85 gMemoryCounters.netAllocationCount -= 1; 86 } 87 88 void operator delete(void* ptr, const std::nothrow_t&) noexcept 89 { 90 ::operator delete(ptr); 91 } 92 93 void operator delete[](void* ptr) noexcept 94 { 95 ::operator delete(ptr); 96 } 97 98 void operator delete[](void* ptr, const std::nothrow_t&) noexcept 99 { 100 ::operator delete(ptr); 101 } 102 103 // ==== End count memory allocations ==== 104 105 106 typedef int (*FuzzProc) (const uint8_t *data, size_t size); 107 108 const std::map<std::string, FuzzProc> procs = { 109 {"sort", fuzzing::sort}, 110 {"stable_sort", fuzzing::stable_sort}, 111 {"partition", fuzzing::partition}, 112 {"partition_copy", fuzzing::partition_copy}, 113 {"stable_partition", fuzzing::stable_partition}, 114 {"unique", fuzzing::unique}, 115 {"unique_copy", fuzzing::unique_copy}, 116 {"nth_element", fuzzing::nth_element}, 117 {"partial_sort", fuzzing::partial_sort}, 118 {"partial_sort_copy", fuzzing::partial_sort_copy}, 119 {"make_heap", fuzzing::make_heap}, 120 {"push_heap", fuzzing::push_heap}, 121 {"pop_heap", fuzzing::pop_heap}, 122 {"regex_ECMAScript", fuzzing::regex_ECMAScript}, 123 {"regex_POSIX", fuzzing::regex_POSIX}, 124 {"regex_extended", fuzzing::regex_extended}, 125 {"regex_awk", fuzzing::regex_awk}, 126 {"regex_grep", fuzzing::regex_grep}, 127 {"regex_egrep", fuzzing::regex_egrep}, 128 {"search", fuzzing::search} 129 }; 130 131 132 133 bool verbose = false; 134 135 void test_one(const char *filename, FuzzProc fp) 136 { 137 std::vector<uint8_t> v; 138 std::ifstream f (filename, std::ios::binary); 139 if (!f.is_open()) 140 std::cerr << "## Can't open '" << filename << "'" << std::endl; 141 else 142 { 143 typedef std::istream_iterator<uint8_t> Iter; 144 std::copy(Iter(f), Iter(), std::back_inserter(v)); 145 if (verbose) 146 std::cout << "File '" << filename << "' contains " << v.size() << " entries" << std::endl; 147 ZeroMemoryCounters(); 148 const auto start_time = std::chrono::high_resolution_clock::now(); 149 int ret = fp (v.data(), v.size()); 150 const auto finish_time = std::chrono::high_resolution_clock::now(); 151 MemoryCounters mc = gMemoryCounters; 152 if (ret != 0) 153 std::cerr << "## Failure code: " << ret << std::endl; 154 if (verbose) 155 { 156 std::cout << "Execution time: " 157 << std::chrono::duration_cast<std::chrono::milliseconds>(finish_time - start_time).count() 158 << " milliseconds" << std::endl; 159 std::cout << "Memory: " 160 << mc.totalBytesAllocated << " bytes allocated (" 161 << mc.totalAllocationCount << " allocations); " 162 << mc.netAllocationCount << " allocations remain" << std::endl; 163 } 164 } 165 } 166 167 void usage (const char *name) 168 { 169 std::cout << "Usage: " << name << " -r proc [-v] files..." << std::endl; 170 std::cout << "Supported routines:" << std::endl; 171 for (const auto &p : procs) 172 std::cout << " " << p.first << std::endl; 173 std::cout << std::endl; 174 } 175 176 // Poor man's command-line options 177 const std::string dashR("-r"); 178 const std::string dashV("-v"); 179 180 int main(int argc, char *argv[]) 181 { 182 if (argc < 4 || dashR != argv[1] || procs.find(argv[2]) == procs.end()) 183 usage(argv[0]); 184 else { 185 FuzzProc fp = procs.find(argv[2])->second; 186 int firstFile = 3; 187 if (dashV == argv[firstFile]) 188 { 189 verbose = true; 190 ++firstFile; 191 } 192 for (int i = firstFile; i < argc; ++i) 193 test_one(argv[i], fp); 194 } 195 } 196