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.

562 lines
15 KiB

преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
преди 4 години
  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/ring_list.hpp"
  12. #include <thread>
  13. #include <chrono>
  14. #include <set>
  15. #include <stack>
  16. #include <numeric>
  17. #include <chrono>
  18. #include <random>
  19. #include <iomanip>
  20. #include <iostream>
  21. #include <fstream>
  22. #include <algorithm>
  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. void* a = allocator.allocate(8);
  368. gp_config::assertion(allocator.try_reallocate(a, 16) == false, "could reallocate? was it implemented?");
  369. gp_config::assertion(allocator.deallocate(nullptr) == false, "error, could free an invalid pointer");
  370. allocator.deallocate(a);
  371. {
  372. gp::ring_list<int, gp::aggregator, false> list{allocator};
  373. list.insert(8);
  374. list.insert(16);
  375. list.insert(32);
  376. }
  377. {
  378. gp::array<char, 256> work_array;
  379. gp::arena<> alloc_work(work_array.begin().data, work_array.size());
  380. gp::ring_list<int, gp::arena<>, false> list{alloc_work};
  381. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  382. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  383. gp_config::assertion(list.insert(8) == true, "could allocate in list with good enough allocator");
  384. }
  385. {
  386. gp::array<char, sizeof(int)> once_array;
  387. gp::arena<> alloc_once(once_array.begin().data, once_array.size());
  388. gp::ring_list<int, gp::arena<>, false> list{alloc_once};
  389. gp_config::assertion(list.insert(8) == false, "could allocate in list with insufficient allocator");
  390. }
  391. {
  392. gp::arena<> alloc_none(nullptr, 0);
  393. gp::ring_list<int, gp::arena<>, false> list{alloc_none};
  394. gp_config::assertion(list.insert(8) == false, "could allocate in list with fake allocator");
  395. }
  396. return res;
  397. }
  398. };
  399. append_test dummy_8ijfsd658(new aggregator_test{});
  400. struct array_test : public test_scaffold {
  401. array_test() {
  402. name = __FILE__ ":7";
  403. }
  404. virtual int run() {
  405. int res = 0;
  406. gp::array<int, 8> store;
  407. {
  408. int i = 0;
  409. for(auto& p : store)
  410. {
  411. p = i++;
  412. }
  413. for(auto it = store.rbegin(); it != store.rend(); ++it)
  414. {
  415. gp_config::assertion(*it == --i, "array error");
  416. }
  417. for(const auto& p : store)
  418. {
  419. gp_config::assertion(p == i++, "array error");
  420. }
  421. for(auto it = store.crbegin(); it != store.crend(); ++it)
  422. {
  423. gp_config::assertion(*it == --i, "array error");
  424. }
  425. size_t cnt = 0;
  426. for(const auto& p : store)
  427. {
  428. cnt++;
  429. }
  430. gp_config::assertion(cnt == store.size(), "array error");
  431. cnt = 0;
  432. for(auto& p : store)
  433. {
  434. cnt++;
  435. }
  436. gp_config::assertion(cnt == store.size(), "array error");
  437. cnt = 0;
  438. for(auto it = store.crbegin(); it != store.crend(); ++it)
  439. {
  440. cnt++;
  441. }
  442. gp_config::assertion(cnt == store.size(), "array error");
  443. cnt = 0;
  444. for(auto it = store.rbegin(); it != store.rend(); ++it)
  445. {
  446. cnt++;
  447. }
  448. gp_config::assertion(cnt == store.size(), "array error");
  449. gp::rotate(store.begin(), store.begin()+1, store.end());
  450. gp::array<int, 8> rotated({1,2,3,4,5,6,7,0});
  451. gp_config::assertion(store == rotated, "rotate error");
  452. gp::rotate(store.begin(), store.end()-1, store.end());
  453. gp_config::assertion(store[0] == 0, "rotate error");
  454. }
  455. return res;
  456. }
  457. };
  458. append_test dummy_ajcurgsd3(new array_test{});
  459. struct indexed_array_test : public test_scaffold {
  460. indexed_array_test() {
  461. name = __FILE__ ":7";
  462. }
  463. virtual int run() {
  464. int res = 0;
  465. {
  466. gp::indexed_array<int, 8> store;
  467. size_t idx = store.push (112);
  468. store.push (113);
  469. store.push (114);
  470. gp_config::assertion(store[idx] == 112, "Bad value in indexed array");
  471. store.mark_for_removal(idx);
  472. store.sweep_removed();
  473. for(auto& p : store) {
  474. if(p == 112) res++;
  475. }
  476. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  477. }
  478. {
  479. gp::indexed_array<std::string, 8> store;
  480. size_t idx = store.push ("112");
  481. store.push ("113");
  482. store.push ("114");
  483. gp_config::assertion(store[idx] == "112", "Bad value in indexed array");
  484. store.mark_for_removal(idx);
  485. store.sweep_removed();
  486. for(auto& p : store) {
  487. if(p == "112") res++;
  488. }
  489. gp_config::assertion(store.size() == 2, "Bad size of indexed array");
  490. {
  491. // TODO: write a concrete implementation and test it
  492. // gp::vfs fs;
  493. }
  494. }
  495. return res;
  496. }
  497. };
  498. append_test dummy_khxurgsd3(new indexed_array_test{});