General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
8.7 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #include "test_scaffold.h"
  2. #include "gp/array.hpp"
  3. #include "gp/allocator/buddy.hpp"
  4. #include "gp/allocator/dummy.hpp"
  5. #include "gp/algorithm/repeat.hpp"
  6. #include <thread>
  7. #include <chrono>
  8. #include <set>
  9. #include <stack>
  10. #include <numeric>
  11. #include <chrono>
  12. #include <random>
  13. #include <iomanip>
  14. #include <iostream>
  15. #include <fstream>
  16. #include <algorithm>
  17. #define MACRO_STRGEN(X) #X
  18. #define MACRO_STR(X) MACRO_STRGEN(X)
  19. constexpr bool time_fuzzes = true;
  20. struct static_mapper {
  21. static gp::array<char, 4096> store;
  22. static gp::buddy<> impl;
  23. void* allocate(size_t sz) {
  24. return impl.allocate(sz);
  25. }
  26. bool deallocate(void* ptr) {
  27. return impl.deallocate(ptr);
  28. }
  29. };
  30. alignas(2048) gp::array<char, 4096> static_mapper::store;
  31. gp::buddy<> static_mapper::impl = gp::buddy<>{store.begin().data, store.size()};
  32. struct arraysum_test : public test_scaffold {
  33. arraysum_test() {
  34. name = __FILE__ ":1";
  35. }
  36. virtual int run() {
  37. gp::array<uint32_t, 16> test;
  38. for(auto& elem : test)
  39. {
  40. elem = 12;
  41. }
  42. return std::accumulate(test.begin(), test.end(), 0) != 12*test.size();
  43. }
  44. };
  45. append_test dummy_sd45uisd3(new arraysum_test{});
  46. struct optional_test : public test_scaffold {
  47. optional_test() {
  48. name = __FILE__ ":1";
  49. }
  50. virtual int run() {
  51. int res = 0;
  52. {
  53. gp::optional<uint32_t> test;
  54. if(test.has_value())
  55. {
  56. res++;
  57. }
  58. test = 12;
  59. if(test.has_value())
  60. {
  61. if(test.value()!=12)
  62. {
  63. res++;
  64. }
  65. }
  66. else
  67. {
  68. res++;
  69. }
  70. }
  71. {
  72. gp::optional<std::ifstream> test;
  73. if(test.has_value())
  74. {
  75. res++;
  76. }
  77. test = std::ifstream("/proc/cpuinfo");
  78. if(!test.has_value())
  79. {
  80. res++;
  81. }
  82. }
  83. return res;
  84. }
  85. };
  86. append_test dummy_mlyusisd3(new optional_test{});
  87. struct buddy_test : public test_scaffold {
  88. buddy_test() {
  89. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":3";
  90. rng.seed(seed);
  91. }
  92. std::mt19937 rng{};
  93. int seed = std::random_device{}();
  94. virtual int run() {
  95. int res = 0;
  96. gp::repeat(10, [&](){
  97. gp::array<char, 4096> store;
  98. {
  99. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  100. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> dum_bud{store.size()};
  101. gp::buddy<static_mapper> inner_bud{2048};
  102. gp::dummy_allocator dummyall;
  103. {
  104. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  105. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  106. gp_config::assertion(!inner_bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  107. std::set<void*> ptr_set;
  108. for(int i = 0; i < 2048 / 16; i++)
  109. {
  110. void* v = inner_bud.allocate(16);
  111. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  112. if(v == nullptr) throw gp::runtime_error("allocation failed");
  113. ptr_set.insert(v);
  114. }
  115. bool wut = ptr_set.count(nullptr)!=0 || ptr_set.size()!=(2048/16);
  116. if(wut) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  117. if(nullptr != inner_bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  118. for(auto elem : ptr_set) {
  119. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  120. if(inner_bud.deallocate(elem) == false)
  121. {
  122. res += 1;
  123. }
  124. }
  125. gp_config::assertion(inner_bud.empty(), "allocator should be empty");
  126. }
  127. {
  128. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  129. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  130. std::set<void*> ptr_set;
  131. for(int i = 0; i < 4096 / 16; i++)
  132. {
  133. void* v = bud.allocate(16);
  134. gp_config::assertion(!bud.empty(), "allocator should have elements");
  135. if(v == nullptr) throw gp::runtime_error("allocation failed");
  136. ptr_set.insert(v);
  137. }
  138. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/16)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  139. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  140. for(auto elem : ptr_set) {
  141. gp_config::assertion(!bud.empty(), "allocator should have elements");
  142. if(bud.deallocate(elem) == false)
  143. {
  144. res += 1;
  145. }
  146. }
  147. gp_config::assertion(bud.empty(), "allocator should be empty");
  148. }
  149. {
  150. std::set<void*> ptr_set;
  151. for(int i = 0; i < 4096 / 8; i++)
  152. {
  153. void* v = bud.allocate(8);
  154. gp_config::assertion(!bud.empty(), "allocator should have elements");
  155. if(v == nullptr) throw gp::runtime_error("allocation failed");
  156. ptr_set.insert(v);
  157. }
  158. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  159. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  160. for(auto elem : ptr_set) {
  161. gp_config::assertion(!bud.empty(), "allocator should have elements");
  162. if(bud.deallocate(elem) == false)
  163. {
  164. res += 1;
  165. }
  166. }
  167. gp_config::assertion(bud.empty(), "allocator should be empty");
  168. }
  169. {
  170. std::set<void*> ptr_set;
  171. std::vector<size_t> infill;
  172. std::insert_iterator< std::vector<size_t> > inserter{infill, std::end(infill)};
  173. std::fill_n(inserter, 4096 / 16 / 4, 16);
  174. inserter = std::insert_iterator< std::vector<size_t> >{infill, std::end(infill)};
  175. std::fill_n(inserter, 4096 / 8 / 4, 8);
  176. std::shuffle(infill.begin(), infill.end(), rng);
  177. for(auto sz : infill)
  178. {
  179. void* v = bud.allocate(sz);
  180. gp_config::assertion(!bud.empty(), "allocator should have elements");
  181. if(v == nullptr) throw gp::runtime_error("allocation failed");
  182. ptr_set.insert(v);
  183. }
  184. if(ptr_set.count(nullptr)!=0) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  185. gp_config::assertion(!bud.deallocate((char*)store.begin().data + 1), "misaligned deallocation fails");
  186. for(auto elem : ptr_set) {
  187. gp_config::assertion(!bud.empty(), "allocator should have elements");
  188. if(bud.deallocate(elem) == false)
  189. {
  190. res += 1;
  191. }
  192. }
  193. gp_config::assertion(!bud.deallocate(nullptr), "deallocating out of scope returns false");
  194. gp_config::assertion(bud.empty(), "allocator should be empty");
  195. }
  196. }
  197. });
  198. return res;
  199. }
  200. };
  201. append_test dummy_654sisd3(new buddy_test{});
  202. struct buddy_fuzz_test : public test_scaffold {
  203. buddy_fuzz_test() {
  204. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  205. rng.seed(seed);
  206. }
  207. buddy_fuzz_test(size_t _seed) {
  208. seed = _seed;
  209. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  210. rng.seed(seed);
  211. }
  212. std::mt19937 rng{};
  213. int seed = std::random_device{}();
  214. virtual int run() {
  215. int res = 0;
  216. alignas(8) gp::array<char, 4096> store;
  217. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  218. std::vector<void*> ptr_set;
  219. auto get_random_mem_qt = [&]() -> size_t {
  220. return 1+rng()%(store.size()-1);
  221. };
  222. auto start = std::chrono::steady_clock::now();
  223. {
  224. gp::repeat(FUZZ_STRENGTH, [&](){
  225. void* ptr;
  226. auto sz = get_random_mem_qt();
  227. size_t tries = 0;
  228. std::shuffle(
  229. ptr_set.begin(),
  230. ptr_set.end(),
  231. rng
  232. );
  233. while(!(ptr = bud.allocate(sz)))
  234. {
  235. void* free_ptr = ptr_set.back();
  236. ptr_set.pop_back();
  237. gp_config::assertion(bud.deallocate(free_ptr), "could not free sample");
  238. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  239. }
  240. ptr_set.emplace_back(ptr);
  241. });
  242. for(auto ptr : ptr_set)
  243. {
  244. bud.deallocate(ptr);
  245. }
  246. ptr_set.resize(0);
  247. }
  248. auto duration = std::chrono::steady_clock::now() - start;
  249. start = std::chrono::steady_clock::now();
  250. {
  251. size_t acc = 0;
  252. gp::repeat(FUZZ_STRENGTH, [&](){
  253. void* ptr;
  254. auto sz = get_random_mem_qt();
  255. size_t tries = 0;
  256. std::shuffle(
  257. ptr_set.begin(),
  258. ptr_set.end(),
  259. rng
  260. );
  261. ptr = malloc(sz);
  262. acc+=1;
  263. while(acc > 20)
  264. {
  265. void* free_ptr = ptr_set.back();
  266. free(free_ptr);
  267. acc -= 1;
  268. ptr_set.pop_back();
  269. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  270. }
  271. ptr_set.emplace_back(ptr);
  272. });
  273. for(auto ptr : ptr_set)
  274. {
  275. free(ptr);
  276. }
  277. }
  278. auto reference = std::chrono::steady_clock::now() - start;
  279. std::cout
  280. << "Fuzzing timed at "
  281. << std::chrono::duration_cast<std::chrono::microseconds>(duration).count()
  282. << "µs for "
  283. << FUZZ_STRENGTH
  284. << " (reference: "
  285. << std::chrono::duration_cast<std::chrono::microseconds>(reference).count()
  286. << "µs)"
  287. << std::endl;
  288. return res;
  289. }
  290. };
  291. append_test dummy_df987sd3(new buddy_fuzz_test{781017366});
  292. append_test dummy_df4sisd3(new buddy_fuzz_test{});