master
 1#include <stdlib.h>
 2#include <stdint.h>
 3#include <errno.h>
 4#include "malloc_impl.h"
 5
 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}