xref: /aosp_15_r20/external/musl/src/malloc/mallocng/meta.h (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
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