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