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.

663 lines
17 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
3 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 <thread>
  14. #include <chrono>
  15. #include <set>
  16. #include <stack>
  17. #include <numeric>
  18. #include <chrono>
  19. #include <random>
  20. #include <iomanip>
  21. #include <iostream>
  22. #include <fstream>
  23. #include <algorithm>
  24. #include "gp/vfs/vfs.hpp"
  25. #ifndef FUZZ_STRENGTH
  26. #define FUZZ_STRENGTH 2048
  27. #endif
  28. #define MACRO_STRGEN(X) #X
  29. #define MACRO_STR(X) MACRO_STRGEN(X)
  30. constexpr bool time_fuzzes = true;
  31. struct arraysum_test : public test_scaffold {
  32. arraysum_test() {
  33. name = __FILE__ ":1";
  34. }
  35. virtual int run() {
  36. gp::array<uint32_t, 16> test;
  37. for(auto& elem : test)
  38. {
  39. elem = 12;
  40. }
  41. return std::accumulate(test.begin(), test.end(), 0) != 12*test.size();
  42. }
  43. };
  44. append_test dummy_sd45uisd3(new arraysum_test{});
  45. struct optional_test : public test_scaffold {
  46. optional_test() {
  47. name = __FILE__ ":1";
  48. }
  49. virtual int run() {
  50. int res = 0;
  51. {
  52. gp::optional<uint32_t> test;
  53. if(test.has_value())
  54. {
  55. res++;
  56. }
  57. test = 12;
  58. if(test.has_value())
  59. {
  60. if(test.value()!=12)
  61. {
  62. res++;
  63. }
  64. }
  65. else
  66. {
  67. res++;
  68. }
  69. }
  70. {
  71. gp::optional<std::ifstream> test;
  72. if(test.has_value())
  73. {
  74. res++;
  75. }
  76. test = std::ifstream("/proc/cpuinfo");
  77. if(!test.has_value())
  78. {
  79. res++;
  80. }
  81. }
  82. return res;
  83. }
  84. };
  85. append_test dummy_mlyusisd3(new optional_test{});
  86. struct buddy_test : public test_scaffold {
  87. buddy_test() {
  88. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":3";
  89. rng.seed(seed);
  90. }
  91. std::mt19937 rng{};
  92. int seed = std::random_device{}();
  93. virtual int run() {
  94. int res = 0;
  95. gp::repeat(10, [&](){
  96. gp::array<char, 4096> store;
  97. {
  98. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()};
  99. gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> dum_bud{store.size()};
  100. gp::buddy<static_mapper> inner_bud{2048};
  101. gp::dummy_allocator dummyall;
  102. {
  103. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  104. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  105. gp_config::assertion(!inner_bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  106. std::set<void*> ptr_set;
  107. for(int i = 0; i < 2048 / 16; i++)
  108. {
  109. void* v = inner_bud.allocate(16);
  110. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  111. if(v == nullptr) throw gp::runtime_error("allocation failed");
  112. ptr_set.insert(v);
  113. }
  114. bool wut = ptr_set.count(nullptr)!=0 || ptr_set.size()!=(2048/16);
  115. if(wut) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  116. if(nullptr != inner_bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  117. for(auto elem : ptr_set) {
  118. gp_config::assertion(!inner_bud.empty(), "allocator should have elements");
  119. if(inner_bud.deallocate(elem) == false)
  120. {
  121. res += 1;
  122. }
  123. }
  124. gp_config::assertion(inner_bud.empty(), "allocator should be empty");
  125. }
  126. {
  127. gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?");
  128. gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?");
  129. std::set<void*> ptr_set;
  130. for(int i = 0; i < 4096 / 16; i++)
  131. {
  132. void* v = bud.allocate(16);
  133. gp_config::assertion(!bud.empty(), "allocator should have elements");
  134. if(v == nullptr) throw gp::runtime_error("allocation failed");
  135. ptr_set.insert(v);
  136. }
  137. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/16)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  138. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  139. for(auto elem : ptr_set) {
  140. gp_config::assertion(!bud.empty(), "allocator should have elements");
  141. if(bud.deallocate(elem) == false)
  142. {
  143. res += 1;
  144. }
  145. }
  146. gp_config::assertion(bud.empty(), "allocator should be empty");
  147. }
  148. {
  149. std::set<void*> ptr_set;
  150. for(int i = 0; i < 4096 / 8; i++)
  151. {
  152. void* v = bud.allocate(8);
  153. gp_config::assertion(!bud.empty(), "allocator should have elements");
  154. if(v == nullptr) throw gp::runtime_error("allocation failed");
  155. ptr_set.insert(v);
  156. }
  157. if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  158. if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected");
  159. for(auto elem : ptr_set) {
  160. gp_config::assertion(!bud.empty(), "allocator should have elements");
  161. if(bud.deallocate(elem) == false)
  162. {
  163. res += 1;
  164. }
  165. }
  166. gp_config::assertion(bud.empty(), "allocator should be empty");
  167. }
  168. {
  169. std::set<void*> ptr_set;
  170. std::vector<size_t> infill;
  171. std::insert_iterator< std::vector<size_t> > inserter{infill, std::end(infill)};
  172. std::fill_n(inserter, 4096 / 16 / 4, 16);
  173. inserter = std::insert_iterator< std::vector<size_t> >{infill, std::end(infill)};
  174. std::fill_n(inserter, 4096 / 8 / 4, 8);
  175. std::shuffle(infill.begin(), infill.end(), rng);
  176. for(auto sz : infill)
  177. {
  178. void* v = bud.allocate(sz);
  179. gp_config::assertion(!bud.empty(), "allocator should have elements");
  180. if(v == nullptr) throw gp::runtime_error("allocation failed");
  181. ptr_set.insert(v);
  182. }
  183. if(ptr_set.count(nullptr)!=0) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__));
  184. gp_config::assertion(!bud.deallocate((char*)store.begin().data + 1), "misaligned deallocation fails");
  185. for(auto elem : ptr_set) {
  186. gp_config::assertion(!bud.empty(), "allocator should have elements");
  187. if(bud.deallocate(elem) == false)
  188. {
  189. res += 1;
  190. }
  191. }
  192. gp_config::assertion(!bud.deallocate(nullptr), "deallocating out of scope returns false");
  193. gp_config::assertion(bud.empty(), "allocator should be empty");
  194. }
  195. }
  196. });
  197. return res;
  198. }
  199. };
  200. append_test dummy_654sisd3(new buddy_test{});
  201. // TODO: should implement a test that tries to wrongly remove pointers as well as to allocate them correctly
  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{});
  293. struct ring_list_test : public test_scaffold {
  294. ring_list_test() {
  295. name = __FILE__ ":5";
  296. }
  297. virtual int run() {
  298. int res = 0;
  299. alignas(8) gp::array<char, 4096> store;
  300. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  301. local_allocator bud{&*store.begin(), store.size()};
  302. {
  303. using string_ring = gp::ring_list<std::string, local_allocator, false>;
  304. auto p = new(bud.allocate(sizeof(std::string))) std::string("Hello");
  305. auto orig = new(bud.allocate(sizeof(string_ring::node))) string_ring::node(p);
  306. string_ring ring{orig, bud};
  307. ring.insert("World");
  308. auto it = ring.explore();
  309. std::string test = "";
  310. do{
  311. test += *it;
  312. ++it;
  313. }while(it != ring.explore());
  314. res += (test != "HelloWorld");
  315. }
  316. return res;
  317. }
  318. };
  319. append_test dummy_867fdrgsd3(new ring_list_test{});
  320. struct aggregator_test : public test_scaffold {
  321. aggregator_test() {
  322. name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":6";
  323. rng.seed(seed);
  324. }
  325. std::mt19937 rng{};
  326. int seed = std::random_device{}();
  327. virtual int run() {
  328. int res = 0;
  329. alignas(8) gp::array<char, 4096> store;
  330. using local_allocator = gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)>;
  331. local_allocator bud{&*store.begin(), store.size()};
  332. alignas(8) gp::array<char, 4096> store2;
  333. local_allocator bud2{&*store2.begin(), store2.size()};
  334. gp::aggregator allocator{bud};
  335. allocator.insert(bud2);
  336. {
  337. std::vector<void*> ptr_set;
  338. auto get_random_mem_qt = [&]() -> size_t {
  339. return 1+rng()%(store.size()-1);
  340. };
  341. auto start = std::chrono::steady_clock::now();
  342. {
  343. gp::repeat(FUZZ_STRENGTH, [&](){
  344. void* ptr;
  345. auto sz = get_random_mem_qt();
  346. size_t tries = 0;
  347. std::shuffle(
  348. ptr_set.begin(),
  349. ptr_set.end(),
  350. rng
  351. );
  352. while(!(ptr = allocator.allocate(sz)))
  353. {
  354. void* free_ptr = ptr_set.back();
  355. ptr_set.pop_back();
  356. gp_config::assertion(allocator.deallocate(free_ptr), "could not free sample");
  357. gp_config::assertion(++tries <= store.size(), "infinite fuzzing");
  358. }
  359. ptr_set.emplace_back(ptr);
  360. });
  361. for(auto ptr : ptr_set)
  362. {
  363. bud.deallocate(ptr);
  364. }
  365. ptr_set.resize(0);
  366. }
  367. auto duration = std::chrono::steady_clock::now() - start;
  368. }
  369. void* a = allocator.allocate(8);
  370. gp_config::assertion(allocator.try_reallocate(a, 16) == false, "could reallocate? was it implemented?");
  371. gp_config::assertion(allocator.deallocate(nullptr) == false, "error, could free an invalid pointer");
  372. allocator.deallocate(a);
  373. {
  374. gp::ring_list<int, gp::aggregator, false> list{allocator};
  375. list.insert(8);
  376. list.insert(16);
  377. list.insert(32);
  378. }
  379. {
  380. gp::array<char, 256> work_array;
  381. gp::arena<> alloc_work(work_array.begin().data, work_array.size());
  382. gp::ring_list<int, gp::arena<>, false> list{alloc_work};
  383. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  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. }
  387. {
  388. gp::array<char, sizeof(int)> once_array;
  389. gp::arena<> alloc_once(once_array.begin().data, once_array.size());
  390. gp::ring_list<int, gp::arena<>, false> list{alloc_once};
  391. gp_config::assertion(list.insert(8) == false, "could allocate in list with insufficient allocator");
  392. }
  393. {
  394. gp::arena<> alloc_none(nullptr, 0);
  395. gp::ring_list<int, gp::arena<>, false> list{alloc_none};
  396. gp_config::assertion(list.insert(8) == false, "could allocate in list with fake allocator");
  397. }
  398. return res;
  399. }
  400. };
  401. append_test dummy_8ijfsd658(new aggregator_test{});
  402. struct array_test : public test_scaffold {
  403. array_test() {
  404. name = __FILE__ ":7";
  405. }
  406. virtual int run() {
  407. int res = 0;
  408. gp::array<int, 8> store;
  409. {
  410. int i = 0;
  411. for(auto& p : store)
  412. {
  413. p = i++;
  414. }
  415. for(auto it = store.rbegin(); it != store.rend(); ++it)
  416. {
  417. gp_config::assertion(*it == --i, "array error");
  418. }
  419. for(const auto& p : store)
  420. {
  421. gp_config::assertion(p == i++, "array error");
  422. }
  423. for(auto it = store.crbegin(); it != store.crend(); ++it)
  424. {
  425. gp_config::assertion(*it == --i, "array error");
  426. }
  427. size_t cnt = 0;
  428. for(const auto& p : store)
  429. {
  430. cnt++;
  431. }
  432. gp_config::assertion(cnt == store.size(), "array error");
  433. cnt = 0;
  434. for(auto& p : store)
  435. {
  436. cnt++;
  437. }
  438. gp_config::assertion(cnt == store.size(), "array error");
  439. cnt = 0;
  440. for(auto it = store.crbegin(); it != store.crend(); ++it)
  441. {
  442. cnt++;
  443. }
  444. gp_config::assertion(cnt == store.size(), "array error");
  445. cnt = 0;
  446. for(auto it = store.rbegin(); it != store.rend(); ++it)
  447. {
  448. cnt++;
  449. }
  450. gp_config::assertion(cnt == store.size(), "array error");
  451. gp::rotate(store.begin(), store.begin()+1, store.end());
  452. gp::array<int, 8> rotated({1,2,3,4,5,6,7,0});
  453. gp_config::assertion(store == rotated, "rotate error");
  454. gp::rotate(store.begin(), store.end()-1, store.end());
  455. gp_config::assertion(store[0] == 0, "rotate error");
  456. }
  457. return res;
  458. }
  459. };
  460. append_test dummy_ajcurgsd3(new array_test{});
  461. struct indexed_array_test : public test_scaffold {
  462. indexed_array_test() {
  463. name = __FILE__ ":7";
  464. }
  465. virtual int run() {
  466. int res = 0;
  467. {
  468. gp::indexed_array<int, 8> store;
  469. size_t idx = store.push (112);
  470. store.push (113);
  471. store.push (114);
  472. gp_config::assertion(store[idx] == 112, "Bad value in indexed array");
  473. store.mark_for_removal(idx);
  474. store.sweep_removed();
  475. for(auto& p : store) {
  476. if(p == 112) res++;
  477. }
  478. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  479. }
  480. {
  481. gp::indexed_array<std::string, 8> store;
  482. size_t idx = store.push ("112");
  483. store.push ("113");
  484. store.push ("114");
  485. gp_config::assertion(store[idx] == "112", "Bad value in indexed array");
  486. store.mark_for_removal(idx);
  487. store.sweep_removed();
  488. for(auto& p : store) {
  489. if(p == "112") res++;
  490. }
  491. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  492. {
  493. // TODO: write a concrete implementation and test it
  494. // gp::vfs fs;
  495. }
  496. }
  497. return res;
  498. }
  499. };
  500. append_test dummy_khxurgsd3(new indexed_array_test{});
  501. struct move_uninitialized_test : public test_scaffold {
  502. move_uninitialized_test() {
  503. name = __FILE__ ":8";
  504. }
  505. struct tester {
  506. size_t* const incremented;
  507. tester(size_t* ptr)
  508. : incremented(ptr)
  509. {}
  510. tester(tester&& oth)
  511. : incremented(oth.incremented)
  512. {
  513. ++*incremented;
  514. }
  515. };
  516. virtual int run() {
  517. int res = 0;
  518. {
  519. size_t counter;
  520. using src_t = gp::array<tester, 16>;
  521. src_t *source = reinterpret_cast<src_t*>(malloc(sizeof(src_t)));
  522. gp::array<char, sizeof(tester)*16> buffer;
  523. for(auto& a : *source) {
  524. new(&a) tester(&counter);
  525. }
  526. gp::move_uninitialized(*source, buffer.as_buffer().cast<tester>());
  527. free(source);
  528. }
  529. return res;
  530. }
  531. };
  532. append_test dummy_hkfyr5f5(new move_uninitialized_test{});
  533. struct clamp_test : public test_scaffold {
  534. clamp_test() {
  535. name = __FILE__ ":9";
  536. }
  537. virtual int run() {
  538. int res = 0;
  539. {
  540. res += gp::clamp<float>(0.0, -1.0, 1.0);
  541. res += gp::clamp<float>(-1.0, 1.0, 0.0);
  542. res += gp::max(-1, -2, 0, -3);
  543. }
  544. return res;
  545. }
  546. };
  547. append_test dummy_gsdh25f5(new clamp_test{});
  548. struct buffer_test : public test_scaffold {
  549. buffer_test() {
  550. name = __FILE__ ":10";
  551. }
  552. virtual int run() {
  553. int res = 0;
  554. {
  555. gp::array<char, 24> data;
  556. gp::array<char, 24> data_e;
  557. gp::buffer<char> handle = data.as_buffer();
  558. handle[12] = '&';
  559. gp_config::assertion(*(handle.begin()+12) == '&', "Could not assign to the buffer");
  560. res += 1;
  561. try {
  562. handle[24] = 16;
  563. res += 1;
  564. handle[-1] = 16;
  565. res += 1;
  566. handle[1024] = 16;
  567. } catch (...) {
  568. res -= 1;
  569. }
  570. res += 1;
  571. try {
  572. auto cast = handle.cast<gp::array<char, 32>>();
  573. } catch (...) {
  574. res -= 1;
  575. }
  576. auto cast = handle.template cast<gp::array<char, 6>>().template cast<gp::array<char, 4>>();
  577. gp_config::assertion(false == (data == data_e), "Different arrays should return false here");
  578. }
  579. return res;
  580. }
  581. };
  582. append_test dummy_gs87ytf5f5(new buffer_test{});