[Concept,11/24] malloc: Fix malloc_usable_size() to handle mcheck headers
Commit Message
From: Simon Glass <simon.glass@canonical.com>
When mcheck is enabled, malloc_usable_size() returns incorrect results
because mem2chunk() is called on the offset user pointer rather than the
actual chunk.
The pointer returned to the user is offset by the mcheck header, but
malloc_usable_size() is unaware of this. Add a wrapper that returns the
user-requested size stored in the mcheck header. This fixes test
failures when CONFIG_MCHECK_CALLER_LEN is set to larger values.
Also add a wrapper for the case where MALLOC_DEBUG is enabled without
MCHECK_HEAP_PROTECTION, since MALLOC_DEBUG makes
dlmalloc_usable_size_impl() static but no public dlmalloc_usable_size
exists outside the mcheck block.
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---
common/dlmalloc.c | 39 ++++++++++++++++++++++++++++++++-------
1 file changed, 32 insertions(+), 7 deletions(-)
@@ -648,6 +648,7 @@ static inline void MALLOC_COPY(void *dest, const void *src, size_t sz) { memcpy(
#define dlrealloc_impl dlrealloc
#define dlmemalign_impl dlmemalign
#define dlcalloc_impl dlcalloc
+#define dlmalloc_usable_size_impl dlmalloc_usable_size
#endif
static bool malloc_testing; /* enable test mode */
@@ -5943,13 +5944,15 @@ int dlmallopt(int param_number, int value) {
return change_mparam(param_number, value);
}
-size_t dlmalloc_usable_size(const void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk((void*)mem);
- if (is_inuse(p))
- return chunksize(p) - overhead_for(p);
- }
- return 0;
+STATIC_IF_MCHECK size_t dlmalloc_usable_size_impl(const void *mem)
+{
+ if (mem != 0) {
+ mchunkptr p = mem2chunk((void *)mem);
+
+ if (is_inuse(p))
+ return chunksize(p) - overhead_for(p);
+ }
+ return 0;
}
#if CONFIG_IS_ENABLED(MCHECK_HEAP_PROTECTION)
@@ -6098,6 +6101,20 @@ void *dlcalloc(size_t n, size_t elem_size)
return mcheck_alloc_noclean_posthook(p, n * elem_size, mcheck_caller());
}
+size_t dlmalloc_usable_size(const void *mem)
+{
+ if (!mem)
+ return 0;
+
+ if (mcheck_disabled)
+ return dlmalloc_usable_size_impl(mem);
+
+ /* Return the user-requested size from mcheck header */
+ const struct mcheck_hdr *hdr = &((const struct mcheck_hdr *)mem)[-1];
+
+ return hdr->size;
+}
+
/* mcheck API */
int mcheck_pedantic(mcheck_abortfunc_t f)
{
@@ -6145,6 +6162,14 @@ void *dlcalloc(size_t n, size_t elem_size)
}
#endif /* MCHECK_HEAP_PROTECTION */
+#if CONFIG_IS_ENABLED(MALLOC_DEBUG) && !CONFIG_IS_ENABLED(MCHECK_HEAP_PROTECTION)
+/* Wrapper needed when MALLOC_DEBUG makes dlmalloc_usable_size_impl static */
+size_t dlmalloc_usable_size(const void *mem)
+{
+ return dlmalloc_usable_size_impl(mem);
+}
+#endif
+
#if !CONFIG_IS_ENABLED(MCHECK_HEAP_PROTECTION)
/* Stub when mcheck is not enabled */
void mcheck_set_disabled(bool disabled)