1*c9945492SAndroid Build Coastguard Worker #ifndef MALLOC_META_H
2*c9945492SAndroid Build Coastguard Worker #define MALLOC_META_H
3*c9945492SAndroid Build Coastguard Worker
4*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
5*c9945492SAndroid Build Coastguard Worker #include <errno.h>
6*c9945492SAndroid Build Coastguard Worker #include <limits.h>
7*c9945492SAndroid Build Coastguard Worker #include "glue.h"
8*c9945492SAndroid Build Coastguard Worker
9*c9945492SAndroid Build Coastguard Worker __attribute__((__visibility__("hidden")))
10*c9945492SAndroid Build Coastguard Worker extern const uint16_t size_classes[];
11*c9945492SAndroid Build Coastguard Worker
12*c9945492SAndroid Build Coastguard Worker #define MMAP_THRESHOLD 131052
13*c9945492SAndroid Build Coastguard Worker
14*c9945492SAndroid Build Coastguard Worker #define UNIT 16
15*c9945492SAndroid Build Coastguard Worker #define IB 4
16*c9945492SAndroid Build Coastguard Worker
17*c9945492SAndroid Build Coastguard Worker struct group {
18*c9945492SAndroid Build Coastguard Worker struct meta *meta;
19*c9945492SAndroid Build Coastguard Worker unsigned char active_idx:5;
20*c9945492SAndroid Build Coastguard Worker char pad[UNIT - sizeof(struct meta *) - 1];
21*c9945492SAndroid Build Coastguard Worker unsigned char storage[];
22*c9945492SAndroid Build Coastguard Worker };
23*c9945492SAndroid Build Coastguard Worker
24*c9945492SAndroid Build Coastguard Worker struct meta {
25*c9945492SAndroid Build Coastguard Worker struct meta *prev, *next;
26*c9945492SAndroid Build Coastguard Worker struct group *mem;
27*c9945492SAndroid Build Coastguard Worker volatile int avail_mask, freed_mask;
28*c9945492SAndroid Build Coastguard Worker uintptr_t last_idx:5;
29*c9945492SAndroid Build Coastguard Worker uintptr_t freeable:1;
30*c9945492SAndroid Build Coastguard Worker uintptr_t sizeclass:6;
31*c9945492SAndroid Build Coastguard Worker uintptr_t maplen:8*sizeof(uintptr_t)-12;
32*c9945492SAndroid Build Coastguard Worker };
33*c9945492SAndroid Build Coastguard Worker
34*c9945492SAndroid Build Coastguard Worker struct meta_area {
35*c9945492SAndroid Build Coastguard Worker uint64_t check;
36*c9945492SAndroid Build Coastguard Worker struct meta_area *next;
37*c9945492SAndroid Build Coastguard Worker int nslots;
38*c9945492SAndroid Build Coastguard Worker struct meta slots[];
39*c9945492SAndroid Build Coastguard Worker };
40*c9945492SAndroid Build Coastguard Worker
41*c9945492SAndroid Build Coastguard Worker struct malloc_context {
42*c9945492SAndroid Build Coastguard Worker uint64_t secret;
43*c9945492SAndroid Build Coastguard Worker #ifndef PAGESIZE
44*c9945492SAndroid Build Coastguard Worker size_t pagesize;
45*c9945492SAndroid Build Coastguard Worker #endif
46*c9945492SAndroid Build Coastguard Worker int init_done;
47*c9945492SAndroid Build Coastguard Worker unsigned mmap_counter;
48*c9945492SAndroid Build Coastguard Worker struct meta *free_meta_head;
49*c9945492SAndroid Build Coastguard Worker struct meta *avail_meta;
50*c9945492SAndroid Build Coastguard Worker size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;
51*c9945492SAndroid Build Coastguard Worker struct meta_area *meta_area_head, *meta_area_tail;
52*c9945492SAndroid Build Coastguard Worker unsigned char *avail_meta_areas;
53*c9945492SAndroid Build Coastguard Worker struct meta *active[48];
54*c9945492SAndroid Build Coastguard Worker size_t usage_by_class[48];
55*c9945492SAndroid Build Coastguard Worker uint8_t unmap_seq[32], bounces[32];
56*c9945492SAndroid Build Coastguard Worker uint8_t seq;
57*c9945492SAndroid Build Coastguard Worker uintptr_t brk;
58*c9945492SAndroid Build Coastguard Worker };
59*c9945492SAndroid Build Coastguard Worker
60*c9945492SAndroid Build Coastguard Worker __attribute__((__visibility__("hidden")))
61*c9945492SAndroid Build Coastguard Worker extern struct malloc_context ctx;
62*c9945492SAndroid Build Coastguard Worker
63*c9945492SAndroid Build Coastguard Worker #ifdef PAGESIZE
64*c9945492SAndroid Build Coastguard Worker #define PGSZ PAGESIZE
65*c9945492SAndroid Build Coastguard Worker #else
66*c9945492SAndroid Build Coastguard Worker #define PGSZ ctx.pagesize
67*c9945492SAndroid Build Coastguard Worker #endif
68*c9945492SAndroid Build Coastguard Worker
69*c9945492SAndroid Build Coastguard Worker __attribute__((__visibility__("hidden")))
70*c9945492SAndroid Build Coastguard Worker struct meta *alloc_meta(void);
71*c9945492SAndroid Build Coastguard Worker
72*c9945492SAndroid Build Coastguard Worker __attribute__((__visibility__("hidden")))
73*c9945492SAndroid Build Coastguard Worker int is_allzero(void *);
74*c9945492SAndroid Build Coastguard Worker
queue(struct meta ** phead,struct meta * m)75*c9945492SAndroid Build Coastguard Worker static inline void queue(struct meta **phead, struct meta *m)
76*c9945492SAndroid Build Coastguard Worker {
77*c9945492SAndroid Build Coastguard Worker assert(!m->next);
78*c9945492SAndroid Build Coastguard Worker assert(!m->prev);
79*c9945492SAndroid Build Coastguard Worker if (*phead) {
80*c9945492SAndroid Build Coastguard Worker struct meta *head = *phead;
81*c9945492SAndroid Build Coastguard Worker m->next = head;
82*c9945492SAndroid Build Coastguard Worker m->prev = head->prev;
83*c9945492SAndroid Build Coastguard Worker m->next->prev = m->prev->next = m;
84*c9945492SAndroid Build Coastguard Worker } else {
85*c9945492SAndroid Build Coastguard Worker m->prev = m->next = m;
86*c9945492SAndroid Build Coastguard Worker *phead = m;
87*c9945492SAndroid Build Coastguard Worker }
88*c9945492SAndroid Build Coastguard Worker }
89*c9945492SAndroid Build Coastguard Worker
dequeue(struct meta ** phead,struct meta * m)90*c9945492SAndroid Build Coastguard Worker static inline void dequeue(struct meta **phead, struct meta *m)
91*c9945492SAndroid Build Coastguard Worker {
92*c9945492SAndroid Build Coastguard Worker if (m->next != m) {
93*c9945492SAndroid Build Coastguard Worker m->prev->next = m->next;
94*c9945492SAndroid Build Coastguard Worker m->next->prev = m->prev;
95*c9945492SAndroid Build Coastguard Worker if (*phead == m) *phead = m->next;
96*c9945492SAndroid Build Coastguard Worker } else {
97*c9945492SAndroid Build Coastguard Worker *phead = 0;
98*c9945492SAndroid Build Coastguard Worker }
99*c9945492SAndroid Build Coastguard Worker m->prev = m->next = 0;
100*c9945492SAndroid Build Coastguard Worker }
101*c9945492SAndroid Build Coastguard Worker
dequeue_head(struct meta ** phead)102*c9945492SAndroid Build Coastguard Worker static inline struct meta *dequeue_head(struct meta **phead)
103*c9945492SAndroid Build Coastguard Worker {
104*c9945492SAndroid Build Coastguard Worker struct meta *m = *phead;
105*c9945492SAndroid Build Coastguard Worker if (m) dequeue(phead, m);
106*c9945492SAndroid Build Coastguard Worker return m;
107*c9945492SAndroid Build Coastguard Worker }
108*c9945492SAndroid Build Coastguard Worker
free_meta(struct meta * m)109*c9945492SAndroid Build Coastguard Worker static inline void free_meta(struct meta *m)
110*c9945492SAndroid Build Coastguard Worker {
111*c9945492SAndroid Build Coastguard Worker *m = (struct meta){0};
112*c9945492SAndroid Build Coastguard Worker queue(&ctx.free_meta_head, m);
113*c9945492SAndroid Build Coastguard Worker }
114*c9945492SAndroid Build Coastguard Worker
activate_group(struct meta * m)115*c9945492SAndroid Build Coastguard Worker static inline uint32_t activate_group(struct meta *m)
116*c9945492SAndroid Build Coastguard Worker {
117*c9945492SAndroid Build Coastguard Worker assert(!m->avail_mask);
118*c9945492SAndroid Build Coastguard Worker uint32_t mask, act = (2u<<m->mem->active_idx)-1;
119*c9945492SAndroid Build Coastguard Worker do mask = m->freed_mask;
120*c9945492SAndroid Build Coastguard Worker while (a_cas(&m->freed_mask, mask, mask&~act)!=mask);
121*c9945492SAndroid Build Coastguard Worker return m->avail_mask = mask & act;
122*c9945492SAndroid Build Coastguard Worker }
123*c9945492SAndroid Build Coastguard Worker
get_slot_index(const unsigned char * p)124*c9945492SAndroid Build Coastguard Worker static inline int get_slot_index(const unsigned char *p)
125*c9945492SAndroid Build Coastguard Worker {
126*c9945492SAndroid Build Coastguard Worker return p[-3] & 31;
127*c9945492SAndroid Build Coastguard Worker }
128*c9945492SAndroid Build Coastguard Worker
get_meta(const unsigned char * p)129*c9945492SAndroid Build Coastguard Worker static inline struct meta *get_meta(const unsigned char *p)
130*c9945492SAndroid Build Coastguard Worker {
131*c9945492SAndroid Build Coastguard Worker assert(!((uintptr_t)p & 15));
132*c9945492SAndroid Build Coastguard Worker int offset = *(const uint16_t *)(p - 2);
133*c9945492SAndroid Build Coastguard Worker int index = get_slot_index(p);
134*c9945492SAndroid Build Coastguard Worker if (p[-4]) {
135*c9945492SAndroid Build Coastguard Worker assert(!offset);
136*c9945492SAndroid Build Coastguard Worker offset = *(uint32_t *)(p - 8);
137*c9945492SAndroid Build Coastguard Worker assert(offset > 0xffff);
138*c9945492SAndroid Build Coastguard Worker }
139*c9945492SAndroid Build Coastguard Worker const struct group *base = (const void *)(p - UNIT*offset - UNIT);
140*c9945492SAndroid Build Coastguard Worker const struct meta *meta = base->meta;
141*c9945492SAndroid Build Coastguard Worker assert(meta->mem == base);
142*c9945492SAndroid Build Coastguard Worker assert(index <= meta->last_idx);
143*c9945492SAndroid Build Coastguard Worker assert(!(meta->avail_mask & (1u<<index)));
144*c9945492SAndroid Build Coastguard Worker assert(!(meta->freed_mask & (1u<<index)));
145*c9945492SAndroid Build Coastguard Worker const struct meta_area *area = (void *)((uintptr_t)meta & -4096);
146*c9945492SAndroid Build Coastguard Worker assert(area->check == ctx.secret);
147*c9945492SAndroid Build Coastguard Worker if (meta->sizeclass < 48) {
148*c9945492SAndroid Build Coastguard Worker assert(offset >= size_classes[meta->sizeclass]*index);
149*c9945492SAndroid Build Coastguard Worker assert(offset < size_classes[meta->sizeclass]*(index+1));
150*c9945492SAndroid Build Coastguard Worker } else {
151*c9945492SAndroid Build Coastguard Worker assert(meta->sizeclass == 63);
152*c9945492SAndroid Build Coastguard Worker }
153*c9945492SAndroid Build Coastguard Worker if (meta->maplen) {
154*c9945492SAndroid Build Coastguard Worker assert(offset <= meta->maplen*4096UL/UNIT - 1);
155*c9945492SAndroid Build Coastguard Worker }
156*c9945492SAndroid Build Coastguard Worker return (struct meta *)meta;
157*c9945492SAndroid Build Coastguard Worker }
158*c9945492SAndroid Build Coastguard Worker
get_nominal_size(const unsigned char * p,const unsigned char * end)159*c9945492SAndroid Build Coastguard Worker static inline size_t get_nominal_size(const unsigned char *p, const unsigned char *end)
160*c9945492SAndroid Build Coastguard Worker {
161*c9945492SAndroid Build Coastguard Worker size_t reserved = p[-3] >> 5;
162*c9945492SAndroid Build Coastguard Worker if (reserved >= 5) {
163*c9945492SAndroid Build Coastguard Worker assert(reserved == 5);
164*c9945492SAndroid Build Coastguard Worker reserved = *(const uint32_t *)(end-4);
165*c9945492SAndroid Build Coastguard Worker assert(reserved >= 5);
166*c9945492SAndroid Build Coastguard Worker assert(!end[-5]);
167*c9945492SAndroid Build Coastguard Worker }
168*c9945492SAndroid Build Coastguard Worker assert(reserved <= end-p);
169*c9945492SAndroid Build Coastguard Worker assert(!*(end-reserved));
170*c9945492SAndroid Build Coastguard Worker // also check the slot's overflow byte
171*c9945492SAndroid Build Coastguard Worker assert(!*end);
172*c9945492SAndroid Build Coastguard Worker return end-reserved-p;
173*c9945492SAndroid Build Coastguard Worker }
174*c9945492SAndroid Build Coastguard Worker
get_stride(const struct meta * g)175*c9945492SAndroid Build Coastguard Worker static inline size_t get_stride(const struct meta *g)
176*c9945492SAndroid Build Coastguard Worker {
177*c9945492SAndroid Build Coastguard Worker if (!g->last_idx && g->maplen) {
178*c9945492SAndroid Build Coastguard Worker return g->maplen*4096UL - UNIT;
179*c9945492SAndroid Build Coastguard Worker } else {
180*c9945492SAndroid Build Coastguard Worker return UNIT*size_classes[g->sizeclass];
181*c9945492SAndroid Build Coastguard Worker }
182*c9945492SAndroid Build Coastguard Worker }
183*c9945492SAndroid Build Coastguard Worker
set_size(unsigned char * p,unsigned char * end,size_t n)184*c9945492SAndroid Build Coastguard Worker static inline void set_size(unsigned char *p, unsigned char *end, size_t n)
185*c9945492SAndroid Build Coastguard Worker {
186*c9945492SAndroid Build Coastguard Worker int reserved = end-p-n;
187*c9945492SAndroid Build Coastguard Worker if (reserved) end[-reserved] = 0;
188*c9945492SAndroid Build Coastguard Worker if (reserved >= 5) {
189*c9945492SAndroid Build Coastguard Worker *(uint32_t *)(end-4) = reserved;
190*c9945492SAndroid Build Coastguard Worker end[-5] = 0;
191*c9945492SAndroid Build Coastguard Worker reserved = 5;
192*c9945492SAndroid Build Coastguard Worker }
193*c9945492SAndroid Build Coastguard Worker p[-3] = (p[-3]&31) + (reserved<<5);
194*c9945492SAndroid Build Coastguard Worker }
195*c9945492SAndroid Build Coastguard Worker
enframe(struct meta * g,int idx,size_t n,int ctr)196*c9945492SAndroid Build Coastguard Worker static inline void *enframe(struct meta *g, int idx, size_t n, int ctr)
197*c9945492SAndroid Build Coastguard Worker {
198*c9945492SAndroid Build Coastguard Worker size_t stride = get_stride(g);
199*c9945492SAndroid Build Coastguard Worker size_t slack = (stride-IB-n)/UNIT;
200*c9945492SAndroid Build Coastguard Worker unsigned char *p = g->mem->storage + stride*idx;
201*c9945492SAndroid Build Coastguard Worker unsigned char *end = p+stride-IB;
202*c9945492SAndroid Build Coastguard Worker // cycle offset within slot to increase interval to address
203*c9945492SAndroid Build Coastguard Worker // reuse, facilitate trapping double-free.
204*c9945492SAndroid Build Coastguard Worker int off = (p[-3] ? *(uint16_t *)(p-2) + 1 : ctr) & 255;
205*c9945492SAndroid Build Coastguard Worker assert(!p[-4]);
206*c9945492SAndroid Build Coastguard Worker if (off > slack) {
207*c9945492SAndroid Build Coastguard Worker size_t m = slack;
208*c9945492SAndroid Build Coastguard Worker m |= m>>1; m |= m>>2; m |= m>>4;
209*c9945492SAndroid Build Coastguard Worker off &= m;
210*c9945492SAndroid Build Coastguard Worker if (off > slack) off -= slack+1;
211*c9945492SAndroid Build Coastguard Worker assert(off <= slack);
212*c9945492SAndroid Build Coastguard Worker }
213*c9945492SAndroid Build Coastguard Worker if (off) {
214*c9945492SAndroid Build Coastguard Worker // store offset in unused header at offset zero
215*c9945492SAndroid Build Coastguard Worker // if enframing at non-zero offset.
216*c9945492SAndroid Build Coastguard Worker *(uint16_t *)(p-2) = off;
217*c9945492SAndroid Build Coastguard Worker p[-3] = 7<<5;
218*c9945492SAndroid Build Coastguard Worker p += UNIT*off;
219*c9945492SAndroid Build Coastguard Worker // for nonzero offset there is no permanent check
220*c9945492SAndroid Build Coastguard Worker // byte, so make one.
221*c9945492SAndroid Build Coastguard Worker p[-4] = 0;
222*c9945492SAndroid Build Coastguard Worker }
223*c9945492SAndroid Build Coastguard Worker *(uint16_t *)(p-2) = (size_t)(p-g->mem->storage)/UNIT;
224*c9945492SAndroid Build Coastguard Worker p[-3] = idx;
225*c9945492SAndroid Build Coastguard Worker set_size(p, end, n);
226*c9945492SAndroid Build Coastguard Worker return p;
227*c9945492SAndroid Build Coastguard Worker }
228*c9945492SAndroid Build Coastguard Worker
size_to_class(size_t n)229*c9945492SAndroid Build Coastguard Worker static inline int size_to_class(size_t n)
230*c9945492SAndroid Build Coastguard Worker {
231*c9945492SAndroid Build Coastguard Worker n = (n+IB-1)>>4;
232*c9945492SAndroid Build Coastguard Worker if (n<10) return n;
233*c9945492SAndroid Build Coastguard Worker n++;
234*c9945492SAndroid Build Coastguard Worker int i = (28-a_clz_32(n))*4 + 8;
235*c9945492SAndroid Build Coastguard Worker if (n>size_classes[i+1]) i+=2;
236*c9945492SAndroid Build Coastguard Worker if (n>size_classes[i]) i++;
237*c9945492SAndroid Build Coastguard Worker return i;
238*c9945492SAndroid Build Coastguard Worker }
239*c9945492SAndroid Build Coastguard Worker
size_overflows(size_t n)240*c9945492SAndroid Build Coastguard Worker static inline int size_overflows(size_t n)
241*c9945492SAndroid Build Coastguard Worker {
242*c9945492SAndroid Build Coastguard Worker if (n >= SIZE_MAX/2 - 4096) {
243*c9945492SAndroid Build Coastguard Worker errno = ENOMEM;
244*c9945492SAndroid Build Coastguard Worker return 1;
245*c9945492SAndroid Build Coastguard Worker }
246*c9945492SAndroid Build Coastguard Worker return 0;
247*c9945492SAndroid Build Coastguard Worker }
248*c9945492SAndroid Build Coastguard Worker
step_seq(void)249*c9945492SAndroid Build Coastguard Worker static inline void step_seq(void)
250*c9945492SAndroid Build Coastguard Worker {
251*c9945492SAndroid Build Coastguard Worker if (ctx.seq==255) {
252*c9945492SAndroid Build Coastguard Worker for (int i=0; i<32; i++) ctx.unmap_seq[i] = 0;
253*c9945492SAndroid Build Coastguard Worker ctx.seq = 1;
254*c9945492SAndroid Build Coastguard Worker } else {
255*c9945492SAndroid Build Coastguard Worker ctx.seq++;
256*c9945492SAndroid Build Coastguard Worker }
257*c9945492SAndroid Build Coastguard Worker }
258*c9945492SAndroid Build Coastguard Worker
record_seq(int sc)259*c9945492SAndroid Build Coastguard Worker static inline void record_seq(int sc)
260*c9945492SAndroid Build Coastguard Worker {
261*c9945492SAndroid Build Coastguard Worker if (sc-7U < 32) ctx.unmap_seq[sc-7] = ctx.seq;
262*c9945492SAndroid Build Coastguard Worker }
263*c9945492SAndroid Build Coastguard Worker
account_bounce(int sc)264*c9945492SAndroid Build Coastguard Worker static inline void account_bounce(int sc)
265*c9945492SAndroid Build Coastguard Worker {
266*c9945492SAndroid Build Coastguard Worker if (sc-7U < 32) {
267*c9945492SAndroid Build Coastguard Worker int seq = ctx.unmap_seq[sc-7];
268*c9945492SAndroid Build Coastguard Worker if (seq && ctx.seq-seq < 10) {
269*c9945492SAndroid Build Coastguard Worker if (ctx.bounces[sc-7]+1 < 100)
270*c9945492SAndroid Build Coastguard Worker ctx.bounces[sc-7]++;
271*c9945492SAndroid Build Coastguard Worker else
272*c9945492SAndroid Build Coastguard Worker ctx.bounces[sc-7] = 150;
273*c9945492SAndroid Build Coastguard Worker }
274*c9945492SAndroid Build Coastguard Worker }
275*c9945492SAndroid Build Coastguard Worker }
276*c9945492SAndroid Build Coastguard Worker
decay_bounces(int sc)277*c9945492SAndroid Build Coastguard Worker static inline void decay_bounces(int sc)
278*c9945492SAndroid Build Coastguard Worker {
279*c9945492SAndroid Build Coastguard Worker if (sc-7U < 32 && ctx.bounces[sc-7])
280*c9945492SAndroid Build Coastguard Worker ctx.bounces[sc-7]--;
281*c9945492SAndroid Build Coastguard Worker }
282*c9945492SAndroid Build Coastguard Worker
is_bouncing(int sc)283*c9945492SAndroid Build Coastguard Worker static inline int is_bouncing(int sc)
284*c9945492SAndroid Build Coastguard Worker {
285*c9945492SAndroid Build Coastguard Worker return (sc-7U < 32 && ctx.bounces[sc-7] >= 100);
286*c9945492SAndroid Build Coastguard Worker }
287*c9945492SAndroid Build Coastguard Worker
288*c9945492SAndroid Build Coastguard Worker #endif
289