Search code examples
cpointersmemory-managementalignment

How to free aligned pointer?


I found two simple and sufficient ways to align pointers. Extended discussion can be found here. Here they are:

void* allocate_align_1(size_t size, uintptr_t align)
{
    void* addr = malloc(size + align);

    uintptr_t aligned_addr = (uintptr_t)addr;    
    aligned_addr += align - (aligned_addr % align);

    return (void*)aligned_addr;
}

void* allocate_align_2(size_t size, uintptr_t align)
{
    void* addr = malloc(size + align);

    uintptr_t aligned_addr = (uintptr_t)addr;    
    aligned_addr = (aligned_addr + (align - 1)) & -align;

    return (void*)aligned_addr;
}

Link on coliru.

My question is how deallocate_align(void* addr, uintptr_t align) function can be implemented? Can pointer which was returned by malloc be restored from addr and align align? Then it should just be passed to free.


Solution

  • If the pointer (and possibly the alignment size) is your only information, you'd need to store some kind of metadata (the original pointer, alignment offset etc.) somewhere. It might be before your allocated memory block, which you can then access when performing the deallocation, or some registry (e.g. hashtable or map) somewhere else, where you will store the metadata and retrieve them according to the address when de-allocating.

    One possible (oversimplified) implementation (not tested, just for illustration - in the real case, the stored value will also need to be aligned properly, if align is smaller than the suitable alignment for uintptr_t):

    void* allocate_align_1(size_t size, uintptr_t align)
    {
        void* addr = malloc(size + align + sizeof(uintptr_t));
    
        uintptr_t aligned_addr = (uintptr_t)addr + sizeof(uintptr_t);    
        aligned_addr += align - (aligned_addr % align);
    
        // store the original address
        *(uintptr_t*)(aligned_addr - sizeof(uintptr_t)) = (uintptr_t)addr;
    
        return (void*)aligned_addr;
    }
    

    Then in deallocate, you can access the data (for proper use there could/should be some check of a guard value or similar to make sure the correct data is really there), an example without checking:

    void deallocate(void * ptr)
    {
        uintptr_t orig_ptr = *(uintptr_t*)((uintptr_t)ptr - sizeof(uintptr_t));
        free((void*)orig_ptr);
    }