assert(invalid_ptr_realloc!=nullptr,"should have returned a 10 char buf and ignored invalid ptr");
eos_assert(invalid_ptr_realloc!=nullptr,"should have returned a 10 char buf and ignored invalid ptr");
assert(nullptr_realloc<invalid_ptr_realloc,"should have created invalid_ptr_realloc after nullptr_realloc");// test specific to implementation (can remove for refactor)
eos_assert(nullptr_realloc<invalid_ptr_realloc,"should have created invalid_ptr_realloc after nullptr_realloc");// test specific to implementation (can remove for refactor)
}
}
// this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time)
// this test verifies that malloc can allocate 15 64K pages and treat them as one big heap space (if sbrk is not called in the mean time)
voidtest_memory::test_memory_hunk()
voidtest_memory::test_memory_hunk()
{
{
// try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header)
// try to allocate the largest buffer we can, which is 15 contiguous 64K pages (with the 4 char space for the ptr header)
char*ptr1=(char*)eosio::malloc(15*64*1024-4);
char*ptr1=(char*)malloc(15*64*1024-4);
assert(ptr1!=nullptr,"should have allocated a ~983K char buf");
eos_assert(ptr1!=nullptr,"should have allocated a ~983K char buf");
}
}
voidtest_memory::test_memory_hunks()
voidtest_memory::test_memory_hunks()
{
{
// leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary,
// leave 784 bytes of initial buffer to allocate later (rounds up to nearest 8 byte boundary,
// 16 bytes bigger than remainder left below in 15 64K page heap))
// 16 bytes bigger than remainder left below in 15 64K page heap))
char*ptr1=(char*)eosio::malloc(7404);
char*ptr1=(char*)malloc(7404);
assert(ptr1!=nullptr,"should have allocated a 7404 char buf");
eos_assert(ptr1!=nullptr,"should have allocated a 7404 char buf");
char*last_ptr=nullptr;
char*last_ptr=nullptr;
// 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate
// 96 * (10 * 1024 - 15) => 15 ~64K pages with 768 byte buffer left to allocate
for(inti=0;i<96;++i)
for(inti=0;i<96;++i)
{
{
char*ptr2=(char*)eosio::malloc(10*1024-15);
char*ptr2=(char*)malloc(10*1024-15);
assert(ptr2!=nullptr,"should have allocated a ~10K char buf");
eos_assert(ptr2!=nullptr,"should have allocated a ~10K char buf");
if(last_ptr!=nullptr)
if(last_ptr!=nullptr)
{
{
// - 15 rounds to -8
// - 15 rounds to -8
assert(last_ptr+10*1024-8==ptr2,"should allocate the very next ptr");// test specific to implementation (can remove for refactor)
eos_assert(last_ptr+10*1024-8==ptr2,"should allocate the very next ptr");// test specific to implementation (can remove for refactor)
}
}
last_ptr=ptr2;
last_ptr=ptr2;
}
}
// try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776
// try to allocate a buffer slightly larger than the remaining buffer| 765 + 4 rounds to 776
char*ptr3=(char*)eosio::malloc(765);
char*ptr3=(char*)malloc(765);
assert(ptr3!=nullptr,"should have allocated a 772 char buf");
eos_assert(ptr3!=nullptr,"should have allocated a 772 char buf");
assert(ptr1+7408==ptr3,"should allocate the very next ptr after ptr1 in initial heap");// test specific to implementation (can remove for refactor)
eos_assert(ptr1+7408==ptr3,"should allocate the very next ptr after ptr1 in initial heap");// test specific to implementation (can remove for refactor)
// use all but 8 chars
// use all but 8 chars
char*ptr4=(char*)eosio::malloc(764);
char*ptr4=(char*)malloc(764);
assert(ptr4!=nullptr,"should have allocated a 764 char buf");
eos_assert(ptr4!=nullptr,"should have allocated a 764 char buf");
assert(last_ptr+10*1024-8==ptr4,"should allocate the very next ptr after last_ptr at end of contiguous heap");// test specific to implementation (can remove for refactor)
eos_assert(last_ptr+10*1024-8==ptr4,"should allocate the very next ptr after last_ptr at end of contiguous heap");// test specific to implementation (can remove for refactor)
// use up remaining 8 chars
// use up remaining 8 chars
char*ptr5=(char*)eosio::malloc(4);
char*ptr5=(char*)malloc(4);
assert(ptr5!=nullptr,"should have allocated a 4 char buf");
eos_assert(ptr5!=nullptr,"should have allocated a 4 char buf");
assert(ptr3+776==ptr5,"should allocate the very next ptr after ptr3 in initial heap");// test specific to implementation (can remove for refactor)
eos_assert(ptr3+776==ptr5,"should allocate the very next ptr after ptr3 in initial heap");// test specific to implementation (can remove for refactor)
// nothing left to allocate
// nothing left to allocate
char*ptr6=(char*)eosio::malloc(4);
char*ptr6=(char*)malloc(4);
assert(ptr6==nullptr,"should not have allocated a char buf");
eos_assert(ptr6==nullptr,"should not have allocated a char buf");
}
}
voidtest_memory::test_memory_hunks_disjoint()
voidtest_memory::test_memory_hunks_disjoint()
{
{
// leave 8 bytes of initial buffer to allocate later
// leave 8 bytes of initial buffer to allocate later
char*ptr1=(char*)eosio::malloc(8*1024-12);
char*ptr1=(char*)malloc(8*1024-12);
assert(ptr1!=nullptr,"should have allocated a 8184 char buf");
eos_assert(ptr1!=nullptr,"should have allocated a 8184 char buf");
// can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part
// can only make 14 extra (64K) heaps for malloc, since calls to sbrk will eat up part
// allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow
// allocates a new heap for each request, since sbrk call doesn't allow contiguous heaps to grow
loop_ptr1[i]=(char*)eosio::malloc(64*1024-28);
loop_ptr1[i]=(char*)malloc(64*1024-28);
assert(loop_ptr1[i]!=nullptr,"should have allocated a 64K char buf");
eos_assert(loop_ptr1[i]!=nullptr,"should have allocated a 64K char buf");
assert(sbrk(4)!=nullptr,"should be able to allocate 8 bytes");
eos_assert(sbrk(4)!=nullptr,"should be able to allocate 8 bytes");
}
}
// the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls
// the 15th extra heap is reduced in size because of the 14 * 8 bytes allocated by sbrk calls
// will leave 8 bytes to allocate later (verifying that we circle back in the list
// will leave 8 bytes to allocate later (verifying that we circle back in the list
char*ptr2=(char*)eosio::malloc(65412);
char*ptr2=(char*)malloc(65412);
assert(ptr2!=nullptr,"should have allocated a 65412 char buf");
eos_assert(ptr2!=nullptr,"should have allocated a 65412 char buf");
char*loop_ptr2[14];
char*loop_ptr2[14];
for(inti=0;i<14;++i)
for(inti=0;i<14;++i)
{
{
// 12 char buffer to leave 8 bytes for another pass
// 12 char buffer to leave 8 bytes for another pass
loop_ptr2[i]=(char*)eosio::malloc(12);
loop_ptr2[i]=(char*)malloc(12);
assert(loop_ptr2[i]!=nullptr,"should have allocated a 12 char buf");
eos_assert(loop_ptr2[i]!=nullptr,"should have allocated a 12 char buf");
assert(loop_ptr1[i]+64*1024-24==loop_ptr2[i],"loop_ptr2[i] should be very next pointer after loop_ptr1[i]");
eos_assert(loop_ptr1[i]+64*1024-24==loop_ptr2[i],"loop_ptr2[i] should be very next pointer after loop_ptr1[i]");
}
}
// this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining
// this shows that searching for free ptrs starts at the last loop to find free memory, not at the begining
char*ptr3=(char*)eosio::malloc(4);
char*ptr3=(char*)malloc(4);
assert(ptr3!=nullptr,"should have allocated a 4 char buf");
eos_assert(ptr3!=nullptr,"should have allocated a 4 char buf");
assert(loop_ptr2[13]+16==ptr3,"should allocate the very next ptr after loop_ptr2[13]");// test specific to implementation (can remove for refactor)
eos_assert(loop_ptr2[13]+16==ptr3,"should allocate the very next ptr after loop_ptr2[13]");// test specific to implementation (can remove for refactor)
char*ptr4=(char*)eosio::malloc(4);
char*ptr4=(char*)malloc(4);
assert(ptr4!=nullptr,"should have allocated a 4 char buf");
eos_assert(ptr4!=nullptr,"should have allocated a 4 char buf");
assert(ptr2+65416==ptr4,"should allocate the very next ptr after ptr2 in last heap");// test specific to implementation (can remove for refactor)
eos_assert(ptr2+65416==ptr4,"should allocate the very next ptr after ptr2 in last heap");// test specific to implementation (can remove for refactor)
char*ptr5=(char*)eosio::malloc(4);
char*ptr5=(char*)malloc(4);
assert(ptr5!=nullptr,"should have allocated a 4 char buf");
eos_assert(ptr5!=nullptr,"should have allocated a 4 char buf");
assert(ptr1+8184==ptr5,"should allocate the very next ptr after ptr1 in last heap");// test specific to implementation (can remove for refactor)
eos_assert(ptr1+8184==ptr5,"should allocate the very next ptr after ptr1 in last heap");// test specific to implementation (can remove for refactor)
// will eat up remaining memory (14th heap already used up)
// will eat up remaining memory (14th heap already used up)
char*loop_ptr3[13];
char*loop_ptr3[13];
for(inti=0;i<13;++i)
for(inti=0;i<13;++i)
{
{
// 4 char buffer to use up buffer
// 4 char buffer to use up buffer
loop_ptr3[i]=(char*)eosio::malloc(4);
loop_ptr3[i]=(char*)malloc(4);
assert(loop_ptr3[i]!=nullptr,"should have allocated a 4 char buf");
eos_assert(loop_ptr3[i]!=nullptr,"should have allocated a 4 char buf");
assert(loop_ptr2[i]+16==loop_ptr3[i],"loop_ptr3[i] should be very next pointer after loop_ptr2[i]");
eos_assert(loop_ptr2[i]+16==loop_ptr3[i],"loop_ptr3[i] should be very next pointer after loop_ptr2[i]");
}
}
char*ptr6=(char*)eosio::malloc(4);
char*ptr6=(char*)malloc(4);
assert(ptr6==nullptr,"should not have allocated a char buf");
eos_assert(ptr6==nullptr,"should not have allocated a char buf");
eosio::free(loop_ptr1[3]);
free(loop_ptr1[3]);
eosio::free(loop_ptr2[3]);
free(loop_ptr2[3]);
eosio::free(loop_ptr3[3]);
free(loop_ptr3[3]);
char*slot3_ptr[64];
char*slot3_ptr[64];
for(inti=0;i<64;++i)
for(inti=0;i<64;++i)
{
{
slot3_ptr[i]=(char*)eosio::malloc(1020);
slot3_ptr[i]=(char*)malloc(1020);
assert(slot3_ptr[i]!=nullptr,"should have allocated a 1020 char buf");
eos_assert(slot3_ptr[i]!=nullptr,"should have allocated a 1020 char buf");
if(i==0)
if(i==0)
assert(loop_ptr1[3]==slot3_ptr[0],"loop_ptr1[3] should be very next pointer after slot3_ptr[0]");
eos_assert(loop_ptr1[3]==slot3_ptr[0],"loop_ptr1[3] should be very next pointer after slot3_ptr[0]");
else
else
assert(slot3_ptr[i-1]+1024==slot3_ptr[i],"slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]");
eos_assert(slot3_ptr[i-1]+1024==slot3_ptr[i],"slot3_ptr[i] should be very next pointer after slot3_ptr[i-1]");
}
}
char*ptr7=(char*)eosio::malloc(4);
char*ptr7=(char*)malloc(4);
assert(ptr7==nullptr,"should not have allocated a char buf");
eos_assert(ptr7==nullptr,"should not have allocated a char buf");