1*c9945492SAndroid Build Coastguard Worker #define _GNU_SOURCE
2*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
3*c9945492SAndroid Build Coastguard Worker #include <string.h>
4*c9945492SAndroid Build Coastguard Worker #include <limits.h>
5*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
6*c9945492SAndroid Build Coastguard Worker #include <errno.h>
7*c9945492SAndroid Build Coastguard Worker #include <sys/mman.h>
8*c9945492SAndroid Build Coastguard Worker #include "libc.h"
9*c9945492SAndroid Build Coastguard Worker #include "atomic.h"
10*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
11*c9945492SAndroid Build Coastguard Worker #include "malloc_impl.h"
12*c9945492SAndroid Build Coastguard Worker #include "fork_impl.h"
13*c9945492SAndroid Build Coastguard Worker
14*c9945492SAndroid Build Coastguard Worker #define malloc __libc_malloc_impl
15*c9945492SAndroid Build Coastguard Worker #define realloc __libc_realloc
16*c9945492SAndroid Build Coastguard Worker #define free __libc_free
17*c9945492SAndroid Build Coastguard Worker
18*c9945492SAndroid Build Coastguard Worker #if defined(__GNUC__) && defined(__PIC__)
19*c9945492SAndroid Build Coastguard Worker #define inline inline __attribute__((always_inline))
20*c9945492SAndroid Build Coastguard Worker #endif
21*c9945492SAndroid Build Coastguard Worker
22*c9945492SAndroid Build Coastguard Worker static struct {
23*c9945492SAndroid Build Coastguard Worker volatile uint64_t binmap;
24*c9945492SAndroid Build Coastguard Worker struct bin bins[64];
25*c9945492SAndroid Build Coastguard Worker volatile int split_merge_lock[2];
26*c9945492SAndroid Build Coastguard Worker } mal;
27*c9945492SAndroid Build Coastguard Worker
28*c9945492SAndroid Build Coastguard Worker /* Synchronization tools */
29*c9945492SAndroid Build Coastguard Worker
lock(volatile int * lk)30*c9945492SAndroid Build Coastguard Worker static inline void lock(volatile int *lk)
31*c9945492SAndroid Build Coastguard Worker {
32*c9945492SAndroid Build Coastguard Worker int need_locks = libc.need_locks;
33*c9945492SAndroid Build Coastguard Worker if (need_locks) {
34*c9945492SAndroid Build Coastguard Worker while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1);
35*c9945492SAndroid Build Coastguard Worker if (need_locks < 0) libc.need_locks = 0;
36*c9945492SAndroid Build Coastguard Worker }
37*c9945492SAndroid Build Coastguard Worker }
38*c9945492SAndroid Build Coastguard Worker
unlock(volatile int * lk)39*c9945492SAndroid Build Coastguard Worker static inline void unlock(volatile int *lk)
40*c9945492SAndroid Build Coastguard Worker {
41*c9945492SAndroid Build Coastguard Worker if (lk[0]) {
42*c9945492SAndroid Build Coastguard Worker a_store(lk, 0);
43*c9945492SAndroid Build Coastguard Worker if (lk[1]) __wake(lk, 1, 1);
44*c9945492SAndroid Build Coastguard Worker }
45*c9945492SAndroid Build Coastguard Worker }
46*c9945492SAndroid Build Coastguard Worker
lock_bin(int i)47*c9945492SAndroid Build Coastguard Worker static inline void lock_bin(int i)
48*c9945492SAndroid Build Coastguard Worker {
49*c9945492SAndroid Build Coastguard Worker lock(mal.bins[i].lock);
50*c9945492SAndroid Build Coastguard Worker if (!mal.bins[i].head)
51*c9945492SAndroid Build Coastguard Worker mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);
52*c9945492SAndroid Build Coastguard Worker }
53*c9945492SAndroid Build Coastguard Worker
unlock_bin(int i)54*c9945492SAndroid Build Coastguard Worker static inline void unlock_bin(int i)
55*c9945492SAndroid Build Coastguard Worker {
56*c9945492SAndroid Build Coastguard Worker unlock(mal.bins[i].lock);
57*c9945492SAndroid Build Coastguard Worker }
58*c9945492SAndroid Build Coastguard Worker
first_set(uint64_t x)59*c9945492SAndroid Build Coastguard Worker static int first_set(uint64_t x)
60*c9945492SAndroid Build Coastguard Worker {
61*c9945492SAndroid Build Coastguard Worker #if 1
62*c9945492SAndroid Build Coastguard Worker return a_ctz_64(x);
63*c9945492SAndroid Build Coastguard Worker #else
64*c9945492SAndroid Build Coastguard Worker static const char debruijn64[64] = {
65*c9945492SAndroid Build Coastguard Worker 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
66*c9945492SAndroid Build Coastguard Worker 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
67*c9945492SAndroid Build Coastguard Worker 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
68*c9945492SAndroid Build Coastguard Worker 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
69*c9945492SAndroid Build Coastguard Worker };
70*c9945492SAndroid Build Coastguard Worker static const char debruijn32[32] = {
71*c9945492SAndroid Build Coastguard Worker 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
72*c9945492SAndroid Build Coastguard Worker 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
73*c9945492SAndroid Build Coastguard Worker };
74*c9945492SAndroid Build Coastguard Worker if (sizeof(long) < 8) {
75*c9945492SAndroid Build Coastguard Worker uint32_t y = x;
76*c9945492SAndroid Build Coastguard Worker if (!y) {
77*c9945492SAndroid Build Coastguard Worker y = x>>32;
78*c9945492SAndroid Build Coastguard Worker return 32 + debruijn32[(y&-y)*0x076be629 >> 27];
79*c9945492SAndroid Build Coastguard Worker }
80*c9945492SAndroid Build Coastguard Worker return debruijn32[(y&-y)*0x076be629 >> 27];
81*c9945492SAndroid Build Coastguard Worker }
82*c9945492SAndroid Build Coastguard Worker return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58];
83*c9945492SAndroid Build Coastguard Worker #endif
84*c9945492SAndroid Build Coastguard Worker }
85*c9945492SAndroid Build Coastguard Worker
86*c9945492SAndroid Build Coastguard Worker static const unsigned char bin_tab[60] = {
87*c9945492SAndroid Build Coastguard Worker 32,33,34,35,36,36,37,37,38,38,39,39,
88*c9945492SAndroid Build Coastguard Worker 40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43,
89*c9945492SAndroid Build Coastguard Worker 44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,
90*c9945492SAndroid Build Coastguard Worker 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,
91*c9945492SAndroid Build Coastguard Worker };
92*c9945492SAndroid Build Coastguard Worker
bin_index(size_t x)93*c9945492SAndroid Build Coastguard Worker static int bin_index(size_t x)
94*c9945492SAndroid Build Coastguard Worker {
95*c9945492SAndroid Build Coastguard Worker x = x / SIZE_ALIGN - 1;
96*c9945492SAndroid Build Coastguard Worker if (x <= 32) return x;
97*c9945492SAndroid Build Coastguard Worker if (x < 512) return bin_tab[x/8-4];
98*c9945492SAndroid Build Coastguard Worker if (x > 0x1c00) return 63;
99*c9945492SAndroid Build Coastguard Worker return bin_tab[x/128-4] + 16;
100*c9945492SAndroid Build Coastguard Worker }
101*c9945492SAndroid Build Coastguard Worker
bin_index_up(size_t x)102*c9945492SAndroid Build Coastguard Worker static int bin_index_up(size_t x)
103*c9945492SAndroid Build Coastguard Worker {
104*c9945492SAndroid Build Coastguard Worker x = x / SIZE_ALIGN - 1;
105*c9945492SAndroid Build Coastguard Worker if (x <= 32) return x;
106*c9945492SAndroid Build Coastguard Worker x--;
107*c9945492SAndroid Build Coastguard Worker if (x < 512) return bin_tab[x/8-4] + 1;
108*c9945492SAndroid Build Coastguard Worker return bin_tab[x/128-4] + 17;
109*c9945492SAndroid Build Coastguard Worker }
110*c9945492SAndroid Build Coastguard Worker
111*c9945492SAndroid Build Coastguard Worker #if 0
112*c9945492SAndroid Build Coastguard Worker void __dump_heap(int x)
113*c9945492SAndroid Build Coastguard Worker {
114*c9945492SAndroid Build Coastguard Worker struct chunk *c;
115*c9945492SAndroid Build Coastguard Worker int i;
116*c9945492SAndroid Build Coastguard Worker for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c))
117*c9945492SAndroid Build Coastguard Worker fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n",
118*c9945492SAndroid Build Coastguard Worker c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)),
119*c9945492SAndroid Build Coastguard Worker c->csize & 15,
120*c9945492SAndroid Build Coastguard Worker NEXT_CHUNK(c)->psize & 15);
121*c9945492SAndroid Build Coastguard Worker for (i=0; i<64; i++) {
122*c9945492SAndroid Build Coastguard Worker if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) {
123*c9945492SAndroid Build Coastguard Worker fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head);
124*c9945492SAndroid Build Coastguard Worker if (!(mal.binmap & 1ULL<<i))
125*c9945492SAndroid Build Coastguard Worker fprintf(stderr, "missing from binmap!\n");
126*c9945492SAndroid Build Coastguard Worker } else if (mal.binmap & 1ULL<<i)
127*c9945492SAndroid Build Coastguard Worker fprintf(stderr, "binmap wrongly contains %d!\n", i);
128*c9945492SAndroid Build Coastguard Worker }
129*c9945492SAndroid Build Coastguard Worker }
130*c9945492SAndroid Build Coastguard Worker #endif
131*c9945492SAndroid Build Coastguard Worker
132*c9945492SAndroid Build Coastguard Worker /* This function returns true if the interval [old,new]
133*c9945492SAndroid Build Coastguard Worker * intersects the 'len'-sized interval below &libc.auxv
134*c9945492SAndroid Build Coastguard Worker * (interpreted as the main-thread stack) or below &b
135*c9945492SAndroid Build Coastguard Worker * (the current stack). It is used to defend against
136*c9945492SAndroid Build Coastguard Worker * buggy brk implementations that can cross the stack. */
137*c9945492SAndroid Build Coastguard Worker
traverses_stack_p(uintptr_t old,uintptr_t new)138*c9945492SAndroid Build Coastguard Worker static int traverses_stack_p(uintptr_t old, uintptr_t new)
139*c9945492SAndroid Build Coastguard Worker {
140*c9945492SAndroid Build Coastguard Worker const uintptr_t len = 8<<20;
141*c9945492SAndroid Build Coastguard Worker uintptr_t a, b;
142*c9945492SAndroid Build Coastguard Worker
143*c9945492SAndroid Build Coastguard Worker b = (uintptr_t)libc.auxv;
144*c9945492SAndroid Build Coastguard Worker a = b > len ? b-len : 0;
145*c9945492SAndroid Build Coastguard Worker if (new>a && old<b) return 1;
146*c9945492SAndroid Build Coastguard Worker
147*c9945492SAndroid Build Coastguard Worker b = (uintptr_t)&b;
148*c9945492SAndroid Build Coastguard Worker a = b > len ? b-len : 0;
149*c9945492SAndroid Build Coastguard Worker if (new>a && old<b) return 1;
150*c9945492SAndroid Build Coastguard Worker
151*c9945492SAndroid Build Coastguard Worker return 0;
152*c9945492SAndroid Build Coastguard Worker }
153*c9945492SAndroid Build Coastguard Worker
154*c9945492SAndroid Build Coastguard Worker /* Expand the heap in-place if brk can be used, or otherwise via mmap,
155*c9945492SAndroid Build Coastguard Worker * using an exponential lower bound on growth by mmap to make
156*c9945492SAndroid Build Coastguard Worker * fragmentation asymptotically irrelevant. The size argument is both
157*c9945492SAndroid Build Coastguard Worker * an input and an output, since the caller needs to know the size
158*c9945492SAndroid Build Coastguard Worker * allocated, which will be larger than requested due to page alignment
159*c9945492SAndroid Build Coastguard Worker * and mmap minimum size rules. The caller is responsible for locking
160*c9945492SAndroid Build Coastguard Worker * to prevent concurrent calls. */
161*c9945492SAndroid Build Coastguard Worker
__expand_heap(size_t * pn)162*c9945492SAndroid Build Coastguard Worker static void *__expand_heap(size_t *pn)
163*c9945492SAndroid Build Coastguard Worker {
164*c9945492SAndroid Build Coastguard Worker static uintptr_t brk;
165*c9945492SAndroid Build Coastguard Worker static unsigned mmap_step;
166*c9945492SAndroid Build Coastguard Worker size_t n = *pn;
167*c9945492SAndroid Build Coastguard Worker
168*c9945492SAndroid Build Coastguard Worker if (n > SIZE_MAX/2 - PAGE_SIZE) {
169*c9945492SAndroid Build Coastguard Worker errno = ENOMEM;
170*c9945492SAndroid Build Coastguard Worker return 0;
171*c9945492SAndroid Build Coastguard Worker }
172*c9945492SAndroid Build Coastguard Worker n += -n & PAGE_SIZE-1;
173*c9945492SAndroid Build Coastguard Worker
174*c9945492SAndroid Build Coastguard Worker if (!brk) {
175*c9945492SAndroid Build Coastguard Worker brk = __syscall(SYS_brk, 0);
176*c9945492SAndroid Build Coastguard Worker brk += -brk & PAGE_SIZE-1;
177*c9945492SAndroid Build Coastguard Worker }
178*c9945492SAndroid Build Coastguard Worker
179*c9945492SAndroid Build Coastguard Worker if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n)
180*c9945492SAndroid Build Coastguard Worker && __syscall(SYS_brk, brk+n)==brk+n) {
181*c9945492SAndroid Build Coastguard Worker *pn = n;
182*c9945492SAndroid Build Coastguard Worker brk += n;
183*c9945492SAndroid Build Coastguard Worker return (void *)(brk-n);
184*c9945492SAndroid Build Coastguard Worker }
185*c9945492SAndroid Build Coastguard Worker
186*c9945492SAndroid Build Coastguard Worker size_t min = (size_t)PAGE_SIZE << mmap_step/2;
187*c9945492SAndroid Build Coastguard Worker if (n < min) n = min;
188*c9945492SAndroid Build Coastguard Worker void *area = __mmap(0, n, PROT_READ|PROT_WRITE,
189*c9945492SAndroid Build Coastguard Worker MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
190*c9945492SAndroid Build Coastguard Worker if (area == MAP_FAILED) return 0;
191*c9945492SAndroid Build Coastguard Worker *pn = n;
192*c9945492SAndroid Build Coastguard Worker mmap_step++;
193*c9945492SAndroid Build Coastguard Worker return area;
194*c9945492SAndroid Build Coastguard Worker }
195*c9945492SAndroid Build Coastguard Worker
expand_heap(size_t n)196*c9945492SAndroid Build Coastguard Worker static struct chunk *expand_heap(size_t n)
197*c9945492SAndroid Build Coastguard Worker {
198*c9945492SAndroid Build Coastguard Worker static void *end;
199*c9945492SAndroid Build Coastguard Worker void *p;
200*c9945492SAndroid Build Coastguard Worker struct chunk *w;
201*c9945492SAndroid Build Coastguard Worker
202*c9945492SAndroid Build Coastguard Worker /* The argument n already accounts for the caller's chunk
203*c9945492SAndroid Build Coastguard Worker * overhead needs, but if the heap can't be extended in-place,
204*c9945492SAndroid Build Coastguard Worker * we need room for an extra zero-sized sentinel chunk. */
205*c9945492SAndroid Build Coastguard Worker n += SIZE_ALIGN;
206*c9945492SAndroid Build Coastguard Worker
207*c9945492SAndroid Build Coastguard Worker p = __expand_heap(&n);
208*c9945492SAndroid Build Coastguard Worker if (!p) return 0;
209*c9945492SAndroid Build Coastguard Worker
210*c9945492SAndroid Build Coastguard Worker /* If not just expanding existing space, we need to make a
211*c9945492SAndroid Build Coastguard Worker * new sentinel chunk below the allocated space. */
212*c9945492SAndroid Build Coastguard Worker if (p != end) {
213*c9945492SAndroid Build Coastguard Worker /* Valid/safe because of the prologue increment. */
214*c9945492SAndroid Build Coastguard Worker n -= SIZE_ALIGN;
215*c9945492SAndroid Build Coastguard Worker p = (char *)p + SIZE_ALIGN;
216*c9945492SAndroid Build Coastguard Worker w = MEM_TO_CHUNK(p);
217*c9945492SAndroid Build Coastguard Worker w->psize = 0 | C_INUSE;
218*c9945492SAndroid Build Coastguard Worker }
219*c9945492SAndroid Build Coastguard Worker
220*c9945492SAndroid Build Coastguard Worker /* Record new heap end and fill in footer. */
221*c9945492SAndroid Build Coastguard Worker end = (char *)p + n;
222*c9945492SAndroid Build Coastguard Worker w = MEM_TO_CHUNK(end);
223*c9945492SAndroid Build Coastguard Worker w->psize = n | C_INUSE;
224*c9945492SAndroid Build Coastguard Worker w->csize = 0 | C_INUSE;
225*c9945492SAndroid Build Coastguard Worker
226*c9945492SAndroid Build Coastguard Worker /* Fill in header, which may be new or may be replacing a
227*c9945492SAndroid Build Coastguard Worker * zero-size sentinel header at the old end-of-heap. */
228*c9945492SAndroid Build Coastguard Worker w = MEM_TO_CHUNK(p);
229*c9945492SAndroid Build Coastguard Worker w->csize = n | C_INUSE;
230*c9945492SAndroid Build Coastguard Worker
231*c9945492SAndroid Build Coastguard Worker return w;
232*c9945492SAndroid Build Coastguard Worker }
233*c9945492SAndroid Build Coastguard Worker
adjust_size(size_t * n)234*c9945492SAndroid Build Coastguard Worker static int adjust_size(size_t *n)
235*c9945492SAndroid Build Coastguard Worker {
236*c9945492SAndroid Build Coastguard Worker /* Result of pointer difference must fit in ptrdiff_t. */
237*c9945492SAndroid Build Coastguard Worker if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
238*c9945492SAndroid Build Coastguard Worker if (*n) {
239*c9945492SAndroid Build Coastguard Worker errno = ENOMEM;
240*c9945492SAndroid Build Coastguard Worker return -1;
241*c9945492SAndroid Build Coastguard Worker } else {
242*c9945492SAndroid Build Coastguard Worker *n = SIZE_ALIGN;
243*c9945492SAndroid Build Coastguard Worker return 0;
244*c9945492SAndroid Build Coastguard Worker }
245*c9945492SAndroid Build Coastguard Worker }
246*c9945492SAndroid Build Coastguard Worker *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
247*c9945492SAndroid Build Coastguard Worker return 0;
248*c9945492SAndroid Build Coastguard Worker }
249*c9945492SAndroid Build Coastguard Worker
unbin(struct chunk * c,int i)250*c9945492SAndroid Build Coastguard Worker static void unbin(struct chunk *c, int i)
251*c9945492SAndroid Build Coastguard Worker {
252*c9945492SAndroid Build Coastguard Worker if (c->prev == c->next)
253*c9945492SAndroid Build Coastguard Worker a_and_64(&mal.binmap, ~(1ULL<<i));
254*c9945492SAndroid Build Coastguard Worker c->prev->next = c->next;
255*c9945492SAndroid Build Coastguard Worker c->next->prev = c->prev;
256*c9945492SAndroid Build Coastguard Worker c->csize |= C_INUSE;
257*c9945492SAndroid Build Coastguard Worker NEXT_CHUNK(c)->psize |= C_INUSE;
258*c9945492SAndroid Build Coastguard Worker }
259*c9945492SAndroid Build Coastguard Worker
bin_chunk(struct chunk * self,int i)260*c9945492SAndroid Build Coastguard Worker static void bin_chunk(struct chunk *self, int i)
261*c9945492SAndroid Build Coastguard Worker {
262*c9945492SAndroid Build Coastguard Worker self->next = BIN_TO_CHUNK(i);
263*c9945492SAndroid Build Coastguard Worker self->prev = mal.bins[i].tail;
264*c9945492SAndroid Build Coastguard Worker self->next->prev = self;
265*c9945492SAndroid Build Coastguard Worker self->prev->next = self;
266*c9945492SAndroid Build Coastguard Worker if (self->prev == BIN_TO_CHUNK(i))
267*c9945492SAndroid Build Coastguard Worker a_or_64(&mal.binmap, 1ULL<<i);
268*c9945492SAndroid Build Coastguard Worker }
269*c9945492SAndroid Build Coastguard Worker
trim(struct chunk * self,size_t n)270*c9945492SAndroid Build Coastguard Worker static void trim(struct chunk *self, size_t n)
271*c9945492SAndroid Build Coastguard Worker {
272*c9945492SAndroid Build Coastguard Worker size_t n1 = CHUNK_SIZE(self);
273*c9945492SAndroid Build Coastguard Worker struct chunk *next, *split;
274*c9945492SAndroid Build Coastguard Worker
275*c9945492SAndroid Build Coastguard Worker if (n >= n1 - DONTCARE) return;
276*c9945492SAndroid Build Coastguard Worker
277*c9945492SAndroid Build Coastguard Worker next = NEXT_CHUNK(self);
278*c9945492SAndroid Build Coastguard Worker split = (void *)((char *)self + n);
279*c9945492SAndroid Build Coastguard Worker
280*c9945492SAndroid Build Coastguard Worker split->psize = n | C_INUSE;
281*c9945492SAndroid Build Coastguard Worker split->csize = n1-n;
282*c9945492SAndroid Build Coastguard Worker next->psize = n1-n;
283*c9945492SAndroid Build Coastguard Worker self->csize = n | C_INUSE;
284*c9945492SAndroid Build Coastguard Worker
285*c9945492SAndroid Build Coastguard Worker int i = bin_index(n1-n);
286*c9945492SAndroid Build Coastguard Worker lock_bin(i);
287*c9945492SAndroid Build Coastguard Worker
288*c9945492SAndroid Build Coastguard Worker bin_chunk(split, i);
289*c9945492SAndroid Build Coastguard Worker
290*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
291*c9945492SAndroid Build Coastguard Worker }
292*c9945492SAndroid Build Coastguard Worker
malloc(size_t n)293*c9945492SAndroid Build Coastguard Worker void *malloc(size_t n)
294*c9945492SAndroid Build Coastguard Worker {
295*c9945492SAndroid Build Coastguard Worker struct chunk *c;
296*c9945492SAndroid Build Coastguard Worker int i, j;
297*c9945492SAndroid Build Coastguard Worker uint64_t mask;
298*c9945492SAndroid Build Coastguard Worker
299*c9945492SAndroid Build Coastguard Worker if (adjust_size(&n) < 0) return 0;
300*c9945492SAndroid Build Coastguard Worker
301*c9945492SAndroid Build Coastguard Worker if (n > MMAP_THRESHOLD) {
302*c9945492SAndroid Build Coastguard Worker size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE;
303*c9945492SAndroid Build Coastguard Worker char *base = __mmap(0, len, PROT_READ|PROT_WRITE,
304*c9945492SAndroid Build Coastguard Worker MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
305*c9945492SAndroid Build Coastguard Worker if (base == (void *)-1) return 0;
306*c9945492SAndroid Build Coastguard Worker c = (void *)(base + SIZE_ALIGN - OVERHEAD);
307*c9945492SAndroid Build Coastguard Worker c->csize = len - (SIZE_ALIGN - OVERHEAD);
308*c9945492SAndroid Build Coastguard Worker c->psize = SIZE_ALIGN - OVERHEAD;
309*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(c);
310*c9945492SAndroid Build Coastguard Worker }
311*c9945492SAndroid Build Coastguard Worker
312*c9945492SAndroid Build Coastguard Worker i = bin_index_up(n);
313*c9945492SAndroid Build Coastguard Worker if (i<63 && (mal.binmap & (1ULL<<i))) {
314*c9945492SAndroid Build Coastguard Worker lock_bin(i);
315*c9945492SAndroid Build Coastguard Worker c = mal.bins[i].head;
316*c9945492SAndroid Build Coastguard Worker if (c != BIN_TO_CHUNK(i) && CHUNK_SIZE(c)-n <= DONTCARE) {
317*c9945492SAndroid Build Coastguard Worker unbin(c, i);
318*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
319*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(c);
320*c9945492SAndroid Build Coastguard Worker }
321*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
322*c9945492SAndroid Build Coastguard Worker }
323*c9945492SAndroid Build Coastguard Worker lock(mal.split_merge_lock);
324*c9945492SAndroid Build Coastguard Worker for (mask = mal.binmap & -(1ULL<<i); mask; mask -= (mask&-mask)) {
325*c9945492SAndroid Build Coastguard Worker j = first_set(mask);
326*c9945492SAndroid Build Coastguard Worker lock_bin(j);
327*c9945492SAndroid Build Coastguard Worker c = mal.bins[j].head;
328*c9945492SAndroid Build Coastguard Worker if (c != BIN_TO_CHUNK(j)) {
329*c9945492SAndroid Build Coastguard Worker unbin(c, j);
330*c9945492SAndroid Build Coastguard Worker unlock_bin(j);
331*c9945492SAndroid Build Coastguard Worker break;
332*c9945492SAndroid Build Coastguard Worker }
333*c9945492SAndroid Build Coastguard Worker unlock_bin(j);
334*c9945492SAndroid Build Coastguard Worker }
335*c9945492SAndroid Build Coastguard Worker if (!mask) {
336*c9945492SAndroid Build Coastguard Worker c = expand_heap(n);
337*c9945492SAndroid Build Coastguard Worker if (!c) {
338*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
339*c9945492SAndroid Build Coastguard Worker return 0;
340*c9945492SAndroid Build Coastguard Worker }
341*c9945492SAndroid Build Coastguard Worker }
342*c9945492SAndroid Build Coastguard Worker trim(c, n);
343*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
344*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(c);
345*c9945492SAndroid Build Coastguard Worker }
346*c9945492SAndroid Build Coastguard Worker
__malloc_allzerop(void * p)347*c9945492SAndroid Build Coastguard Worker int __malloc_allzerop(void *p)
348*c9945492SAndroid Build Coastguard Worker {
349*c9945492SAndroid Build Coastguard Worker return IS_MMAPPED(MEM_TO_CHUNK(p));
350*c9945492SAndroid Build Coastguard Worker }
351*c9945492SAndroid Build Coastguard Worker
realloc(void * p,size_t n)352*c9945492SAndroid Build Coastguard Worker void *realloc(void *p, size_t n)
353*c9945492SAndroid Build Coastguard Worker {
354*c9945492SAndroid Build Coastguard Worker struct chunk *self, *next;
355*c9945492SAndroid Build Coastguard Worker size_t n0, n1;
356*c9945492SAndroid Build Coastguard Worker void *new;
357*c9945492SAndroid Build Coastguard Worker
358*c9945492SAndroid Build Coastguard Worker if (!p) return malloc(n);
359*c9945492SAndroid Build Coastguard Worker
360*c9945492SAndroid Build Coastguard Worker if (adjust_size(&n) < 0) return 0;
361*c9945492SAndroid Build Coastguard Worker
362*c9945492SAndroid Build Coastguard Worker self = MEM_TO_CHUNK(p);
363*c9945492SAndroid Build Coastguard Worker n1 = n0 = CHUNK_SIZE(self);
364*c9945492SAndroid Build Coastguard Worker
365*c9945492SAndroid Build Coastguard Worker if (n<=n0 && n0-n<=DONTCARE) return p;
366*c9945492SAndroid Build Coastguard Worker
367*c9945492SAndroid Build Coastguard Worker if (IS_MMAPPED(self)) {
368*c9945492SAndroid Build Coastguard Worker size_t extra = self->psize;
369*c9945492SAndroid Build Coastguard Worker char *base = (char *)self - extra;
370*c9945492SAndroid Build Coastguard Worker size_t oldlen = n0 + extra;
371*c9945492SAndroid Build Coastguard Worker size_t newlen = n + extra;
372*c9945492SAndroid Build Coastguard Worker /* Crash on realloc of freed chunk */
373*c9945492SAndroid Build Coastguard Worker if (extra & 1) a_crash();
374*c9945492SAndroid Build Coastguard Worker if (newlen < PAGE_SIZE && (new = malloc(n-OVERHEAD))) {
375*c9945492SAndroid Build Coastguard Worker n0 = n;
376*c9945492SAndroid Build Coastguard Worker goto copy_free_ret;
377*c9945492SAndroid Build Coastguard Worker }
378*c9945492SAndroid Build Coastguard Worker newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE;
379*c9945492SAndroid Build Coastguard Worker if (oldlen == newlen) return p;
380*c9945492SAndroid Build Coastguard Worker base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE);
381*c9945492SAndroid Build Coastguard Worker if (base == (void *)-1)
382*c9945492SAndroid Build Coastguard Worker goto copy_realloc;
383*c9945492SAndroid Build Coastguard Worker self = (void *)(base + extra);
384*c9945492SAndroid Build Coastguard Worker self->csize = newlen - extra;
385*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(self);
386*c9945492SAndroid Build Coastguard Worker }
387*c9945492SAndroid Build Coastguard Worker
388*c9945492SAndroid Build Coastguard Worker next = NEXT_CHUNK(self);
389*c9945492SAndroid Build Coastguard Worker
390*c9945492SAndroid Build Coastguard Worker /* Crash on corrupted footer (likely from buffer overflow) */
391*c9945492SAndroid Build Coastguard Worker if (next->psize != self->csize) a_crash();
392*c9945492SAndroid Build Coastguard Worker
393*c9945492SAndroid Build Coastguard Worker if (n < n0) {
394*c9945492SAndroid Build Coastguard Worker int i = bin_index_up(n);
395*c9945492SAndroid Build Coastguard Worker int j = bin_index(n0);
396*c9945492SAndroid Build Coastguard Worker if (i<j && (mal.binmap & (1ULL << i)))
397*c9945492SAndroid Build Coastguard Worker goto copy_realloc;
398*c9945492SAndroid Build Coastguard Worker struct chunk *split = (void *)((char *)self + n);
399*c9945492SAndroid Build Coastguard Worker self->csize = split->psize = n | C_INUSE;
400*c9945492SAndroid Build Coastguard Worker split->csize = next->psize = n0-n | C_INUSE;
401*c9945492SAndroid Build Coastguard Worker __bin_chunk(split);
402*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(self);
403*c9945492SAndroid Build Coastguard Worker }
404*c9945492SAndroid Build Coastguard Worker
405*c9945492SAndroid Build Coastguard Worker lock(mal.split_merge_lock);
406*c9945492SAndroid Build Coastguard Worker
407*c9945492SAndroid Build Coastguard Worker size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next);
408*c9945492SAndroid Build Coastguard Worker if (n0+nsize >= n) {
409*c9945492SAndroid Build Coastguard Worker int i = bin_index(nsize);
410*c9945492SAndroid Build Coastguard Worker lock_bin(i);
411*c9945492SAndroid Build Coastguard Worker if (!(next->csize & C_INUSE)) {
412*c9945492SAndroid Build Coastguard Worker unbin(next, i);
413*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
414*c9945492SAndroid Build Coastguard Worker next = NEXT_CHUNK(next);
415*c9945492SAndroid Build Coastguard Worker self->csize = next->psize = n0+nsize | C_INUSE;
416*c9945492SAndroid Build Coastguard Worker trim(self, n);
417*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
418*c9945492SAndroid Build Coastguard Worker return CHUNK_TO_MEM(self);
419*c9945492SAndroid Build Coastguard Worker }
420*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
421*c9945492SAndroid Build Coastguard Worker }
422*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
423*c9945492SAndroid Build Coastguard Worker
424*c9945492SAndroid Build Coastguard Worker copy_realloc:
425*c9945492SAndroid Build Coastguard Worker /* As a last resort, allocate a new chunk and copy to it. */
426*c9945492SAndroid Build Coastguard Worker new = malloc(n-OVERHEAD);
427*c9945492SAndroid Build Coastguard Worker if (!new) return 0;
428*c9945492SAndroid Build Coastguard Worker copy_free_ret:
429*c9945492SAndroid Build Coastguard Worker memcpy(new, p, (n<n0 ? n : n0) - OVERHEAD);
430*c9945492SAndroid Build Coastguard Worker free(CHUNK_TO_MEM(self));
431*c9945492SAndroid Build Coastguard Worker return new;
432*c9945492SAndroid Build Coastguard Worker }
433*c9945492SAndroid Build Coastguard Worker
__bin_chunk(struct chunk * self)434*c9945492SAndroid Build Coastguard Worker void __bin_chunk(struct chunk *self)
435*c9945492SAndroid Build Coastguard Worker {
436*c9945492SAndroid Build Coastguard Worker struct chunk *next = NEXT_CHUNK(self);
437*c9945492SAndroid Build Coastguard Worker
438*c9945492SAndroid Build Coastguard Worker /* Crash on corrupted footer (likely from buffer overflow) */
439*c9945492SAndroid Build Coastguard Worker if (next->psize != self->csize) a_crash();
440*c9945492SAndroid Build Coastguard Worker
441*c9945492SAndroid Build Coastguard Worker lock(mal.split_merge_lock);
442*c9945492SAndroid Build Coastguard Worker
443*c9945492SAndroid Build Coastguard Worker size_t osize = CHUNK_SIZE(self), size = osize;
444*c9945492SAndroid Build Coastguard Worker
445*c9945492SAndroid Build Coastguard Worker /* Since we hold split_merge_lock, only transition from free to
446*c9945492SAndroid Build Coastguard Worker * in-use can race; in-use to free is impossible */
447*c9945492SAndroid Build Coastguard Worker size_t psize = self->psize & C_INUSE ? 0 : CHUNK_PSIZE(self);
448*c9945492SAndroid Build Coastguard Worker size_t nsize = next->csize & C_INUSE ? 0 : CHUNK_SIZE(next);
449*c9945492SAndroid Build Coastguard Worker
450*c9945492SAndroid Build Coastguard Worker if (psize) {
451*c9945492SAndroid Build Coastguard Worker int i = bin_index(psize);
452*c9945492SAndroid Build Coastguard Worker lock_bin(i);
453*c9945492SAndroid Build Coastguard Worker if (!(self->psize & C_INUSE)) {
454*c9945492SAndroid Build Coastguard Worker struct chunk *prev = PREV_CHUNK(self);
455*c9945492SAndroid Build Coastguard Worker unbin(prev, i);
456*c9945492SAndroid Build Coastguard Worker self = prev;
457*c9945492SAndroid Build Coastguard Worker size += psize;
458*c9945492SAndroid Build Coastguard Worker }
459*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
460*c9945492SAndroid Build Coastguard Worker }
461*c9945492SAndroid Build Coastguard Worker if (nsize) {
462*c9945492SAndroid Build Coastguard Worker int i = bin_index(nsize);
463*c9945492SAndroid Build Coastguard Worker lock_bin(i);
464*c9945492SAndroid Build Coastguard Worker if (!(next->csize & C_INUSE)) {
465*c9945492SAndroid Build Coastguard Worker unbin(next, i);
466*c9945492SAndroid Build Coastguard Worker next = NEXT_CHUNK(next);
467*c9945492SAndroid Build Coastguard Worker size += nsize;
468*c9945492SAndroid Build Coastguard Worker }
469*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
470*c9945492SAndroid Build Coastguard Worker }
471*c9945492SAndroid Build Coastguard Worker
472*c9945492SAndroid Build Coastguard Worker int i = bin_index(size);
473*c9945492SAndroid Build Coastguard Worker lock_bin(i);
474*c9945492SAndroid Build Coastguard Worker
475*c9945492SAndroid Build Coastguard Worker self->csize = size;
476*c9945492SAndroid Build Coastguard Worker next->psize = size;
477*c9945492SAndroid Build Coastguard Worker bin_chunk(self, i);
478*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
479*c9945492SAndroid Build Coastguard Worker
480*c9945492SAndroid Build Coastguard Worker /* Replace middle of large chunks with fresh zero pages */
481*c9945492SAndroid Build Coastguard Worker if (size > RECLAIM && (size^(size-osize)) > size-osize) {
482*c9945492SAndroid Build Coastguard Worker uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE;
483*c9945492SAndroid Build Coastguard Worker uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE;
484*c9945492SAndroid Build Coastguard Worker int e = errno;
485*c9945492SAndroid Build Coastguard Worker #if 1
486*c9945492SAndroid Build Coastguard Worker __madvise((void *)a, b-a, MADV_DONTNEED);
487*c9945492SAndroid Build Coastguard Worker #else
488*c9945492SAndroid Build Coastguard Worker __mmap((void *)a, b-a, PROT_READ|PROT_WRITE,
489*c9945492SAndroid Build Coastguard Worker MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
490*c9945492SAndroid Build Coastguard Worker #endif
491*c9945492SAndroid Build Coastguard Worker errno = e;
492*c9945492SAndroid Build Coastguard Worker }
493*c9945492SAndroid Build Coastguard Worker
494*c9945492SAndroid Build Coastguard Worker unlock_bin(i);
495*c9945492SAndroid Build Coastguard Worker }
496*c9945492SAndroid Build Coastguard Worker
unmap_chunk(struct chunk * self)497*c9945492SAndroid Build Coastguard Worker static void unmap_chunk(struct chunk *self)
498*c9945492SAndroid Build Coastguard Worker {
499*c9945492SAndroid Build Coastguard Worker size_t extra = self->psize;
500*c9945492SAndroid Build Coastguard Worker char *base = (char *)self - extra;
501*c9945492SAndroid Build Coastguard Worker size_t len = CHUNK_SIZE(self) + extra;
502*c9945492SAndroid Build Coastguard Worker /* Crash on double free */
503*c9945492SAndroid Build Coastguard Worker if (extra & 1) a_crash();
504*c9945492SAndroid Build Coastguard Worker int e = errno;
505*c9945492SAndroid Build Coastguard Worker __munmap(base, len);
506*c9945492SAndroid Build Coastguard Worker errno = e;
507*c9945492SAndroid Build Coastguard Worker }
508*c9945492SAndroid Build Coastguard Worker
free(void * p)509*c9945492SAndroid Build Coastguard Worker void free(void *p)
510*c9945492SAndroid Build Coastguard Worker {
511*c9945492SAndroid Build Coastguard Worker if (!p) return;
512*c9945492SAndroid Build Coastguard Worker
513*c9945492SAndroid Build Coastguard Worker struct chunk *self = MEM_TO_CHUNK(p);
514*c9945492SAndroid Build Coastguard Worker
515*c9945492SAndroid Build Coastguard Worker if (IS_MMAPPED(self))
516*c9945492SAndroid Build Coastguard Worker unmap_chunk(self);
517*c9945492SAndroid Build Coastguard Worker else
518*c9945492SAndroid Build Coastguard Worker __bin_chunk(self);
519*c9945492SAndroid Build Coastguard Worker }
520*c9945492SAndroid Build Coastguard Worker
__malloc_donate(char * start,char * end)521*c9945492SAndroid Build Coastguard Worker void __malloc_donate(char *start, char *end)
522*c9945492SAndroid Build Coastguard Worker {
523*c9945492SAndroid Build Coastguard Worker size_t align_start_up = (SIZE_ALIGN-1) & (-(uintptr_t)start - OVERHEAD);
524*c9945492SAndroid Build Coastguard Worker size_t align_end_down = (SIZE_ALIGN-1) & (uintptr_t)end;
525*c9945492SAndroid Build Coastguard Worker
526*c9945492SAndroid Build Coastguard Worker /* Getting past this condition ensures that the padding for alignment
527*c9945492SAndroid Build Coastguard Worker * and header overhead will not overflow and will leave a nonzero
528*c9945492SAndroid Build Coastguard Worker * multiple of SIZE_ALIGN bytes between start and end. */
529*c9945492SAndroid Build Coastguard Worker if (end - start <= OVERHEAD + align_start_up + align_end_down)
530*c9945492SAndroid Build Coastguard Worker return;
531*c9945492SAndroid Build Coastguard Worker start += align_start_up + OVERHEAD;
532*c9945492SAndroid Build Coastguard Worker end -= align_end_down;
533*c9945492SAndroid Build Coastguard Worker
534*c9945492SAndroid Build Coastguard Worker struct chunk *c = MEM_TO_CHUNK(start), *n = MEM_TO_CHUNK(end);
535*c9945492SAndroid Build Coastguard Worker c->psize = n->csize = C_INUSE;
536*c9945492SAndroid Build Coastguard Worker c->csize = n->psize = C_INUSE | (end-start);
537*c9945492SAndroid Build Coastguard Worker __bin_chunk(c);
538*c9945492SAndroid Build Coastguard Worker }
539*c9945492SAndroid Build Coastguard Worker
__malloc_atfork(int who)540*c9945492SAndroid Build Coastguard Worker void __malloc_atfork(int who)
541*c9945492SAndroid Build Coastguard Worker {
542*c9945492SAndroid Build Coastguard Worker if (who<0) {
543*c9945492SAndroid Build Coastguard Worker lock(mal.split_merge_lock);
544*c9945492SAndroid Build Coastguard Worker for (int i=0; i<64; i++)
545*c9945492SAndroid Build Coastguard Worker lock(mal.bins[i].lock);
546*c9945492SAndroid Build Coastguard Worker } else if (!who) {
547*c9945492SAndroid Build Coastguard Worker for (int i=0; i<64; i++)
548*c9945492SAndroid Build Coastguard Worker unlock(mal.bins[i].lock);
549*c9945492SAndroid Build Coastguard Worker unlock(mal.split_merge_lock);
550*c9945492SAndroid Build Coastguard Worker } else {
551*c9945492SAndroid Build Coastguard Worker for (int i=0; i<64; i++)
552*c9945492SAndroid Build Coastguard Worker mal.bins[i].lock[0] = mal.bins[i].lock[1] = 0;
553*c9945492SAndroid Build Coastguard Worker mal.split_merge_lock[1] = 0;
554*c9945492SAndroid Build Coastguard Worker mal.split_merge_lock[0] = 0;
555*c9945492SAndroid Build Coastguard Worker }
556*c9945492SAndroid Build Coastguard Worker }
557