diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2006-04-24 19:23:43 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2006-04-24 19:23:43 +0000 |
commit | b073eac299215a2c87e8bd2b3d24727678ae6010 (patch) | |
tree | da07be8c0caaee628f803b5aa9c92a3e41712abf /lib/libc | |
parent | 7f43ca82483f7d40be2de8b3e06f9e8540ff489c (diff) |
Do not leave an hole in the directory list if allocation of the
region succeeds, but allocation a required page dir failed. This
can happen if we're really close to ulimit after allocation the
region of the size requested. See malloc_ulimit1 regress test.
Tested by many; thanks.
Diffstat (limited to 'lib/libc')
-rw-r--r-- | lib/libc/stdlib/malloc.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 4a38c53bbd2..b858bbb739a 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.81 2006/04/18 18:26:13 otto Exp $ */ +/* $OpenBSD: malloc.c,v 1.82 2006/04/24 19:23:42 otto Exp $ */ /* * ---------------------------------------------------------------------------- @@ -487,14 +487,16 @@ map_pages(size_t pages) u_long idx, pidx, lidx; caddr_t result, tail; u_long index, lindex; + void *pdregion = NULL; + size_t dirs, cnt; pages <<= malloc_pageshift; result = MMAP(pages + malloc_guard); if (result == MAP_FAILED) { - errno = ENOMEM; #ifdef MALLOC_EXTRA_SANITY wrtwarning("(ES): map_pages fails"); #endif /* MALLOC_EXTRA_SANITY */ + errno = ENOMEM; return (NULL); } index = ptr2index(result); @@ -510,19 +512,31 @@ map_pages(size_t pages) malloc_brk = tail; last_index = lindex; } + + dirs = lidx - pidx; + /* Insert directory pages, if needed. */ - pdir_lookup(index, &pi); + if (pdir_lookup(index, &pi) != 0) + dirs++; + + if (dirs > 0) { + pdregion = MMAP(malloc_pagesize * dirs); + if (pdregion == MAP_FAILED) { + munmap(result, tail - result); +#ifdef MALLOC_EXTRA_SANITY + wrtwarning("(ES): map_pages fails"); +#endif + errno = ENOMEM; + return (NULL); + } + } + cnt = 0; for (idx = pidx, spi = pi; idx <= lidx; idx++) { if (pi == NULL || PD_IDX(pi->dirnum) != idx) { - if ((pd = MMAP(malloc_pagesize)) == MAP_FAILED) { - errno = ENOMEM; /* XXX */ - munmap(result, (size_t)(tail - result)); -#ifdef MALLOC_EXTRA_SANITY - wrtwarning("(ES): map_pages fails"); -#endif /* MALLOC_EXTRA_SANITY */ - return (NULL); - } + pd = (struct pginfo **)((char *)pdregion + + cnt * malloc_pagesize); + cnt++; memset(pd, 0, malloc_pagesize); pi = (struct pdinfo *) ((caddr_t) pd + pdi_off); pi->base = pd; @@ -561,6 +575,13 @@ map_pages(size_t pages) spi = pi; pi = spi->next; } +#ifdef MALLOC_EXTRA_SANITY + if (cnt > dirs) + wrtwarning("(ES): cnt > dirs"); +#endif /* MALLOC_EXTRA_SANITY */ + if (cnt < dirs) + munmap((char *)pdregion + cnt * malloc_pagesize, + (dirs - cnt) * malloc_pagesize); return (result); } |