7246a99b808a27cea8d758ec35df83392e09009a
[musl] / src / malloc / memalign.c
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <errno.h>
4 #include "libc.h"
5 #include "malloc_impl.h"
6
7 void *__memalign(size_t align, size_t len)
8 {
9         unsigned char *mem, *new;
10
11         if ((align & -align) != align) {
12                 errno = EINVAL;
13                 return 0;
14         }
15
16         if (len > SIZE_MAX - align) {
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
55 weak_alias(__memalign, memalign);