1

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.

Viktor
  • 1,004
  • 1
  • 10
  • 16

2 Answers2

1

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);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
EmDroid
  • 5,918
  • 18
  • 18
  • could you give an example how to store and use such metadata? – Viktor Jul 18 '17 at 15:32
  • What is the metadata in C. What is the _'some registry somewhere else'_? – 0___________ Jul 18 '17 at 15:39
  • @PeterJ "Metadata" is some extra data about the pointer (e.g. the original address or the alignment offset) which will allow to retrieve the original pointer to be freed. Registry might be e.g. a hash map storing metadata for each particular allocated pointer (somewhere else meaning that it is an extra structure not connected with the allocated memory directly). – EmDroid Jul 18 '17 at 15:47
  • Updated with an (untested) example how the deallocation function might access the data in the principle. – EmDroid Jul 18 '17 at 15:58
  • `*(uintptr_t)(aligned_addr - sizeof(uintptr_t)) = (uintptr_t)addr;` -> `*(uintptr_t *)(aligned_addr - sizeof(uintptr_t)) = (uintptr_t)addr;` and same problem for deallocation: `uintptr_t orig_ptr = *(uintptr_t)((uintptr_t)ptr - sizeof(uintptr_t));` -> `uintptr_t orig_ptr = *(uintptr_t *)((uintptr_t)ptr - sizeof(uintptr_t));` – chqrlie Jul 18 '17 at 16:08
  • Yep, I actually didn't try to compile it :) – EmDroid Jul 18 '17 at 16:10
  • Good answer. Thanks! – Viktor Jul 18 '17 at 16:11
  • 1
    This isn't guaranteed to work. For example, a call such as `allocate_align_1( 4, 4);` is going to generate `SIGBUS` on 64-bit SPARC at `*(uintptr_t*)(aligned_addr - sizeof(uintptr_t)) = (uintptr_t)addr;` In short, there's no guarantee that `aligned_address - sizeof( uintptr_t )` will produce an address "suitable for any use". Or in my example, suitable for storing a 64-bit pointer value, which on 64-bit SPARC has to be on an 8-byte boundary, IIRC. – Andrew Henle Jul 18 '17 at 16:12
  • 1
    @ Andrew Henle From this discussion I learnt that better is to use library functions otherwise no guarantees. – Viktor Jul 18 '17 at 16:16
  • 1
    @AndrewHenle True, the stored value will also need to be properly aligned if the value of `align` is small, updated the answer with the note. – EmDroid Jul 18 '17 at 16:26
0

If you use gnu C/C++ compilers malloc is already aligned

The address of a block returned by malloc or realloc in GNU systems is always a multiple of eight (or sixteen on 64-bit systems).

So if your align is needed for the processor - you do need to align.

If you need a non standard align you will need to keep the original pointer as well for example:

typedef struct {
  void *original;
  void *aligned;
} mypointer;

    void* allocate_align_(mypointer *p; size_t size, uintptr_t align)
    {
        p -> original = malloc(size + align);
    ...
    //aligning code here
        p ->aligned = ... //(some math & pointer operations) do not change the p -> original
        return p- > aligned;
    }

    void align_free(mypointer *p) 
    {
        free(p -> original);
    }

it is not real code do no error checking etc. just the idea

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 1
    `malloc` is not even part of the gcc compiler toolchain. t is a freestanding implementation without libc. So it is not clear how you can even make any assimptions. And OP seems to want to specify an arbitrary alignment, which `malloc` does not provide. The code is clumsy to use, e.g. other functions have to be aware of the `struct`. – too honest for this site Jul 18 '17 at 15:31
  • It is true that `malloc` should normally return pointers aligned for any use, however you might want to align differently for e.g. SSE etc. which might have different alignment requirements than the CPU. – EmDroid Jul 18 '17 at 15:33
  • Also for this to work, you would actually need to return and keep the entire struct, not just the `p->aligned`, as there is no way to retrieve `p` or `p->original` from the value of `p->aligned` ... however if returning just `p`, it might be a possible solution. – EmDroid Jul 18 '17 at 15:35
  • @Olaf Great comment !!!! https://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html https://www.gnu.org/software/libc/manual/html_mono/libc.html#Basic-Allocation – 0___________ Jul 18 '17 at 15:35
  • @axalis what for? You have the original pointer stored. And you use it for free – 0___________ Jul 18 '17 at 15:36
  • @PeterJ: Reading comments **carefully** and **understanding** seems to be a diominishing virtue. From your text "… gnu C/C++ compilers …". My comment **explicitly** was about the gcc **compiler toolchain**. From the [gcc documentation](https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Standards.html#C-Language) : "_ GCC aims towards being usable as a conforming freestanding implementation, or **as the compiler** for a conforming hosted implementation._" (emphasis mine). It explicitly excludes the library! – too honest for this site Jul 18 '17 at 15:45
  • @Olaf Reading OP questions **carefully** and **understanding** seems to be a diminishing virtue. if you exclude the libraries any discussion about any library function including malloc() & free() is pointless. – 0___________ Jul 18 '17 at 15:52
  • @PeterJ: Where did I say to exclude them? You are just trying to explain apples using oranges. This is not related to the gcc compiler, but the libc, of which glibc is **one possible** implementation. And that one provides a much more straight and easy way. – too honest for this site Jul 18 '17 at 15:56
  • @PeterJ Yes, actually I missed that the `mypointer` in your example is a global variable and I thought it is just defining the struct. However that way you can only ever manage a single pointer which is not so flexible (the OP might e.g. want to allocate more blocks at the same time). – EmDroid Jul 18 '17 at 15:57
  • @Olaf sorry mate. you missed the first word if. But anyway - please find any malloc impementation which does not return aligned value. I do know any. – 0___________ Jul 18 '17 at 15:59
  • @PeterJ: On an 8 bit system alignment past a byte does not make much sense. It worked fine on my system. Nevertheless, you intentionally only pick part of my comments, intentionally ignoring the more relevant parts. This leads nowhere, I'm out. You have the last word. – too honest for this site Jul 18 '17 at 16:03
  • 2
    @PeterJ Aligned to *what*? The C standard merely requires that the alignment be suitable for "generic" strictly-standard-conforming C. Not for any platform-specific uses that may have much more strict alignment considerations. Saying "malloc is already aligned" in a vacuum is about as useful as saying "all char buffers are already aligned". No, they're **NOT**. – Andrew Henle Jul 18 '17 at 16:04
  • 1
    @Olaf _'You have the last word.'_ of course because I am right. But this one was quite interesting - _'malloc is not even part of the gcc compiler toolchain. t is a freestanding implementation without libc.'_ And I stupid believed documentations : http://man7.org/linux/man-pages/man3/free.3.html And 8 bit systems - great example - what about intel 4004? – 0___________ Jul 18 '17 at 16:19