[glibc/arm/malloc-mte-v1] malloc: aarch64: Add MTE ifunc resolvers
Yury Khrustalev via Glibc-cvs <[email protected]> Thu, 7 May 2026 12:45:39 +0000 (GMT)
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=43bd158d8978e7cf6c2a9918a30f24958d738444 commit 43bd158d8978e7cf6c2a9918a30f24958d738444 Author: Yury Khrustalev <[email protected]> Date: Tue Apr 28 16:31:37 2026 +0100 malloc: aarch64: Add MTE ifunc resolvers We introduce the ARCH_INIT_MALLOC() macro that is defined in the sysdep headers to allow doing target-specific initialisation in __ptmalloc_init. On AArch64 we use this macro to modify global variables in malloc.c when MTE is enabled based on the runtime value calculated from the glibc.mem.aarch64_mte tunable. We create AArch64-specific version of the 'malloc-size.h' header to provide custom 'memsize()' and 'checked_request2size()'. This is required to support MTE memory tagging without the need to check its status every time. We modify ifunc resolvers for AArch64 to return MTE-aware versions if malloc functions when MTE is enabled. At this point these *_mte functions don't actually do any memory tagging. This will be done in a subsequent commit. Finally, we add the glibc.mem.aarch64_mte tunable to all malloc tests on AArch64. On systems without MTE this will have no effect but on systems with MTE it will make sure that tests are executed with memory tagging enabled in sync mode. Diff: --- malloc/arena.c | 5 +++ sysdeps/aarch64/Makefile | 1 + sysdeps/aarch64/malloc-ifuncs.c | 21 ++++++++++ sysdeps/aarch64/malloc-init.h | 29 +++++++++++++ sysdeps/aarch64/malloc-mte.c | 70 +++++++++++++++++++++++++++++++ sysdeps/aarch64/malloc-mte.h | 42 +++++++++++++++++++ sysdeps/aarch64/malloc-size.h | 71 ++++++++++++++++++++++++++++++++ sysdeps/generic/malloc-init.h | 24 +++++++++++ sysdeps/unix/sysv/linux/aarch64/Makefile | 19 +++++++++ 9 files changed, 282 insertions(+) diff --git a/malloc/arena.c b/malloc/arena.c index 023cb3ba06..49dea9e17d 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -22,6 +22,8 @@ #define TUNABLE_NAMESPACE malloc #include <elf/dl-tunables.h> +#include <malloc-init.h> + /* Compile-time constants. */ #define HEAP_MIN_SIZE (32 * 1024) @@ -288,6 +290,9 @@ __ptmalloc_init (void) do_set_mmap_threshold (mp_.hp_pagesize); __always_fail_morecore = true; } + + /* Perform any target-specific initialisation. */ + ARCH_INIT_MALLOC (); } /* Managing heaps and arenas (for concurrent threads) */ diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile index 8fcd8526ac..733bf2adec 100644 --- a/sysdeps/aarch64/Makefile +++ b/sysdeps/aarch64/Makefile @@ -105,6 +105,7 @@ endif ifeq ($(subdir),malloc) sysdep_routines += \ malloc-ifuncs \ + malloc-mte \ # sysdep_routines endif # malloc directory diff --git a/sysdeps/aarch64/malloc-ifuncs.c b/sysdeps/aarch64/malloc-ifuncs.c index 128ebe10d9..f58683525a 100644 --- a/sysdeps/aarch64/malloc-ifuncs.c +++ b/sysdeps/aarch64/malloc-ifuncs.c @@ -20,12 +20,19 @@ #include <malloc/malloc-internal.h> #include <malloc-ifuncs.h> +#include <ldsodefs.h> + +#include "malloc-mte.h" + +#define MTE_ENABLED (GL (dl_aarch64_mte) != MTE_TUNABLE_NONE) /* AArch64-specific resolvers for malloc ifuncs. */ IFUNC_PROTO (__libc_malloc); IFUNC_RESOLVER (__libc_malloc, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_malloc_mte; return __libc_malloc_core; } strong_alias (__libc_malloc, malloc) @@ -33,6 +40,8 @@ strong_alias (__libc_malloc, malloc) IFUNC_PROTO (__libc_calloc); IFUNC_RESOLVER (__libc_calloc, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_calloc_mte; return __libc_calloc_core; } weak_alias (__libc_calloc, calloc) @@ -40,6 +49,8 @@ weak_alias (__libc_calloc, calloc) IFUNC_PROTO (__libc_memalign); IFUNC_RESOLVER (__libc_memalign, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_memalign_mte; return __libc_memalign_core; } weak_alias (__libc_memalign, memalign) @@ -47,6 +58,8 @@ weak_alias (__libc_memalign, memalign) IFUNC_PROTO (__libc_valloc); IFUNC_RESOLVER (__libc_valloc, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_valloc_mte; return __libc_valloc_core; } weak_alias (__libc_valloc, valloc) @@ -54,6 +67,8 @@ weak_alias (__libc_valloc, valloc) IFUNC_PROTO (__libc_pvalloc); IFUNC_RESOLVER (__libc_pvalloc, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_pvalloc_mte; return __libc_pvalloc_core; } weak_alias (__libc_pvalloc, pvalloc) @@ -61,6 +76,8 @@ weak_alias (__libc_pvalloc, pvalloc) IFUNC_PROTO (__libc_realloc); IFUNC_RESOLVER (__libc_realloc, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_realloc_mte; return __libc_realloc_core; } strong_alias (__libc_realloc, realloc) @@ -68,6 +85,8 @@ strong_alias (__libc_realloc, realloc) IFUNC_PROTO (__libc_free); IFUNC_RESOLVER (__libc_free, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __libc_free_mte; return __libc_free_core; } # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_26) @@ -78,6 +97,8 @@ strong_alias (__libc_free, free) IFUNC_PROTO (__malloc_usable_size); IFUNC_RESOLVER (__malloc_usable_size, uint64_t arg0, uint64_t arg1[]) { + if (MTE_ENABLED) + return __malloc_usable_size_mte; return __malloc_usable_size_core; } weak_alias (__malloc_usable_size, malloc_usable_size) diff --git a/sysdeps/aarch64/malloc-init.h b/sysdeps/aarch64/malloc-init.h new file mode 100644 index 0000000000..39fc89e668 --- /dev/null +++ b/sysdeps/aarch64/malloc-init.h @@ -0,0 +1,29 @@ +/* Definitions for malloc init: aarch64 version. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _AARCH64_MALLOC_INIT_H +#define _AARCH64_MALLOC_INIT_H + +#define ARCH_INIT_MALLOC() \ + if (GL (dl_aarch64_mte) != MTE_TUNABLE_NONE) \ + { \ + extra_mmap_prot |= PROT_MTE; \ + __always_fail_morecore = true; \ + } + +#endif /* _AARCH64_MALLOC_INIT_H */ diff --git a/sysdeps/aarch64/malloc-mte.c b/sysdeps/aarch64/malloc-mte.c new file mode 100644 index 0000000000..a98533c321 --- /dev/null +++ b/sysdeps/aarch64/malloc-mte.c @@ -0,0 +1,70 @@ +/* Implementation for MTE (memory tagging) in malloc. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include "malloc-mte.h" +#include "aarch64-mte.h" + +#include <malloc-ifuncs.h> + +void *__libc_malloc_mte (size_t bytes) +{ + return __libc_malloc_core (bytes); +} +libc_hidden_def (__libc_malloc_mte) + +void *__libc_calloc_mte (size_t n, size_t elem_size) +{ + return __libc_calloc_core (n, elem_size); +} +libc_hidden_def (__libc_calloc_mte) + +void *__libc_memalign_mte (size_t alignment, size_t bytes) +{ + return __libc_memalign_core (alignment, bytes); +} +libc_hidden_def (__libc_memalign_mte) + +void *__libc_valloc_mte (size_t bytes) +{ + return __libc_valloc_core (bytes); +} +libc_hidden_def (__libc_valloc_mte) + +void *__libc_pvalloc_mte (size_t bytes) +{ + return __libc_pvalloc_core (bytes); +} +libc_hidden_def (__libc_pvalloc_mte) + +void *__libc_realloc_mte (void *oldmem, size_t bytes) +{ + return __libc_realloc_core (oldmem, bytes); +} +libc_hidden_def (__libc_realloc_mte) + +void __libc_free_mte (void *mem) +{ + __libc_free_core (mem); +} +libc_hidden_def (__libc_free_mte) + +size_t __malloc_usable_size_mte (void *m) +{ + return __malloc_usable_size_core (m); +} +libc_hidden_def (__malloc_usable_size_mte) diff --git a/sysdeps/aarch64/malloc-mte.h b/sysdeps/aarch64/malloc-mte.h new file mode 100644 index 0000000000..b37ec6069d --- /dev/null +++ b/sysdeps/aarch64/malloc-mte.h @@ -0,0 +1,42 @@ +/* Definitions and macros for MTE (memory tagging) in malloc. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _AARCH64_MALLOC_MTE_H +#define _AARCH64_MALLOC_MTE_H + +#include <stddef.h> +#include <sys/cdefs.h> + +void *__libc_malloc_mte (size_t); +libc_hidden_proto (__libc_malloc_mte) +void *__libc_calloc_mte (size_t, size_t); +libc_hidden_proto (__libc_calloc_mte) +void *__libc_memalign_mte (size_t, size_t); +libc_hidden_proto (__libc_memalign_mte) +void *__libc_valloc_mte (size_t); +libc_hidden_proto (__libc_valloc_mte) +void *__libc_pvalloc_mte (size_t); +libc_hidden_proto (__libc_pvalloc_mte) +void *__libc_realloc_mte (void *, size_t); +libc_hidden_proto (__libc_realloc_mte) +void __libc_free_mte (void *); +libc_hidden_proto (__libc_free_mte) +size_t __malloc_usable_size_mte (void *); +libc_hidden_proto (__malloc_usable_size_mte) + +#endif /* _AARCH64_MALLOC_MTE_H */ diff --git a/sysdeps/aarch64/malloc-size.h b/sysdeps/aarch64/malloc-size.h new file mode 100644 index 0000000000..04af687331 --- /dev/null +++ b/sysdeps/aarch64/malloc-size.h @@ -0,0 +1,71 @@ +/* Size-related definitions for malloc: aarch64 version. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _AARCH64_MALLOC_SIZE_H +#define _AARCH64_MALLOC_SIZE_H + +#include <malloc-chunk.h> +#include <stdint.h> +#include <sys/cdefs.h> + +/* The smallest size we can malloc is an aligned minimal chunk. */ +#define MINSIZE \ + (unsigned long)(((MIN_CHUNK_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) + +/* Pad request bytes into a usable size -- internal version. Note: This must + be a macro that evaluates to a compile time constant if passed a literal + constant. */ +#define request2size(req) \ + (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ + MINSIZE : \ + ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* MTE uses 16-byte granules. */ +#define MTE_GRANULE_SIZE 16 + +/* Memory tagging is not supported with small granule. */ +verify (MTE_GRANULE_SIZE > SIZE_SZ); + +/* Memory tagging is not supported with large granule. */ +verify (MTE_GRANULE_SIZE <= CHUNK_HDR_SZ); + +/* Check if REQ overflows when padded and aligned and if the resulting + value is less than PTRDIFF_T. Returns the requested size or + MINSIZE in case the value is less than MINSIZE, or SIZE_MAX if any + of the previous checks fail. */ +static __always_inline __attribute_maybe_unused__ size_t +checked_request2size (size_t req) __nonnull (1) +{ + if (__glibc_unlikely (req > PTRDIFF_MAX)) + return SIZE_MAX; + req = (req + (MTE_GRANULE_SIZE - 1)) + & ~(size_t) (MTE_GRANULE_SIZE - 1); + return request2size (req); +} + +/* Like chunksize, but do not mask SIZE_BITS. */ +#define chunksize_nomask(p) ((p)->mchunk_size) + +/* Get size, ignoring use bits. */ +#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS)) + +/* This is the size of the real usable data in the chunk. Not valid for + dumped heap chunks. */ +#define memsize(p) (chunksize (p) - CHUNK_HDR_SZ) + +#endif /* _AARCH64_MALLOC_SIZE_H */ diff --git a/sysdeps/generic/malloc-init.h b/sysdeps/generic/malloc-init.h new file mode 100644 index 0000000000..2d6b6f8cbe --- /dev/null +++ b/sysdeps/generic/malloc-init.h @@ -0,0 +1,24 @@ +/* Definition for malloc init: generic version. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#ifndef _GENERIC_MALLOC_INIT_H +#define _GENERIC_MALLOC_INIT_H + +#define ARCH_INIT_MALLOC() + +#endif /* _GENERIC_MALLOC_INIT_H */ diff --git a/sysdeps/unix/sysv/linux/aarch64/Makefile b/sysdeps/unix/sysv/linux/aarch64/Makefile index 7e17e7741f..213893214d 100644 --- a/sysdeps/unix/sysv/linux/aarch64/Makefile +++ b/sysdeps/unix/sysv/linux/aarch64/Makefile @@ -371,6 +371,25 @@ ifeq ($(subdir),stdlib) gen-as-const-headers += ucontext_i.sym endif +ifeq ($(subdir),malloc) +# Add MTE tunable to all malloc tests except malloc-check and mcheck variants +tests-malloc-memtag = \ + $(tests) \ + $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \ + $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) \ + $(tests-malloc-largetcache:%=%-malloc-largetcache) \ + # tests-malloc-memtag + +tests-exclude-malloc-check += $(tests-for-mte) +tests-exclude-mcheck += $(tests-for-mte) + +define tests-malloc-memtag-ENVS +$(1)-TUNABLES += glibc.mem.aarch64_mte=sync +endef + +$(foreach t,$(tests-malloc-memtag),$(eval $(call tests-malloc-memtag-ENVS,$(t)))) +endif # ifeq ($(subdir),malloc) + abi-variants := lp64 abi-variants += lp64_be