move __expand_heap into malloc.c
[oweals/musl.git] / src / malloc / aligned_alloc.c
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 || __malloc_replaced) {
16                 errno = ENOMEM;
17                 return 0;
18         }
19
20         if (align <= SIZE_ALIGN)
21                 return malloc(len);
22
23         if (!(mem = malloc(len + align-1)))
24                 return 0;
25
26         new = (void *)((uintptr_t)mem + align-1 & -align);
27         if (new == mem) return mem;
28
29         struct chunk *c = MEM_TO_CHUNK(mem);
30         struct chunk *n = MEM_TO_CHUNK(new);
31
32         if (IS_MMAPPED(c)) {
33                 /* Apply difference between aligned and original
34                  * address to the "extra" field of mmapped chunk. */
35                 n->psize = c->psize + (new-mem);
36                 n->csize = c->csize - (new-mem);
37                 return new;
38         }
39
40         struct chunk *t = NEXT_CHUNK(c);
41
42         /* Split the allocated chunk into two chunks. The aligned part
43          * that will be used has the size in its footer reduced by the
44          * difference between the aligned and original addresses, and
45          * the resulting size copied to its header. A new header and
46          * footer are written for the split-off part to be freed. */
47         n->psize = c->csize = C_INUSE | (new-mem);
48         n->csize = t->psize -= new-mem;
49
50         __bin_chunk(c);
51         return new;
52 }