|
|
@ -2,13 +2,38 @@ |
|
|
|
#include "gp/array.hpp"
|
|
|
|
#include "gp/allocator/buddy.hpp"
|
|
|
|
#include "gp/allocator/dummy.hpp"
|
|
|
|
#include "gp/algorithm/repeat.hpp"
|
|
|
|
#include <thread>
|
|
|
|
#include <chrono>
|
|
|
|
#include <set>
|
|
|
|
#include <stack>
|
|
|
|
#include <numeric>
|
|
|
|
#include <chrono>
|
|
|
|
#include <random>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#define MACRO_STRGEN(X) #X
|
|
|
|
#define MACRO_STR(X) MACRO_STRGEN(X)
|
|
|
|
|
|
|
|
constexpr bool time_fuzzes = true; |
|
|
|
|
|
|
|
struct static_mapper { |
|
|
|
static gp::array<char, 4096> store; |
|
|
|
static gp::buddy<> impl; |
|
|
|
|
|
|
|
void* allocate(size_t sz) { |
|
|
|
return impl.allocate(sz); |
|
|
|
} |
|
|
|
|
|
|
|
bool deallocate(void* ptr) { |
|
|
|
return impl.deallocate(ptr); |
|
|
|
} |
|
|
|
}; |
|
|
|
alignas(2048) gp::array<char, 4096> static_mapper::store; |
|
|
|
gp::buddy<> static_mapper::impl = gp::buddy<>{store.begin().data, store.size()}; |
|
|
|
|
|
|
|
struct arraysum_test : public test_scaffold { |
|
|
|
arraysum_test() { |
|
|
@ -83,31 +108,227 @@ append_test dummy_mlyusisd3(new optional_test{}); |
|
|
|
|
|
|
|
struct buddy_test : public test_scaffold { |
|
|
|
buddy_test() { |
|
|
|
name = __FILE__ ":3"; |
|
|
|
name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":3"; |
|
|
|
rng.seed(seed); |
|
|
|
} |
|
|
|
|
|
|
|
std::mt19937 rng{}; |
|
|
|
int seed = std::random_device{}(); |
|
|
|
|
|
|
|
virtual int run() { |
|
|
|
int res = 0; |
|
|
|
gp::repeat(10, [&](){ |
|
|
|
gp::array<char, 4096> store; |
|
|
|
{ |
|
|
|
gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()}; |
|
|
|
gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> dum_bud{store.size()}; |
|
|
|
gp::buddy<static_mapper> inner_bud{2048}; |
|
|
|
gp::dummy_allocator dummyall; |
|
|
|
{ |
|
|
|
gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?"); |
|
|
|
gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?"); |
|
|
|
gp_config::assertion(!inner_bud.try_reallocate(nullptr, 0), "reallocation works wut?"); |
|
|
|
std::set<void*> ptr_set; |
|
|
|
for(int i = 0; i < 2048 / 16; i++) |
|
|
|
{ |
|
|
|
void* v = inner_bud.allocate(16); |
|
|
|
gp_config::assertion(!inner_bud.empty(), "allocator should have elements"); |
|
|
|
if(v == nullptr) throw gp::runtime_error("allocation failed"); |
|
|
|
ptr_set.insert(v); |
|
|
|
} |
|
|
|
bool wut = ptr_set.count(nullptr)!=0 || ptr_set.size()!=(2048/16); |
|
|
|
if(wut) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__)); |
|
|
|
if(nullptr != inner_bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected"); |
|
|
|
|
|
|
|
for(auto elem : ptr_set) { |
|
|
|
gp_config::assertion(!inner_bud.empty(), "allocator should have elements"); |
|
|
|
if(inner_bud.deallocate(elem) == false) |
|
|
|
{ |
|
|
|
res += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
gp_config::assertion(inner_bud.empty(), "allocator should be empty"); |
|
|
|
} |
|
|
|
{ |
|
|
|
gp_config::assertion(!dummyall.try_reallocate(nullptr, 0), "reallocation works wut?"); |
|
|
|
gp_config::assertion(!bud.try_reallocate(nullptr, 0), "reallocation works wut?"); |
|
|
|
std::set<void*> ptr_set; |
|
|
|
for(int i = 0; i < 4096 / 16; i++) |
|
|
|
{ |
|
|
|
void* v = bud.allocate(16); |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(v == nullptr) throw gp::runtime_error("allocation failed"); |
|
|
|
ptr_set.insert(v); |
|
|
|
} |
|
|
|
if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/16)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__)); |
|
|
|
if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected"); |
|
|
|
|
|
|
|
for(auto elem : ptr_set) { |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(bud.deallocate(elem) == false) |
|
|
|
{ |
|
|
|
res += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
gp_config::assertion(bud.empty(), "allocator should be empty"); |
|
|
|
} |
|
|
|
{ |
|
|
|
std::set<void*> ptr_set; |
|
|
|
for(int i = 0; i < 4096 / 8; i++) |
|
|
|
{ |
|
|
|
void* v = bud.allocate(8); |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(v == nullptr) throw gp::runtime_error("allocation failed"); |
|
|
|
ptr_set.insert(v); |
|
|
|
} |
|
|
|
if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__)); |
|
|
|
if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected"); |
|
|
|
|
|
|
|
for(auto elem : ptr_set) { |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(bud.deallocate(elem) == false) |
|
|
|
{ |
|
|
|
res += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
gp_config::assertion(bud.empty(), "allocator should be empty"); |
|
|
|
} |
|
|
|
{ |
|
|
|
std::set<void*> ptr_set; |
|
|
|
std::vector<size_t> infill; |
|
|
|
std::insert_iterator< std::vector<size_t> > inserter{infill, std::end(infill)}; |
|
|
|
std::fill_n(inserter, 4096 / 16 / 4, 16); |
|
|
|
inserter = std::insert_iterator< std::vector<size_t> >{infill, std::end(infill)}; |
|
|
|
std::fill_n(inserter, 4096 / 8 / 4, 8); |
|
|
|
std::shuffle(infill.begin(), infill.end(), rng); |
|
|
|
for(auto sz : infill) |
|
|
|
{ |
|
|
|
void* v = bud.allocate(sz); |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(v == nullptr) throw gp::runtime_error("allocation failed"); |
|
|
|
ptr_set.insert(v); |
|
|
|
} |
|
|
|
if(ptr_set.count(nullptr)!=0) throw gp::runtime_error("some allocations failed line: " MACRO_STR(__LINE__)); |
|
|
|
|
|
|
|
gp_config::assertion(!bud.deallocate((char*)store.begin().data + 1), "misaligned deallocation fails"); |
|
|
|
for(auto elem : ptr_set) { |
|
|
|
gp_config::assertion(!bud.empty(), "allocator should have elements"); |
|
|
|
if(bud.deallocate(elem) == false) |
|
|
|
{ |
|
|
|
res += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
gp_config::assertion(!bud.deallocate(nullptr), "deallocating out of scope returns false"); |
|
|
|
gp_config::assertion(bud.empty(), "allocator should be empty"); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
return res; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
append_test dummy_654sisd3(new buddy_test{}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gp::array<char, 4096> store; |
|
|
|
|
|
|
|
struct buddy_fuzz_test : public test_scaffold { |
|
|
|
buddy_fuzz_test() { |
|
|
|
name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4"; |
|
|
|
rng.seed(seed); |
|
|
|
} |
|
|
|
|
|
|
|
buddy_fuzz_test(size_t _seed) { |
|
|
|
seed = _seed; |
|
|
|
name = std::string(__FILE__ "seed_") + std::to_string(seed) + ":4"; |
|
|
|
rng.seed(seed); |
|
|
|
} |
|
|
|
|
|
|
|
std::mt19937 rng{}; |
|
|
|
int seed = std::random_device{}(); |
|
|
|
|
|
|
|
virtual int run() { |
|
|
|
int res = 0; |
|
|
|
alignas(8) gp::array<char, 4096> store; |
|
|
|
gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()}; |
|
|
|
std::vector<void*> ptr_set; |
|
|
|
auto get_random_mem_qt = [&]() -> size_t { |
|
|
|
return 1+rng()%(store.size()-1); |
|
|
|
}; |
|
|
|
|
|
|
|
auto start = std::chrono::steady_clock::now(); |
|
|
|
{ |
|
|
|
gp::buddy<gp::dummy_allocator, gp::math::msb<uint64_t>(4096)> bud{&*store.begin(), store.size()}; |
|
|
|
std::set<void*> ptr_set; |
|
|
|
for(int i = 0; i < 4096 / 8; i++) |
|
|
|
gp::repeat(FUZZ_STRENGTH, [&](){ |
|
|
|
void* ptr; |
|
|
|
auto sz = get_random_mem_qt(); |
|
|
|
size_t tries = 0; |
|
|
|
std::shuffle( |
|
|
|
ptr_set.begin(), |
|
|
|
ptr_set.end(), |
|
|
|
rng |
|
|
|
); |
|
|
|
while(!(ptr = bud.allocate(sz))) |
|
|
|
{ |
|
|
|
void* free_ptr = ptr_set.back(); |
|
|
|
ptr_set.pop_back(); |
|
|
|
gp_config::assertion(bud.deallocate(free_ptr), "could not free sample"); |
|
|
|
gp_config::assertion(++tries <= store.size(), "infinite fuzzing"); |
|
|
|
} |
|
|
|
ptr_set.emplace_back(ptr); |
|
|
|
}); |
|
|
|
for(auto ptr : ptr_set) |
|
|
|
{ |
|
|
|
bud.deallocate(ptr); |
|
|
|
} |
|
|
|
ptr_set.resize(0); |
|
|
|
} |
|
|
|
auto duration = std::chrono::steady_clock::now() - start; |
|
|
|
|
|
|
|
start = std::chrono::steady_clock::now(); |
|
|
|
{ |
|
|
|
size_t acc = 0; |
|
|
|
gp::repeat(FUZZ_STRENGTH, [&](){ |
|
|
|
void* ptr; |
|
|
|
auto sz = get_random_mem_qt(); |
|
|
|
size_t tries = 0; |
|
|
|
std::shuffle( |
|
|
|
ptr_set.begin(), |
|
|
|
ptr_set.end(), |
|
|
|
rng |
|
|
|
); |
|
|
|
ptr = malloc(sz); |
|
|
|
acc+=1; |
|
|
|
while(acc > 20) |
|
|
|
{ |
|
|
|
void* free_ptr = ptr_set.back(); |
|
|
|
free(free_ptr); |
|
|
|
acc -= 1; |
|
|
|
ptr_set.pop_back(); |
|
|
|
gp_config::assertion(++tries <= store.size(), "infinite fuzzing"); |
|
|
|
} |
|
|
|
ptr_set.emplace_back(ptr); |
|
|
|
}); |
|
|
|
for(auto ptr : ptr_set) |
|
|
|
{ |
|
|
|
void* v = bud.allocate(8); |
|
|
|
if(v == nullptr) throw gp::runtime_error("allocation failed"); |
|
|
|
ptr_set.insert(v); |
|
|
|
free(ptr); |
|
|
|
} |
|
|
|
std::cout << ptr_set.size() << "//" << ptr_set.count(nullptr); |
|
|
|
if(ptr_set.count(nullptr)!=0 || ptr_set.size()!=(4096/8)) throw gp::runtime_error("some allocations failed"); |
|
|
|
res++; |
|
|
|
res += nullptr == bud.allocate(8); |
|
|
|
if(nullptr != bud.allocate(8)) throw gp::runtime_error("allocation succeeded, failure was expected"); |
|
|
|
++res; |
|
|
|
} |
|
|
|
auto reference = std::chrono::steady_clock::now() - start; |
|
|
|
|
|
|
|
|
|
|
|
std::cout |
|
|
|
<< "Fuzzing timed at " |
|
|
|
<< std::chrono::duration_cast<std::chrono::microseconds>(duration).count() |
|
|
|
<< "µs for " |
|
|
|
<< FUZZ_STRENGTH |
|
|
|
<< " (reference: " |
|
|
|
<< std::chrono::duration_cast<std::chrono::microseconds>(reference).count() |
|
|
|
<< "µs)" |
|
|
|
<< std::endl; |
|
|
|
|
|
|
|
return res; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
append_test dummy_654sisd3(new buddy_test{}); |
|
|
|
append_test dummy_df987sd3(new buddy_fuzz_test{781017366}); |
|
|
|
append_test dummy_df4sisd3(new buddy_fuzz_test{}); |