From ed5636e71836ca5a55b64a007372b9238011226a Mon Sep 17 00:00:00 2001 From: otto <> Date: Sun, 18 Nov 2018 16:15:18 +0000 Subject: [PATCH] Implement malloc_usable_size(); ok millert@ deraadt@ and jmc@ for the man page --- src/include/stdlib.h | 3 +- src/lib/libc/stdlib/malloc.3 | 34 ++++++++++++--- src/lib/libc/stdlib/malloc.c | 80 +++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 7 deletions(-) diff --git a/src/include/stdlib.h b/src/include/stdlib.h index d546444c..b0f3dd14 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -1,4 +1,4 @@ -/* $OpenBSD: stdlib.h,v 1.73 2018/11/05 08:23:40 otto Exp $ */ +/* $OpenBSD: stdlib.h,v 1.74 2018/11/18 16:15:18 otto Exp $ */ /* $NetBSD: stdlib.h,v 1.25 1995/12/27 21:19:08 jtc Exp $ */ /*- @@ -112,6 +112,7 @@ long labs(long); ldiv_t ldiv(long, long); void *malloc(size_t); #if __BSD_VISIBLE +size_t malloc_usable_size(void *); void freezero(void *, size_t) __attribute__ ((__bounded__(__buffer__,1,2))); void *reallocarray(void *, size_t, size_t); diff --git a/src/lib/libc/stdlib/malloc.3 b/src/lib/libc/stdlib/malloc.3 index 35222a15..c1776f61 100644 --- a/src/lib/libc/stdlib/malloc.3 +++ b/src/lib/libc/stdlib/malloc.3 @@ -30,9 +30,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $OpenBSD: malloc.3,v 1.118 2018/11/08 05:58:21 otto Exp $ +.\" $OpenBSD: malloc.3,v 1.119 2018/11/18 16:15:18 otto Exp $ .\" -.Dd $Mdocdate: November 8 2018 $ +.Dd $Mdocdate: November 18 2018 $ .Dt MALLOC 3 .Os .Sh NAME @@ -43,7 +43,8 @@ .Nm reallocarray , .Nm recallocarray , .Nm freezero , -.Nm aligned_alloc +.Nm aligned_alloc , +.Nm malloc_usable_size .Nd memory allocation and deallocation .Sh SYNOPSIS .In stdlib.h @@ -63,6 +64,8 @@ .Fn freezero "void *ptr" "size_t size" .Ft void * .Fn aligned_alloc "size_t alignment" "size_t size" +.Ft size_t +.Fn malloc_usable_size "void *ptr" .Vt char *malloc_options ; .Sh DESCRIPTION The standard functions @@ -191,7 +194,7 @@ must be a value such that .Fa size is the size of the earlier allocation that returned .Fa ptr , -otherwise the behaviour is undefined. +otherwise the behavior is undefined. .Pp The .Fn freezero @@ -233,6 +236,25 @@ If is not a multiple of .Fa alignment , behavior is undefined. +.Pp +The +.Fn malloc_usable_size +function returns the actual size of the allocated memory pointed to by +.Va ptr . +If +.Va ptr +is +.Dv NULL , +it returns 0. +If +.Va ptr +was never returned by an allocation function or freed before, +the behavior is undefined. +This function should not be relied upon since it exposes some of the internal +workings of the +.Fn malloc +family of functions. +Writing beyond the requested size introduces undefined behavior. .Sh RETURN VALUES Upon successful completion, the allocation functions return a pointer to the allocated space; otherwise, @@ -618,7 +640,9 @@ function appeared in .Ox 6.2 . The .Fn aligned_alloc -function appeared in +and +.Fn malloc_usable_size +functions appeared in .Ox 6.5 . .Sh CAVEATS When using diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index af9cf391..ee4d4c05 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.c,v 1.251 2018/11/06 08:01:43 otto Exp $ */ +/* $OpenBSD: malloc.c,v 1.252 2018/11/18 16:15:18 otto Exp $ */ /* * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek * Copyright (c) 2012 Matthew Dempsky @@ -1466,6 +1466,84 @@ freezero(void *ptr, size_t sz) } DEF_WEAK(freezero); +static size_t +osize(struct dir_info *argpool, void *p) +{ + struct dir_info *pool; + struct region_info *r; + char *saved_function; + size_t sz; + int i; + + pool = argpool; + r = find(pool, p); + if (r == NULL) { + if (mopts.malloc_mt) { + for (i = 0; i < _MALLOC_MUTEXES; i++) { + if (i == argpool->mutex) + continue; + pool->active--; + _MALLOC_UNLOCK(pool->mutex); + pool = mopts.malloc_pool[i]; + _MALLOC_LOCK(pool->mutex); + pool->active++; + r = find(pool, p); + if (r != NULL) { + saved_function = pool->func; + pool->func = argpool->func; + break; + } + } + } + if (r == NULL) + wrterror(argpool, "bogus pointer (double free?) %p", p); + } + + REALSIZE(sz, r); + if (sz > MALLOC_MAXCHUNK) { + if (MALLOC_MOVE_COND(sz)) + sz = MALLOC_PAGESIZE - ((char *)p - (char *)r->p); + else + sz = PAGEROUND(sz); + } + if (argpool != pool) { + pool->active--; + pool->func = saved_function; + _MALLOC_UNLOCK(pool->mutex); + _MALLOC_LOCK(argpool->mutex); + argpool->active++; + } + return sz; +} + +size_t +malloc_usable_size(void *ptr) +{ + struct dir_info *d; + int saved_errno = errno; + size_t sz; + + /* This is legal. */ + if (ptr == NULL) + return 0; + + d = getpool(); + if (d == NULL) + wrterror(d, "malloc_usable_size() called before allocation"); + _MALLOC_LOCK(d->mutex); + d->func = "malloc_usable_size"; + if (d->active++) { + malloc_recurse(d); + return 0; + } + sz = osize(d, ptr); + d->active--; + _MALLOC_UNLOCK(d->mutex); + errno = saved_errno; + return sz; +} +DEF_WEAK(malloc_usable_size); + static void * orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) {