Kernel: kmalloc now detects corruption

Kmalloc checks if its nodes have corrupted. This was happening
because of stack overflow.
This commit is contained in:
Bananymous 2023-04-11 23:36:46 +03:00
parent 809eb2fe3e
commit a0bd3dc54f
1 changed files with 45 additions and 6 deletions

View File

@ -4,6 +4,8 @@
#include <kernel/kprint.h> #include <kernel/kprint.h>
#include <kernel/multiboot.h> #include <kernel/multiboot.h>
#include <kernel/Thread.h>
#define MB (1 << 20) #define MB (1 << 20)
static constexpr size_t s_kmalloc_min_align = alignof(max_align_t); static constexpr size_t s_kmalloc_min_align = alignof(max_align_t);
@ -55,6 +57,7 @@ private:
uint8_t m_data[0]; uint8_t m_data[0];
}; };
static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align); static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align);
struct kmalloc_info struct kmalloc_info
{ {
static constexpr uintptr_t base = 0x00400000; static constexpr uintptr_t base = 0x00400000;
@ -182,6 +185,32 @@ void kmalloc_dump_info()
kprintln(" free: 0x{8H}", s_kmalloc_fixed_info.free); kprintln(" free: 0x{8H}", s_kmalloc_fixed_info.free);
} }
static bool is_corrupted()
{
auto& info = s_kmalloc_info;
auto* temp = info.first();
for (; temp->end() <= info.end; temp = temp->after());
return (uintptr_t)temp != info.end;
}
static void debug_dump()
{
auto& info = s_kmalloc_info;
uint32_t used = 0;
uint32_t free = 0;
for (auto* node = info.first(); node->data() <= info.end; node = node->after())
{
(node->used() ? used : free) += sizeof(kmalloc_node) + node->size_no_align();
dprintln("{} node {H} -> {H}", node->used() ? "used" : "free", node->data(), node->end());
}
dprintln("total used: {}", used);
dprintln("total free: {}", free);
dprintln(" {}", used + free);
}
static void* kmalloc_fixed() static void* kmalloc_fixed()
{ {
auto& info = s_kmalloc_fixed_info; auto& info = s_kmalloc_fixed_info;
@ -282,10 +311,7 @@ static void* kmalloc_impl(size_t size, size_t align)
void* kmalloc(size_t size) void* kmalloc(size_t size)
{ {
void* res = kmalloc(size, s_kmalloc_min_align); return kmalloc(size, s_kmalloc_min_align);
if (res == nullptr)
dwarnln("could not allocate {} bytes", size);
return res;
} }
static constexpr bool is_power_of_two(size_t value) static constexpr bool is_power_of_two(size_t value)
@ -297,7 +323,6 @@ static constexpr bool is_power_of_two(size_t value)
void* kmalloc(size_t size, size_t align) void* kmalloc(size_t size, size_t align)
{ {
const kmalloc_info& info = s_kmalloc_info; const kmalloc_info& info = s_kmalloc_info;
if (size == 0 || size >= info.size) if (size == 0 || size >= info.size)
@ -316,7 +341,19 @@ void* kmalloc(size_t size, size_t align)
if (ptrdiff_t rem = size % s_kmalloc_min_align) if (ptrdiff_t rem = size % s_kmalloc_min_align)
size += s_kmalloc_min_align - rem; size += s_kmalloc_min_align - rem;
return kmalloc_impl(size, align);
ASSERT(!is_corrupted());
if (void* res = kmalloc_impl(size, align))
return res;
dwarnln("could not allocate {H} bytes ({} aligned)", size, align);
dwarnln(" {6H} free (fixed)", s_kmalloc_fixed_info.free);
dwarnln(" {6H} free", s_kmalloc_info.free);
debug_dump();
Debug::dump_stack_trace();
return nullptr;
} }
void kfree(void* address) void kfree(void* address)
@ -362,6 +399,8 @@ void kfree(void* address)
} }
else if (s_kmalloc_info.base <= address_uint && address_uint < s_kmalloc_info.end) else if (s_kmalloc_info.base <= address_uint && address_uint < s_kmalloc_info.end)
{ {
ASSERT(!is_corrupted());
auto& info = s_kmalloc_info; auto& info = s_kmalloc_info;
auto* node = info.from_address(address); auto* node = info.from_address(address);