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