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.

533 lines
14 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
4 years ago
  1. #include "test_scaffold.h"
  2. #include "allocator.hpp"
  3. #include "gp/array.hpp"
  4. #include "gp/indexed_array.hpp"
  5. #include "gp/allocator/aggregator.hpp"
  6. #include "gp/allocator/buddy.hpp"
  7. #include "gp/allocator/dummy.hpp"
  8. #include "gp/algorithm/repeat.hpp"
  9. #include "gp/algorithm/rotate.hpp"
  10. #include "gp/ring_list.hpp"
  11. #include <thread>
  12. #include <chrono>
  13. #include <set>
  14. #include <stack>
  15. #include <numeric>
  16. #include <chrono>
  17. #include <random>
  18. #include <iomanip>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <algorithm>
  22. #include "gp/vfs/vfs.hpp"
  23. #ifndef FUZZ_STRENGTH
  24. #define FUZZ_STRENGTH 2048
  25. #endif
  26. #define MACRO_STRGEN(X) #X
  27. #define MACRO_STR(X) MACRO_STRGEN(X)
  28. constexpr bool time_fuzzes = true;
  29. struct arraysum_test : public test_scaffold {
  30. arraysum_test() {
  31. name = __FILE__ ":1";
  32. }
  33. virtual int run() {
  34. gp::array<uint32_t, 16> test;
  35. for(auto& elem : test)
  36. {
  37. elem = 12;
  38. }
  39. return std::accumulate(test.begin(), test.end(), 0) != 12*test.size();
  40. }
  41. };
  42. append_test dummy_sd45uisd3(new arraysum_test{});
  43. struct optional_test : public test_scaffold {
  44. optional_test() {
  45. name = __FILE__ ":1";
  46. }
  47. virtual int run() {
  48. int res = 0;
  49. {
  50. gp::optional<uint32_t> test;
  51. if(test.has_value())
  52. {
  53. res++;
  54. }
  55. test = 12;
  56. if(test.has_value())
  57. {
  58. if(test.value()!=12)
  59. {
  60. res++;
  61. }
  62. }
  63. else
  64. {
  65. res++;
  66. }
  67. }
  68. {
  69. gp::optional<std::ifstream> test;
  70. if(test.has_value())
  71. {
  72. res++;
  73. }
  74. test = std::ifstream("/proc/cpuinfo");
  75. if(!test.has_value())
  76. {
  77. res++;
  78. }
  79. }
  80. return res;
  81. }
  82. };
  83. append_test dummy_mlyusisd3(new optional_test{});
  84. struct buddy_test : public test_scaffold {
  85. buddy_test() {
  86. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":3";
  87. rng.seed(seed);
  88. }
  89. std::mt19937 rng{};
  90. int seed = std::random_device{}();
  91. virtual int run() {
  92. int res = 0;
  93. gp::repeat(10, [&](){
  94. gp::array<char, 4096> store;
  95. {
  96. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  97. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> dum_bud{store.size()};
  98. gp::buddy<static_mapper> inner_bud{2048};
  99. gp::dummy_allocator dummyall;
  100. {
  101. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  102. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  103. gp_config::assertion(!inner_bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  104. std::set<void*> ptr_set;
  105. for(int i = 0; i < 2048 / 16; i++)
  106. {
  107. void* v = inner_bud.allocate(16);
  108. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  109. if(v == nullptr) throw gp::runtime_error("allocation failed");
  110. ptr_set.insert(v);
  111. }
  112. bool wut = ptr_set.count(nullptr)!=0 || ptr_set.size()!=(2048/16);
  113. if(wut) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  114. if(nullptr != inner_bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  115. for(auto elem : ptr_set) {
  116. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  117. if(inner_bud.deallocate(elem) == false)
  118. {
  119. res += 1;
  120. }
  121. }
  122. gp_config::assertion(inner_bud.empty(), "allocator should be empty");
  123. }
  124. {
  125. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  126. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  127. std::set<void*> ptr_set;
  128. for(int i = 0; i < 4096 / 16; i++)
  129. {
  130. void* v = bud.allocate(16);
  131. gp_config::assertion(!bud.empty(), "allocator should have elements");
  132. if(v == nullptr) throw gp::runtime_error("allocation failed");
  133. ptr_set.insert(v);
  134. }
  135. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/16)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  136. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  137. for(auto elem : ptr_set) {
  138. gp_config::assertion(!bud.empty(), "allocator should have elements");
  139. if(bud.deallocate(elem) == false)
  140. {
  141. res += 1;
  142. }
  143. }
  144. gp_config::assertion(bud.empty(), "allocator should be empty");
  145. }
  146. {
  147. std::set<void*> ptr_set;
  148. for(int i = 0; i < 4096 / 8; i++)
  149. {
  150. void* v = bud.allocate(8);
  151. gp_config::assertion(!bud.empty(), "allocator should have elements");
  152. if(v == nullptr) throw gp::runtime_error("allocation failed");
  153. ptr_set.insert(v);
  154. }
  155. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  156. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  157. for(auto elem : ptr_set) {
  158. gp_config::assertion(!bud.empty(), "allocator should have elements");
  159. if(bud.deallocate(elem) == false)
  160. {
  161. res += 1;
  162. }
  163. }
  164. gp_config::assertion(bud.empty(), "allocator should be empty");
  165. }
  166. {
  167. std::set<void*> ptr_set;
  168. std::vector<size_t> infill;
  169. std::insert_iterator< std::vector<size_t> > inserter{infill, std::end(infill)};
  170. std::fill_n(inserter, 4096 / 16 / 4, 16);
  171. inserter = std::insert_iterator< std::vector<size_t> >{infill, std::end(infill)};
  172. std::fill_n(inserter, 4096 / 8 / 4, 8);
  173. std::shuffle(infill.begin(), infill.end(), rng);
  174. for(auto sz : infill)
  175. {
  176. void* v = bud.allocate(sz);
  177. gp_config::assertion(!bud.empty(), "allocator should have elements");
  178. if(v == nullptr) throw gp::runtime_error("allocation failed");
  179. ptr_set.insert(v);
  180. }
  181. if(ptr_set.count(nullptr)!=0) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  182. gp_config::assertion(!bud.deallocate((char*)store.begin().data + 1), "misaligned deallocation fails");
  183. for(auto elem : ptr_set) {
  184. gp_config::assertion(!bud.empty(), "allocator should have elements");
  185. if(bud.deallocate(elem) == false)
  186. {
  187. res += 1;
  188. }
  189. }
  190. gp_config::assertion(!bud.deallocate(nullptr), "deallocating out of scope returns false");
  191. gp_config::assertion(bud.empty(), "allocator should be empty");
  192. }
  193. }
  194. });
  195. return res;
  196. }
  197. };
  198. append_test dummy_654sisd3(new buddy_test{});
  199. // TODO: should implement a test that tries to wrongly remove pointers as well as to allocate them correctly
  200. struct buddy_fuzz_test : public test_scaffold {
  201. buddy_fuzz_test() {
  202. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  203. rng.seed(seed);
  204. }
  205. buddy_fuzz_test(size_t _seed) {
  206. seed = _seed;
  207. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  208. rng.seed(seed);
  209. }
  210. std::mt19937 rng{};
  211. int seed = std::random_device{}();
  212. virtual int run() {
  213. int res = 0;
  214. alignas(8) gp::array<char, 4096> store;
  215. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  216. std::vector<void*> ptr_set;
  217. auto get_random_mem_qt = [&]() -> size_t {
  218. return 1+rng()%(store.size()-1);
  219. };
  220. auto start = std::chrono::steady_clock::now();
  221. {
  222. gp::repeat(FUZZ_STRENGTH, [&](){
  223. void* ptr;
  224. auto sz = get_random_mem_qt();
  225. size_t tries = 0;
  226. std::shuffle(
  227. ptr_set.begin(),
  228. ptr_set.end(),
  229. rng
  230. );
  231. while(!(ptr = bud.allocate(sz)))
  232. {
  233. void* free_ptr = ptr_set.back();
  234. ptr_set.pop_back();
  235. gp_config::assertion(bud.deallocate(free_ptr), "could not free sample");
  236. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  237. }
  238. ptr_set.emplace_back(ptr);
  239. });
  240. for(auto ptr : ptr_set)
  241. {
  242. bud.deallocate(ptr);
  243. }
  244. ptr_set.resize(0);
  245. }
  246. auto duration = std::chrono::steady_clock::now() - start;
  247. start = std::chrono::steady_clock::now();
  248. {
  249. size_t acc = 0;
  250. gp::repeat(FUZZ_STRENGTH, [&](){
  251. void* ptr;
  252. auto sz = get_random_mem_qt();
  253. size_t tries = 0;
  254. std::shuffle(
  255. ptr_set.begin(),
  256. ptr_set.end(),
  257. rng
  258. );
  259. ptr = malloc(sz);
  260. acc+=1;
  261. while(acc > 20)
  262. {
  263. void* free_ptr = ptr_set.back();
  264. free(free_ptr);
  265. acc -= 1;
  266. ptr_set.pop_back();
  267. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  268. }
  269. ptr_set.emplace_back(ptr);
  270. });
  271. for(auto ptr : ptr_set)
  272. {
  273. free(ptr);
  274. }
  275. }
  276. auto reference = std::chrono::steady_clock::now() - start;
  277. std::cout
  278. << "Fuzzing timed at "
  279. << std::chrono::duration_cast<std::chrono::microseconds>(duration).count()
  280. << "µs for "
  281. << FUZZ_STRENGTH
  282. << " (reference: "
  283. << std::chrono::duration_cast<std::chrono::microseconds>(reference).count()
  284. << "µs)"
  285. << std::endl;
  286. return res;
  287. }
  288. };
  289. append_test dummy_df987sd3(new buddy_fuzz_test{781017366});
  290. append_test dummy_df4sisd3(new buddy_fuzz_test{});
  291. struct ring_list_test : public test_scaffold {
  292. ring_list_test() {
  293. name = __FILE__ ":5";
  294. }
  295. virtual int run() {
  296. int res = 0;
  297. alignas(8) gp::array<char, 4096> store;
  298. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  299. local_allocator bud{&*store.begin(), store.size()};
  300. {
  301. using string_ring = gp::ring_list<std::string, local_allocator, false>;
  302. auto p = new(bud.allocate(sizeof(std::string))) std::string("Hello");
  303. auto orig = new(bud.allocate(sizeof(string_ring::node))) string_ring::node(p);
  304. string_ring ring{orig, bud};
  305. ring.insert("World");
  306. auto it = ring.explore();
  307. std::string test = "";
  308. do{
  309. test += *it;
  310. ++it;
  311. }while(it != ring.explore());
  312. res += (test != "HelloWorld");
  313. }
  314. return res;
  315. }
  316. };
  317. append_test dummy_867fdrgsd3(new ring_list_test{});
  318. struct aggregator_test : public test_scaffold {
  319. aggregator_test() {
  320. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":6";
  321. rng.seed(seed);
  322. }
  323. std::mt19937 rng{};
  324. int seed = std::random_device{}();
  325. virtual int run() {
  326. int res = 0;
  327. alignas(8) gp::array<char, 4096> store;
  328. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  329. local_allocator bud{&*store.begin(), store.size()};
  330. alignas(8) gp::array<char, 4096> store2;
  331. local_allocator bud2{&*store2.begin(), store2.size()};
  332. gp::aggregator allocator{bud};
  333. allocator.insert(bud2);
  334. {
  335. std::vector<void*> ptr_set;
  336. auto get_random_mem_qt = [&]() -> size_t {
  337. return 1+rng()%(store.size()-1);
  338. };
  339. auto start = std::chrono::steady_clock::now();
  340. {
  341. gp::repeat(FUZZ_STRENGTH, [&](){
  342. void* ptr;
  343. auto sz = get_random_mem_qt();
  344. size_t tries = 0;
  345. std::shuffle(
  346. ptr_set.begin(),
  347. ptr_set.end(),
  348. rng
  349. );
  350. while(!(ptr = allocator.allocate(sz)))
  351. {
  352. void* free_ptr = ptr_set.back();
  353. ptr_set.pop_back();
  354. gp_config::assertion(allocator.deallocate(free_ptr), "could not free sample");
  355. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  356. }
  357. ptr_set.emplace_back(ptr);
  358. });
  359. for(auto ptr : ptr_set)
  360. {
  361. bud.deallocate(ptr);
  362. }
  363. ptr_set.resize(0);
  364. }
  365. auto duration = std::chrono::steady_clock::now() - start;
  366. }
  367. return res;
  368. }
  369. };
  370. append_test dummy_8ijfsd658(new aggregator_test{});
  371. struct array_test : public test_scaffold {
  372. array_test() {
  373. name = __FILE__ ":7";
  374. }
  375. virtual int run() {
  376. int res = 0;
  377. gp::array<int, 8> store;
  378. {
  379. int i = 0;
  380. for(auto& p : store)
  381. {
  382. p = i++;
  383. }
  384. for(auto it = store.rbegin(); it != store.rend(); ++it)
  385. {
  386. gp_config::assertion(*it == --i, "array error");
  387. }
  388. for(const auto& p : store)
  389. {
  390. gp_config::assertion(p == i++, "array error");
  391. }
  392. for(auto it = store.crbegin(); it != store.crend(); ++it)
  393. {
  394. gp_config::assertion(*it == --i, "array error");
  395. }
  396. size_t cnt = 0;
  397. for(const auto& p : store)
  398. {
  399. cnt++;
  400. }
  401. gp_config::assertion(cnt == store.size(), "array error");
  402. cnt = 0;
  403. for(auto& p : store)
  404. {
  405. cnt++;
  406. }
  407. gp_config::assertion(cnt == store.size(), "array error");
  408. cnt = 0;
  409. for(auto it = store.crbegin(); it != store.crend(); ++it)
  410. {
  411. cnt++;
  412. }
  413. gp_config::assertion(cnt == store.size(), "array error");
  414. cnt = 0;
  415. for(auto it = store.rbegin(); it != store.rend(); ++it)
  416. {
  417. cnt++;
  418. }
  419. gp_config::assertion(cnt == store.size(), "array error");
  420. gp::rotate(store.begin(), store.begin()+1, store.end());
  421. gp::array<int, 8> rotated({1,2,3,4,5,6,7,0});
  422. gp_config::assertion(store == rotated, "rotate error");
  423. gp::rotate(store.begin(), store.end()-1, store.end());
  424. gp_config::assertion(store[0] == 0, "rotate error");
  425. }
  426. return res;
  427. }
  428. };
  429. append_test dummy_ajcurgsd3(new array_test{});
  430. struct indexed_array_test : public test_scaffold {
  431. indexed_array_test() {
  432. name = __FILE__ ":7";
  433. }
  434. virtual int run() {
  435. int res = 0;
  436. {
  437. gp::indexed_array<int, 8> store;
  438. size_t idx = store.push (112);
  439. store.push (113);
  440. store.push (114);
  441. gp_config::assertion(store[idx] == 112, "Bad value in indexed array");
  442. store.mark_for_removal(idx);
  443. store.sweep_removed();
  444. for(auto& p : store) {
  445. if(p == 112) res++;
  446. }
  447. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  448. }
  449. {
  450. gp::indexed_array<std::string, 8> store;
  451. size_t idx = store.push ("112");
  452. store.push ("113");
  453. store.push ("114");
  454. gp_config::assertion(store[idx] == "112", "Bad value in indexed array");
  455. store.mark_for_removal(idx);
  456. store.sweep_removed();
  457. for(auto& p : store) {
  458. if(p == "112") res++;
  459. }
  460. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  461. {
  462. // TODO: write a concrete implementation and test it
  463. // gp::vfs fs;
  464. }
  465. }
  466. return res;
  467. }
  468. };
  469. append_test dummy_khxurgsd3(new indexed_array_test{});