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.

690 lines
18 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
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/arena.hpp"
  7. #include "gp/allocator/buddy.hpp"
  8. #include "gp/allocator/dummy.hpp"
  9. #include "gp/algorithm/repeat.hpp"
  10. #include "gp/algorithm/rotate.hpp"
  11. #include "gp/algorithm/move.hpp"
  12. #include "gp/ring_list.hpp"
  13. #include "gp/bitops.hpp"
  14. #include <thread>
  15. #include <chrono>
  16. #include <set>
  17. #include <stack>
  18. #include <numeric>
  19. #include <chrono>
  20. #include <random>
  21. #include <iomanip>
  22. #include <iostream>
  23. #include <fstream>
  24. #include <algorithm>
  25. #include "gp/vfs/vfs.hpp"
  26. #ifndef FUZZ_STRENGTH
  27. #define FUZZ_STRENGTH 2048
  28. #endif
  29. #define MACRO_STRGEN(X) #X
  30. #define MACRO_STR(X) MACRO_STRGEN(X)
  31. constexpr bool time_fuzzes = true;
  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. // TODO: should implement a test that tries to wrongly remove pointers as well as to allocate them correctly
  203. struct buddy_fuzz_test : public test_scaffold {
  204. buddy_fuzz_test() {
  205. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  206. rng.seed(seed);
  207. }
  208. buddy_fuzz_test(size_t _seed) {
  209. seed = _seed;
  210. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4";
  211. rng.seed(seed);
  212. }
  213. std::mt19937 rng{};
  214. int seed = std::random_device{}();
  215. virtual int run() {
  216. int res = 0;
  217. alignas(8) gp::array<char, 4096> store;
  218. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  219. std::vector<void*> ptr_set;
  220. auto get_random_mem_qt = [&]() -> size_t {
  221. return 1+rng()%(store.size()-1);
  222. };
  223. auto start = std::chrono::steady_clock::now();
  224. {
  225. gp::repeat(FUZZ_STRENGTH, [&](){
  226. void* ptr;
  227. auto sz = get_random_mem_qt();
  228. size_t tries = 0;
  229. std::shuffle(
  230. ptr_set.begin(),
  231. ptr_set.end(),
  232. rng
  233. );
  234. while(!(ptr = bud.allocate(sz)))
  235. {
  236. void* free_ptr = ptr_set.back();
  237. ptr_set.pop_back();
  238. gp_config::assertion(bud.deallocate(free_ptr), "could not free sample");
  239. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  240. }
  241. ptr_set.emplace_back(ptr);
  242. });
  243. for(auto ptr : ptr_set)
  244. {
  245. bud.deallocate(ptr);
  246. }
  247. ptr_set.resize(0);
  248. }
  249. auto duration = std::chrono::steady_clock::now() - start;
  250. start = std::chrono::steady_clock::now();
  251. {
  252. size_t acc = 0;
  253. gp::repeat(FUZZ_STRENGTH, [&](){
  254. void* ptr;
  255. auto sz = get_random_mem_qt();
  256. size_t tries = 0;
  257. std::shuffle(
  258. ptr_set.begin(),
  259. ptr_set.end(),
  260. rng
  261. );
  262. ptr = malloc(sz);
  263. acc+=1;
  264. while(acc > 20)
  265. {
  266. void* free_ptr = ptr_set.back();
  267. free(free_ptr);
  268. acc -= 1;
  269. ptr_set.pop_back();
  270. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  271. }
  272. ptr_set.emplace_back(ptr);
  273. });
  274. for(auto ptr : ptr_set)
  275. {
  276. free(ptr);
  277. }
  278. }
  279. auto reference = std::chrono::steady_clock::now() - start;
  280. std::cout
  281. << "Fuzzing timed at "
  282. << std::chrono::duration_cast<std::chrono::microseconds>(duration).count()
  283. << "µs for "
  284. << FUZZ_STRENGTH
  285. << " (reference: "
  286. << std::chrono::duration_cast<std::chrono::microseconds>(reference).count()
  287. << "µs)"
  288. << std::endl;
  289. return res;
  290. }
  291. };
  292. append_test dummy_df987sd3(new buddy_fuzz_test{781017366});
  293. append_test dummy_df4sisd3(new buddy_fuzz_test{});
  294. struct ring_list_test : public test_scaffold {
  295. ring_list_test() {
  296. name = __FILE__ ":5";
  297. }
  298. virtual int run() {
  299. int res = 0;
  300. alignas(8) gp::array<char, 4096> store;
  301. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  302. local_allocator bud{&*store.begin(), store.size()};
  303. {
  304. using string_ring = gp::ring_list<std::string, local_allocator, false>;
  305. auto p = new(bud.allocate(sizeof(std::string))) std::string("Hello");
  306. auto orig = new(bud.allocate(sizeof(string_ring::node))) string_ring::node(p);
  307. string_ring ring{orig, bud};
  308. ring.insert("World");
  309. auto it = ring.explore();
  310. std::string test = "";
  311. do{
  312. test += *it;
  313. ++it;
  314. }while(it != ring.explore());
  315. res += (test != "HelloWorld");
  316. }
  317. return res;
  318. }
  319. };
  320. append_test dummy_867fdrgsd3(new ring_list_test{});
  321. struct aggregator_test : public test_scaffold {
  322. aggregator_test() {
  323. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":6";
  324. rng.seed(seed);
  325. }
  326. std::mt19937 rng{};
  327. int seed = std::random_device{}();
  328. virtual int run() {
  329. int res = 0;
  330. alignas(8) gp::array<char, 4096> store;
  331. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  332. local_allocator bud{&*store.begin(), store.size()};
  333. alignas(8) gp::array<char, 4096> store2;
  334. local_allocator bud2{&*store2.begin(), store2.size()};
  335. gp::aggregator allocator{bud};
  336. allocator.insert(bud2);
  337. {
  338. std::vector<void*> ptr_set;
  339. auto get_random_mem_qt = [&]() -> size_t {
  340. return 1+rng()%(store.size()-1);
  341. };
  342. auto start = std::chrono::steady_clock::now();
  343. {
  344. gp::repeat(FUZZ_STRENGTH, [&](){
  345. void* ptr;
  346. auto sz = get_random_mem_qt();
  347. size_t tries = 0;
  348. std::shuffle(
  349. ptr_set.begin(),
  350. ptr_set.end(),
  351. rng
  352. );
  353. while(!(ptr = allocator.allocate(sz)))
  354. {
  355. void* free_ptr = ptr_set.back();
  356. ptr_set.pop_back();
  357. gp_config::assertion(allocator.deallocate(free_ptr), "could not free sample");
  358. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  359. }
  360. ptr_set.emplace_back(ptr);
  361. });
  362. for(auto ptr : ptr_set)
  363. {
  364. bud.deallocate(ptr);
  365. }
  366. ptr_set.resize(0);
  367. }
  368. auto duration = std::chrono::steady_clock::now() - start;
  369. }
  370. void* a = allocator.allocate(8);
  371. gp_config::assertion(allocator.try_reallocate(a, 16) == false, "could reallocate? was it implemented?");
  372. gp_config::assertion(allocator.deallocate(nullptr) == false, "error, could free an invalid pointer");
  373. allocator.deallocate(a);
  374. {
  375. gp::ring_list<int, gp::aggregator, false> list{allocator};
  376. list.insert(8);
  377. list.insert(16);
  378. list.insert(32);
  379. }
  380. {
  381. gp::array<char, 256> work_array;
  382. gp::arena<> alloc_work(work_array.begin().data, work_array.size());
  383. gp::ring_list<int, gp::arena<>, false> list{alloc_work};
  384. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  385. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  386. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  387. }
  388. {
  389. gp::array<char, sizeof(int)> once_array;
  390. gp::arena<> alloc_once(once_array.begin().data, once_array.size());
  391. gp::ring_list<int, gp::arena<>, false> list{alloc_once};
  392. gp_config::assertion(list.insert(8) == false, "could allocate in list with insufficient allocator");
  393. }
  394. {
  395. gp::arena<> alloc_none(nullptr, 0);
  396. gp::ring_list<int, gp::arena<>, false> list{alloc_none};
  397. gp_config::assertion(list.insert(8) == false, "could allocate in list with fake allocator");
  398. }
  399. return res;
  400. }
  401. };
  402. append_test dummy_8ijfsd658(new aggregator_test{});
  403. struct array_test : public test_scaffold {
  404. array_test() {
  405. name = __FILE__ ":7";
  406. }
  407. virtual int run() {
  408. int res = 0;
  409. gp::array<int, 8> store;
  410. {
  411. int i = 0;
  412. for(auto& p : store)
  413. {
  414. p = i++;
  415. }
  416. for(auto it = store.rbegin(); it != store.rend(); ++it)
  417. {
  418. gp_config::assertion(*it == --i, "array error");
  419. }
  420. for(const auto& p : store)
  421. {
  422. gp_config::assertion(p == i++, "array error");
  423. }
  424. for(auto it = store.crbegin(); it != store.crend(); ++it)
  425. {
  426. gp_config::assertion(*it == --i, "array error");
  427. }
  428. size_t cnt = 0;
  429. for(const auto& p : store)
  430. {
  431. cnt++;
  432. }
  433. gp_config::assertion(cnt == store.size(), "array error");
  434. cnt = 0;
  435. for(auto& p : store)
  436. {
  437. cnt++;
  438. }
  439. gp_config::assertion(cnt == store.size(), "array error");
  440. cnt = 0;
  441. for(auto it = store.crbegin(); it != store.crend(); ++it)
  442. {
  443. cnt++;
  444. }
  445. gp_config::assertion(cnt == store.size(), "array error");
  446. cnt = 0;
  447. for(auto it = store.rbegin(); it != store.rend(); ++it)
  448. {
  449. cnt++;
  450. }
  451. gp_config::assertion(cnt == store.size(), "array error");
  452. gp::rotate(store.begin(), store.begin()+1, store.end());
  453. gp::array<int, 8> rotated({1,2,3,4,5,6,7,0});
  454. gp_config::assertion(store == rotated, "rotate error");
  455. gp::rotate(store.begin(), store.end()-1, store.end());
  456. gp_config::assertion(store[0] == 0, "rotate error");
  457. }
  458. return res;
  459. }
  460. };
  461. append_test dummy_ajcurgsd3(new array_test{});
  462. struct indexed_array_test : public test_scaffold {
  463. indexed_array_test() {
  464. name = __FILE__ ":7";
  465. }
  466. virtual int run() {
  467. int res = 0;
  468. {
  469. gp::indexed_array<int, 8> store;
  470. size_t idx = store.push (112);
  471. store.push (113);
  472. store.push (114);
  473. gp_config::assertion(store[idx] == 112, "Bad value in indexed array");
  474. store.mark_for_removal(idx);
  475. store.sweep_removed();
  476. for(auto& p : store) {
  477. if(p == 112) res++;
  478. }
  479. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  480. }
  481. {
  482. gp::indexed_array<std::string, 8> store;
  483. size_t idx = store.push ("112");
  484. store.push ("113");
  485. store.push ("114");
  486. gp_config::assertion(store[idx] == "112", "Bad value in indexed array");
  487. store.mark_for_removal(idx);
  488. store.sweep_removed();
  489. for(auto& p : store) {
  490. if(p == "112") res++;
  491. }
  492. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  493. {
  494. // TODO: write a concrete implementation and test it
  495. // gp::vfs fs;
  496. }
  497. }
  498. return res;
  499. }
  500. };
  501. append_test dummy_khxurgsd3(new indexed_array_test{});
  502. struct move_uninitialized_test : public test_scaffold {
  503. move_uninitialized_test() {
  504. name = __FILE__ ":8";
  505. }
  506. struct tester {
  507. size_t* const incremented;
  508. tester(size_t* ptr)
  509. : incremented(ptr)
  510. {}
  511. tester(tester&& oth)
  512. : incremented(oth.incremented)
  513. {
  514. ++*incremented;
  515. }
  516. };
  517. virtual int run() {
  518. int res = 0;
  519. {
  520. size_t counter;
  521. using src_t = gp::array<tester, 16>;
  522. src_t *source = reinterpret_cast<src_t*>(malloc(sizeof(src_t)));
  523. gp::array<char, sizeof(tester)*16> buffer;
  524. for(auto& a : *source) {
  525. new(&a) tester(&counter);
  526. }
  527. gp::move_uninitialized(*source, buffer.as_buffer().cast<tester>());
  528. free(source);
  529. }
  530. return res;
  531. }
  532. };
  533. append_test dummy_hkfyr5f5(new move_uninitialized_test{});
  534. struct clamp_test : public test_scaffold {
  535. clamp_test() {
  536. name = __FILE__ ":9";
  537. }
  538. virtual int run() {
  539. int res = 0;
  540. {
  541. res += gp::clamp<float>(0.0, -1.0, 1.0);
  542. res += gp::clamp<float>(-1.0, 1.0, 0.0);
  543. res += gp::max(-1, -2, 0, -3);
  544. }
  545. return res;
  546. }
  547. };
  548. append_test dummy_gsdh25f5(new clamp_test{});
  549. struct buffer_test : public test_scaffold {
  550. buffer_test() {
  551. name = __FILE__ ":10";
  552. }
  553. virtual int run() {
  554. int res = 0;
  555. {
  556. gp::array<char, 24> data;
  557. gp::array<char, 24> data_e;
  558. gp::buffer<char> handle = data.as_buffer();
  559. handle[12] = '&';
  560. gp_config::assertion(*(handle.begin()+12) == '&', "Could not assign to the buffer");
  561. res += 1;
  562. try {
  563. handle[24] = 16;
  564. res += 1;
  565. handle[-1] = 16;
  566. res += 1;
  567. handle[1024] = 16;
  568. } catch (...) {
  569. res -= 1;
  570. }
  571. res += 1;
  572. try {
  573. auto cast = handle.cast<gp::array<char, 32>>();
  574. } catch (...) {
  575. res -= 1;
  576. }
  577. auto cast = handle.template cast<gp::array<char, 6>>().template cast<gp::array<char, 4>>();
  578. gp_config::assertion(false == (data == data_e), "Different arrays should return false here");
  579. }
  580. return res;
  581. }
  582. };
  583. append_test dummy_gs87ytf5f5(new buffer_test{});
  584. struct endian_test : public test_scaffold {
  585. endian_test() {
  586. name = __FILE__ ":11";
  587. }
  588. virtual int run() {
  589. int res = 0;
  590. {
  591. gp::endian_wrapper<uint32_t> a = 0x41424344UL;
  592. #pragma clang diagnostic push
  593. #pragma clang diagnostic ignored "-Wfour-char-constants"
  594. #pragma gcc diagnostic push
  595. #pragma gcc diagnostic ignored "-Wfour-char-constants"
  596. gp_config::assertion(a.value != 'ABCD', "Not a big endian in a big endian wrapper");
  597. #pragma gcc diagnostic pop
  598. #pragma clang diagnostic pop
  599. gp_config::assertion(gp::swap_endian<uint32_t>(0x41424344UL)==0x44434241UL, "swap_endian doesn't swap endian");
  600. }
  601. return res;
  602. }
  603. };
  604. append_test dummy_45zelotf5f5(new endian_test{});