fuzz_test.cpp 5.6 KB

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