summaryrefslogtreecommitdiff
path: root/userland
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-03-21 22:37:24 +0100
committerAnton Kling <anton@kling.gg>2024-03-21 22:42:44 +0100
commit1217ad6470585cd57c17eaec020598457cd89230 (patch)
tree545e88545aca311411608446d6958e31f8d7e637 /userland
parenta950021011e41b7d4fd285dde278cf9b06f89574 (diff)
libc: fix malloc implementation
I don't know what was wrong but memory allocations were failing. I removed the old code and replaced it with the malloc implementation which exists in the kernel. Now it doesn't crash so I guess it is fine ¯\_(ツ)_/¯
Diffstat (limited to 'userland')
-rw-r--r--userland/libc/malloc/malloc.c193
1 files changed, 97 insertions, 96 deletions
diff --git a/userland/libc/malloc/malloc.c b/userland/libc/malloc/malloc.c
index 79d1d5f..d1bc5ca 100644
--- a/userland/libc/malloc/malloc.c
+++ b/userland/libc/malloc/malloc.c
@@ -1,41 +1,32 @@
#include <assert.h>
-#include <errno.h>
-#include <malloc/malloc.h>
#include <math.h>
#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
+#include <stdlib.h>
+#include <typedefs.h>
#define NEW_ALLOC_SIZE 0x20000
-#define MALLOC_HEADER_MAGIC 0x1337F00D
-#define MALLOC_HEADER_PAD 0x11223344
#define IS_FREE (1 << 0)
#define IS_FINAL (1 << 1)
typedef struct MallocHeader {
- uint32_t magic;
- uint32_t size;
- uint8_t flags;
+ u64 magic;
+ u32 size;
+ u8 flags;
struct MallocHeader *n;
} MallocHeader;
-uint64_t delta_page(uint64_t a) { return 0x1000 - (a % 0x1000); }
+u64 delta_page(u64 a) {
+ return 0x1000 - (a % 0x1000);
+}
MallocHeader *head = NULL;
MallocHeader *final = NULL;
-uint32_t total_heap_size = 0;
+u32 total_heap_size = 0;
int init_heap(void) {
head = (MallocHeader *)sbrk(NEW_ALLOC_SIZE);
- if ((void *)-1 == head) {
- perror("sbrk");
- exit(1);
- }
total_heap_size += NEW_ALLOC_SIZE - sizeof(MallocHeader);
- head->magic = MALLOC_HEADER_MAGIC;
+ head->magic = 0xdde51ab9410268b1;
head->size = NEW_ALLOC_SIZE - sizeof(MallocHeader);
head->flags = IS_FREE | IS_FINAL;
head->n = NULL;
@@ -49,27 +40,37 @@ int add_heap_memory(size_t min_desired) {
allocation_size += delta_page(allocation_size);
void *p;
if ((void *)(-1) == (p = (void *)sbrk(allocation_size))) {
- perror("sbrk");
return 0;
}
total_heap_size += allocation_size - sizeof(MallocHeader);
void *e = final;
- e = (void *)((uint32_t)e + final->size);
+ e = (void *)((u32)e + final->size);
if (p == e) {
final->size += allocation_size - sizeof(MallocHeader);
return 1;
}
MallocHeader *new_entry = p;
- new_entry->magic = MALLOC_HEADER_MAGIC;
new_entry->size = allocation_size - sizeof(MallocHeader);
new_entry->flags = IS_FREE | IS_FINAL;
new_entry->n = NULL;
+ new_entry->magic = 0xdde51ab9410268b1;
final->n = new_entry;
final = new_entry;
return 1;
}
-MallocHeader *next_header(MallocHeader *a) { return a->n; }
+MallocHeader *next_header(MallocHeader *a) {
+ assert(a->magic == 0xdde51ab9410268b1);
+ if (a->n) {
+ if (a->n->magic != 0xdde51ab9410268b1) {
+ printf("Real magic value is: %x\n", a->n->magic);
+ printf("location: %x\n", &(a->n->magic));
+ assert(0);
+ }
+ return a->n;
+ }
+ return NULL;
+}
MallocHeader *next_close_header(MallocHeader *a) {
if (!a) {
@@ -77,127 +78,107 @@ MallocHeader *next_close_header(MallocHeader *a) {
for (;;)
;
}
- if (a->flags & IS_FINAL)
+ if (a->flags & IS_FINAL) {
return NULL;
+ }
return next_header(a);
}
-MallocHeader *find_free_entry(uint32_t s, int align) {
+MallocHeader *find_free_entry(u32 s) {
// A new header is required as well as the newly allocated chunk
- if (!head)
+ s += sizeof(MallocHeader);
+ if (!head) {
init_heap();
+ }
MallocHeader *p = head;
for (; p; p = next_header(p)) {
- if (!(p->flags & IS_FREE))
+ assert(p->magic == 0xdde51ab9410268b1);
+ if (!(p->flags & IS_FREE)) {
continue;
- uint64_t required_size = s;
- if (align) {
- void *addy = p;
- addy = (void *)((uint32_t)addy + sizeof(MallocHeader));
- uint64_t d = delta_page((uint32_t)addy);
- if (d < sizeof(MallocHeader) && d != 0)
- continue;
- required_size += d;
}
- if (p->size < required_size)
+ u64 required_size = s;
+ if (p->size < required_size) {
continue;
+ }
return p;
}
return NULL;
}
void merge_headers(MallocHeader *b) {
- if (!(b->flags & IS_FREE))
+ if (!(b->flags & IS_FREE)) {
return;
+ }
MallocHeader *n = next_close_header(b);
- if (!n)
+ if (!n) {
return;
+ }
- if (!(n->flags & IS_FREE))
+ if (!(n->flags & IS_FREE)) {
return;
+ }
- // Remove the next header and just increase the newly freed header
b->size += n->size;
b->flags |= n->flags & IS_FINAL;
b->n = n->n;
- if (n == final)
+ if (n == final) {
final = b;
+ }
}
-extern int errno;
-// https://pubs.opengroup.org/onlinepubs/9699919799/
-void *int_malloc(size_t s, int align) {
- if (!head)
- init_heap();
+void *malloc(size_t s) {
+ s += 0x1000;
size_t n = s;
- MallocHeader *free_entry = find_free_entry(s, align);
+ MallocHeader *free_entry = find_free_entry(s);
if (!free_entry) {
if (!add_heap_memory(s)) {
- errno = ENOMEM;
- printf("ENOMEM\n");
+ assert(0);
return NULL;
}
- return int_malloc(s, align);
+ return malloc(s);
}
- void *rc = (void *)((uint32_t)free_entry + sizeof(MallocHeader));
-
- if (align) {
- uint64_t d = delta_page((uint32_t)rc);
- n = d;
- n -= sizeof(MallocHeader);
- }
+ void *rc = (void *)(free_entry + 1);
// Create a new header
- MallocHeader *new_entry =
- (MallocHeader *)((uint32_t)free_entry + n + sizeof(MallocHeader));
- new_entry->magic = MALLOC_HEADER_MAGIC;
+ MallocHeader *new_entry = (MallocHeader *)((uintptr_t)rc + n);
new_entry->flags = free_entry->flags;
new_entry->n = free_entry->n;
new_entry->size = free_entry->size - n - sizeof(MallocHeader);
- if (free_entry == final)
+ new_entry->magic = 0xdde51ab9410268b1;
+
+ if (free_entry == final) {
final = new_entry;
+ }
merge_headers(new_entry);
// Modify the free entry
free_entry->size = n;
free_entry->flags = 0;
free_entry->n = new_entry;
-
- if (align && ((uint32_t)rc % 0x1000) != 0) {
- void *c = int_malloc(s, 1);
- free(rc);
- rc = c;
- return rc;
+ free_entry->magic = 0xdde51ab9410268b1;
+ for (int i = 0; i < s; i++) {
+ *(char *)rc = 'A';
}
- randomfill(rc, s);
- return rc;
-}
-
-void *malloc(size_t s) { return int_malloc(s + 1, 0); }
-
-// https://pubs.opengroup.org/onlinepubs/9699919799/
-void *calloc(size_t nelem, size_t elsize) {
- // The calloc() function shall allocate unused space for an array of
- // nelem elements each of whose size in bytes is elsize.
- size_t alloc_size = nelem * elsize;
- void *rc = malloc(alloc_size);
- // The space shall be initialized to all bits 0.
- memset(rc, 0, alloc_size);
return rc;
}
size_t get_mem_size(void *ptr) {
- if (!ptr)
+ if (!ptr) {
return 0;
- return ((MallocHeader *)((u32)ptr - sizeof(MallocHeader)))->size;
+ }
+ return ((MallocHeader *)((uintptr_t)ptr - sizeof(MallocHeader)))->size;
}
void *realloc(void *ptr, size_t size) {
void *rc = malloc(size);
- if (!rc)
+ if (!rc) {
return NULL;
+ }
+ if (!ptr) {
+ return rc;
+ }
size_t l = get_mem_size(ptr);
size_t to_copy = min(l, size);
memcpy(rc, ptr, to_copy);
@@ -205,24 +186,44 @@ void *realloc(void *ptr, size_t size) {
return rc;
}
+// This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+// if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *reallocarray(void *ptr, size_t nmemb, size_t size) {
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 &&
+ SIZE_MAX / nmemb < size) {
+ return NULL;
+ }
+
+ return realloc(ptr, nmemb * size);
+}
+
+void *allocarray(size_t nmemb, size_t size) {
+ return reallocarray(NULL, nmemb, size);
+}
+
+void *calloc(size_t nelem, size_t elsize) {
+ void *rc = allocarray(nelem, elsize);
+ if (!rc) {
+ return NULL;
+ }
+ memset(rc, 0, nelem * elsize);
+ return rc;
+}
+
void free(void *p) {
- if (!p)
+ if (!p) {
return;
+ }
// FIXME: This assumes that p is at the start of a allocated area.
- // Is this a assumption that can be made?
- MallocHeader *h = (MallocHeader *)((uint32_t)p - sizeof(MallocHeader));
- if (MALLOC_HEADER_MAGIC != h->magic) {
-#ifdef LIBC_DEBUG
- printf("LibC Malloc: free() is attempted at the incorrect location or at a corrupted header.\n");
- printf("h->magic: %x\n", h->magic);
- printf("&h->magic: %x\n", &(h->magic));
-#endif
+ // Could this be avoided in a simple way?
+ MallocHeader *h = (MallocHeader *)((uintptr_t)p - sizeof(MallocHeader));
+ assert(h->magic == 0xdde51ab9410268b1);
+ if (h->flags & IS_FREE) {
return;
}
- if (h->flags & IS_FREE)
- return;
- randomfill(p, h->size);
h->flags |= IS_FREE;
merge_headers(h);
}