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