Implement realloc (#99)

This commit is contained in:
Alex Kotov 2022-06-27 13:32:41 +03:00 committed by GitHub
parent 0922a18e70
commit f5ae8400c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 203 additions and 48 deletions

View File

@ -43,7 +43,6 @@
} \
} while (0)
static void *KernAux_FreeList_calloc (void *malloc, size_t nmemb, size_t size);
static void KernAux_FreeList_free (void *malloc, void *ptr);
static void *KernAux_FreeList_malloc (void *malloc, size_t size);
static void *KernAux_FreeList_realloc(void *malloc, void *ptr, size_t size);
@ -73,7 +72,7 @@ void KernAux_FreeList_init(
) {
KERNAUX_ASSERT(free_list);
free_list->malloc.calloc = KernAux_FreeList_calloc;
free_list->malloc.calloc = NULL;
free_list->malloc.free = KernAux_FreeList_free;
free_list->malloc.malloc = KernAux_FreeList_malloc;
free_list->malloc.realloc = KernAux_FreeList_realloc;
@ -123,35 +122,16 @@ block_found:
UNLOCK(free_list);
}
void *KernAux_FreeList_calloc(
void *const malloc,
const size_t nmemb,
const size_t size
) {
KERNAUX_ASSERT(malloc);
const size_t total_size = nmemb * size;
KERNAUX_ASSERT(total_size >= nmemb);
KERNAUX_ASSERT(total_size >= size);
KERNAUX_ASSERT(total_size / nmemb == size);
void *const ptr = KernAux_FreeList_malloc(malloc, total_size);
if (ptr) memset(ptr, 0, total_size);
return ptr;
}
void KernAux_FreeList_free(void *const malloc, void *const ptr)
{
const KernAux_FreeList free_list = malloc;
KERNAUX_ASSERT(free_list);
if (!ptr) return;
KERNAUX_ASSERT(ptr);
LOCK(free_list);
KernAux_FreeList_Node node =
CONTAINER_OF(ptr, struct KernAux_FreeList_Node, block);
KernAux_FreeList_Node last_node = NULL;
for (
@ -183,9 +163,8 @@ block_added:
void *KernAux_FreeList_malloc(void *const malloc, const size_t size)
{
const KernAux_FreeList free_list = malloc;
KERNAUX_ASSERT(free_list);
if (size == 0) return NULL;
KERNAUX_ASSERT(size);
LOCK(free_list);
@ -226,18 +205,29 @@ void *KernAux_FreeList_malloc(void *const malloc, const size_t size)
void *KernAux_FreeList_realloc(
void *const malloc,
void *const ptr,
const size_t size
void *const old_ptr,
const size_t new_size
) {
const KernAux_FreeList free_list = malloc;
KERNAUX_ASSERT(free_list);
KERNAUX_ASSERT(old_ptr);
KERNAUX_ASSERT(new_size);
KERNAUX_ASSERT(0); // TODO
(void)free_list;
(void)ptr;
(void)size;
LOCK(free_list);
return NULL;
KernAux_FreeList_Node node =
CONTAINER_OF(old_ptr, struct KernAux_FreeList_Node, block);
const size_t old_size = node->size - NODE_HEADER_SIZE;
void *new_ptr = KernAux_FreeList_malloc(free_list, new_size);
if (new_ptr) {
const size_t min_size = old_size < new_size ? old_size : new_size;
memcpy(new_ptr, old_ptr, min_size);
}
UNLOCK(free_list);
return new_ptr;
}
void KernAux_FreeList_defrag(const KernAux_FreeList free_list)

View File

@ -6,13 +6,24 @@
#include <kernaux/generic/malloc.h>
#include <stddef.h>
#include <string.h>
void *KernAux_Malloc_calloc(KernAux_Malloc malloc, size_t nmemb, size_t size)
{
KERNAUX_ASSERT(malloc);
KERNAUX_ASSERT(malloc->calloc);
return malloc->calloc((void*)malloc, nmemb, size);
// Common implementation
const size_t total_size = nmemb * size;
if (!total_size) return NULL;
if (total_size / nmemb != size) return NULL;
// Inherited implementation
if (malloc->calloc) return malloc->calloc((void*)malloc, nmemb, size);
// Default implementation
void *const ptr = KernAux_Malloc_malloc(malloc, total_size);
if (ptr) memset(ptr, 0, total_size);
return ptr;
}
void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
@ -20,6 +31,10 @@ void KernAux_Malloc_free(KernAux_Malloc malloc, void *ptr)
KERNAUX_ASSERT(malloc);
KERNAUX_ASSERT(malloc->free);
// Common implementation
if (!ptr) return;
// Inherited implementation
malloc->free((void*)malloc, ptr);
}
@ -28,6 +43,10 @@ void *KernAux_Malloc_malloc(KernAux_Malloc malloc, size_t size)
KERNAUX_ASSERT(malloc);
KERNAUX_ASSERT(malloc->malloc);
// Common implementation
if (!size) return NULL;
// Inherited implementation
return malloc->malloc((void*)malloc, size);
}
@ -36,5 +55,13 @@ void *KernAux_Malloc_realloc(KernAux_Malloc malloc, void *ptr, size_t size)
KERNAUX_ASSERT(malloc);
KERNAUX_ASSERT(malloc->realloc);
// Common implementation
if (!ptr) return KernAux_Malloc_malloc(malloc, size);
if (!size) {
KernAux_Malloc_free(malloc, ptr);
return NULL;
}
// Inherited implementation
return malloc->realloc((void*)malloc, ptr, size);
}

View File

@ -8,19 +8,55 @@
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
static void test_default();
static void test_cross_zone_defrag();
static void test_calloc();
static void test_calloc_nomem();
static void test_cross_zone_defrag();
static void test_calloc_overflow();
static void test_calloc_zero();
static void test_realloc_alloc();
static void test_realloc_free();
static void test_realloc_memcpy();
static void test_realloc_increase();
static void test_realloc_decrease();
static size_t nodes_count(KernAux_FreeList free_list);
static const char *const hello = "Hello, World!";
void test_main()
{
test_default();
test_cross_zone_defrag();
test_calloc();
test_calloc_nomem();
test_cross_zone_defrag();
test_calloc_overflow();
test_calloc_zero();
test_realloc_alloc();
test_realloc_free();
test_realloc_memcpy();
test_realloc_increase();
test_realloc_decrease();
}
size_t nodes_count(const KernAux_FreeList free_list)
{
size_t nodes_count = 0;
for (
KernAux_FreeList_Node item_node = free_list->head;
item_node;
item_node = item_node->next
) {
++nodes_count;
}
return nodes_count;
}
void test_default()
@ -65,6 +101,16 @@ void test_default()
assert(ptr7 == ptr2);
}
void test_cross_zone_defrag()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, &zone[0], 500);
KernAux_FreeList_add_zone(&free_list, &zone[500], 500);
assert(nodes_count(&free_list) == 1);
}
void test_calloc()
{
char zone[1000];
@ -86,21 +132,113 @@ void test_calloc_nomem()
assert(ptr == NULL);
}
void test_cross_zone_defrag()
void test_calloc_overflow()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, &zone[0], 500);
KernAux_FreeList_add_zone(&free_list, &zone[500], 500);
size_t nodes_count = 0;
for (
KernAux_FreeList_Node item_node = free_list.head;
item_node;
item_node = item_node->next
) {
++nodes_count;
KernAux_FreeList_add_zone(&free_list, zone, SIZE_MAX);
{
void *const ptr = KernAux_Malloc_calloc(&free_list.malloc, 2, SIZE_MAX);
assert(ptr == NULL);
}
{
void *const ptr = KernAux_Malloc_calloc(&free_list.malloc, SIZE_MAX, 2);
assert(ptr == NULL);
}
assert(nodes_count == 1);
}
void test_calloc_zero()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
void *const ptr1 = KernAux_Malloc_calloc(&free_list.malloc, 0, 900);
assert(ptr1 == NULL);
void *const ptr2 = KernAux_Malloc_calloc(&free_list.malloc, 900, 0);
assert(ptr2 == NULL);
}
void test_realloc_alloc()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
void *const ptr = KernAux_Malloc_realloc(&free_list.malloc, NULL, 900);
assert(ptr != NULL);
}
void test_realloc_free()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
void *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 900);
assert(ptr1 != NULL);
void *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 0);
assert(ptr2 == NULL);
void *const ptr3 = KernAux_Malloc_malloc(&free_list.malloc, 900);
assert(ptr3 != NULL);
}
void test_realloc_memcpy()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 400);
assert(ptr1 != NULL);
memset(ptr1, 0, 400);
strcpy(ptr1, hello);
strcpy(&ptr1[400 - strlen(hello) - 1], hello);
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 400);
assert(ptr2 != NULL);
assert(strcmp(ptr2, hello) == 0);
assert(strcmp(&ptr2[400 - strlen(hello) - 1], hello) == 0);
}
void test_realloc_increase()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 300);
assert(ptr1 != NULL);
memset(ptr1, 0, 300);
strcpy(ptr1, hello);
strcpy(&ptr1[300 - strlen(hello) - 1], hello);
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 500);
assert(ptr2 != NULL);
assert(strcmp(ptr2, hello) == 0);
assert(strcmp(&ptr2[300 - strlen(hello) - 1], hello) == 0);
}
void test_realloc_decrease()
{
char zone[1000];
struct KernAux_FreeList free_list = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&free_list, zone, sizeof(zone));
char *const ptr1 = KernAux_Malloc_malloc(&free_list.malloc, 500);
assert(ptr1 != NULL);
memset(ptr1, 0, 300);
strcpy(ptr1, hello);
strcpy(&ptr1[300 - strlen(hello) - 1], hello);
char *const ptr2 = KernAux_Malloc_realloc(&free_list.malloc, ptr1, 300);
assert(ptr2 != NULL);
assert(strcmp(ptr2, hello) == 0);
assert(strcmp(&ptr2[300 - strlen(hello) - 1], hello) == 0);
}