reverse dependency order of memalign and aligned_alloc
[musl] / src / malloc / memalign.c
index 61f456e..e06c76e 100644 (file)
@@ -1,13 +1,52 @@
 #include <stdlib.h>
+#include <stdint.h>
 #include <errno.h>
+#include "malloc_impl.h"
 
-void *memalign(size_t align, size_t len)
+void *aligned_alloc(size_t align, size_t len)
 {
-       void *mem;
-       int ret;
-       if ((ret = posix_memalign(&mem, align, len))) {
-               errno = ret;
+       unsigned char *mem, *new;
+
+       if ((align & -align) != align) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       if (len > SIZE_MAX - align || __malloc_replaced) {
+               errno = ENOMEM;
+               return 0;
+       }
+
+       if (align <= SIZE_ALIGN)
+               return malloc(len);
+
+       if (!(mem = malloc(len + align-1)))
                return 0;
+
+       new = (void *)((uintptr_t)mem + align-1 & -align);
+       if (new == mem) return mem;
+
+       struct chunk *c = MEM_TO_CHUNK(mem);
+       struct chunk *n = MEM_TO_CHUNK(new);
+
+       if (IS_MMAPPED(c)) {
+               /* Apply difference between aligned and original
+                * address to the "extra" field of mmapped chunk. */
+               n->psize = c->psize + (new-mem);
+               n->csize = c->csize - (new-mem);
+               return new;
        }
-       return mem;
+
+       struct chunk *t = NEXT_CHUNK(c);
+
+       /* Split the allocated chunk into two chunks. The aligned part
+        * that will be used has the size in its footer reduced by the
+        * difference between the aligned and original addresses, and
+        * the resulting size copied to its header. A new header and
+        * footer are written for the split-off part to be freed. */
+       n->psize = c->csize = C_INUSE | (new-mem);
+       n->csize = t->psize -= new-mem;
+
+       __bin_chunk(c);
+       return new;
 }