LibC: Add malloc.h with some GNU extension

This adds `reallocarray`, `malloc_usable_size`, `mallinfo`, `mallinfo2`
This commit is contained in:
2026-07-07 09:30:54 +03:00
parent 0843b8989d
commit 20392c6cc1
3 changed files with 135 additions and 3 deletions

View File

@@ -0,0 +1,54 @@
#ifndef _MALLOC_H
#define _MALLOC_H 1
#include <sys/cdefs.h>
__BEGIN_DECLS
#define __need_size_t
#include <stddef.h>
struct mallinfo
{
int arena;
int ordblks;
int smblks;
int hblks;
int hblkhd;
int usmblks;
int fsmblks;
int uordblks;
int fordblks;
int keepcost;
};
struct mallinfo2
{
size_t arena;
size_t ordblks;
size_t smblks;
size_t hblks;
size_t hblkhd;
size_t usmblks;
size_t fsmblks;
size_t uordblks;
size_t fordblks;
size_t keepcost;
};
void* malloc(size_t total_size);
void free(void* ptr);
void* realloc(void* ptr, size_t size);
void* calloc(size_t nmemb, size_t size);
void* reallocarray(void* ptr, size_t nmemb, size_t size);
void* aligned_alloc(size_t alignment, size_t size);
int posix_memalign(void** memptr, size_t alignment, size_t size);
size_t malloc_usable_size(void* ptr);
struct mallinfo mallinfo(void);
struct mallinfo2 mallinfo2(void);
__END_DECLS
#endif

View File

@@ -89,6 +89,7 @@ int rand(void);
int rand_r(unsigned* seed);
long random(void);
void* realloc(void* ptr, size_t size);
void* reallocarray(void* ptr, size_t nmemb, size_t size);
char* realpath(const char* __restrict file_name, char* __restrict resolved_name);
unsigned short* seed48(unsigned short seed16v[3]);
int setenv(const char* envname, const char* envval, int overwrite);

View File

@@ -1,7 +1,9 @@
#include <BAN/Atomic.h>
#include <BAN/Math.h>
#include <assert.h>
#include <errno.h>
#include <malloc.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
@@ -220,6 +222,9 @@ static size_t s_allocator_capacity { 0 };
static BitmapAllocator* s_allocators { nullptr };
static pthread_mutex_t s_allocator_lock = PTHREAD_MUTEX_INITIALIZER;
static BAN::Atomic<size_t> s_mmap_count { 0 };
static BAN::Atomic<size_t> s_mmap_bytes { 0 };
void* malloc(size_t total_size)
{
if (total_size >= s_mmap_threshold)
@@ -230,6 +235,9 @@ void* malloc(size_t total_size)
if (address == MAP_FAILED)
return nullptr;
s_mmap_count++;
s_mmap_bytes += mmap_size;
auto& header = static_cast<MmapAllocationHeader*>(address)[0];
header = {
.mmap_size = mmap_size,
@@ -294,6 +302,8 @@ void free(void* ptr)
pthread_mutex_unlock(&s_allocator_lock);
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
s_mmap_count--;
s_mmap_bytes += header.mmap_size;
munmap(static_cast<uint8_t*>(ptr) - header.offset, header.mmap_size);
}
@@ -311,7 +321,7 @@ static size_t allocation_size(void* ptr)
pthread_mutex_unlock(&s_allocator_lock);
const auto& header = static_cast<MmapAllocationHeader*>(ptr)[-1];
return header.mmap_size - sizeof(MmapAllocationHeader);
return header.mmap_size - header.offset;
}
void* realloc(void* ptr, size_t size)
@@ -346,13 +356,14 @@ void* realloc(void* ptr, size_t size)
void* calloc(size_t nmemb, size_t size)
{
const size_t total = nmemb * size;
if (size != 0 && total / size != nmemb)
if (BAN::Math::will_multiplication_overflow(nmemb, size))
{
errno = ENOMEM;
return nullptr;
}
const size_t total = nmemb * size;
void* ptr = malloc(total);
if (ptr == nullptr)
return nullptr;
@@ -361,6 +372,17 @@ void* calloc(size_t nmemb, size_t size)
return ptr;
}
void* reallocarray(void* ptr, size_t nmemb, size_t size)
{
if (BAN::Math::will_multiplication_overflow(nmemb, size))
{
errno = ENOMEM;
return nullptr;
}
return realloc(ptr, nmemb * size);
}
void* aligned_alloc(size_t alignment, size_t size)
{
if (!BAN::Math::is_power_of_two(alignment))
@@ -380,6 +402,9 @@ void* aligned_alloc(size_t alignment, size_t size)
if (address == MAP_FAILED)
return nullptr;
s_mmap_count++;
s_mmap_bytes += mmap_size;
uintptr_t data = reinterpret_cast<uintptr_t>(address) + sizeof(MmapAllocationHeader);
if (auto rem = data % alignment)
data += alignment - rem;
@@ -404,3 +429,55 @@ int posix_memalign(void** memptr, size_t alignment, size_t size)
return (*memptr = aligned_alloc(alignment, size)) ? 0 : -1;
}
size_t malloc_usable_size(void* ptr)
{
if (ptr == nullptr)
return 0;
return allocation_size(ptr);
}
struct mallinfo mallinfo(void)
{
constexpr auto saturate = [](size_t value) -> int {
if (value > static_cast<size_t>(BAN::numeric_limits<int>::max()))
return BAN::numeric_limits<int>::max();
return value;
};
const auto info = mallinfo2();
return {
.arena = saturate(info.arena),
.ordblks = saturate(info.ordblks),
.smblks = saturate(info.smblks),
.hblks = saturate(info.hblks),
.hblkhd = saturate(info.hblkhd),
.usmblks = saturate(info.usmblks),
.fsmblks = saturate(info.fsmblks),
.uordblks = saturate(info.uordblks),
.fordblks = saturate(info.fordblks),
.keepcost = saturate(info.keepcost),
};
}
struct mallinfo2 mallinfo2(void)
{
struct mallinfo2 info {};
pthread_mutex_lock(&s_allocator_lock);
info.arena = s_allocator_count * s_allocator_size;
for (size_t i = 0; i < s_allocator_count; i++)
{
const size_t total_mem = s_allocators[i].total_chunks * s_allocator_chunk_size;
const size_t free_mem = s_allocators[i].free_chunks * s_allocator_chunk_size;
info.fordblks += free_mem;
info.uordblks += total_mem - free_mem;
}
pthread_mutex_unlock(&s_allocator_lock);
info.hblks = s_mmap_count.load();
info.hblkhd = s_mmap_bytes.load();
info.uordblks += info.hblkhd;
return info;
}