fix(mem): typo = instead of - corrupted initial heap block size!! - #102
Conversation
In memory_init(), line 46 assigns heap_end = HEAP_VIRT_START instead of subtracting, due to a =/- typo. This makes the first free block claim a size of ~3.2 GB (0xCFFFFFF0), so any large malloc returns pointers into unmapped virtual memory (page fault on write). It also resets heap_end to the heap start, so heap_grow() would remap fresh physical frames over existing blocks, corrupting the heap and leaking PMM frames.
|
LGTM, add yourself as a contributor in the README file ! |
|
How it triggers, with the typo memory_init runs: head->size = (heap_end = HEAP_VIRT_START) - HEADER_SIZE;so the free list advertises a single block of 0xD0000000 - 16 = 0xCFFFFFF0 (about 3.2 GB) while only HEAP_INITIAL_PAGES (16 x 4 KB = 64 KB) are actually mapped. It also resets heap_end back to HEAP_VIRT_START. Any allocation bigger than the 64 KB that is really mapped is handed out without growing the heap, because malloc thinks the first block is huge: char *p = malloc(0x20000); // 128 KB, "fits" in the fake 3.2 GB block
memset(p, 0x41, 0x20000); // writes past the 64 KB that is mappedThe memset walks off the end of the mapped region and faults at the first unmapped page (around 0xD0010000). And since heap_end was reset to the heap start, the next heap_grow re-maps fresh physical frames on top of the existing blocks, so even correctly sized allocations start corrupting each other and leak PMM frames. Fix: head->size = (heap_end - HEAP_VIRT_START) - HEADER_SIZE; so the block advertises the real 64 KB minus the header. |
In memory_init(), line 46 assigns heap_end = HEAP_VIRT_START instead of subtracting, due to a =/- typo. This makes the first free block claim a size of ~3.2 GB (0xCFFFFFF0), so any large malloc returns pointers into unmapped virtual memory (page fault on write). It also resets heap_end to the heap start, so heap_grow() would remap fresh physical frames over existing blocks, corrupting the heap and leaking PMM frames.