blob: 508c3b65f2df17ec2b661eb950c3a271f2aee1df [file] [log] [blame]
Marshall Clowdf8546a2018-01-18 16:52:19 +00001// -*- C++ -*-
2//===------------------------- fuzz_test.cpp ------------------------------===//
3//
Chandler Carruthd2012102019-01-19 10:56:40 +00004// 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
Marshall Clowdf8546a2018-01-18 16:52:19 +00007//
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
Marshall Clow92c5b912018-01-18 18:37:11 +000021// TODO: should add some memory tracking, too.
22
Marshall Clowdf8546a2018-01-18 16:52:19 +000023
24#include <iostream>
25#include <fstream>
Marshall Clow1e2e4ed2018-01-18 17:01:34 +000026#include <iterator>
Marshall Clowdf8546a2018-01-18 16:52:19 +000027#include <vector>
28#include <map>
29#include <chrono>
30
31#include "fuzzing.h"
32
Marshall Clow92c5b912018-01-18 18:37:11 +000033// ==== Count memory allocations ====
34
35struct MemoryCounters {
36 size_t totalAllocationCount;
37 size_t netAllocationCount;
38 size_t totalBytesAllocated;
39 };
40
41MemoryCounters gMemoryCounters;
42
43void ZeroMemoryCounters() {
44 gMemoryCounters.totalAllocationCount = 0;
45 gMemoryCounters.netAllocationCount = 0;
46 gMemoryCounters.totalBytesAllocated = 0;
47}
48
49void* 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
61void* 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
68void* operator new[](std::size_t size)
69{
70 return ::operator new(size);
71}
72
73void* 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
80void operator delete(void* ptr) noexcept
81{
82 if (ptr)
83 ::free(ptr);
84 gMemoryCounters.netAllocationCount -= 1;
85}
86
87void operator delete(void* ptr, const std::nothrow_t&) noexcept
88{
89 ::operator delete(ptr);
90}
91
92void operator delete[](void* ptr) noexcept
93{
94 ::operator delete(ptr);
95}
96
97void operator delete[](void* ptr, const std::nothrow_t&) noexcept
98{
99 ::operator delete(ptr);
100}
101
102// ==== End count memory allocations ====
103
104
Marshall Clowdf8546a2018-01-18 16:52:19 +0000105typedef int (*FuzzProc) (const uint8_t *data, size_t size);
106
107const 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
132bool verbose = false;
133
134void 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;
Marshall Clow92c5b912018-01-18 18:37:11 +0000140 else
141 {
Marshall Clowdf8546a2018-01-18 16:52:19 +0000142 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;
Marshall Clow92c5b912018-01-18 18:37:11 +0000146 ZeroMemoryCounters();
Marshall Clow1e2e4ed2018-01-18 17:01:34 +0000147 const auto start_time = std::chrono::high_resolution_clock::now();
Marshall Clowdf8546a2018-01-18 16:52:19 +0000148 int ret = fp (v.data(), v.size());
Marshall Clow1e2e4ed2018-01-18 17:01:34 +0000149 const auto finish_time = std::chrono::high_resolution_clock::now();
Marshall Clow92c5b912018-01-18 18:37:11 +0000150 MemoryCounters mc = gMemoryCounters;
Marshall Clowdf8546a2018-01-18 16:52:19 +0000151 if (ret != 0)
152 std::cerr << "## Failure code: " << ret << std::endl;
153 if (verbose)
Marshall Clow92c5b912018-01-18 18:37:11 +0000154 {
Marshall Clowdf8546a2018-01-18 16:52:19 +0000155 std::cout << "Execution time: "
156 << std::chrono::duration_cast<std::chrono::milliseconds>(finish_time - start_time).count()
157 << " milliseconds" << std::endl;
Louis Dionnefd77e4f2019-10-23 10:40:15 -0700158 std::cout << "Memory: "
Marshall Clow92c5b912018-01-18 18:37:11 +0000159 << mc.totalBytesAllocated << " bytes allocated ("
160 << mc.totalAllocationCount << " allocations); "
161 << mc.netAllocationCount << " allocations remain" << std::endl;
Marshall Clowdf8546a2018-01-18 16:52:19 +0000162 }
Marshall Clow92c5b912018-01-18 18:37:11 +0000163 }
Marshall Clowdf8546a2018-01-18 16:52:19 +0000164}
165
166void 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
176const std::string dashR("-r");
177const std::string dashV("-v");
178
179int 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}