Home > Blockchain >  storing value behind the malloced and aligned pointer C
storing value behind the malloced and aligned pointer C

Time:03-27

Reference code : https://embeddedartistry.com/blog/2017/02/22/generating-aligned-memory/

void * aligned_malloc(size_t align, size_t size)
{
    void * ptr = NULL;
    
    // We want it to be a power of two since
    // align_up operates on powers of two
    assert((align & (align - 1)) == 0);

    if(align && size)
    {
        /*
         * We know we have to fit an offset value
         * We also allocate extra bytes to ensure we 
         * can meet the alignment
         */
        uint32_t hdr_size = PTR_OFFSET_SZ   (align - 1);
        void * p = malloc(size   hdr_size);

        if(p)
        {
            /*
             * Add the offset size to malloc's pointer 
             * (we will always store that)
             * Then align the resulting value to the 
             * target alignment
             */
            ptr = (void *) align_up(((uintptr_t)p   PTR_OFFSET_SZ), align);

            // Calc`enter code here`ulate the offset and store it 
            // behind our aligned pointer
            *((offset_t *)ptr - 1) = 
                (offset_t)((uintptr_t)ptr - (uintptr_t)p);

        } // else NULL, could not malloc
    } //else NULL, invalid arguments

    return ptr;
}

I do not understand how this line stores value behind the ptr. "*((offset_t *)ptr - 1) = (offset_t)((uintptr_t)ptr - (uintptr_t)p);"

CodePudding user response:

After the allocation and calculation, ptr contains the value this routine will return to its caller, which is the address for the caller to use to store its data.

(offset_t *)ptr converts this address to the type offset_t *.

Then (offset_t *)ptr - 1 calculates a location in memory that is earlier (lower addressed) by the distance of one offset_t object.

Then *((offset_t *)ptr - 1) = …; stores a value in that location.

CodePudding user response:

In addition to other good answers:

ptr = (void *) align_up(((uintptr_t)p PTR_OFFSET_SZ), align); lays the seeds for undefined behavior (UB) as aligned_malloc() does not certainly meet max_align_t.

malloc() always provides a pointer that meets this requirement of aligning to at least sizeof(max_align_t) and much code relies on that. aligned_malloc() does not certainly meet that - it should.

Do not recommend this code "as is" for portability.

To do this right, aligned_malloc() and align_up() must consider the maximum of both max_align_t and size.

void * aligned_malloc(size_t align, size_t size) {
  assert(...);
  if (size < sizeof(max_algin_t)) {
    size = sizeof(max_algin_t);
  }
  ...
  • Related