|
aligned allocations are handled by over-allocating enough to ensure an
aligned subrange exists and framing the usable space to that subrange.
the framing can only handle offsets up to a 32-bit multiple of the
allocation UNIT (16 bytes), and aligned_alloc correctly checks for and
rejects larger alignments.
however, when get_meta reads back the offset, the type of the variable
and everything else in the expression where it's used was int, not
size_t, and offset*UNIT can overflow. modulo the "anything can happen"
aspect of overflow being undefined, a clean trap will occur and the
program will terminate. this would happen on any call to free,
realloc, or malloc_usable_size call on the large-alignment object.
switch the type of offset in get_meta from int to size_t. this has
been checked not to break any of the subsequent assertions:
- assert(offset > 0xffff) was wrongly rejecting offsets that would be
interpreted as negative when converted to signed int. this is fixed
by processing offset as unsigned.
- the check against the slot boundaries switches which assert would
catch values that were previously interpreted as negative, but the
net effect is the same.
- the check against maplen was already converting to unsigned long due
to the 4096UL in the expression. in doing so, it was incorrectly
sign-extending the offset rather than zero-extending. this is fixed
by using unsigned type to begin with.
in addition, take the opportunity to trap on offsets were offset*UNIT
would overflow. this cannot happen on 64-bit archs (and it should be
optimized out by the compiler there), but it's an additional signal we
can use to catch out-of-bounds writes on 32-bit ones. and the check
only happens when operating on extremely large, overaligned objects,
so the relative cost of checking is essentially zero.
|
|
the files added come from the mallocng development repo, commit
2ed58817cca5bc055974e5a0e43c280d106e696b. they comprise a new malloc
implementation, developed over the past 9 months, to replace the old
allocator (since dubbed "oldmalloc") with one that retains low code
size and minimal baseline memory overhead while avoiding fundamental
flaws in oldmalloc and making significant enhancements. these include
highly controlled fragmentation, fine-grained ability to return memory
to the system when freed, and strong hardening against dynamic memory
usage errors by the caller.
internally, mallocng derives most of these properties from tightly
structuring memory, creating space for allocations as uniform-sized
slots within individually mmapped (and individually freeable)
allocation groups. smaller-than-pagesize groups are created within
slots of larger ones. minimal group size is very small, and larger
sizes (in geometric progression) only come into play when usage is
high.
all data necessary for maintaining consistency of the allocator state
is tracked in out-of-band metadata, reachable via a validated path
from minimal in-band metadata. all pointers passed (to free, etc.) are
validated before any stores to memory take place. early reuse of freed
slots is avoided via approximate LRU order of freed slots. further
hardening against use-after-free and double-free, even in the case
where the freed slot has been reused, is made by cycling the offset
within the slot at which the allocation is placed; this is possible
whenever the slot size is larger than the requested allocation.
|