Простым решением является реализация альтернативных функций динамической памяти с использованием mmap()
.
void* alt_malloc( size_t size )
{
void* mem = mmap( NULL, size + sizeof(size_t),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ) ;
if( mem != MAP_FAILED )
{
*(size_t*)mem = size ;
}
else
{
mem = NULL ;
}
return mem + sizeof( size_t) ;
}
void* alt_calloc( size_t nitems, size_t size)
{
return alt_malloc( nitems * size ) ;
}
void alt_free( void* mem )
{
if( mem != NULL) munmap( mem, *((size_t*)mem - 1) ) ;
}
void* alt_realloc( void *old_mem, size_t new_size )
{
void* new_mem = alt_malloc( new_size ) ;
if( new_mem != NULL )
{
size_t old_size = *((size_t*)old_mem - 1) ;
size_t copy_size = old_size > new_size ? new_size : old_size ;
memcpy( new_mem, old_mem, copy_size ) ;
alt_free( old_mem ) ;
}
return new_mem ;
}
Следующий тест:
#define ALLOC_SIZE 1024 * 1024
int main()
{
char* test = alt_malloc( ALLOC_SIZE ) ;
memset( test, 'X', ALLOC_SIZE ) ;
printf( "%p : %c %c\n", test, test[0], test[ALLOC_SIZE-1] ) ;
test = alt_realloc( test, ALLOC_SIZE * 2 ) ;
printf( "%p : %c %c\n", test, test[0], test[ALLOC_SIZE-1] ) ;
alt_free( test ) ;
return 0;
}
Выходы:
0x7f102957d008 : X X
0x7f1028ea3008 : X X
Демонстрация того, что memset()
охватывает экстент начального блока и что realloc создал новый блок и скопировал данные.
Более эффективное, хотя и несколько более сложное решение, заключается в использовании mmap()
выделить альтернативную кучу, а затем реализовать менеджер кучи, работающий с этим блоком, в качестве альтернативы стандартным функциям.Нет недостатка в примерах управления кучей.
Например, вы можете взять распределитель библиотек Newlib C с измененными именами и реализовать системный вызов sbrk()
(снова переименованный для предотвращения конфликтов), используя mmap()
для предоставления памяти альтернативной куче.