1 #include <stdlib.h>
2 #include <errno.h>
3 #include "meta.h"
4
5 #ifdef USE_JEMALLOC
6 extern void* je_memalign(size_t align, size_t len);
7 #endif
8
9 #ifdef HOOK_ENABLE
__libc_aligned_alloc(size_t align,size_t len)10 void *__libc_aligned_alloc(size_t align, size_t len)
11 #else
12 void *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