1#include <stdlib.h>
2#include <errno.h>
3#include "meta.h"
4
5#ifdef USE_JEMALLOC
6extern void* je_memalign(size_t align, size_t len);
7#endif
8
9#ifdef HOOK_ENABLE
10void *__libc_aligned_alloc(size_t align, size_t len)
11#else
12void *aligned_alloc(size_t align, size_t len)
13#endif
14{
15#ifdef USE_JEMALLOC
16	return je_memalign(align, len);
17#endif
18	if ((align & -align) != align) {
19		errno = EINVAL;
20		return 0;
21	}
22
23	if (len > SIZE_MAX - align || align >= (1ULL<<31)*UNIT) {
24		errno = ENOMEM;
25		return 0;
26	}
27
28	if (DISABLE_ALIGNED_ALLOC) {
29		errno = ENOMEM;
30		return 0;
31	}
32
33	if (align <= UNIT) align = UNIT;
34
35	unsigned char *p = malloc(len + align - UNIT);
36	if (!p)
37		return 0;
38
39	struct meta *g = get_meta(p);
40	int idx = get_slot_index(p);
41	size_t stride = get_stride(g);
42	unsigned char *start = g->mem->storage + stride*idx;
43	unsigned char *end = g->mem->storage + stride*(idx+1) - IB;
44	size_t adj = -(uintptr_t)p & (align-1);
45
46	if (!adj) {
47		set_size(p, end, len);
48		return p;
49	}
50	p += adj;
51	uint32_t offset = (size_t)(p-g->mem->storage)/UNIT;
52	if (offset <= 0xffff) {
53		*(uint16_t *)(p-2) = offset;
54		p[-4] = 0;
55	} else {
56		// use a 32-bit offset if 16-bit doesn't fit. for this,
57		// 16-bit field must be zero, [-4] byte nonzero.
58		*(uint16_t *)(p-2) = 0;
59		*(uint32_t *)(p-8) = offset;
60		p[-4] = 1;
61	}
62	p[-3] = idx;
63	set_size(p, end, len);
64	// store offset to aligned enframing. this facilitates cycling
65	// offset and also iteration of heap for debugging/measurement.
66	// for extreme overalignment it won't fit but these are classless
67	// allocations anyway.
68	*(uint16_t *)(start - 2) = (size_t)(p-start)/UNIT;
69	start[-3] = 7<<5;
70	return p;
71}
72