From 118f2caf23b16395273c727a56f4fa0b00343641 Mon Sep 17 00:00:00 2001 From: tedu <> Date: Sun, 18 May 2014 17:49:47 +0000 Subject: [PATCH] factor out a bit of the chunk index code and use it to make sure that a freed chunk is actually freeable immediately. catch more errors. hints/ok otto --- src/lib/libc/stdlib/malloc.c | 47 +++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index c0542fc9..3f544006 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.163 2014/05/12 19:02:20 tedu Exp $ */ +/* $OpenBSD: malloc.c,v 1.164 2014/05/18 17:49:47 tedu Exp $ */ /* * Copyright (c) 2008, 2010, 2011 Otto Moerbeek * Copyright (c) 2012 Matthew Dempsky @@ -966,34 +966,47 @@ malloc_bytes(struct dir_info *d, size_t size, void *f) return ((char *)bp->page + k); } - -/* - * Free a chunk, and possibly the page it's on, if the page becomes empty. - */ -static void -free_bytes(struct dir_info *d, struct region_info *r, void *ptr) +static uint32_t +find_chunknum(struct dir_info *d, struct region_info *r, void *ptr) { - struct chunk_head *mp; struct chunk_info *info; - int i, listnum; + uint32_t chunknum; info = (struct chunk_info *)r->size; if (info->canary != d->canary1) wrterror("chunk info corrupted", NULL); /* Find the chunk number on the page */ - i = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; + chunknum = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) { wrterror("modified chunk-pointer", ptr); - return; + return -1; } - if (info->bits[i / MALLOC_BITS] & (1U << (i % MALLOC_BITS))) { + if (info->bits[chunknum / MALLOC_BITS] & + (1U << (chunknum % MALLOC_BITS))) { wrterror("chunk is already free", ptr); - return; + return -1; } + return chunknum; +} - info->bits[i / MALLOC_BITS] |= 1U << (i % MALLOC_BITS); +/* + * Free a chunk, and possibly the page it's on, if the page becomes empty. + */ +static void +free_bytes(struct dir_info *d, struct region_info *r, void *ptr) +{ + struct chunk_head *mp; + struct chunk_info *info; + uint32_t chunknum; + int listnum; + + info = (struct chunk_info *)r->size; + if ((chunknum = find_chunknum(d, r, ptr)) == -1) + return; + + info->bits[chunknum / MALLOC_BITS] |= 1U << (chunknum % MALLOC_BITS); info->free++; if (info->free == 1) { @@ -1204,9 +1217,15 @@ ofree(void *p) if (mopts.malloc_junk && sz > 0) memset(p, SOME_FREEJUNK, sz); if (!mopts.malloc_freenow) { + if (find_chunknum(g_pool, r, p) == -1) + return; i = getrbyte() & MALLOC_DELAYED_CHUNK_MASK; tmp = p; p = g_pool->delayed_chunks[i]; + if (tmp == p) { + wrterror("double free", p); + return; + } g_pool->delayed_chunks[i] = tmp; } if (p != NULL) {