using malloc implementation types/macros/idioms for memalign

the generated code should be mostly unchanged, except for explicit use
of C_INUSE in place of copying the low bits from existing chunk
headers/footers.

these changes also remove mild UB due to dubious arithmetic on
pointers into imaginary size_t[] arrays.
This commit is contained in:
Rich Felker 2018-04-19 20:45:48 -04:00
parent 23389b1988
commit 3c2cbbe7ba
1 changed files with 22 additions and 20 deletions

View File

@ -2,49 +2,51 @@
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include "libc.h" #include "libc.h"
#include "malloc_impl.h"
void *__memalign(size_t align, size_t len) void *__memalign(size_t align, size_t len)
{ {
unsigned char *mem, *new, *end; unsigned char *mem, *new;
size_t header, footer;
if ((align & -align) != align) { if ((align & -align) != align) {
errno = EINVAL; errno = EINVAL;
return NULL; return 0;
} }
if (len > SIZE_MAX - align) { if (len > SIZE_MAX - align) {
errno = ENOMEM; errno = ENOMEM;
return NULL; return 0;
} }
if (align <= 4*sizeof(size_t)) { if (align <= SIZE_ALIGN)
if (!(mem = malloc(len))) return malloc(len);
return NULL;
return mem;
}
if (!(mem = malloc(len + align-1))) if (!(mem = malloc(len + align-1)))
return NULL; return 0;
new = (void *)((uintptr_t)mem + align-1 & -align); new = (void *)((uintptr_t)mem + align-1 & -align);
if (new == mem) return mem; if (new == mem) return mem;
header = ((size_t *)mem)[-1]; struct chunk *c = MEM_TO_CHUNK(mem);
struct chunk *n = MEM_TO_CHUNK(new);
if (!(header & 7)) { if (IS_MMAPPED(c)) {
((size_t *)new)[-2] = ((size_t *)mem)[-2] + (new-mem); /* Apply difference between aligned and original
((size_t *)new)[-1] = ((size_t *)mem)[-1] - (new-mem); * address to the "extra" field of mmapped chunk. */
n->psize = c->psize + (new-mem);
n->csize = c->csize - (new-mem);
return new; return new;
} }
end = mem + (header & -8); struct chunk *t = NEXT_CHUNK(c);
footer = ((size_t *)end)[-2];
((size_t *)mem)[-1] = header&7 | new-mem; /* Split the allocated chunk into two chunks. The aligned part
((size_t *)new)[-2] = footer&7 | new-mem; * that will be used has the size in its footer reduced by the
((size_t *)new)[-1] = header&7 | end-new; * difference between the aligned and original addresses, and
((size_t *)end)[-2] = footer&7 | end-new; * 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;
free(mem); free(mem);
return new; return new;