Contract checklist
□ legal alignments power of two (validate!); floor at sizeof(void*)
□ base allocator malloc/free, 8-byte aligned; calling them inside
the layer IS the design
□ aligned_free receives ONLY the pointer <- the forcing requirement
□ mixing with plain free undefined behavior, both directions — say why
□ overhead budget bounded + stated (tens of bytes OK)
□ threading add NO shared mutable state
The design
aligned_malloc(size, align):
validate: align power of two, size > 0
raw = malloc(size + align - 1 + sizeof(void*))
start = raw + sizeof(void*) -- leave stash room FIRST
P = (start + align-1) & ~(align-1)
P[-1] = raw -- the stash
return P
aligned_free(P):
free( P[-1] ) -- read the stash, free original
Worked walk (memorize the shape, not the digits): raw 0x1003, start 0x100B, +15 & ~0xF → P 0x1010, stash at 0x1008 holds 0x1003. Check: P aligned, stash inside block, payload fits.
Invariants
- P % alignment == 0 - original pointer always at P - sizeof(void*) - stash and payload both inside the malloc'd block (budget guarantees it) - aligned_free frees exactly the original block, once - the layer holds no state outside the blocks themselves (intrusive only)
Rejected alternatives (know why)
side table shared mutable state -> lock on hot path; nodes need allocating
(debug-build tool, not release design)
retry loop unbounded latency; still needs bookkeeping eventually
recompute impossible — the offset depends on where malloc's block landed;
something MUST be written down
Complexity facts
time O(1) over base malloc/free
space worst case align - 1 + sizeof(void*) per allocation
(linear in alignment — regime ends near page-size alignments)
What earns points, per report dimension
- Requirements & interface — power-of-two rule pinned and validated; the pointer-only aligned_free recognized as forcing the design; overhead budget stated.
- Core design & invariants — over-allocate/round-up/stash with the budget derived, invariants stated, side table killed on shared state with the reasoning said aloud.
- Extension probe — the round will stress the contract; points come from locating the stress against your invariants and costing the response honestly.
- Complexity honesty — O(1) with its because; overhead linear in alignment admitted, with where the design's regime ends.
- Communication — the arithmetic walked on real digits unprompted; the mixing failure mode narrated as part of the contract.