xref: /netbsd-src/lib/libc/stdlib/malloc.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*	$NetBSD: malloc.c,v 1.16 1999/01/29 08:11:36 kleink Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)malloc.c	8.1 (Berkeley) 6/4/93";
40 #else
41 __RCSID("$NetBSD: malloc.c,v 1.16 1999/01/29 08:11:36 kleink Exp $");
42 #endif
43 #endif /* LIBC_SCCS and not lint */
44 
45 /*
46  * malloc.c (Caltech) 2/21/82
47  * Chris Kingsley, kingsley@cit-20.
48  *
49  * This is a very fast storage allocator.  It allocates blocks of a small
50  * number of different sizes, and keeps free lists of each size.  Blocks that
51  * don't exactly fit are passed up to the next larger size.  In this
52  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
53  * This is designed for use in a virtual memory environment.
54  */
55 
56 #include "namespace.h"
57 #include <sys/types.h>
58 #if defined(DEBUG) || defined(RCHECK)
59 #include <sys/uio.h>
60 #endif
61 #if defined(RCHECK) || defined(MSTATS)
62 #include <stdio.h>
63 #endif
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67 #include "reentrant.h"
68 
69 
70 /*
71  * The overhead on a block is at least 4 bytes.  When free, this space
72  * contains a pointer to the next free block, and the bottom two bits must
73  * be zero.  When in use, the first byte is set to MAGIC, and the second
74  * byte is the size index.  The remaining bytes are for alignment.
75  * If range checking is enabled then a second word holds the size of the
76  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
77  * The order of elements is critical: ov_magic must overlay the low order
78  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
79  */
80 union	overhead {
81 	union	overhead *ov_next;	/* when free */
82 	struct {
83 		u_char	ovu_magic;	/* magic number */
84 		u_char	ovu_index;	/* bucket # */
85 #ifdef RCHECK
86 		u_short	ovu_rmagic;	/* range magic number */
87 		u_long	ovu_size;	/* actual block size */
88 #endif
89 	} ovu;
90 #define	ov_magic	ovu.ovu_magic
91 #define	ov_index	ovu.ovu_index
92 #define	ov_rmagic	ovu.ovu_rmagic
93 #define	ov_size		ovu.ovu_size
94 };
95 
96 #define	MAGIC		0xef		/* magic # on accounting info */
97 #ifdef RCHECK
98 #define RMAGIC		0x5555		/* magic # on range info */
99 #endif
100 
101 #ifdef RCHECK
102 #define	RSLOP		sizeof (u_short)
103 #else
104 #define	RSLOP		0
105 #endif
106 
107 /*
108  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
109  * smallest allocatable block is 8 bytes.  The overhead information
110  * precedes the data area returned to the user.
111  */
112 #define	NBUCKETS 30
113 static	union overhead *nextf[NBUCKETS];
114 
115 static	long pagesz;			/* page size */
116 static	int pagebucket;			/* page size bucket */
117 
118 #ifdef MSTATS
119 /*
120  * nmalloc[i] is the difference between the number of mallocs and frees
121  * for a given block size.
122  */
123 static	u_int nmalloc[NBUCKETS];
124 #endif
125 
126 #ifdef _REENT
127 static	mutex_t malloc_mutex = MUTEX_INITIALIZER;
128 #endif
129 
130 static void morecore __P((int));
131 static int findbucket __P((union overhead *, int));
132 #ifdef MSTATS
133 void mstats __P((const char *));
134 #endif
135 
136 #if defined(DEBUG) || defined(RCHECK)
137 #define	ASSERT(p)   if (!(p)) botch(__STRING(p))
138 
139 static void botch __P((const char *));
140 
141 /*
142  * NOTE: since this may be called while malloc_mutex is locked, stdio must not
143  *       be used in this function.
144  */
145 static void
146 botch(s)
147 	const char *s;
148 {
149 	struct iovec iov[3];
150 
151 	iov[0].iov_base	= "\nassertion botched: ";
152 	iov[0].iov_len	= 20;
153 	iov[1].iov_base	= (void *)s;
154 	iov[1].iov_len	= strlen(s);
155 	iov[2].iov_base	= "\n";
156 	iov[2].iov_len	= 1;
157 
158 	/*
159 	 * This place deserves a word of warning: a cancellation point will
160 	 * occur when executing writev(), and we might be still owning
161 	 * malloc_mutex.  At this point we need to disable cancellation
162 	 * until `after' abort() because i) establishing a cancellation handler
163 	 * might, depending on the implementation, result in another malloc()
164 	 * to be executed, and ii) it is really not desirable to let execution
165 	 * continue.  `Fix me.'
166 	 *
167 	 * Note that holding mutex_lock during abort() is safe.
168 	 */
169 
170 	(void)writev(STDERR_FILENO, iov, 3);
171 	abort();
172 }
173 #else
174 #define	ASSERT(p)
175 #endif
176 
177 void *
178 malloc(nbytes)
179 	size_t nbytes;
180 {
181   	union overhead *op;
182 	int bucket;
183   	long n;
184 	unsigned amt;
185 
186 	mutex_lock(&malloc_mutex);
187 
188 	/*
189 	 * First time malloc is called, setup page size and
190 	 * align break pointer so all data will be page aligned.
191 	 */
192 	if (pagesz == 0) {
193 		pagesz = n = getpagesize();
194 		ASSERT(pagesz > 0);
195 		op = (union overhead *)(void *)sbrk(0);
196   		n = n - sizeof (*op) - ((long)op & (n - 1));
197 		if (n < 0)
198 			n += pagesz;
199 		if (n) {
200 			if (sbrk((int)n) == (void *)-1) {
201 				mutex_unlock(&malloc_mutex);
202 				return (NULL);
203 			}
204 		}
205 		bucket = 0;
206 		amt = 8;
207 		while (pagesz > amt) {
208 			amt <<= 1;
209 			bucket++;
210 		}
211 		pagebucket = bucket;
212 	}
213 	/*
214 	 * Convert amount of memory requested into closest block size
215 	 * stored in hash buckets which satisfies request.
216 	 * Account for space used per block for accounting.
217 	 */
218 	if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
219 #ifndef RCHECK
220 		amt = 8;	/* size of first bucket */
221 		bucket = 0;
222 #else
223 		amt = 16;	/* size of first bucket */
224 		bucket = 1;
225 #endif
226 		n = -((long)sizeof (*op) + RSLOP);
227 	} else {
228 		amt = (unsigned)pagesz;
229 		bucket = pagebucket;
230 	}
231 	while (nbytes > amt + n) {
232 		amt <<= 1;
233 		if (amt == 0)
234 			return (NULL);
235 		bucket++;
236 	}
237 	/*
238 	 * If nothing in hash bucket right now,
239 	 * request more memory from the system.
240 	 */
241   	if ((op = nextf[bucket]) == NULL) {
242   		morecore(bucket);
243   		if ((op = nextf[bucket]) == NULL) {
244 			mutex_unlock(&malloc_mutex);
245   			return (NULL);
246 		}
247 	}
248 	/* remove from linked list */
249   	nextf[bucket] = op->ov_next;
250 	op->ov_magic = MAGIC;
251 	op->ov_index = bucket;
252 #ifdef MSTATS
253   	nmalloc[bucket]++;
254 #endif
255 	mutex_unlock(&malloc_mutex);
256 #ifdef RCHECK
257 	/*
258 	 * Record allocated size of block and
259 	 * bound space with magic numbers.
260 	 */
261 	op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
262 	op->ov_rmagic = RMAGIC;
263   	*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
264 #endif
265   	return ((void *)(op + 1));
266 }
267 
268 /*
269  * Allocate more memory to the indicated bucket.
270  */
271 static void
272 morecore(bucket)
273 	int bucket;
274 {
275   	union overhead *op;
276 	long sz;		/* size of desired block */
277   	long amt;			/* amount to allocate */
278   	long nblks;			/* how many blocks we get */
279 
280 	/*
281 	 * sbrk_size <= 0 only for big, FLUFFY, requests (about
282 	 * 2^30 bytes on a VAX, I think) or for a negative arg.
283 	 */
284 	sz = 1 << (bucket + 3);
285 #ifdef DEBUG
286 	ASSERT(sz > 0);
287 #else
288 	if (sz <= 0)
289 		return;
290 #endif
291 	if (sz < pagesz) {
292 		amt = pagesz;
293   		nblks = amt / sz;
294 	} else {
295 		amt = sz + pagesz;
296 		nblks = 1;
297 	}
298 	op = (union overhead *)(void *)sbrk((int)amt);
299 	/* no more room! */
300   	if ((long)op == -1)
301   		return;
302 	/*
303 	 * Add new memory allocated to that on
304 	 * free list for this hash bucket.
305 	 */
306   	nextf[bucket] = op;
307   	while (--nblks > 0) {
308 		op->ov_next =
309 		    (union overhead *)(void *)((caddr_t)(void *)op+(size_t)sz);
310 		op = op->ov_next;
311   	}
312 }
313 
314 void
315 free(cp)
316 	void *cp;
317 {
318 	long size;
319 	union overhead *op;
320 
321   	if (cp == NULL)
322   		return;
323 	op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
324 #ifdef DEBUG
325   	ASSERT(op->ov_magic == MAGIC);		/* make sure it was in use */
326 #else
327 	if (op->ov_magic != MAGIC)
328 		return;				/* sanity */
329 #endif
330 #ifdef RCHECK
331   	ASSERT(op->ov_rmagic == RMAGIC);
332 	ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
333 #endif
334   	size = op->ov_index;
335   	ASSERT(size < NBUCKETS);
336 	mutex_lock(&malloc_mutex);
337 	op->ov_next = nextf[(unsigned int)size];/* also clobbers ov_magic */
338   	nextf[(unsigned int)size] = op;
339 #ifdef MSTATS
340   	nmalloc[(size_t)size]--;
341 #endif
342 	mutex_unlock(&malloc_mutex);
343 }
344 
345 /*
346  * When a program attempts "storage compaction" as mentioned in the
347  * old malloc man page, it realloc's an already freed block.  Usually
348  * this is the last block it freed; occasionally it might be farther
349  * back.  We have to search all the free lists for the block in order
350  * to determine its bucket: 1st we make one pass thru the lists
351  * checking only the first block in each; if that fails we search
352  * ``__realloc_srchlen'' blocks in each list for a match (the variable
353  * is extern so the caller can modify it).  If that fails we just copy
354  * however many bytes was given to realloc() and hope it's not huge.
355  */
356 int __realloc_srchlen = 4;	/* 4 should be plenty, -1 =>'s whole list */
357 
358 void *
359 realloc(cp, nbytes)
360 	void *cp;
361 	size_t nbytes;
362 {
363   	u_long onb;
364 	long i;
365 	union overhead *op;
366 	char *res;
367 	int was_alloced = 0;
368 
369   	if (cp == NULL)
370   		return (malloc(nbytes));
371 	if (nbytes == 0) {
372 		free (cp);
373 		return (NULL);
374 	}
375 	op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
376 	mutex_lock(&malloc_mutex);
377 	if (op->ov_magic == MAGIC) {
378 		was_alloced++;
379 		i = op->ov_index;
380 	} else {
381 		/*
382 		 * Already free, doing "compaction".
383 		 *
384 		 * Search for the old block of memory on the
385 		 * free list.  First, check the most common
386 		 * case (last element free'd), then (this failing)
387 		 * the last ``__realloc_srchlen'' items free'd.
388 		 * If all lookups fail, then assume the size of
389 		 * the memory block being realloc'd is the
390 		 * largest possible (so that all "nbytes" of new
391 		 * memory are copied into).  Note that this could cause
392 		 * a memory fault if the old area was tiny, and the moon
393 		 * is gibbous.  However, that is very unlikely.
394 		 */
395 		if ((i = findbucket(op, 1)) < 0 &&
396 		    (i = findbucket(op, __realloc_srchlen)) < 0)
397 			i = NBUCKETS;
398 	}
399 	onb = (u_long)1 << (u_long)(i + 3);
400 	if (onb < pagesz)
401 		onb -= sizeof (*op) + RSLOP;
402 	else
403 		onb += pagesz - sizeof (*op) - RSLOP;
404 	/* avoid the copy if same size block */
405 	if (was_alloced) {
406 		if (i) {
407 			i = (long)1 << (long)(i + 2);
408 			if (i < pagesz)
409 				i -= sizeof (*op) + RSLOP;
410 			else
411 				i += pagesz - sizeof (*op) - RSLOP;
412 		}
413 		if (nbytes <= onb && nbytes > i) {
414 #ifdef RCHECK
415 			op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
416 			*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
417 #endif
418 			mutex_unlock(&malloc_mutex);
419 			return (cp);
420 
421 		}
422 #ifndef _REENT
423 		else
424 			free(cp);
425 #endif
426 	}
427 	mutex_unlock(&malloc_mutex);
428 	if ((res = malloc(nbytes)) == NULL) {
429 #ifdef _REENT
430 		free(cp);
431 #endif
432 		return (NULL);
433 	}
434 #ifndef _REENT
435 	if (cp != res)		/* common optimization if "compacting" */
436 		(void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
437 #else
438 	(void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
439 	free(cp);
440 #endif
441   	return (res);
442 }
443 
444 /*
445  * Search ``srchlen'' elements of each free list for a block whose
446  * header starts at ``freep''.  If srchlen is -1 search the whole list.
447  * Return bucket number, or -1 if not found.
448  */
449 static int
450 findbucket(freep, srchlen)
451 	union overhead *freep;
452 	int srchlen;
453 {
454 	union overhead *p;
455 	int i, j;
456 
457 	for (i = 0; i < NBUCKETS; i++) {
458 		j = 0;
459 		for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
460 			if (p == freep)
461 				return (i);
462 			j++;
463 		}
464 	}
465 	return (-1);
466 }
467 
468 #ifdef MSTATS
469 /*
470  * mstats - print out statistics about malloc
471  *
472  * Prints two lines of numbers, one showing the length of the free list
473  * for each size category, the second showing the number of mallocs -
474  * frees for each size category.
475  */
476 void
477 mstats(s)
478 	char *s;
479 {
480   	int i, j;
481   	union overhead *p;
482   	int totfree = 0,
483   	totused = 0;
484 
485   	fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
486   	for (i = 0; i < NBUCKETS; i++) {
487   		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
488   			;
489   		fprintf(stderr, " %d", j);
490   		totfree += j * (1 << (i + 3));
491   	}
492   	fprintf(stderr, "\nused:\t");
493   	for (i = 0; i < NBUCKETS; i++) {
494   		fprintf(stderr, " %d", nmalloc[i]);
495   		totused += nmalloc[i] * (1 << (i + 3));
496   	}
497   	fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
498 	    totused, totfree);
499 }
500 #endif
501