aligned_alloc.c raw

   1  #include <stdlib.h>
   2  #include <stdint.h>
   3  #include <errno.h>
   4  #include "malloc_impl.h"
   5  
   6  void *aligned_alloc(size_t align, size_t len)
   7  {
   8  	unsigned char *mem, *new;
   9  
  10  	if ((align & -align) != align) {
  11  		errno = EINVAL;
  12  		return 0;
  13  	}
  14  
  15  	if (len > SIZE_MAX - align ||
  16  	    (__malloc_replaced && !__aligned_alloc_replaced)) {
  17  		errno = ENOMEM;
  18  		return 0;
  19  	}
  20  
  21  	if (align <= SIZE_ALIGN)
  22  		return malloc(len);
  23  
  24  	if (!(mem = malloc(len + align-1)))
  25  		return 0;
  26  
  27  	new = (void *)((uintptr_t)mem + align-1 & -align);
  28  	if (new == mem) return mem;
  29  
  30  	struct chunk *c = MEM_TO_CHUNK(mem);
  31  	struct chunk *n = MEM_TO_CHUNK(new);
  32  
  33  	if (IS_MMAPPED(c)) {
  34  		/* Apply difference between aligned and original
  35  		 * address to the "extra" field of mmapped chunk. */
  36  		n->psize = c->psize + (new-mem);
  37  		n->csize = c->csize - (new-mem);
  38  		return new;
  39  	}
  40  
  41  	struct chunk *t = NEXT_CHUNK(c);
  42  
  43  	/* Split the allocated chunk into two chunks. The aligned part
  44  	 * that will be used has the size in its footer reduced by the
  45  	 * difference between the aligned and original addresses, and
  46  	 * the resulting size copied to its header. A new header and
  47  	 * footer are written for the split-off part to be freed. */
  48  	n->psize = c->csize = C_INUSE | (new-mem);
  49  	n->csize = t->psize -= new-mem;
  50  
  51  	__bin_chunk(c);
  52  	return new;
  53  }
  54