summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2008-10-03 18:44:30 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2008-10-03 18:44:30 +0000
commit3ed768f4dc2ac321ae74f18f47c627194c9cd78d (patch)
tree76bc47c612c49dc322ea62f807466e6cb72ce9ab /lib/libc
parent73b4d6fa72b5d71c2cb3271fc2ac8c8321fa0b02 (diff)
when increasing the size of a larger than a page allocation try
mapping the region next to the existing one first; there's a pretty high chance there's a hole there we can use; ok deraadt@ tedu@
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdlib/malloc.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index 1bd5c9f89c5..a205253fd48 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.c,v 1.99 2008/10/03 18:42:45 otto Exp $ */
+/* $OpenBSD: malloc.c,v 1.100 2008/10/03 18:44:29 otto Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
@@ -78,6 +78,9 @@
#define MMAP(sz) mmap(NULL, (size_t)(sz), PROT_READ | PROT_WRITE, \
MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)
+#define MMAPA(a,sz) mmap((a), (size_t)(sz), PROT_READ | PROT_WRITE, \
+ MAP_ANON | MAP_PRIVATE, -1, (off_t) 0)
+
struct region_info {
void *p; /* page; low bits used to mark chunks */
uintptr_t size; /* size for pages, or chunk_info pointer */
@@ -440,6 +443,27 @@ unmap(struct dir_info *d, void *p, size_t sz)
wrtwarning("malloc cache overflow");
}
+static void
+zapcacheregion(struct dir_info *d, void *p)
+{
+ u_int i;
+ struct region_info *r;
+ size_t rsz;
+
+ for (i = 0; i < malloc_cache; i++) {
+ r = &d->free_regions[i];
+ if (r->p == p) {
+ rsz = r->size << MALLOC_PAGESHIFT;
+ if (munmap(r->p, rsz))
+ wrterror("munmap");
+ r->p = NULL;
+ d->free_regions_size -= r->size;
+ r->size = 0;
+ malloc_used -= rsz;
+ }
+ }
+}
+
static void *
map(struct dir_info *d, size_t sz, int zero_fill)
{
@@ -1277,7 +1301,21 @@ orealloc(void *p, size_t newsz)
size_t roldsz = PAGEROUND(goldsz);
size_t rnewsz = PAGEROUND(gnewsz);
- if (rnewsz < roldsz) {
+ if (rnewsz > roldsz) {
+ if (!malloc_guard) {
+ zapcacheregion(&g_pool, p + roldsz);
+ q = MMAPA(p + roldsz, rnewsz - roldsz);
+ if (q == p + roldsz) {
+ malloc_used += rnewsz - roldsz;
+ if (malloc_junk)
+ memset(q, SOME_JUNK,
+ rnewsz - roldsz);
+ r->size = newsz;
+ return p;
+ } else if (q != MAP_FAILED)
+ munmap(q, rnewsz - roldsz);
+ }
+ } else if (rnewsz < roldsz) {
if (malloc_guard) {
if (mprotect((char *)p + roldsz - malloc_guard,
malloc_guard, PROT_READ | PROT_WRITE))
@@ -1289,7 +1327,7 @@ orealloc(void *p, size_t newsz)
unmap(&g_pool, (char *)p + rnewsz, roldsz - rnewsz);
r->size = gnewsz;
return p;
- } else if (rnewsz == roldsz) {
+ } else {
if (newsz > oldsz && malloc_junk)
memset((char *)p + newsz, SOME_JUNK,
rnewsz - malloc_guard - newsz);