diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 028eff2b..ace34c96 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $ */ +/* $OpenBSD: malloc.c,v 1.84 2006/10/24 04:35:30 tedu Exp $ */ /* * ---------------------------------------------------------------------------- @@ -75,6 +75,18 @@ #define malloc_pageshift (PGSHIFT) #endif +#ifndef malloc_minsize +#define malloc_minsize 16UL +#endif + +#if !defined(malloc_pagesize) +#define malloc_pagesize (1UL<next; + memset(p, 0, sizeof *p); + return p; +} + +static struct pginfo * +alloc_pginfo() +{ + struct pginfo *p; + int i; + + if (pginfo_list == NULL) { + p = MMAP(malloc_pagesize); + if (!p) + return NULL; + for (i = 0; i < malloc_pagesize / sizeof(*p); i++) { + p[i].next = pginfo_list; + pginfo_list = &p[i]; + } + } + p = pginfo_list; + pginfo_list = p->next; + memset(p, 0, sizeof *p); + return p; +} + +static void +put_pgfree(struct pgfree *p) +{ + p->next = pgfree_list; + pgfree_list = p; +} + +static void +put_pginfo(struct pginfo *p) +{ + p->next = pginfo_list; + pginfo_list = p; +} + /* * Function for page directory lookup. */ @@ -764,12 +825,12 @@ malloc_init(void) static void * malloc_pages(size_t size) { - void *p, *delay_free = NULL, *tp; + void *p, *tp; int i; struct pginfo **pd; struct pdinfo *pi; u_long pidx, index; - struct pgfree *pf; + struct pgfree *pf, *delay_free = NULL; size = pageround(size) + malloc_guard; @@ -936,7 +997,7 @@ malloc_pages(size_t size) if (px == NULL) px = delay_free; else - ifree(delay_free); + put_pgfree(delay_free); } return (p); } @@ -945,7 +1006,7 @@ malloc_pages(size_t size) * Allocate a page of fragments */ -static __inline__ int +static int malloc_make_chunks(int bits) { struct pginfo *bp, **pd; @@ -955,17 +1016,13 @@ malloc_make_chunks(int bits) #endif /* MALLOC_EXTRA_SANITY */ void *pp; long i, k; - size_t l; /* Allocate a new bucket */ - pp = malloc_pages((size_t) malloc_pagesize); + pp = malloc_pages((size_t)malloc_pagesize); if (pp == NULL) return (0); /* Find length of admin structure */ - l = sizeof *bp - sizeof(u_long); - l += sizeof(u_long) * - (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS); /* Don't waste more than two chunks on this */ @@ -975,14 +1032,10 @@ malloc_make_chunks(int bits) * pginfo page. * --> Treat it like the big chunk alloc, get a second data page. */ - if (bits != 0 && (1UL << (bits)) <= l + l) { - bp = (struct pginfo *) pp; - } else { - bp = (struct pginfo *) imalloc(l); - if (bp == NULL) { - ifree(pp); - return (0); - } + bp = alloc_pginfo(); + if (bp == NULL) { + ifree(pp); + return (0); } /* memory protect the page allocated in the malloc(0) case */ @@ -998,7 +1051,7 @@ malloc_make_chunks(int bits) k = mprotect(pp, malloc_pagesize, PROT_NONE); if (k < 0) { ifree(pp); - ifree(bp); + put_pginfo(bp); return (0); } } else { @@ -1019,18 +1072,6 @@ malloc_make_chunks(int bits) for (; i < k; i++) bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS); - k = (long)l; - if (bp == bp->page) { - /* Mark the ones we stole for ourselves */ - for (i = 0; k > 0; i++) { - bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS)); - bp->free--; - bp->total--; - k -= (1 << bits); - } - } - /* MALLOC_LOCK */ - pdir_lookup(ptr2index(pp), &pi); #ifdef MALLOC_EXTRA_SANITY pidx = PI_IDX(ptr2index(pp)); @@ -1325,7 +1366,7 @@ irealloc(void *ptr, size_t size) /* * Free a sequence of pages */ -static __inline__ void +static void free_pages(void *ptr, u_long index, struct pginfo * info) { u_long i, pidx, lidx; @@ -1409,8 +1450,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info) mprotect(ptr, l, PROT_NONE); /* Add to free-list. */ - if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL) - goto not_return; + if (px == NULL && (px = alloc_pgfree()) == NULL) + goto not_return; px->page = ptr; px->pdir = spi; px->size = l; @@ -1578,7 +1619,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) /* XXX: We could realloc/shrink the pagedir here I guess. */ if (pf->size == 0) { /* Remove from free-list as well. */ if (px) - ifree(px); + put_pgfree(px); if ((px = pf->prev) != &free_list) { if (pi == NULL && last_index == (index - 1)) { if (spi == NULL) { @@ -1592,7 +1633,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) pdi_mod) - 1; for (pi = spi, i = index; pd[PI_OFF(i)] == MALLOC_NOT_MINE; - i--) + i--) { #ifdef MALLOC_EXTRA_SANITY if (!PI_OFF(i)) { pi = pi->prev; @@ -1601,10 +1642,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info) pd = pi->base; i = (PD_IDX(pi->dirnum) + 1) * pdi_mod; } -#else /* !MALLOC_EXTRA_SANITY */ - { - } #endif /* MALLOC_EXTRA_SANITY */ + } malloc_brk = index2ptr(i + 1); } last_index = i; @@ -1622,7 +1661,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) } not_return: if (pt != NULL) - ifree(pt); + put_pgfree(pt); } /* @@ -1630,16 +1669,41 @@ not_return: */ /* ARGSUSED */ -static __inline__ void -free_bytes(void *ptr, u_long index, struct pginfo * info) +static void +free_bytes(void *ptr) { - struct pginfo **mp, **pd; + struct pginfo **mp, **pd, *info; struct pdinfo *pi; #ifdef MALLOC_EXTRA_SANITY u_long pidx; #endif /* MALLOC_EXTRA_SANITY */ + u_long index; void *vp; long i; + void *tmpptr; + unsigned int tmpidx; + /* pointers that we will want to free at some future time */ + static void *chunk_buffer[16]; + + + /* delay return, returning a random something from before instead */ + tmpidx = arc4random() % 16; + tmpptr = chunk_buffer[tmpidx]; + chunk_buffer[tmpidx] = ptr; + ptr = tmpptr; + if (!ptr) + return; + + index = ptr2index(ptr); + + pdir_lookup(index, &pi); + if (pi != last_dir) { + prev_dir = last_dir; + last_dir = pi; + } + pd = pi->base; + info = pd[PI_OFF(index)]; + /* Find the chunk number on the page */ i = ((u_long) ptr & malloc_pagemask) >> info->shift; @@ -1711,9 +1775,8 @@ free_bytes(void *ptr, u_long index, struct pginfo * info) if (info->size == 0) mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE); - vp = info->page; /* Order is important ! */ - if (vp != (void *) info) - ifree(info); + vp = info->page; + put_pginfo(info); ifree(vp); } @@ -1736,7 +1799,7 @@ ifree(void *ptr) return; if (malloc_ptrguard && PTR_ALIGNED(ptr)) - ptr = (char *) ptr - PTR_GAP; + ptr = (char *)ptr - PTR_GAP; index = ptr2index(ptr); @@ -1750,6 +1813,7 @@ ifree(void *ptr) wrtwarning("ifree: junk pointer, too high to make sense"); return; } + pdir_lookup(index, &pi); #ifdef MALLOC_EXTRA_SANITY pidx = PI_IDX(index); @@ -1769,11 +1833,11 @@ ifree(void *ptr) if (info < MALLOC_MAGIC) free_pages(ptr, index, info); else - free_bytes(ptr, index, info); + free_bytes(ptr); /* does not matter if malloc_bytes fails */ if (px == NULL) - px = malloc_bytes(sizeof *px); + px = alloc_pgfree(); return; }