diff options
| author | christos <christos@NetBSD.org> | 2001-05-06 04:48:41 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2001-05-06 04:48:41 +0000 |
| commit | b2126f94bb059a1cecc318b18e9621515ecbfe21 (patch) | |
| tree | 12fb2ff942fd6b05f55a93c35383808028f4d2e4 /lib/libc/stdlib/malloc.c | |
| parent | 8a43d56a884973258e2fc0f03ba4bb3f6135add3 (diff) | |
More fixes:
1. use uintptr_t instead of u_long
2. check for overflow in map_pages and malloc_pages
3. bring in fixes from FreeBSD [int -> size_t, and a missing THREAD_UNLOCK]
4. rewrite map_pages to use sbrk() only to grow memory (avoids extra syscall
and elides bug in brk(2) that ross is fixing)
5. restore the break point to its original value if the mmap(2) for the page
directory or the alignment sbrk breaks.
reviewed by: chuq and ross
tested by: make build and reboot
Now memtest nearly works; unfortunately there is no way currently to lower
the break point as we free, so memtest keeps trying to reduce memory when
mlock() fails and that does not work.
Diffstat (limited to 'lib/libc/stdlib/malloc.c')
| -rw-r--r-- | lib/libc/stdlib/malloc.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index a88c3b91d23..cdffc80fea6 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $NetBSD: malloc.c,v 1.37 2001/05/03 15:35:12 christos Exp $ */ +/* $NetBSD: malloc.c,v 1.38 2001/05/06 04:48:41 christos Exp $ */ /* * ---------------------------------------------------------------------------- @@ -98,6 +98,7 @@ int utrace __P((const char *, void *, size_t)); #include <errno.h> #include <fcntl.h> #include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -160,7 +161,8 @@ static size_t malloc_pagemask; #endif #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) -#define ptr2idx(foo) (((size_t)(u_long)(foo) >> malloc_pageshift)-malloc_origo) +#define ptr2idx(foo) \ + (((size_t)(uintptr_t)(foo) >> malloc_pageshift)-malloc_origo) #ifndef THREAD_LOCK #define THREAD_LOCK() @@ -305,24 +307,45 @@ wrtwarning(char *p) static void * map_pages(size_t pages) { - caddr_t result, tail; + caddr_t result, rresult, tail; + intptr_t bytes = pages << malloc_pageshift; - result = (caddr_t)pageround((size_t)(u_long)sbrk((intptr_t)0)); - tail = result + (pages << malloc_pageshift); + if (bytes < 0 || (size_t)bytes < pages) { + errno = ENOMEM; + return NULL; + } - if (brk(tail)) { -#ifdef MALLOC_EXTRA_SANITY - wrterror("(ES): map_pages fails\n"); -#endif /* MALLOC_EXTRA_SANITY */ - return 0; + if ((result = sbrk(bytes)) == (void *)-1) + return NULL; + + /* + * Round to a page, in case sbrk(2) did not do this for us + */ + rresult = (caddr_t)pageround((size_t)(uintptr_t)result); + if (result < rresult) { + /* make sure we have enough space to fit bytes */ + if (sbrk((intptr_t)(rresult - result)) == (void *) -1) { + /* we failed, put everything back */ + if (brk(result)) { + wrterror("brk(2) failed [internal error]\n"); + } + } } + tail = rresult + (size_t)bytes; + last_idx = ptr2idx(tail) - 1; malloc_brk = tail; - if ((last_idx+1) >= malloc_ninfo && !extend_pgdir(last_idx)) - return 0;; + if ((last_idx+1) >= malloc_ninfo && !extend_pgdir(last_idx)) { + malloc_brk = result; + last_idx = ptr2idx(malloc_brk) - 1; + /* Put back break point since we failed. */ + if (brk(malloc_brk)) + wrterror("brk(2) failed [internal error]\n"); + return 0; + } - return result; + return rresult; } /* @@ -480,7 +503,7 @@ malloc_init (void) * We need a maximum of malloc_pageshift buckets, steal these from the * front of the page_directory; */ - malloc_origo = pageround((size_t)(u_long)sbrk((intptr_t)0)) + malloc_origo = pageround((size_t)(uintptr_t)sbrk((intptr_t)0)) >> malloc_pageshift; malloc_origo -= malloc_pageshift; @@ -510,11 +533,16 @@ static void * malloc_pages(size_t size) { void *p, *delay_free = 0; - int i; + size_t i; struct pgfree *pf; size_t idx; - size = pageround(size); + idx = pageround(size); + if (idx < size) { + errno = ENOMEM; + return NULL; + } else + size = idx; p = 0; @@ -774,7 +802,7 @@ irealloc(void *ptr, size_t size) if (*mp == MALLOC_FIRST) { /* Page allocation */ /* Check the pointer */ - if ((size_t)(u_long)ptr & malloc_pagemask) { + if ((size_t)(uintptr_t)ptr & malloc_pagemask) { wrtwarning("modified (page-) pointer.\n"); return 0; } @@ -792,13 +820,13 @@ irealloc(void *ptr, size_t size) } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */ /* Check the pointer for sane values */ - if (((size_t)(u_long)ptr & ((*mp)->size-1))) { + if (((size_t)(uintptr_t)ptr & ((*mp)->size-1))) { wrtwarning("modified (chunk-) pointer.\n"); return 0; } /* Find the chunk index in the page */ - i = ((size_t)(u_long)ptr & malloc_pagemask) >> (*mp)->shift; + i = ((size_t)(uintptr_t)ptr & malloc_pagemask) >> (*mp)->shift; /* Verify that it isn't a free chunk already */ if ((*mp)->bits[i/MALLOC_BITS] & (1<<(i%MALLOC_BITS))) { @@ -857,7 +885,7 @@ free_pages(void *ptr, size_t idx, struct pginfo *info) return; } - if ((size_t)(u_long)ptr & malloc_pagemask) { + if ((size_t)(uintptr_t)ptr & malloc_pagemask) { wrtwarning("modified (page-) pointer.\n"); return; } @@ -977,9 +1005,9 @@ free_bytes(void *ptr, size_t idx, struct pginfo *info) void *vp; /* Find the chunk number on the page */ - i = ((size_t)(u_long)ptr & malloc_pagemask) >> info->shift; + i = ((size_t)(uintptr_t)ptr & malloc_pagemask) >> info->shift; - if (((size_t)(u_long)ptr & (info->size-1))) { + if (((size_t)(uintptr_t)ptr & (info->size-1))) { wrtwarning("modified (chunk-) pointer.\n"); return; } @@ -1113,6 +1141,7 @@ free(void *ptr) if (malloc_active++) { wrtwarning("recursive call.\n"); malloc_active--; + THREAD_UNLOCK(); return; } else { ifree(ptr); |
