diff options
| author | tedu <> | 2014-05-18 17:49:47 +0000 |
|---|---|---|
| committer | tedu <> | 2014-05-18 17:49:47 +0000 |
| commit | b274e53c54eb4a5bfe7289c4926b37ede04932ab (patch) | |
| tree | dd37544b726ba1d11afb0550f742cf8e566c81e0 /src/lib/libc/stdlib/malloc.c | |
| parent | a500e5dea993d13c6404fed5ab624440bc9fdb8f (diff) | |
| download | openbsd-b274e53c54eb4a5bfe7289c4926b37ede04932ab.tar.gz openbsd-b274e53c54eb4a5bfe7289c4926b37ede04932ab.tar.bz2 openbsd-b274e53c54eb4a5bfe7289c4926b37ede04932ab.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
Diffstat (limited to 'src/lib/libc/stdlib/malloc.c')
| -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) { |
