From 2b324ac62ddeac3683fbd4d4939c1bfdd887acd4 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 29 Jan 2024 21:47:24 +0100 Subject: [PATCH] Implement malloc with a working free --- core/uaddrspace.c | 5 ++- userspace/assert.h | 6 +-- userspace/libc.c | 102 ++++++++++++++++++++++++++++++------------ userspace/main_user.c | 24 +++++++--- 4 files changed, 97 insertions(+), 40 deletions(-) diff --git a/core/uaddrspace.c b/core/uaddrspace.c index efd224c..6f4a4ee 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -5,6 +5,7 @@ #include "list.h" #include "mem.h" #include "mmuContext.h" +#include "paging.h" #include "process.h" #include "stdarg.h" #include "thread.h" @@ -78,7 +79,7 @@ int uAddrSpaceDelete(struct uAddrSpace *addr) // TODO Implement me with real ressources assertmsg(reg->res == NULL, "Unsupported mapper ressource"); // This is memory allocated for the heap just unmap it to free it - pr_devel("Freeing heap for process %s\n", processGetName(addr->process)); + pr_devel("Freeing heap 0x%lx for process %s\n", reg->addr, processGetName(addr->process)); pageUnmap(reg->addr); free(reg); } @@ -127,7 +128,7 @@ int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) struct uAddrVirtualReg *newReg; int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; - pr_devel("Checking %lx inside %lx and %lx\n", addr, as->heapStart, as->heapStart +as->heapSize); + pr_devel("Checking 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart, as->heapStart +as->heapSize); if (addr < as->heapStart || addr >= as->heapStart + as->heapSize) { return -1; } diff --git a/userspace/assert.h b/userspace/assert.h index 9465514..94e7c5b 100644 --- a/userspace/assert.h +++ b/userspace/assert.h @@ -5,8 +5,7 @@ do { \ if (!(p)) { \ printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \ - while (1) { \ - } \ + _exit(-1); \ } \ } while (0) @@ -15,7 +14,6 @@ if (!(p)) { \ printf("BUG at %s:%d assert(%s)\n", __FILE__, __LINE__, #p); \ printf(__VA_ARGS__); \ - while (1) { \ - } \ + _exit(-1); \ } \ } while (0) diff --git a/userspace/libc.c b/userspace/libc.c index 80df4e9..4b1dff0 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -1,4 +1,5 @@ #include "libc.h" +#include "list.h" #include "minmax.h" #include "swintr.h" #include "syscall.h" @@ -585,45 +586,90 @@ void *sbrk(intptr_t increment) if (increment == 0) { return current; } - if (syscall1(SYSCALL_ID_BRK, (uintptr_t)current + increment)) { + if ((uintptr_t)syscall1(SYSCALL_ID_BRK, (uintptr_t)current + increment) < ((uintptr_t)current + increment)) { // errno = ENOMEM return (void *)-1; } return current; } -static char *heapTop = 0; -static char *heapFree = 0; -static char *lastAlloc = 0; +// Malloc internal +struct heapBlock { + size_t size; + struct heapBlock *next, *prev; + int free; +}; + +static struct heapBlock *heapBlkList = NULL; + +struct heapBlock *findFreeBlock(size_t size){ + struct heapBlock *cur = NULL; + struct heapBlock *found = NULL; + int idx; + list_foreach(heapBlkList, cur, idx){ + if(cur->size >= size && cur->free){ + found = cur; + break; + } + } + return found; +} + +struct heapBlock *allocNewBlock(size_t size) { + struct heapBlock *blk = sbrk(size + sizeof(struct heapBlock)); + struct heapBlock *head = sbrk(0); + size_t blkSize = (intptr_t)head - (intptr_t)blk - sizeof(struct heapBlock); + if (blk == (void *)-1) { + return NULL; + } + blk->size = blkSize; + blk->free = 1; + list_add_tail(heapBlkList, blk); + return blk; +} + +struct heapBlock *splitBlock(struct heapBlock *blk, size_t neededSize) +{ + if (blk->size < neededSize + sizeof(struct heapBlock) + 1) { + return NULL; + } + struct heapBlock *newBlk = (struct heapBlock *)((uintptr_t)(blk + 1) + neededSize); + newBlk->free = 1; + newBlk->size = blk->size - sizeof(struct heapBlock) - neededSize; + blk->size = neededSize; + return newBlk; +} void *malloc(size_t size) { - if (heapTop == 0) { - heapTop = heapFree = sbrk(0); - } else { - heapTop = sbrk(0); - } + if (size == 0) + return NULL; - if (heapFree + size + sizeof(size) > heapTop) { - if (brk(heapTop + size + sizeof(size))) - return NULL; + struct heapBlock *blk = findFreeBlock(size); + if (!blk) + blk = allocNewBlock(size); + if (!blk) + return NULL; + struct heapBlock *remainBlock = splitBlock(blk, size); + if (remainBlock) { + list_add_head(heapBlkList, remainBlock); } - - *((size_t *)heapFree) = size; - heapFree += sizeof(size); - lastAlloc = heapFree; - heapFree += size; - return lastAlloc; + blk->free = 0; + return blk + 1; // return the area after the blk description } -void free(void *ptr) -{ - void *size_addr = ((char *)ptr - sizeof(size_t)); - size_t size = *(size_t *)size_addr; - if (heapFree - size == ptr) { - heapFree = size_addr; - } - //TODO ELSE - - return; +struct heapBlock *getHeapBlock(void *ptr) { + return (struct heapBlock *)ptr - 1; } + + +void free(void *ptr){ + if(!ptr) + return; + + struct heapBlock *blk = getHeapBlock(ptr); + + assert(blk->free == 0); + blk->free = 1; +} + diff --git a/userspace/main_user.c b/userspace/main_user.c index f28e678..420b3bc 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -24,21 +24,33 @@ int func_suicide() char *initialHeap = 0; int func_alloc() { - if (initialHeap == 0) { - initialHeap = sbrk(0); + initialHeap = sbrk(0); } printf("Testing allocation\n"); - int allocSize = 4096 * 2; + int allocSize = 4096 * 2; char *currentHeap = sbrk(0); if (currentHeap - initialHeap < allocSize) { - brk(initialHeap + allocSize); + brk(initialHeap + allocSize); } int *allocatedData = (int *)initialHeap; for (unsigned int i = 0; i < allocSize / sizeof(int); i++) { - allocatedData[i] = i; + allocatedData[i] = i; } - printf("Success\n"); + printf("Success\nTesting malloc\n"); + uintptr_t heap = (uintptr_t)sbrk(0); + + for (int i = 0; i < 12; i++) { + void *ptr = malloc(1 << i); + printf("malloc size %d: 0x%p\n", (1 << i), ptr); + if (ptr == NULL) { + printf("Malloc failed\n"); + } + memset(ptr, 0, 1 << i); + free(ptr); + } + uintptr_t newHeap = (uintptr_t)sbrk(0); + printf("Malloc used %dB\n", newHeap - heap); return 0; }