xref: /openbsd-src/lib/libc/stdlib/malloc.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  */
9 
10 #if defined(LIBC_SCCS) && !defined(lint)
11 static char rcsid[] = "$OpenBSD: malloc.c,v 1.19 1996/11/24 00:41:30 niklas Exp $";
12 #endif /* LIBC_SCCS and not lint */
13 
14 /*
15  * Defining EXTRA_SANITY will enable extra checks which are related
16  * to internal conditions and consistency in malloc.c. This has a
17  * noticeable runtime performance hit, and generally will not do you
18  * any good unless you fiddle with the internals of malloc or want
19  * to catch random pointer corruption as early as possible.
20  */
21 #undef EXTRA_SANITY
22 
23 /*
24  * Defining MALLOC_STATS will enable you to call malloc_dump() and set
25  * the [dD] options in the MALLOC_OPTIONS environment variable.
26  * It has no run-time performance hit, but does pull in stdio...
27  */
28 #undef MALLOC_STATS
29 
30 #if defined(EXTRA_SANITY) && !defined(MALLOC_STATS)
31 # define MALLOC_STATS	/* required for EXTRA_SANITY */
32 #endif
33 
34 /*
35  * What to use for Junk.  This is the byte value we use to fill with
36  * when the 'J' option is enabled.
37  */
38 #define SOME_JUNK	0xd0		/* as in "Duh" :-) */
39 
40 /*
41  * No user serviceable parts behind this point.
42  */
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/mman.h>
52 
53 /*
54  * If these weren't defined here, they would be calculated on the fly,
55  * at a considerable cost in performance.
56  */
57 #ifdef __OpenBSD__
58 #   if defined(__alpha__) || defined(__m68k__) || defined(__mips__) || \
59        defined(__i386__) || defined(__m88k__) || defined(__ns32k__) || \
60        defined(__vax__)
61 #	define	malloc_pagesize		(NBPG)
62 #	define	malloc_pageshift	(PGSHIFT)
63 #	define	malloc_maxsize		(malloc_pagesize >> 1)
64 #	define	malloc_minsize		16U
65 #   endif /* __i386__ */
66 #endif /* __OpenBSD__ */
67 
68 /*
69  * This structure describes a page worth of chunks.
70  */
71 
72 struct pginfo {
73     struct pginfo	*next;	/* next on the free list */
74     void		*page;	/* Pointer to the page */
75     u_short		size;	/* size of this page's chunks */
76     u_short		shift;	/* How far to shift for this size chunks */
77     u_short		free;	/* How many free chunks */
78     u_short		total;	/* How many chunk */
79     u_long		bits[1]; /* Which chunks are free */
80 };
81 
82 /*
83  * This structure describes a number of free pages.
84  */
85 
86 struct pgfree {
87     struct pgfree	*next;	/* next run of free pages */
88     struct pgfree	*prev;	/* prev run of free pages */
89     void		*page;	/* pointer to free pages */
90     void		*end;	/* pointer to end of free pages */
91     u_long		size;	/* number of bytes free */
92 };
93 
94 /*
95  * How many bits per u_long in the bitmap.
96  * Change only if not 8 bits/byte
97  */
98 #define	MALLOC_BITS	(8*sizeof(u_long))
99 
100 /*
101  * Magic values to put in the page_directory
102  */
103 #define MALLOC_NOT_MINE	((struct pginfo*) 0)
104 #define MALLOC_FREE 	((struct pginfo*) 1)
105 #define MALLOC_FIRST	((struct pginfo*) 2)
106 #define MALLOC_FOLLOW	((struct pginfo*) 3)
107 #define MALLOC_MAGIC	((struct pginfo*) 4)
108 
109 /*
110  * The i386 architecture has some very convenient instructions.
111  * We might as well use them.  There are C-language backups, but
112  * they are considerably slower.
113  */
114 #if defined(__i386__) && defined(__GNUC__)
115 #define ffs _ffs
116 static __inline int
117 _ffs(input)
118 	unsigned input;
119 {
120 	int result;
121 	__asm("bsfl %1, %0" : "=r" (result) : "r" (input));
122 	return result+1;
123 }
124 
125 #define fls _fls
126 static __inline int
127 _fls(input)
128 	unsigned input;
129 {
130 	int result;
131 	__asm("bsrl %1, %0" : "=r" (result) : "r" (input));
132 	return result+1;
133 }
134 
135 #define set_bit _set_bit
136 static __inline void
137 _set_bit(pi, bit)
138 	struct pginfo *pi;
139 	int bit;
140 {
141 	__asm("btsl %0, (%1)" :
142 	: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
143 }
144 
145 #define clr_bit _clr_bit
146 static __inline void
147 _clr_bit(pi, bit)
148 	struct pginfo *pi;
149 	int bit;
150 {
151 	__asm("btcl %0, (%1)" :
152 	: "r" (bit & (MALLOC_BITS-1)), "r" (pi->bits+(bit/MALLOC_BITS)));
153 }
154 
155 #endif /* __i386__ && __GNUC__ */
156 
157 /*
158  * Set to one when malloc_init has been called
159  */
160 static	unsigned	initialized;
161 
162 /*
163  * The size of a page.
164  * Must be a integral multiplum of the granularity of mmap(2).
165  * Your toes will curl if it isn't a power of two
166  */
167 #ifndef malloc_pagesize
168 static	unsigned        malloc_pagesize;
169 #endif /* malloc_pagesize */
170 
171 /* A mask for the offset inside a page.  */
172 #define malloc_pagemask	((malloc_pagesize)-1)
173 
174 #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask)))
175 #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo)
176 
177 /* malloc_pagesize == 1 << malloc_pageshift */
178 #ifndef malloc_pageshift
179 static	unsigned	malloc_pageshift;
180 #endif /* malloc_pageshift */
181 
182 /*
183  * The smallest allocation we bother about.
184  * Must be power of two
185  */
186 #ifndef malloc_minsize
187 static	unsigned  malloc_minsize;
188 #endif /* malloc_minsize */
189 
190 /*
191  * The largest chunk we care about.
192  * Must be smaller than pagesize
193  * Must be power of two
194  */
195 #ifndef malloc_maxsize
196 static	unsigned  malloc_maxsize;
197 #endif /* malloc_maxsize */
198 
199 /* The minimum size (in pages) of the free page cache.  */
200 static	unsigned  malloc_cache = 16;
201 
202 /* The offset from pagenumber to index into the page directory */
203 static	u_long  malloc_origo;
204 
205 /* The last index in the page directory we care about */
206 static	u_long  last_index;
207 
208 /* Pointer to page directory. Allocated "as if with" malloc */
209 static	struct	pginfo **page_dir;
210 
211 /* How many slots in the page directory */
212 static	unsigned	malloc_ninfo;
213 
214 /* Free pages line up here */
215 static struct pgfree	free_list;
216 
217 /* Abort(), user doesn't handle problems.  */
218 static int malloc_abort;
219 
220 /* Are we trying to die ?  */
221 static int suicide;
222 
223 #ifdef MALLOC_STATS
224 /* dump statistics */
225 static int malloc_stats;
226 #endif /* MALLOC_STATS */
227 
228 /* always realloc ?  */
229 static int malloc_realloc;
230 
231 #ifdef __FreeBSD__
232 /* pass the kernel a hint on free pages ?  */
233 static int malloc_hint;
234 #endif
235 
236 /* zero fill ?  */
237 static int malloc_zero;
238 
239 /* junk fill ?  */
240 static int malloc_junk;
241 
242 #ifdef __FreeBSD__
243 /* utrace ?  */
244 static int malloc_utrace;
245 
246 struct ut { void *p; size_t s; void *r; };
247 
248 #define UTRACE(a, b, c) \
249 	if (malloc_utrace) \
250 		{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
251 #else /* !__FreeBSD__ */
252 #define UTRACE(a,b,c)
253 #endif
254 
255 /* my last break. */
256 static void *malloc_brk;
257 
258 /* one location cache for free-list holders */
259 static struct pgfree *px;
260 
261 /* compile-time options */
262 char *malloc_options;
263 
264 /*
265  * Necessary function declarations
266  */
267 static int extend_pgdir(u_long index);
268 static void *imalloc(size_t size);
269 static void ifree(void *ptr);
270 static void *irealloc(void *ptr, size_t size);
271 
272 #ifdef MALLOC_STATS
273 void
274 malloc_dump(fd)
275     FILE *fd;
276 {
277     struct pginfo **pd;
278     struct pgfree *pf;
279     int j;
280 
281     pd = page_dir;
282 
283     /* print out all the pages */
284     for(j=0;j<=last_index;j++) {
285 	fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j);
286 	if (pd[j] == MALLOC_NOT_MINE) {
287 	    for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++)
288 		;
289 	    j--;
290 	    fprintf(fd, ".. %5d not mine\n",	j);
291 	} else if (pd[j] == MALLOC_FREE) {
292 	    for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++)
293 		;
294 	    j--;
295 	    fprintf(fd, ".. %5d free\n", j);
296 	} else if (pd[j] == MALLOC_FIRST) {
297 	    for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++)
298 		;
299 	    j--;
300 	    fprintf(fd, ".. %5d in use\n", j);
301 	} else if (pd[j] < MALLOC_MAGIC) {
302 	    fprintf(fd, "(%p)\n", pd[j]);
303 	} else {
304 	    fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n",
305 		pd[j], pd[j]->free, pd[j]->total,
306 		pd[j]->size, pd[j]->page, pd[j]->next);
307 	}
308     }
309 
310     for(pf=free_list.next; pf; pf=pf->next) {
311 	fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
312 		pf, pf->page, pf->end, pf->size, pf->prev, pf->next);
313 	if (pf == pf->next) {
314  		fprintf(fd, "Free_list loops.\n");
315 		break;
316 	}
317     }
318 
319     /* print out various info */
320     fprintf(fd, "Minsize\t%d\n", malloc_minsize);
321     fprintf(fd, "Maxsize\t%d\n", malloc_maxsize);
322     fprintf(fd, "Pagesize\t%d\n", malloc_pagesize);
323     fprintf(fd, "Pageshift\t%d\n", malloc_pageshift);
324     fprintf(fd, "FirstPage\t%ld\n", malloc_origo);
325     fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift,
326 	(last_index + malloc_pageshift) << malloc_pageshift);
327     fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift);
328 }
329 #endif /* MALLOC_STATS */
330 
331 static char *malloc_func;
332 
333 static void
334 wrterror(p)
335     char *p;
336 {
337     char *q = "Malloc error: ";
338     suicide = 1;
339     write(2, q, strlen(q));
340     write(2, malloc_func, strlen(malloc_func));
341     write(2, p, strlen(p));
342 #ifdef MALLOC_STATS
343     if (malloc_stats)
344 	malloc_dump(stderr);
345 #endif /* MALLOC_STATS */
346     abort();
347 }
348 
349 static void
350 wrtwarning(p)
351     char *p;
352 {
353     char *q = "Malloc warning: ";
354     if (malloc_abort)
355 	wrterror(p);
356     write(2, q, strlen(q));
357     write(2, malloc_func, strlen(malloc_func));
358     write(2, p, strlen(p));
359 }
360 
361 #ifdef EXTRA_SANITY
362 static void
363 malloc_exit()
364 {
365     FILE *fd = fopen("malloc.out", "a");
366     char *q = "malloc() warning: Couldn't dump stats.\n";
367     if (fd) {
368         malloc_dump(fd);
369 	fclose(fd);
370     } else
371 	write(2, q, strlen(q));
372 }
373 #endif /* EXTRA_SANITY */
374 
375 
376 /*
377  * Allocate a number of pages from the OS
378  */
379 static caddr_t
380 map_pages(pages)
381     int pages;
382 {
383     caddr_t result, tail;
384 
385     result = (caddr_t)pageround((u_long)sbrk(0));
386     tail = result + (pages << malloc_pageshift);
387 
388     if (brk(tail)) {
389 #ifdef EXTRA_SANITY
390 	wrterror("(ES): map_pages fails\n");
391 #endif /* EXTRA_SANITY */
392 	return 0;
393     }
394 
395     last_index = ptr2index(tail) - 1;
396     malloc_brk = tail;
397 
398     if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index))
399 	return 0;
400 
401     return result;
402 }
403 
404 /*
405  * Set a bit in the bitmap
406  */
407 #ifndef set_bit
408 static __inline void
409 set_bit(pi, bit)
410     struct pginfo *pi;
411     int bit;
412 {
413     pi->bits[bit/MALLOC_BITS] |= 1UL<<(bit%MALLOC_BITS);
414 }
415 #endif /* set_bit */
416 
417 /*
418  * Clear a bit in the bitmap
419  */
420 #ifndef clr_bit
421 static __inline void
422 clr_bit(pi, bit)
423     struct pginfo *pi;
424     int bit;
425 {
426     pi->bits[bit/MALLOC_BITS] &= ~(1UL<<(bit%MALLOC_BITS));
427 }
428 #endif /* clr_bit */
429 
430 #ifndef tst_bit
431 /*
432  * Test a bit in the bitmap
433  */
434 static __inline int
435 tst_bit(pi, bit)
436     struct pginfo *pi;
437     int bit;
438 {
439     return pi->bits[bit/MALLOC_BITS] & (1UL<<(bit%MALLOC_BITS));
440 }
441 #endif /* tst_bit */
442 
443 /*
444  * Find last bit
445  */
446 #ifndef fls
447 static __inline int
448 fls(size)
449     size_t size;
450 {
451     int i = 1;
452     while (size >>= 1)
453 	i++;
454     return i;
455 }
456 #endif /* fls */
457 
458 #if LONG_BIT == WORD_BIT
459 #define ffs_ul ffs
460 #else
461 static __inline int
462 ffs_ul(u_long ul)
463 {
464     u_int n;
465     int i;
466     int k;
467 
468     for (i = 0; i < sizeof (u_long) / sizeof (u_int); i++) {
469 	n = ul & UINT_MAX;
470 	k = ffs (n);
471 	if (k)
472 	    break;
473 	ul >>= (sizeof (u_int) * 8);
474     }
475     if (k)
476 	k += i * sizeof (u_int) * 8;
477     return k;
478 }
479 #endif
480 
481 /*
482  * Extend page directory
483  */
484 static int
485 extend_pgdir(index)
486     u_long index;
487 {
488     struct  pginfo **new, **old;
489     int i;
490     size_t oldlen;
491 
492     /* Make it this many pages */
493     i = index * sizeof *page_dir;
494     i /= malloc_pagesize;
495     i += 2;
496 
497     /* remember the old mapping size */
498     oldlen = malloc_ninfo * sizeof *page_dir;
499 
500     /*
501      * NOTE: we allocate new pages and copy the directory rather than tempt
502      * fate by trying to "grow" the region.. There is nothing to prevent
503      * us from accidently re-mapping space that's been allocated by our caller
504      * via dlopen() or other mmap().
505      *
506      * The copy problem is not too bad, as there is 4K of page index per
507      * 4MB of malloc arena.
508      *
509      * We can totally avoid the copy if we open a file descriptor to associate
510      * the anon mappings with.  Then, when we remap the pages at the new
511      * address, the old pages will be "magically" remapped..  But this means
512      * keeping open a "secret" file descriptor.....
513      */
514 
515     /* Get new pages */
516     new = (struct pginfo**) mmap(0, i * malloc_pagesize, PROT_READ|PROT_WRITE,
517 				 MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
518     if (new == (struct pginfo **)-1)
519 	return 0;
520 
521     /* Copy the old stuff */
522     memcpy(new, page_dir,
523 	    malloc_ninfo * sizeof *page_dir);
524 
525     /* register the new size */
526     malloc_ninfo = i * malloc_pagesize / sizeof *page_dir;
527 
528     /* swap the pointers */
529     old = page_dir;
530     page_dir = new;
531 
532     /* Now free the old stuff */
533     munmap((caddr_t)old, oldlen);
534     return 1;
535 }
536 
537 /*
538  * Initialize the world
539  */
540 static void
541 malloc_init ()
542 {
543     char *p, b[64];
544     int i, j;
545 
546 #ifdef EXTRA_SANITY
547     malloc_junk = 1;
548 #endif /* EXTRA_SANITY */
549 
550     for (i = 0; i < 3; i++) {
551 	if (i == 0) {
552 	    j = readlink("/etc/malloc.conf", b, sizeof b - 1);
553 	    if (j <= 0)
554 		continue;
555 	    b[j] = '\0';
556 	    p = b;
557 	} else if (i == 1 && issetugid() == 0) {
558 	    p = getenv("MALLOC_OPTIONS");
559 	} else if (i == 2) {
560 	    p = malloc_options;
561 	}
562 	else
563 	    p = NULL;
564 	for (; p && *p; p++) {
565 	    switch (*p) {
566 		case '>': malloc_cache   <<= 1; break;
567 		case '<': malloc_cache   >>= 1; break;
568 		case 'a': malloc_abort   = 0; break;
569 		case 'A': malloc_abort   = 1; break;
570 #ifdef MALLOC_STATS
571 		case 'd': malloc_stats   = 0; break;
572 		case 'D': malloc_stats   = 1; break;
573 #endif /* MALLOC_STATS */
574 #ifdef __FreeBSD__
575 		case 'h': malloc_hint    = 0; break;
576 		case 'H': malloc_hint    = 1; break;
577 #endif /* __FreeBSD__ */
578 		case 'r': malloc_realloc = 0; break;
579 		case 'R': malloc_realloc = 1; break;
580 		case 'j': malloc_junk    = 0; break;
581 		case 'J': malloc_junk    = 1; break;
582 #ifdef __FreeBSD__
583 		case 'u': malloc_utrace  = 0; break;
584 		case 'U': malloc_utrace  = 1; break;
585 #endif /* __FreeBSD__ */
586 		case 'z': malloc_zero    = 0; break;
587 		case 'Z': malloc_zero    = 1; break;
588 		default:
589 		    j = malloc_abort;
590 		    malloc_abort = 0;
591 		    wrtwarning("unknown char in MALLOC_OPTIONS\n");
592 		    malloc_abort = j;
593 		    break;
594 	    }
595 	}
596     }
597 
598     UTRACE(0, 0, 0);
599 
600     /*
601      * We want junk in the entire allocation, and zero only in the part
602      * the user asked for.
603      */
604     if (malloc_zero)
605 	malloc_junk=1;
606 
607 #ifdef EXTRA_SANITY
608     if (malloc_stats)
609 	atexit(malloc_exit);
610 #endif /* EXTRA_SANITY */
611 
612 #ifndef malloc_pagesize
613     /* determine our pagesize */
614     malloc_pagesize = getpagesize();
615 #endif /* malloc_pagesize */
616 
617 #ifndef malloc_maxsize
618     malloc_maxsize = malloc_pagesize >> 1;
619 #endif /* malloc_maxsize */
620 
621 #ifndef malloc_pageshift
622     {
623     int i;
624     /* determine how much we shift by to get there */
625     for (i = malloc_pagesize; i > 1; i >>= 1)
626 	malloc_pageshift++;
627     }
628 #endif /* malloc_pageshift */
629 
630 #ifndef malloc_minsize
631     {
632     int i;
633     /*
634      * find the smallest size allocation we will bother about.
635      * this is determined as the smallest allocation that can hold
636      * it's own pginfo;
637      */
638     i = 2;
639     for(;;) {
640 	int j;
641 
642 	/* Figure out the size of the bits */
643 	j = malloc_pagesize/i;
644 	j /= 8;
645 	if (j < sizeof(u_long))
646 		j = sizeof (u_long);
647 	if (sizeof(struct pginfo) + j - sizeof (u_long) <= i)
648 		break;
649 	i += i;
650     }
651     malloc_minsize = i;
652     }
653 #endif /* malloc_minsize */
654 
655     /* Allocate one page for the page directory */
656     page_dir = (struct pginfo **) mmap(0, malloc_pagesize, PROT_READ|PROT_WRITE,
657 				       MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
658     if (page_dir == (struct pginfo **) -1)
659 	wrterror("mmap(2) failed, check limits.\n");
660 
661     /*
662      * We need a maximum of malloc_pageshift buckets, steal these from the
663      * front of the page_directory;
664      */
665     malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift;
666     malloc_origo -= malloc_pageshift;
667 
668     malloc_ninfo = malloc_pagesize / sizeof *page_dir;
669 
670     /* Been here, done that */
671     initialized++;
672 
673     /*
674      * This is a nice hack from Kaleb Keithly (kaleb@x.org).
675      * We can sbrk(2) further back when we keep this on a low address.
676      */
677     px = (struct pgfree *) imalloc (sizeof *px);
678 
679     if (!malloc_cache)
680 	malloc_cache++;
681 
682     malloc_cache <<= malloc_pageshift;
683 }
684 
685 /*
686  * Allocate a number of complete pages
687  */
688 void *
689 malloc_pages(size)
690     size_t size;
691 {
692     void *p, *delay_free = 0;
693     int i;
694     struct pgfree *pf;
695     u_long index;
696 
697     size = pageround(size);
698 
699     p = 0;
700     /* Look for free pages before asking for more */
701     for(pf = free_list.next; pf; pf = pf->next) {
702 
703 #ifdef EXTRA_SANITY
704 	if (pf->size & malloc_pagemask)
705 	    wrterror("(ES): junk length entry on free_list\n");
706 	if (!pf->size)
707 	    wrterror("(ES): zero length entry on free_list\n");
708 	if (pf->page == pf->end)
709 	    wrterror("(ES): zero entry on free_list\n");
710 	if (pf->page > pf->end)
711 	    wrterror("(ES): sick entry on free_list\n");
712 	if ((void*)pf->page >= (void*)sbrk(0))
713 	    wrterror("(ES): entry on free_list past brk\n");
714 	if (page_dir[ptr2index(pf->page)] != MALLOC_FREE)
715 	    wrterror("(ES): non-free first page on free-list\n");
716 	if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE)
717 	    wrterror("(ES): non-free last page on free-list\n");
718 #endif /* EXTRA_SANITY */
719 
720 	if (pf->size < size)
721 	    continue;
722 
723 	if (pf->size == size) {
724 	    p = pf->page;
725 	    if (pf->next)
726 		    pf->next->prev = pf->prev;
727 	    pf->prev->next = pf->next;
728 	    delay_free = pf;
729 	    break;
730 	}
731 
732 	p = pf->page;
733 	pf->page = (char *)pf->page + size;
734 	pf->size -= size;
735 	break;
736     }
737 
738 #ifdef EXTRA_SANITY
739     if (p && page_dir[ptr2index(p)] != MALLOC_FREE)
740 	wrterror("(ES): allocated non-free page on free-list\n");
741 #endif /* EXTRA_SANITY */
742 
743     size >>= malloc_pageshift;
744 
745     /* Map new pages */
746     if (!p)
747 	p = map_pages(size);
748 
749     if (p) {
750 
751 	index = ptr2index(p);
752 	page_dir[index] = MALLOC_FIRST;
753 	for (i=1;i<size;i++)
754 	    page_dir[index+i] = MALLOC_FOLLOW;
755 
756 	if (malloc_junk)
757 	    memset(p, SOME_JUNK, size << malloc_pageshift);
758     }
759 
760     if (delay_free) {
761 	if (!px)
762 	    px = delay_free;
763 	else
764 	    ifree(delay_free);
765     }
766 
767     return p;
768 }
769 
770 /*
771  * Allocate a page of fragments
772  */
773 
774 static __inline int
775 malloc_make_chunks(bits)
776     int bits;
777 {
778     struct  pginfo *bp;
779     void *pp;
780     int i, k, l;
781 
782     /* Allocate a new bucket */
783     pp = malloc_pages(malloc_pagesize);
784     if (!pp)
785 	return 0;
786 
787     /* Find length of admin structure */
788     l = sizeof *bp - sizeof(u_long);
789     l += sizeof(u_long) *
790 	(((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS);
791 
792     /* Don't waste more than two chunks on this */
793     if ((1UL<<(bits)) <= l+l) {
794 	bp = (struct  pginfo *)pp;
795     } else {
796 	bp = (struct  pginfo *)imalloc(l);
797 	if (!bp)
798 	    return 0;
799     }
800 
801     bp->size = (1UL<<bits);
802     bp->shift = bits;
803     bp->total = bp->free = malloc_pagesize >> bits;
804     bp->page = pp;
805 
806     page_dir[ptr2index(pp)] = bp;
807 
808     bp->next = page_dir[bits];
809     page_dir[bits] = bp;
810 
811     /* set all valid bits in the bits */
812     k = bp->total;
813     i = 0;
814 
815     /* Do a bunch at a time */
816     for(;k-i >= MALLOC_BITS; i += MALLOC_BITS)
817 	bp->bits[i / MALLOC_BITS] = (u_long)~0;
818 
819     for(; i < k; i++)
820 	set_bit(bp, i);
821 
822     if (bp == bp->page) {
823 	/* Mark the ones we stole for ourselves */
824 	for(i=0;l > 0;i++) {
825 	    clr_bit(bp, i);
826 	    bp->free--;
827 	    bp->total--;
828 	    l -= (1 << bits);
829 	}
830     }
831 
832     return 1;
833 }
834 
835 /*
836  * Allocate a fragment
837  */
838 static void *
839 malloc_bytes(size)
840     size_t size;
841 {
842     int j;
843     struct  pginfo *bp;
844     int k;
845     u_long *lp;
846 
847     /* Don't bother with anything less than this */
848     if (size < malloc_minsize)
849 	size = malloc_minsize;
850 
851     /* Find the right bucket */
852     j = fls((size)-1);
853 
854     /* If it's empty, make a page more of that size chunks */
855     if (!page_dir[j] && !malloc_make_chunks(j))
856 	return 0;
857 
858     bp = page_dir[j];
859 
860     /* Find first word of bitmap which isn't empty */
861     for (lp = bp->bits; !*lp; lp++)
862 	;
863 
864     /* Find that bit, and tweak it */
865     k = ffs_ul(*lp) - 1;
866     *lp ^= 1UL<<k;
867 
868     /* If there are no more free, remove from free-list */
869     if (!--bp->free) {
870 	page_dir[j] = bp->next;
871 	bp->next = 0;
872     }
873 
874     /* Adjust to the real offset of that chunk */
875     k += (lp-bp->bits)*MALLOC_BITS;
876     k <<= bp->shift;
877 
878     if (malloc_junk)
879 	memset((char *)bp->page + k, SOME_JUNK, bp->size);
880 
881     return (void *)((char *)bp->page + k);
882 }
883 
884 /*
885  * Allocate a piece of memory
886  */
887 static void *
888 imalloc(size)
889     size_t size;
890 {
891     void *result;
892 #ifdef  _THREAD_SAFE
893     int     status;
894 #endif
895 
896     if (!initialized)
897 	malloc_init();
898 
899     if (suicide)
900 	abort();
901 
902     if (size <= malloc_maxsize)
903 	result =  malloc_bytes(size);
904     else
905 	result =  malloc_pages(size);
906 
907     if (malloc_abort && !result)
908 	wrterror("allocation failed.\n");
909 
910     if (malloc_zero)
911 	memset(result, 0, size);
912 
913     return result;
914 }
915 
916 /*
917  * Change the size of an allocation.
918  */
919 static void *
920 irealloc(ptr, size)
921     void *ptr;
922     size_t size;
923 {
924     void *p;
925     u_long osize, index;
926     struct pginfo **mp;
927     int i;
928 #ifdef  _THREAD_SAFE
929     int     status;
930 #endif
931 
932     if (suicide)
933 	return 0;
934 
935     if (!initialized) {
936 	wrtwarning("malloc() has never been called.\n");
937 	return 0;
938     }
939 
940     index = ptr2index(ptr);
941 
942     if (index < malloc_pageshift) {
943 	wrtwarning("junk pointer, too low to make sense.\n");
944 	return 0;
945     }
946 
947     if (index > last_index) {
948 	wrtwarning("junk pointer, too high to make sense.\n");
949 	return 0;
950     }
951 
952     mp = &page_dir[index];
953 
954     if (*mp == MALLOC_FIRST) {			/* Page allocation */
955 
956 	/* Check the pointer */
957 	if ((u_long)ptr & malloc_pagemask) {
958 	    wrtwarning("modified (page-) pointer.\n");
959 	    return 0;
960 	}
961 
962 	/* Find the size in bytes */
963 	for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;)
964 	    osize += malloc_pagesize;
965 
966         if (!malloc_realloc && 			/* unless we have to, */
967 	  size <= osize && 			/* .. or are too small, */
968 	  size > (osize - malloc_pagesize)) {	/* .. or can free a page, */
969 	    return ptr;				/* don't do anything. */
970 	}
971 
972     } else if (*mp >= MALLOC_MAGIC) {		/* Chunk allocation */
973 
974 	/* Check the pointer for sane values */
975 	if (((u_long)ptr & ((*mp)->size-1))) {
976 	    wrtwarning("modified (chunk-) pointer.\n");
977 	    return 0;
978 	}
979 
980 	/* Find the chunk index in the page */
981 	i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift;
982 
983 	/* Verify that it isn't a free chunk already */
984 	if (tst_bit(*mp, i)) {
985 	    wrtwarning("chunk is already free.\n");
986 	    return 0;
987 	}
988 
989 	osize = (*mp)->size;
990 
991 	if (!malloc_realloc &&		/* Unless we have to, */
992 	  size < osize && 		/* ..or are too small, */
993 	  (size > osize/2 ||	 	/* ..or could use a smaller size, */
994 	  osize == malloc_minsize)) {	/* ..(if there is one) */
995 	    return ptr;			/* ..Don't do anything */
996 	}
997 
998     } else {
999 	wrtwarning("pointer to wrong page.\n");
1000 	return 0;
1001     }
1002 
1003     p = imalloc(size);
1004 
1005     if (p) {
1006 	/* copy the lesser of the two sizes, and free the old one */
1007 	if (osize < size)
1008 	    memcpy(p, ptr, osize);
1009 	else
1010 	    memcpy(p, ptr, size);
1011 	ifree(ptr);
1012     }
1013     return p;
1014 }
1015 
1016 /*
1017  * Free a sequence of pages
1018  */
1019 
1020 static __inline void
1021 free_pages(ptr, index, info)
1022     void *ptr;
1023     int index;
1024     struct pginfo *info;
1025 {
1026     int i;
1027     struct pgfree *pf, *pt=0;
1028     u_long l;
1029     void *tail;
1030 
1031     if (info == MALLOC_FREE) {
1032 	wrtwarning("page is already free.\n");
1033 	return;
1034     }
1035 
1036     if (info != MALLOC_FIRST) {
1037 	wrtwarning("pointer to wrong page.\n");
1038 	return;
1039     }
1040 
1041     if ((u_long)ptr & malloc_pagemask) {
1042 	wrtwarning("modified (page-) pointer.\n");
1043 	return;
1044     }
1045 
1046     /* Count how many pages and mark them free at the same time */
1047     page_dir[index] = MALLOC_FREE;
1048     for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++)
1049 	page_dir[index + i] = MALLOC_FREE;
1050 
1051     l = i << malloc_pageshift;
1052 
1053 #ifdef __FreeBSD__
1054     if (malloc_hint)
1055 	madvise(ptr, l, MADV_FREE);
1056 #endif
1057 
1058     tail = (char *)ptr+l;
1059 
1060     /* add to free-list */
1061     if (!px)
1062 	px = imalloc(sizeof *pt);	/* This cannot fail... */
1063     px->page = ptr;
1064     px->end =  tail;
1065     px->size = l;
1066     if (!free_list.next) {
1067 
1068 	/* Nothing on free list, put this at head */
1069 	px->next = free_list.next;
1070 	px->prev = &free_list;
1071 	free_list.next = px;
1072 	pf = px;
1073 	px = 0;
1074 
1075     } else {
1076 
1077 	/* Find the right spot, leave pf pointing to the modified entry. */
1078 	tail = (char *)ptr+l;
1079 
1080 	for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next)
1081 	    ; /* Race ahead here */
1082 
1083 	if (pf->page > tail) {
1084 	    /* Insert before entry */
1085 	    px->next = pf;
1086 	    px->prev = pf->prev;
1087 	    pf->prev = px;
1088 	    px->prev->next = px;
1089 	    pf = px;
1090 	    px = 0;
1091 	} else if (pf->end == ptr ) {
1092 	    /* Append to the previous entry */
1093 	    pf->end = (char *)pf->end + l;
1094 	    pf->size += l;
1095 	    if (pf->next && pf->end == pf->next->page ) {
1096 		/* And collapse the next too. */
1097 		pt = pf->next;
1098 		pf->end = pt->end;
1099 		pf->size += pt->size;
1100 		pf->next = pt->next;
1101 		if (pf->next)
1102 		    pf->next->prev = pf;
1103 	    }
1104 	} else if (pf->page == tail) {
1105 	    /* Prepend to entry */
1106 	    pf->size += l;
1107 	    pf->page = ptr;
1108 	} else if (!pf->next) {
1109 	    /* Append at tail of chain */
1110 	    px->next = 0;
1111 	    px->prev = pf;
1112 	    pf->next = px;
1113 	    pf = px;
1114 	    px = 0;
1115 	} else {
1116 	    wrterror("freelist is destroyed.\n");
1117 	}
1118     }
1119 
1120     /* Return something to OS ? */
1121     if (!pf->next &&				/* If we're the last one, */
1122       pf->size > malloc_cache &&		/* ..and the cache is full, */
1123       pf->end == malloc_brk &&			/* ..and none behind us, */
1124       malloc_brk == sbrk(0)) {			/* ..and it's OK to do... */
1125 
1126 	/*
1127 	 * Keep the cache intact.  Notice that the '>' above guarantees that
1128 	 * the pf will always have at least one page afterwards.
1129 	 */
1130 	pf->end = (char *)pf->page + malloc_cache;
1131 	pf->size = malloc_cache;
1132 
1133 	brk(pf->end);
1134 	malloc_brk = pf->end;
1135 
1136 	index = ptr2index(pf->end);
1137 	last_index = index - 1;
1138 
1139 	for(i=index;i <= last_index;)
1140 	    page_dir[i++] = MALLOC_NOT_MINE;
1141 
1142 	/* XXX: We could realloc/shrink the pagedir here I guess. */
1143     }
1144     if (pt)
1145 	ifree(pt);
1146 }
1147 
1148 /*
1149  * Free a chunk, and possibly the page it's on, if the page becomes empty.
1150  */
1151 
1152 /* ARGSUSED */
1153 static __inline void
1154 free_bytes(ptr, index, info)
1155     void *ptr;
1156     int index;
1157     struct pginfo *info;
1158 {
1159     int i;
1160     struct pginfo **mp;
1161     void *vp;
1162 
1163     /* Find the chunk number on the page */
1164     i = ((u_long)ptr & malloc_pagemask) >> info->shift;
1165 
1166     if (((u_long)ptr & (info->size-1))) {
1167 	wrtwarning("modified (chunk-) pointer.\n");
1168 	return;
1169     }
1170 
1171     if (tst_bit(info, i)) {
1172 	wrtwarning("chunk is already free.\n");
1173 	return;
1174     }
1175 
1176     set_bit(info, i);
1177     info->free++;
1178 
1179     mp = page_dir + info->shift;
1180 
1181     if (info->free == 1) {
1182 
1183 	/* Page became non-full */
1184 
1185 	mp = page_dir + info->shift;
1186 	/* Insert in address order */
1187 	while (*mp && (*mp)->next && (*mp)->next->page < info->page)
1188 	    mp = &(*mp)->next;
1189 	info->next = *mp;
1190 	*mp = info;
1191 	return;
1192     }
1193 
1194     if (info->free != info->total)
1195 	return;
1196 
1197     /* Find & remove this page in the queue */
1198     while (*mp != info) {
1199 	mp = &((*mp)->next);
1200 #ifdef EXTRA_SANITY
1201 	if (!*mp)
1202 		wrterror("(ES): Not on queue\n");
1203 #endif /* EXTRA_SANITY */
1204     }
1205     *mp = info->next;
1206 
1207     /* Free the page & the info structure if need be */
1208     page_dir[ptr2index(info->page)] = MALLOC_FIRST;
1209     vp = info->page;		/* Order is important ! */
1210     if(vp != (void*)info)
1211 	ifree(info);
1212     ifree(vp);
1213 }
1214 
1215 static void
1216 ifree(ptr)
1217     void *ptr;
1218 {
1219     struct pginfo *info;
1220     int index;
1221 #ifdef  _THREAD_SAFE
1222     int     status;
1223 #endif
1224 
1225     /* This is legal */
1226     if (!ptr)
1227 	return;
1228 
1229     if (!initialized) {
1230 	wrtwarning("malloc() has never been called.\n");
1231 	return;
1232     }
1233 
1234     /* If we're already sinking, don't make matters any worse. */
1235     if (suicide)
1236 	return;
1237 
1238     index = ptr2index(ptr);
1239 
1240     if (index < malloc_pageshift) {
1241 	wrtwarning("junk pointer, too low to make sense.\n");
1242 	return;
1243     }
1244 
1245     if (index > last_index) {
1246 	wrtwarning("junk pointer, too high to make sense.\n");
1247 	return;
1248     }
1249 
1250     info = page_dir[index];
1251 
1252     if (info < MALLOC_MAGIC)
1253         free_pages(ptr, index, info);
1254     else
1255 	free_bytes(ptr, index, info);
1256     return;
1257 }
1258 
1259 /*
1260  * These are the public exported interface routines.
1261  */
1262 
1263 #ifdef _THREAD_SAFE
1264 #include <pthread.h>
1265 #include "pthread_private.h"
1266 static int malloc_lock;
1267 #define THREAD_LOCK() _thread_kern_sig_block(&malloc_lock);
1268 #define THREAD_UNLOCK() _thread_kern_sig_unblock(&malloc_lock);
1269 #else
1270 #define THREAD_LOCK()
1271 #define THREAD_UNLOCK()
1272 #endif
1273 
1274 static int malloc_active;
1275 
1276 void *
1277 malloc(size_t size)
1278 {
1279     register void *r;
1280 
1281     malloc_func = "malloc():";
1282     THREAD_LOCK();
1283     if (malloc_active++) {
1284 	wrtwarning("recursive call.\n");
1285         malloc_active--;
1286 	return (0);
1287     }
1288     r = imalloc(size);
1289     UTRACE(0, size, r);
1290     malloc_active--;
1291     THREAD_UNLOCK();
1292     return (r);
1293 }
1294 
1295 void
1296 free(void *ptr)
1297 {
1298     malloc_func = "free():";
1299     THREAD_LOCK();
1300     if (malloc_active++) {
1301 	wrtwarning("recursive call.\n");
1302         malloc_active--;
1303 	return;
1304     }
1305     ifree(ptr);
1306     UTRACE(ptr, 0, 0);
1307     malloc_active--;
1308     THREAD_UNLOCK();
1309     return;
1310 }
1311 
1312 void *
1313 realloc(void *ptr, size_t size)
1314 {
1315     register void *r;
1316 
1317     malloc_func = "realloc():";
1318     THREAD_LOCK();
1319     if (malloc_active++) {
1320 	wrtwarning("recursive call.\n");
1321         malloc_active--;
1322 	return (0);
1323     }
1324     if (!ptr) {
1325 	r = imalloc(size);
1326     } else if (ptr && !size) {
1327 	ifree(ptr);
1328 	r = 0;
1329     } else {
1330         r = irealloc(ptr, size);
1331     }
1332     UTRACE(ptr, size, r);
1333     malloc_active--;
1334     THREAD_UNLOCK();
1335     return (r);
1336 }
1337