.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $OpenBSD: malloc.3,v 1.135 2023/06/23 05:26:45 otto Exp $
+.\" $OpenBSD: malloc.3,v 1.136 2023/06/30 06:24:58 otto Exp $
.\"
-.Dd $Mdocdate: June 23 2023 $
+.Dd $Mdocdate: June 30 2023 $
.Dt MALLOC 3
.Os
.Sh NAME
To view the leak report:
.Pp
.Dl $ kdump -u malloc ...
+.Pp
+By default, the immediate caller of a
+.Nm
+function will be recorded.
+Use malloc options
+.Cm 2
+or
+.Cm 3
+to record the caller one or two stack frames deeper instead.
+These malloc options imply
+.Cm D .
.It Cm F
.Dq Freecheck .
Enable more extensive double free and use after free detection.
.Fn realloc
to avoid these problems on
.Ox .
+.Pp
+The mechanism to record caller functions when using malloc options
+.Cm 2
+or
+.Cm 3
+is not guaranteed to work for all platforms, compilers or compilation
+options,
+and might even crash your program.
+Use
+.Em only
+for debugging purposes.
-/* $OpenBSD: malloc.c,v 1.288 2023/06/23 05:26:45 otto Exp $ */
+/* $OpenBSD: malloc.c,v 1.289 2023/06/30 06:24:58 otto Exp $ */
/*
* Copyright (c) 2008, 2010, 2011, 2016, 2023 Otto Moerbeek <otto@drijf.net>
* Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org>
PROTO_NORMAL(malloc_dump);
static void malloc_exit(void);
#endif
-#define CALLER (DO_STATS ? __builtin_return_address(0) : NULL)
+
+#if defined(__aarch64__) || \
+ defined(__amd64__) || \
+ defined(__arm__)
+static inline void* caller(void)
+{
+ void *p;
+
+ switch (DO_STATS) {
+ case 0:
+ default:
+ return NULL;
+ case 1:
+ p = __builtin_return_address(0);
+ break;
+ case 2:
+ p = __builtin_return_address(1);
+ break;
+ case 3:
+ p = __builtin_return_address(2);
+ break;
+ }
+ return __builtin_extract_return_addr(p);
+}
+#else
+static inline void* caller(void)
+{
+ return DO_STATS == 0 ? NULL :
+ __builtin_extract_return_addr(__builtin_return_address(0));
+}
+#endif
/* low bits of r->p determine size: 0 means >= page size and r->size holding
* real size, otherwise low bits is the bucket + 1
mopts.malloc_stats = 0;
break;
case 'D':
+ case '1':
mopts.malloc_stats = 1;
break;
+ case '2':
+ mopts.malloc_stats = 2;
+ break;
+ case '3':
+ mopts.malloc_stats = 3;
+ break;
#endif /* MALLOC_STATS */
case 'f':
mopts.malloc_freecheck = 0;
int saved_errno = errno;
PROLOGUE(getpool(), "malloc")
- r = omalloc(d, size, 0, CALLER);
+ r = omalloc(d, size, 0, caller());
EPILOGUE()
return r;
}
int saved_errno = errno;
PROLOGUE(mopts.malloc_pool[0], "malloc_conceal")
- r = omalloc(d, size, 0, CALLER);
+ r = omalloc(d, size, 0, caller());
EPILOGUE()
return r;
}
int saved_errno = errno;
PROLOGUE(getpool(), "realloc")
- r = orealloc(&d, ptr, size, CALLER);
+ r = orealloc(&d, ptr, size, caller());
EPILOGUE()
return r;
}
}
size *= nmemb;
- r = omalloc(d, size, 1, CALLER);
+ r = omalloc(d, size, 1, caller());
EPILOGUE()
return r;
}
}
size *= nmemb;
- r = omalloc(d, size, 1, CALLER);
+ r = omalloc(d, size, 1, caller());
EPILOGUE()
return r;
}
oldsize = oldnmemb * size;
}
- r = orecallocarray(&d, ptr, oldsize, newsize, CALLER);
+ r = orecallocarray(&d, ptr, oldsize, newsize, caller());
EPILOGUE()
return r;
}
malloc_recurse(d);
goto err;
}
- r = omemalign(d, alignment, size, 0, CALLER);
+ r = omemalign(d, alignment, size, 0, caller());
d->active--;
_MALLOC_UNLOCK(d->mutex);
if (r == NULL) {
}
PROLOGUE(getpool(), "aligned_alloc")
- r = omemalign(d, alignment, size, 0, CALLER);
+ r = omemalign(d, alignment, size, 0, caller());
EPILOGUE()
return r;
}