diff options
author | tedu <> | 2014-05-18 17:49:47 +0000 |
---|---|---|
committer | tedu <> | 2014-05-18 17:49:47 +0000 |
commit | 6e46a6ffffee60e9690dcc0fca32d26b123b9487 (patch) | |
tree | dd37544b726ba1d11afb0550f742cf8e566c81e0 | |
parent | 524c086481ad769e816ef9cd159a9660962be4e0 (diff) | |
download | openbsd-6e46a6ffffee60e9690dcc0fca32d26b123b9487.tar.gz openbsd-6e46a6ffffee60e9690dcc0fca32d26b123b9487.tar.bz2 openbsd-6e46a6ffffee60e9690dcc0fca32d26b123b9487.zip |
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
-rw-r--r-- | src/lib/libc/stdlib/malloc.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index c0542fc9c8..3f544006fc 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: malloc.c,v 1.163 2014/05/12 19:02:20 tedu Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.164 2014/05/18 17:49:47 tedu Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2008, 2010, 2011 Otto Moerbeek <otto@drijf.net> | 3 | * Copyright (c) 2008, 2010, 2011 Otto Moerbeek <otto@drijf.net> |
4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> | 4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> |
@@ -966,34 +966,47 @@ malloc_bytes(struct dir_info *d, size_t size, void *f) | |||
966 | return ((char *)bp->page + k); | 966 | return ((char *)bp->page + k); |
967 | } | 967 | } |
968 | 968 | ||
969 | 969 | static uint32_t | |
970 | /* | 970 | find_chunknum(struct dir_info *d, struct region_info *r, void *ptr) |
971 | * Free a chunk, and possibly the page it's on, if the page becomes empty. | ||
972 | */ | ||
973 | static void | ||
974 | free_bytes(struct dir_info *d, struct region_info *r, void *ptr) | ||
975 | { | 971 | { |
976 | struct chunk_head *mp; | ||
977 | struct chunk_info *info; | 972 | struct chunk_info *info; |
978 | int i, listnum; | 973 | uint32_t chunknum; |
979 | 974 | ||
980 | info = (struct chunk_info *)r->size; | 975 | info = (struct chunk_info *)r->size; |
981 | if (info->canary != d->canary1) | 976 | if (info->canary != d->canary1) |
982 | wrterror("chunk info corrupted", NULL); | 977 | wrterror("chunk info corrupted", NULL); |
983 | 978 | ||
984 | /* Find the chunk number on the page */ | 979 | /* Find the chunk number on the page */ |
985 | i = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; | 980 | chunknum = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; |
986 | 981 | ||
987 | if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) { | 982 | if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) { |
988 | wrterror("modified chunk-pointer", ptr); | 983 | wrterror("modified chunk-pointer", ptr); |
989 | return; | 984 | return -1; |
990 | } | 985 | } |
991 | if (info->bits[i / MALLOC_BITS] & (1U << (i % MALLOC_BITS))) { | 986 | if (info->bits[chunknum / MALLOC_BITS] & |
987 | (1U << (chunknum % MALLOC_BITS))) { | ||
992 | wrterror("chunk is already free", ptr); | 988 | wrterror("chunk is already free", ptr); |
993 | return; | 989 | return -1; |
994 | } | 990 | } |
991 | return chunknum; | ||
992 | } | ||
995 | 993 | ||
996 | info->bits[i / MALLOC_BITS] |= 1U << (i % MALLOC_BITS); | 994 | /* |
995 | * Free a chunk, and possibly the page it's on, if the page becomes empty. | ||
996 | */ | ||
997 | static void | ||
998 | free_bytes(struct dir_info *d, struct region_info *r, void *ptr) | ||
999 | { | ||
1000 | struct chunk_head *mp; | ||
1001 | struct chunk_info *info; | ||
1002 | uint32_t chunknum; | ||
1003 | int listnum; | ||
1004 | |||
1005 | info = (struct chunk_info *)r->size; | ||
1006 | if ((chunknum = find_chunknum(d, r, ptr)) == -1) | ||
1007 | return; | ||
1008 | |||
1009 | info->bits[chunknum / MALLOC_BITS] |= 1U << (chunknum % MALLOC_BITS); | ||
997 | info->free++; | 1010 | info->free++; |
998 | 1011 | ||
999 | if (info->free == 1) { | 1012 | if (info->free == 1) { |
@@ -1204,9 +1217,15 @@ ofree(void *p) | |||
1204 | if (mopts.malloc_junk && sz > 0) | 1217 | if (mopts.malloc_junk && sz > 0) |
1205 | memset(p, SOME_FREEJUNK, sz); | 1218 | memset(p, SOME_FREEJUNK, sz); |
1206 | if (!mopts.malloc_freenow) { | 1219 | if (!mopts.malloc_freenow) { |
1220 | if (find_chunknum(g_pool, r, p) == -1) | ||
1221 | return; | ||
1207 | i = getrbyte() & MALLOC_DELAYED_CHUNK_MASK; | 1222 | i = getrbyte() & MALLOC_DELAYED_CHUNK_MASK; |
1208 | tmp = p; | 1223 | tmp = p; |
1209 | p = g_pool->delayed_chunks[i]; | 1224 | p = g_pool->delayed_chunks[i]; |
1225 | if (tmp == p) { | ||
1226 | wrterror("double free", p); | ||
1227 | return; | ||
1228 | } | ||
1210 | g_pool->delayed_chunks[i] = tmp; | 1229 | g_pool->delayed_chunks[i] = tmp; |
1211 | } | 1230 | } |
1212 | if (p != NULL) { | 1231 | if (p != NULL) { |