xref: /minix3/libexec/ld.elf_so/xmalloc.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: xmalloc.c,v 1.12 2013/01/24 17:57:29 christos Exp $	*/
2e83f7ba2SBen Gras 
3e83f7ba2SBen Gras /*
4e83f7ba2SBen Gras  * Copyright 1996 John D. Polstra.
5e83f7ba2SBen Gras  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6e83f7ba2SBen Gras  * All rights reserved.
7e83f7ba2SBen Gras  *
8e83f7ba2SBen Gras  * Redistribution and use in source and binary forms, with or without
9e83f7ba2SBen Gras  * modification, are permitted provided that the following conditions
10e83f7ba2SBen Gras  * are met:
11e83f7ba2SBen Gras  * 1. Redistributions of source code must retain the above copyright
12e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer.
13e83f7ba2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
14e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
15e83f7ba2SBen Gras  *    documentation and/or other materials provided with the distribution.
16e83f7ba2SBen Gras  * 3. All advertising materials mentioning features or use of this software
17e83f7ba2SBen Gras  *    must display the following acknowledgement:
18e83f7ba2SBen Gras  *      This product includes software developed by John Polstra.
19e83f7ba2SBen Gras  * 4. The name of the author may not be used to endorse or promote products
20e83f7ba2SBen Gras  *    derived from this software without specific prior written permission.
21e83f7ba2SBen Gras  *
22e83f7ba2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23e83f7ba2SBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24e83f7ba2SBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25e83f7ba2SBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26e83f7ba2SBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27e83f7ba2SBen Gras  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28e83f7ba2SBen Gras  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29e83f7ba2SBen Gras  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30e83f7ba2SBen Gras  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31e83f7ba2SBen Gras  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32e83f7ba2SBen Gras  */
33e83f7ba2SBen Gras 
34e83f7ba2SBen Gras /*
35e83f7ba2SBen Gras  * Copyright (c) 1983 Regents of the University of California.
36e83f7ba2SBen Gras  * All rights reserved.
37e83f7ba2SBen Gras  *
38e83f7ba2SBen Gras  * Redistribution and use in source and binary forms, with or without
39e83f7ba2SBen Gras  * modification, are permitted provided that the following conditions
40e83f7ba2SBen Gras  * are met:
41e83f7ba2SBen Gras  * 1. Redistributions of source code must retain the above copyright
42e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer.
43e83f7ba2SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
44e83f7ba2SBen Gras  *    notice, this list of conditions and the following disclaimer in the
45e83f7ba2SBen Gras  *    documentation and/or other materials provided with the distribution.
46e83f7ba2SBen Gras  * 3. Neither the name of the University nor the names of its contributors
47e83f7ba2SBen Gras  *    may be used to endorse or promote products derived from this software
48e83f7ba2SBen Gras  *    without specific prior written permission.
49e83f7ba2SBen Gras  *
50e83f7ba2SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51e83f7ba2SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52e83f7ba2SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53e83f7ba2SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54e83f7ba2SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55e83f7ba2SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56e83f7ba2SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57e83f7ba2SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58e83f7ba2SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59e83f7ba2SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60e83f7ba2SBen Gras  * SUCH DAMAGE.
61e83f7ba2SBen Gras  */
62e83f7ba2SBen Gras 
63e83f7ba2SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
64e83f7ba2SBen Gras /*static char *sccsid = "from: @(#)malloc.c	5.11 (Berkeley) 2/23/91";*/
65e83f7ba2SBen Gras #endif /* LIBC_SCCS and not lint */
66e83f7ba2SBen Gras 
67e83f7ba2SBen Gras /*
68e83f7ba2SBen Gras  * malloc.c (Caltech) 2/21/82
69e83f7ba2SBen Gras  * Chris Kingsley, kingsley@cit-20.
70e83f7ba2SBen Gras  *
71e83f7ba2SBen Gras  * This is a very fast storage allocator.  It allocates blocks of a small
72e83f7ba2SBen Gras  * number of different sizes, and keeps free lists of each size.  Blocks that
73e83f7ba2SBen Gras  * don't exactly fit are passed up to the next larger size.  In this
74e83f7ba2SBen Gras  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
75e83f7ba2SBen Gras  * This is designed for use in a virtual memory environment.
76e83f7ba2SBen Gras  */
77e83f7ba2SBen Gras 
78e83f7ba2SBen Gras #include <sys/cdefs.h>
79e83f7ba2SBen Gras #ifndef lint
80*84d9c625SLionel Sambuc __RCSID("$NetBSD: xmalloc.c,v 1.12 2013/01/24 17:57:29 christos Exp $");
81e83f7ba2SBen Gras #endif /* not lint */
82e83f7ba2SBen Gras 
83e83f7ba2SBen Gras #include <stdlib.h>
84e83f7ba2SBen Gras #include <string.h>
85e83f7ba2SBen Gras #include <unistd.h>
86e83f7ba2SBen Gras #include <errno.h>
87e83f7ba2SBen Gras 
88e83f7ba2SBen Gras #include <sys/types.h>
89e83f7ba2SBen Gras #include <sys/param.h>
90e83f7ba2SBen Gras #include <sys/mman.h>
91e83f7ba2SBen Gras #include <sys/stat.h>
92e83f7ba2SBen Gras 
93e83f7ba2SBen Gras #include "rtld.h"
94e83f7ba2SBen Gras 
95e83f7ba2SBen Gras /*
96e83f7ba2SBen Gras  * Pre-allocate mmap'ed pages
97e83f7ba2SBen Gras  */
98e83f7ba2SBen Gras #define	NPOOLPAGES	(32*1024/pagesz)
99e83f7ba2SBen Gras static char 		*pagepool_start, *pagepool_end;
100e83f7ba2SBen Gras static int		morepages(int);
101e83f7ba2SBen Gras #define PAGEPOOL_SIZE	(size_t)(pagepool_end - pagepool_start)
102e83f7ba2SBen Gras 
103e83f7ba2SBen Gras /*
104e83f7ba2SBen Gras  * The overhead on a block is at least 4 bytes.  When free, this space
105e83f7ba2SBen Gras  * contains a pointer to the next free block, and the bottom two bits must
106e83f7ba2SBen Gras  * be zero.  When in use, the first byte is set to MAGIC, and the second
107e83f7ba2SBen Gras  * byte is the size index.  The remaining bytes are for alignment.
108e83f7ba2SBen Gras  * If range checking is enabled then a second word holds the size of the
109e83f7ba2SBen Gras  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
110e83f7ba2SBen Gras  * The order of elements is critical: ov_magic must overlay the low order
111e83f7ba2SBen Gras  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
112e83f7ba2SBen Gras  */
113e83f7ba2SBen Gras union	overhead {
114e83f7ba2SBen Gras 	union	overhead *ov_next;	/* when free */
115e83f7ba2SBen Gras 	struct {
116e83f7ba2SBen Gras 		u_char	ovu_magic;	/* magic number */
117e83f7ba2SBen Gras 		u_char	ovu_index;	/* bucket # */
118e83f7ba2SBen Gras #ifdef RCHECK
119e83f7ba2SBen Gras 		u_short	ovu_rmagic;	/* range magic number */
120e83f7ba2SBen Gras 		u_int	ovu_size;	/* actual block size */
121e83f7ba2SBen Gras #endif
122e83f7ba2SBen Gras 	} ovu;
123e83f7ba2SBen Gras #define	ov_magic	ovu.ovu_magic
124e83f7ba2SBen Gras #define	ov_index	ovu.ovu_index
125e83f7ba2SBen Gras #define	ov_rmagic	ovu.ovu_rmagic
126e83f7ba2SBen Gras #define	ov_size		ovu.ovu_size
127e83f7ba2SBen Gras };
128e83f7ba2SBen Gras 
129e83f7ba2SBen Gras static void morecore(size_t);
130e83f7ba2SBen Gras static void *imalloc(size_t);
131e83f7ba2SBen Gras 
132e83f7ba2SBen Gras #define	MAGIC		0xef		/* magic # on accounting info */
133e83f7ba2SBen Gras #define RMAGIC		0x5555		/* magic # on range info */
134e83f7ba2SBen Gras 
135e83f7ba2SBen Gras #ifdef RCHECK
136e83f7ba2SBen Gras #define	RSLOP		(sizeof (u_short))
137e83f7ba2SBen Gras #else
138e83f7ba2SBen Gras #define	RSLOP		0
139e83f7ba2SBen Gras #endif
140e83f7ba2SBen Gras 
141e83f7ba2SBen Gras /*
142e83f7ba2SBen Gras  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
143e83f7ba2SBen Gras  * smallest allocatable block is 8 bytes.  The overhead information
144e83f7ba2SBen Gras  * precedes the data area returned to the user.
145e83f7ba2SBen Gras  */
146e83f7ba2SBen Gras #define	NBUCKETS 30
147e83f7ba2SBen Gras static	union overhead *nextf[NBUCKETS];
148e83f7ba2SBen Gras 
149e83f7ba2SBen Gras static	size_t pagesz;			/* page size */
150e83f7ba2SBen Gras static	size_t pagebucket;		/* page size bucket */
151f14fb602SLionel Sambuc static	size_t pageshift;		/* page size shift */
152e83f7ba2SBen Gras 
153e83f7ba2SBen Gras #ifdef MSTATS
154e83f7ba2SBen Gras /*
155e83f7ba2SBen Gras  * nmalloc[i] is the difference between the number of mallocs and frees
156e83f7ba2SBen Gras  * for a given block size.
157e83f7ba2SBen Gras  */
158e83f7ba2SBen Gras static	u_int nmalloc[NBUCKETS];
159e83f7ba2SBen Gras #endif
160e83f7ba2SBen Gras 
161e83f7ba2SBen Gras #if defined(MALLOC_DEBUG) || defined(RCHECK)
162e83f7ba2SBen Gras #define	ASSERT(p)   if (!(p)) botch("p")
163e83f7ba2SBen Gras static void
botch(const char * s)164e83f7ba2SBen Gras botch(const char *s)
165e83f7ba2SBen Gras {
166e83f7ba2SBen Gras     xwarnx("\r\nassertion botched: %s\r\n", s);
167e83f7ba2SBen Gras     abort();
168e83f7ba2SBen Gras }
169e83f7ba2SBen Gras #else
170e83f7ba2SBen Gras #define	ASSERT(p)
171e83f7ba2SBen Gras #endif
172e83f7ba2SBen Gras 
173e83f7ba2SBen Gras #define TRACE()	xprintf("TRACE %s:%d\n", __FILE__, __LINE__)
174e83f7ba2SBen Gras 
175e83f7ba2SBen Gras static void *
imalloc(size_t nbytes)176e83f7ba2SBen Gras imalloc(size_t nbytes)
177e83f7ba2SBen Gras {
178e83f7ba2SBen Gras   	union overhead *op;
179e83f7ba2SBen Gras   	size_t bucket;
180e83f7ba2SBen Gras 	size_t n, m;
181e83f7ba2SBen Gras 	unsigned amt;
182e83f7ba2SBen Gras 
183e83f7ba2SBen Gras 	/*
184e83f7ba2SBen Gras 	 * First time malloc is called, setup page size and
185e83f7ba2SBen Gras 	 * align break pointer so all data will be page aligned.
186e83f7ba2SBen Gras 	 */
187e83f7ba2SBen Gras 	if (pagesz == 0) {
188e83f7ba2SBen Gras 		pagesz = n = _rtld_pagesz;
189e83f7ba2SBen Gras 		if (morepages(NPOOLPAGES) == 0)
190e83f7ba2SBen Gras 			return NULL;
191e83f7ba2SBen Gras 		op = (union overhead *)(pagepool_start);
192e83f7ba2SBen Gras 		m = sizeof (*op) - (((char *)op - (char *)NULL) & (n - 1));
193e83f7ba2SBen Gras 		if (n < m)
194e83f7ba2SBen Gras 			n += pagesz - m;
195e83f7ba2SBen Gras 		else
196e83f7ba2SBen Gras 			n -= m;
197e83f7ba2SBen Gras   		if (n) {
198e83f7ba2SBen Gras 			pagepool_start += n;
199e83f7ba2SBen Gras 		}
200e83f7ba2SBen Gras 		bucket = 0;
201e83f7ba2SBen Gras 		amt = sizeof(union overhead);
202e83f7ba2SBen Gras 		while (pagesz > amt) {
203e83f7ba2SBen Gras 			amt <<= 1;
204e83f7ba2SBen Gras 			bucket++;
205e83f7ba2SBen Gras 		}
206e83f7ba2SBen Gras 		pagebucket = bucket;
207f14fb602SLionel Sambuc 		pageshift = ffs(pagesz) - 1;
208e83f7ba2SBen Gras 	}
209e83f7ba2SBen Gras 	/*
210e83f7ba2SBen Gras 	 * Convert amount of memory requested into closest block size
211e83f7ba2SBen Gras 	 * stored in hash buckets which satisfies request.
212e83f7ba2SBen Gras 	 * Account for space used per block for accounting.
213e83f7ba2SBen Gras 	 */
214e83f7ba2SBen Gras 	if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
215e83f7ba2SBen Gras 		if (sizeof(union overhead) & (sizeof(union overhead) - 1)) {
216e83f7ba2SBen Gras 		    amt = sizeof(union overhead) * 2;
217e83f7ba2SBen Gras 		    bucket = 1;
218e83f7ba2SBen Gras 		} else {
219e83f7ba2SBen Gras 		    amt = sizeof(union overhead); /* size of first bucket */
220e83f7ba2SBen Gras 		    bucket = 0;
221e83f7ba2SBen Gras 		}
222e83f7ba2SBen Gras 		n = -(sizeof (*op) + RSLOP);
223e83f7ba2SBen Gras 	} else {
224e83f7ba2SBen Gras 		amt = pagesz;
225e83f7ba2SBen Gras 		bucket = pagebucket;
226e83f7ba2SBen Gras 	}
227e83f7ba2SBen Gras 	while (nbytes > amt + n) {
228e83f7ba2SBen Gras 		amt <<= 1;
229e83f7ba2SBen Gras 		if (amt == 0)
230e83f7ba2SBen Gras 			return (NULL);
231e83f7ba2SBen Gras 		bucket++;
232e83f7ba2SBen Gras 	}
233e83f7ba2SBen Gras 	/*
234e83f7ba2SBen Gras 	 * If nothing in hash bucket right now,
235e83f7ba2SBen Gras 	 * request more memory from the system.
236e83f7ba2SBen Gras 	 */
237e83f7ba2SBen Gras   	if ((op = nextf[bucket]) == NULL) {
238e83f7ba2SBen Gras   		morecore(bucket);
239e83f7ba2SBen Gras   		if ((op = nextf[bucket]) == NULL)
240e83f7ba2SBen Gras   			return (NULL);
241e83f7ba2SBen Gras 	}
242e83f7ba2SBen Gras 	/* remove from linked list */
243e83f7ba2SBen Gras   	nextf[bucket] = op->ov_next;
244e83f7ba2SBen Gras 	op->ov_magic = MAGIC;
245e83f7ba2SBen Gras 	op->ov_index = bucket;
246e83f7ba2SBen Gras #ifdef MSTATS
247e83f7ba2SBen Gras   	nmalloc[bucket]++;
248e83f7ba2SBen Gras #endif
249e83f7ba2SBen Gras #ifdef RCHECK
250e83f7ba2SBen Gras 	/*
251e83f7ba2SBen Gras 	 * Record allocated size of block and
252e83f7ba2SBen Gras 	 * bound space with magic numbers.
253e83f7ba2SBen Gras 	 */
254e83f7ba2SBen Gras 	op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
255e83f7ba2SBen Gras 	op->ov_rmagic = RMAGIC;
256e83f7ba2SBen Gras   	*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
257e83f7ba2SBen Gras #endif
258e83f7ba2SBen Gras   	return ((char *)(op + 1));
259e83f7ba2SBen Gras }
260e83f7ba2SBen Gras 
261e83f7ba2SBen Gras /*
262e83f7ba2SBen Gras  * Allocate more memory to the indicated bucket.
263e83f7ba2SBen Gras  */
264e83f7ba2SBen Gras static void
morecore(size_t bucket)265e83f7ba2SBen Gras morecore(size_t bucket)
266e83f7ba2SBen Gras {
267e83f7ba2SBen Gras   	union overhead *op;
268e83f7ba2SBen Gras 	size_t sz;		/* size of desired block */
269e83f7ba2SBen Gras   	size_t amt;		/* amount to allocate */
270e83f7ba2SBen Gras   	size_t nblks;		/* how many blocks we get */
271e83f7ba2SBen Gras 
272e83f7ba2SBen Gras 	/*
273e83f7ba2SBen Gras 	 * sbrk_size <= 0 only for big, FLUFFY, requests (about
274e83f7ba2SBen Gras 	 * 2^30 bytes on a VAX, I think) or for a negative arg.
275e83f7ba2SBen Gras 	 */
276e83f7ba2SBen Gras 	sz = 1 << (bucket + 3);
277e83f7ba2SBen Gras #ifdef MALLOC_DEBUG
278e83f7ba2SBen Gras 	ASSERT(sz > 0);
279e83f7ba2SBen Gras #endif
280e83f7ba2SBen Gras 	if (sz < pagesz) {
281e83f7ba2SBen Gras 		amt = pagesz;
282f14fb602SLionel Sambuc 		nblks = amt >> (bucket + 3);
283e83f7ba2SBen Gras 	} else {
284e83f7ba2SBen Gras 		amt = sz + pagesz;
285e83f7ba2SBen Gras 		nblks = 1;
286e83f7ba2SBen Gras 	}
287e83f7ba2SBen Gras 	if (amt > PAGEPOOL_SIZE)
288f14fb602SLionel Sambuc 		if (morepages((amt >> pageshift) + NPOOLPAGES) == 0)
289e83f7ba2SBen Gras 			return;
290e83f7ba2SBen Gras 	op = (union overhead *)pagepool_start;
291e83f7ba2SBen Gras 	pagepool_start += amt;
292e83f7ba2SBen Gras 
293e83f7ba2SBen Gras 	/*
294e83f7ba2SBen Gras 	 * Add new memory allocated to that on
295e83f7ba2SBen Gras 	 * free list for this hash bucket.
296e83f7ba2SBen Gras 	 */
297e83f7ba2SBen Gras   	nextf[bucket] = op;
298e83f7ba2SBen Gras   	while (--nblks > 0) {
299e83f7ba2SBen Gras 		op->ov_next = (union overhead *)((caddr_t)op + sz);
300e83f7ba2SBen Gras 		op = (union overhead *)((caddr_t)op + sz);
301e83f7ba2SBen Gras   	}
302e83f7ba2SBen Gras }
303e83f7ba2SBen Gras 
304e83f7ba2SBen Gras void
xfree(void * cp)305e83f7ba2SBen Gras xfree(void *cp)
306e83f7ba2SBen Gras {
307e83f7ba2SBen Gras   	int size;
308e83f7ba2SBen Gras 	union overhead *op;
309e83f7ba2SBen Gras 
310e83f7ba2SBen Gras   	if (cp == NULL)
311e83f7ba2SBen Gras   		return;
312e83f7ba2SBen Gras 	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
313e83f7ba2SBen Gras #ifdef MALLOC_DEBUG
314e83f7ba2SBen Gras   	ASSERT(op->ov_magic == MAGIC);		/* make sure it was in use */
315e83f7ba2SBen Gras #else
316e83f7ba2SBen Gras 	if (op->ov_magic != MAGIC)
317e83f7ba2SBen Gras 		return;				/* sanity */
318e83f7ba2SBen Gras #endif
319e83f7ba2SBen Gras #ifdef RCHECK
320e83f7ba2SBen Gras   	ASSERT(op->ov_rmagic == RMAGIC);
321e83f7ba2SBen Gras 	ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
322e83f7ba2SBen Gras #endif
323e83f7ba2SBen Gras   	size = op->ov_index;
324e83f7ba2SBen Gras   	ASSERT(size < NBUCKETS);
325e83f7ba2SBen Gras 	op->ov_next = nextf[size];	/* also clobbers ov_magic */
326e83f7ba2SBen Gras   	nextf[size] = op;
327e83f7ba2SBen Gras #ifdef MSTATS
328e83f7ba2SBen Gras   	nmalloc[size]--;
329e83f7ba2SBen Gras #endif
330e83f7ba2SBen Gras }
331e83f7ba2SBen Gras 
332e83f7ba2SBen Gras static void *
irealloc(void * cp,size_t nbytes)333e83f7ba2SBen Gras irealloc(void *cp, size_t nbytes)
334e83f7ba2SBen Gras {
335e83f7ba2SBen Gras   	size_t onb;
336e83f7ba2SBen Gras 	size_t i;
337e83f7ba2SBen Gras 	union overhead *op;
338e83f7ba2SBen Gras   	char *res;
339e83f7ba2SBen Gras 
340e83f7ba2SBen Gras   	if (cp == NULL)
341e83f7ba2SBen Gras   		return (imalloc(nbytes));
342e83f7ba2SBen Gras 	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
343e83f7ba2SBen Gras 	if (op->ov_magic != MAGIC) {
344e83f7ba2SBen Gras 		static const char *err_str =
345e83f7ba2SBen Gras 		    "memory corruption or double free in realloc\n";
346e83f7ba2SBen Gras 		extern char *__progname;
347e83f7ba2SBen Gras 	        write(STDERR_FILENO, __progname, strlen(__progname));
348e83f7ba2SBen Gras 		write(STDERR_FILENO, err_str, strlen(err_str));
349e83f7ba2SBen Gras 		abort();
350e83f7ba2SBen Gras 	}
351e83f7ba2SBen Gras 
352e83f7ba2SBen Gras 	i = op->ov_index;
353e83f7ba2SBen Gras 	onb = 1 << (i + 3);
354e83f7ba2SBen Gras 	if (onb < pagesz)
355e83f7ba2SBen Gras 		onb -= sizeof (*op) + RSLOP;
356e83f7ba2SBen Gras 	else
357e83f7ba2SBen Gras 		onb += pagesz - sizeof (*op) - RSLOP;
358e83f7ba2SBen Gras 	/* avoid the copy if same size block */
359e83f7ba2SBen Gras 	if (i) {
360e83f7ba2SBen Gras 		i = 1 << (i + 2);
361e83f7ba2SBen Gras 		if (i < pagesz)
362e83f7ba2SBen Gras 			i -= sizeof (*op) + RSLOP;
363e83f7ba2SBen Gras 		else
364e83f7ba2SBen Gras 			i += pagesz - sizeof (*op) - RSLOP;
365e83f7ba2SBen Gras 	}
366e83f7ba2SBen Gras 	if (nbytes <= onb && nbytes > i) {
367e83f7ba2SBen Gras #ifdef RCHECK
368e83f7ba2SBen Gras 		op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
369e83f7ba2SBen Gras 		*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
370e83f7ba2SBen Gras #endif
371e83f7ba2SBen Gras 		return(cp);
372*84d9c625SLionel Sambuc 	}
373e83f7ba2SBen Gras   	if ((res = imalloc(nbytes)) == NULL)
374e83f7ba2SBen Gras   		return (NULL);
375*84d9c625SLionel Sambuc   	if (cp != res) {	/* common optimization if "compacting" */
376e83f7ba2SBen Gras 		memcpy(res, cp, (nbytes < onb) ? nbytes : onb);
377*84d9c625SLionel Sambuc 		xfree(cp);
378*84d9c625SLionel Sambuc 	}
379e83f7ba2SBen Gras   	return (res);
380e83f7ba2SBen Gras }
381e83f7ba2SBen Gras 
382e83f7ba2SBen Gras #ifdef MSTATS
383e83f7ba2SBen Gras /*
384e83f7ba2SBen Gras  * mstats - print out statistics about malloc
385e83f7ba2SBen Gras  *
386e83f7ba2SBen Gras  * Prints two lines of numbers, one showing the length of the free list
387e83f7ba2SBen Gras  * for each size category, the second showing the number of mallocs -
388e83f7ba2SBen Gras  * frees for each size category.
389e83f7ba2SBen Gras  */
390e83f7ba2SBen Gras void
mstats(char * s)391e83f7ba2SBen Gras mstats(char *s)
392e83f7ba2SBen Gras {
393e83f7ba2SBen Gras   	int i, j;
394e83f7ba2SBen Gras   	union overhead *p;
395e83f7ba2SBen Gras   	int totfree = 0,
396e83f7ba2SBen Gras   	totused = 0;
397e83f7ba2SBen Gras 
398e83f7ba2SBen Gras   	xprintf("Memory allocation statistics %s\nfree:\t", s);
399e83f7ba2SBen Gras   	for (i = 0; i < NBUCKETS; i++) {
400e83f7ba2SBen Gras   		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
401e83f7ba2SBen Gras   			;
402e83f7ba2SBen Gras   		xprintf(" %d", j);
403e83f7ba2SBen Gras   		totfree += j * (1 << (i + 3));
404e83f7ba2SBen Gras   	}
405e83f7ba2SBen Gras   	xprintf("\nused:\t");
406e83f7ba2SBen Gras   	for (i = 0; i < NBUCKETS; i++) {
407e83f7ba2SBen Gras   		xprintf(" %d", nmalloc[i]);
408e83f7ba2SBen Gras   		totused += nmalloc[i] * (1 << (i + 3));
409e83f7ba2SBen Gras   	}
410e83f7ba2SBen Gras   	xprintf("\n\tTotal in use: %d, total free: %d\n",
411e83f7ba2SBen Gras 	    totused, totfree);
412e83f7ba2SBen Gras }
413e83f7ba2SBen Gras #endif
414e83f7ba2SBen Gras 
415e83f7ba2SBen Gras 
416e83f7ba2SBen Gras static int
morepages(int n)417e83f7ba2SBen Gras morepages(int n)
418e83f7ba2SBen Gras {
419e83f7ba2SBen Gras 	int	fd = -1;
420e83f7ba2SBen Gras 	int	offset;
421e83f7ba2SBen Gras 
422e83f7ba2SBen Gras #ifdef NEED_DEV_ZERO
423e83f7ba2SBen Gras 	fd = open("/dev/zero", O_RDWR, 0);
424e83f7ba2SBen Gras 	if (fd == -1)
425e83f7ba2SBen Gras 		xerr(1, "/dev/zero");
426e83f7ba2SBen Gras #endif
427e83f7ba2SBen Gras 
428e83f7ba2SBen Gras 	if (PAGEPOOL_SIZE > pagesz) {
429e83f7ba2SBen Gras 		caddr_t	addr = (caddr_t)
430e83f7ba2SBen Gras 			(((long)pagepool_start + pagesz - 1) & ~(pagesz - 1));
431e83f7ba2SBen Gras 		if (munmap(addr, pagepool_end - addr) != 0)
432e83f7ba2SBen Gras 			xwarn("morepages: munmap %p", addr);
433e83f7ba2SBen Gras 	}
434e83f7ba2SBen Gras 
435e83f7ba2SBen Gras 	offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1));
436e83f7ba2SBen Gras 
437e83f7ba2SBen Gras 	if ((pagepool_start = mmap(0, n * pagesz,
438e83f7ba2SBen Gras 			PROT_READ|PROT_WRITE,
439e83f7ba2SBen Gras 			MAP_ANON|MAP_PRIVATE, fd, 0)) == (caddr_t)-1) {
440e83f7ba2SBen Gras 		xprintf("Cannot map anonymous memory");
441e83f7ba2SBen Gras 		return 0;
442e83f7ba2SBen Gras 	}
443e83f7ba2SBen Gras 	pagepool_end = pagepool_start + n * pagesz;
444e83f7ba2SBen Gras 	pagepool_start += offset;
445e83f7ba2SBen Gras 
446e83f7ba2SBen Gras #ifdef NEED_DEV_ZERO
447e83f7ba2SBen Gras 	close(fd);
448e83f7ba2SBen Gras #endif
449e83f7ba2SBen Gras 	return n;
450e83f7ba2SBen Gras }
451e83f7ba2SBen Gras 
452e83f7ba2SBen Gras void *
xcalloc(size_t size)453e83f7ba2SBen Gras xcalloc(size_t size)
454e83f7ba2SBen Gras {
455e83f7ba2SBen Gras 
456e83f7ba2SBen Gras 	return memset(xmalloc(size), 0, size);
457e83f7ba2SBen Gras }
458e83f7ba2SBen Gras 
459e83f7ba2SBen Gras void *
xmalloc(size_t size)460e83f7ba2SBen Gras xmalloc(size_t size)
461e83f7ba2SBen Gras {
462e83f7ba2SBen Gras 	void *p = imalloc(size);
463e83f7ba2SBen Gras 
464e83f7ba2SBen Gras 	if (p == NULL)
465e83f7ba2SBen Gras 		xerr(1, "%s", xstrerror(errno));
466e83f7ba2SBen Gras 	return p;
467e83f7ba2SBen Gras }
468e83f7ba2SBen Gras 
469e83f7ba2SBen Gras void *
xrealloc(void * p,size_t size)470e83f7ba2SBen Gras xrealloc(void *p, size_t size)
471e83f7ba2SBen Gras {
472e83f7ba2SBen Gras 	p = irealloc(p, size);
473e83f7ba2SBen Gras 
474e83f7ba2SBen Gras 	if (p == NULL)
475e83f7ba2SBen Gras 		xerr(1, "%s", xstrerror(errno));
476e83f7ba2SBen Gras 	return p;
477e83f7ba2SBen Gras }
478e83f7ba2SBen Gras 
479e83f7ba2SBen Gras char *
xstrdup(const char * str)480e83f7ba2SBen Gras xstrdup(const char *str)
481e83f7ba2SBen Gras {
482e83f7ba2SBen Gras 	size_t len;
483e83f7ba2SBen Gras 	char *copy;
484e83f7ba2SBen Gras 
485e83f7ba2SBen Gras 	len = strlen(str) + 1;
486e83f7ba2SBen Gras 	copy = xmalloc(len);
487e83f7ba2SBen Gras 	memcpy(copy, str, len);
488e83f7ba2SBen Gras 	return (copy);
489e83f7ba2SBen Gras }
490