1 #include <stdlib.h> 2 #include <stdint.h> 3 #include <errno.h> 4 #include "malloc_impl.h" 5 aligned_alloc(size_t align,size_t len)6void *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