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 
ZeroMemoryCounters()44 void ZeroMemoryCounters() {
45     gMemoryCounters.totalAllocationCount = 0;
46     gMemoryCounters.netAllocationCount = 0;
47     gMemoryCounters.totalBytesAllocated = 0;
48 }
49 
operator new(std::size_t size)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 
operator new(std::size_t size,const std::nothrow_t &)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 
operator new[](std::size_t size)69 void* operator new[](std::size_t size)
70 {
71     return ::operator new(size);
72 }
73 
operator new[](std::size_t size,const std::nothrow_t &)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 
operator delete(void * ptr)81 void  operator delete(void* ptr) noexcept
82 {
83     if (ptr)
84         ::free(ptr);
85     gMemoryCounters.netAllocationCount -= 1;
86 }
87 
operator delete(void * ptr,const std::nothrow_t &)88 void  operator delete(void* ptr, const std::nothrow_t&) noexcept
89 {
90     ::operator delete(ptr);
91 }
92 
operator delete[](void * ptr)93 void  operator delete[](void* ptr) noexcept
94 {
95     ::operator delete(ptr);
96 }
97 
operator delete[](void * ptr,const std::nothrow_t &)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 
test_one(const char * filename,FuzzProc fp)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 
usage(const char * name)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 
main(int argc,char * argv[])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