mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:27:35 +00:00
Some improvements to LibC malloc().
This commit is contained in:
parent
85649077cd
commit
526dcafd57
1 changed files with 37 additions and 33 deletions
|
@ -10,19 +10,25 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#define SANITIZE_LIBC_MALLOC
|
|
||||||
#define MALLOC_SCRUB_BYTE 0x85
|
#define MALLOC_SCRUB_BYTE 0x85
|
||||||
#define FREE_SCRUB_BYTE 0x82
|
#define FREE_SCRUB_BYTE 0x82
|
||||||
|
|
||||||
struct MallocHeader {
|
struct MallocHeader {
|
||||||
uint16_t magic;
|
|
||||||
uint16_t first_chunk_index;
|
uint16_t first_chunk_index;
|
||||||
uint16_t chunk_count;
|
uint16_t chunk_count;
|
||||||
uint16_t xorcheck;
|
size_t size;
|
||||||
|
|
||||||
|
uint32_t compute_xorcheck() const
|
||||||
|
{
|
||||||
|
return 0x19820413 ^ ((first_chunk_index << 16) | chunk_count) ^ size;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MALLOC_MAGIC 0x0413 // happy birthday k
|
struct MallocFooter {
|
||||||
#define CHUNK_SIZE 32
|
uint32_t xorcheck;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 8
|
||||||
#define POOL_SIZE 128 * 1024
|
#define POOL_SIZE 128 * 1024
|
||||||
|
|
||||||
static const size_t malloc_budget = POOL_SIZE;
|
static const size_t malloc_budget = POOL_SIZE;
|
||||||
|
@ -35,7 +41,7 @@ static uint32_t s_malloc_sum_free = POOL_SIZE;
|
||||||
void* malloc(size_t size)
|
void* malloc(size_t size)
|
||||||
{
|
{
|
||||||
// We need space for the MallocHeader structure at the head of the block.
|
// We need space for the MallocHeader structure at the head of the block.
|
||||||
size_t real_size = size + sizeof(MallocHeader);
|
size_t real_size = size + sizeof(MallocHeader) + sizeof(MallocFooter);
|
||||||
|
|
||||||
if (s_malloc_sum_free < real_size) {
|
if (s_malloc_sum_free < real_size) {
|
||||||
fprintf(stderr, "malloc(): Out of memory\ns_malloc_sum_free=%u, real_size=%x\n", s_malloc_sum_free, real_size);
|
fprintf(stderr, "malloc(): Out of memory\ns_malloc_sum_free=%u, real_size=%x\n", s_malloc_sum_free, real_size);
|
||||||
|
@ -72,17 +78,18 @@ void* malloc(size_t size)
|
||||||
byte* ptr = ((byte*)header) + sizeof(MallocHeader);
|
byte* ptr = ((byte*)header) + sizeof(MallocHeader);
|
||||||
header->chunk_count = chunks_needed;
|
header->chunk_count = chunks_needed;
|
||||||
header->first_chunk_index = first_chunk;
|
header->first_chunk_index = first_chunk;
|
||||||
header->magic = MALLOC_MAGIC;
|
header->size = size;
|
||||||
header->xorcheck = header->magic ^ header->first_chunk_index ^ header->chunk_count;
|
|
||||||
|
auto* footer = (MallocFooter*)((byte*)header + (header->chunk_count * CHUNK_SIZE) - sizeof(MallocFooter));
|
||||||
|
footer->xorcheck = header->compute_xorcheck();
|
||||||
|
|
||||||
for (size_t k = first_chunk; k < (first_chunk + chunks_needed); ++k)
|
for (size_t k = first_chunk; k < (first_chunk + chunks_needed); ++k)
|
||||||
s_malloc_map[k / 8] |= 1 << (k % 8);
|
s_malloc_map[k / 8] |= 1 << (k % 8);
|
||||||
|
|
||||||
s_malloc_sum_alloc += header->chunk_count * CHUNK_SIZE;
|
s_malloc_sum_alloc += header->chunk_count * CHUNK_SIZE;
|
||||||
s_malloc_sum_free -= header->chunk_count * CHUNK_SIZE;
|
s_malloc_sum_free -= header->chunk_count * CHUNK_SIZE;
|
||||||
#ifdef SANITIZE_LIBC_MALLOC
|
|
||||||
memset(ptr, MALLOC_SCRUB_BYTE, (header->chunk_count * CHUNK_SIZE) - sizeof(MallocHeader));
|
memset(ptr, MALLOC_SCRUB_BYTE, (header->chunk_count * CHUNK_SIZE) - (sizeof(MallocHeader) + sizeof(MallocFooter)));
|
||||||
#endif
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,30 +107,35 @@ void* malloc(size_t size)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void *ptr)
|
static void validate_mallocation(void* ptr, const char* func)
|
||||||
|
{
|
||||||
|
auto* header = (MallocHeader*)((((byte*)ptr) - sizeof(MallocHeader)));
|
||||||
|
if (header->size == 0) {
|
||||||
|
fprintf(stderr, "%s called on bad pointer %p, size=0\n", func, ptr);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
auto* footer = (MallocFooter*)((byte*)header + (header->chunk_count * CHUNK_SIZE) - sizeof(MallocFooter));
|
||||||
|
uint32_t expected_xorcheck = header->compute_xorcheck();
|
||||||
|
if (footer->xorcheck != expected_xorcheck) {
|
||||||
|
fprintf(stderr, "%s called on bad pointer %p, xorcheck=%w (expected %w)\n", func, ptr, footer->xorcheck, expected_xorcheck);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
{
|
{
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
validate_mallocation(ptr, "free()");
|
||||||
auto* header = (MallocHeader*)((((byte*)ptr) - sizeof(MallocHeader)));
|
auto* header = (MallocHeader*)((((byte*)ptr) - sizeof(MallocHeader)));
|
||||||
if (header->magic != MALLOC_MAGIC) {
|
|
||||||
fprintf(stderr, "free() called on bad pointer %p, magic=%w\n", ptr, header->magic);
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
if (header->xorcheck != (header->magic ^ header->first_chunk_index ^ header->chunk_count)) {
|
|
||||||
fprintf(stderr, "free() called on bad pointer %p, xorcheck=%w\n", ptr, header->xorcheck);
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = header->first_chunk_index; i < (header->first_chunk_index + header->chunk_count); ++i)
|
for (unsigned i = header->first_chunk_index; i < (header->first_chunk_index + header->chunk_count); ++i)
|
||||||
s_malloc_map[i / 8] &= ~(1 << (i % 8));
|
s_malloc_map[i / 8] &= ~(1 << (i % 8));
|
||||||
|
|
||||||
s_malloc_sum_alloc -= header->chunk_count * CHUNK_SIZE;
|
s_malloc_sum_alloc -= header->chunk_count * CHUNK_SIZE;
|
||||||
s_malloc_sum_free += header->chunk_count * CHUNK_SIZE;
|
s_malloc_sum_free += header->chunk_count * CHUNK_SIZE;
|
||||||
|
|
||||||
#ifdef SANITIZE_LIBC_MALLOC
|
|
||||||
memset(header, FREE_SCRUB_BYTE, header->chunk_count * CHUNK_SIZE);
|
memset(header, FREE_SCRUB_BYTE, header->chunk_count * CHUNK_SIZE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __malloc_init()
|
void __malloc_init()
|
||||||
|
@ -143,17 +155,9 @@ void* calloc(size_t nmemb, size_t)
|
||||||
|
|
||||||
void* realloc(void *ptr, size_t size)
|
void* realloc(void *ptr, size_t size)
|
||||||
{
|
{
|
||||||
|
validate_mallocation(ptr, "realloc()");
|
||||||
auto* header = (MallocHeader*)((((byte*)ptr) - sizeof(MallocHeader)));
|
auto* header = (MallocHeader*)((((byte*)ptr) - sizeof(MallocHeader)));
|
||||||
if (header->magic != MALLOC_MAGIC) {
|
size_t old_size = header->size;
|
||||||
fprintf(stderr, "realloc() called on bad pointer %p, magic=%w\n", ptr, header->magic);
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
if (header->xorcheck != (header->magic ^ header->first_chunk_index ^ header->chunk_count)) {
|
|
||||||
fprintf(stderr, "realloc() called on bad pointer %p, xorcheck=%w\n", ptr, header->xorcheck);
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t old_size = header->chunk_count * CHUNK_SIZE;
|
|
||||||
auto* new_ptr = malloc(size);
|
auto* new_ptr = malloc(size);
|
||||||
memcpy(new_ptr, ptr, old_size);
|
memcpy(new_ptr, ptr, old_size);
|
||||||
return new_ptr;
|
return new_ptr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue