I'm writing my own memory allocator here and have come up with a very simple design. I'm wondering if there's anything useful I've missed; I know the basic ideas behind OpenBSD and glibc allocators but I don't have their architecture in front of me.
The goal is to do a minimal allocator (i.e. very little code) that gives good security, performance, and resource management (I hate things bloating to 3 times bigger than needed). Mine's got a few features: - It doesn't detect double-free()s like glibc; but it detects invalid free() addresses, including ones that were previously run through free(). - It detects heap corruption via XOR canaries and a djb2 hash (allocation control -> djb2 -> has ^ canary -> xcanary). - I have decided on a micro-tier design with high aligned macro-tier allocations; simply put, allocations wasting less than 3.125% of physical memory will be done via mmap() and placed at the highest address in the segment such that a read or write 1 byte beyond the end of the allocation will cause a segfault + I may simulate this by allocating 1 excess page and marking it PROT_NONE since I do not know if Linux intentionally guard-pages allocations (I'm not on OpenBSD); this would also be rather cross platform - Micro-tiers are subject to Allocation Gravity. Micro-tier allocations go into 256KiB mmap() segments. The most full segment that an allocation can be placed in is always used. This prevents mostly empty segments from getting new allocations, encouraging their death (once the last allocation is freed from a segment, the segment is munmap()ed), preventing the allocation of MORE segments, and overall getting more memory back to the system. - A primitive thread design is in place which isolates locking conditions for thread allocations as much as simply possible. This basically involves each thread working on what is effectively a separate allocator, with a bridge between them for free() and realloc() to search through. + When a thread terminates, if it still has local allocations, its thread group is orphaned. When a thread creates an allocation without having a thread group, it uses an available orphan if possible. + If there are a lot of orphans it may be advantageous to combine them into the oldest un-orphaned thread such that the different Micro-tiers will not individually get allocations, thus supporting eventual death of spare Micro-tiers. Orphan patterns are trivial to track; this won't cause any problem. I'm also considering other features: - The simple addition of prescribble/postscribble option. Prescribbling would fill memory with 0xaa when allocated; while postscribbling would fill it with 0x55 after free(). This would cause failure when making bad assumptions about freshly malloc()'d memory or when accessing free()d segments. - Post-xcanary. Enforce allocations to be considered of length (control_data + data + xcanary), such that the xcanary in the control_data and the xcanary after the last byte would be the same. Writes one beyond the end of micro-tier allocated pages would destroy the canary and get detected next time a malloc(), realloc(), or free() interacted with that allocation. The design I've chosen is a micro-tier design based on glibc's handling of large allocations. glibc allocates 128K or larger allocations using mmap(); 128KiB+1B wastes 4095 bytes (on 4K page systems), roughly 1/32 of the allocated memory. As long as only 1/32 of the physical memory is wasted, allocating with mmap() should be sane. Note that the number chosen is rather arbitrary and can be tightened or loosened to taste; OpenBSD for example would be this design at 1/2 (anything over a page gets mmap() in OBSD, and can only waste 50%). The inspiration from OpenBSD for guard pages leads me to the high-aligned allocations in macro-tier pages, allowing me to artificially create segfaults where normal allocators wouldn't be able to enforce proper behavior. Failing this immediate retribution in micro-tier allocations, which pack multiple allocations into a 256K mmap() segment, the post-xcanary idea will probably allow for detection of off-by-one at a later date. Did I miss anything important? -- John Moser <[EMAIL PROTECTED]> [demime 1.01d removed an attachment of type application/pgp-signature which had a name of signature.asc]