[PATCH] slab: align ZERO_SIZE_PTR to ARCH_KMALLOC_MINALIGN

Karl Mehltretter <[email protected]>
Newsgroups dev.linux.lists.llvm,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <[email protected]>
The kmalloc entry points are annotated with __assume_kmalloc_alignment
but return ZERO_SIZE_PTR, currently (void *)16, for zero-size requests.
This violates the annotation when ARCH_KMALLOC_MINALIGN exceeds 16.

This can mislead compiler optimizations. Current compilers retain the
ZERO_OR_NULL_PTR() range check, but GCC and Clang eliminate an exact
ZERO_SIZE_PTR comparison after an annotated allocation. Clang's UBSAN
also reports the failed alignment assumption on armv5.

Set ZERO_SIZE_PTR to ARCH_KMALLOC_MINALIGN when it exceeds 16 and keep
the existing value otherwise. Assert that the alignment does not exceed
128, which keeps the sentinel below PAGE_SIZE and the low pointer
poison values. Deriving the value from the architecture also avoids
changing architectures such as s390, where low absolute addresses are
valid.

Fixes: 94a58c360a45 ("slab.h: sprinkle __assume_aligned attributes")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Karl Mehltretter <[email protected]>
---

Notes:
    This version is based on the RFC discussion [1].
    
    [1] https://lore.kernel.org/r/[email protected]
    
    A tree-wide audit found no users depending on the numeric value of
    ZERO_SIZE_PTR.
    
    The static assertion follows the ARCH_KMALLOC_MINALIGN fallback, the
    first point where the macro is guaranteed to be defined.
    
    Tested on bcc44b6785f21:
    
      - armv5, armv7, mips64, ppc44x and sh4 with minimum alignments from
        32 to 128
      - x86_64, arm64, riscv64, s390x and m68k as unchanged controls
      - Clang 21 with CONFIG_UBSAN_ALIGNMENT on armv5 no longer shows the
        alignment assumption report
      - no text, data or bss size change on armv5 or arm64
      - the exact ZERO_SIZE_PTR comparison remains in armv5 code
        generation
    
    The sh4 test needed two unrelated workarounds, both reproduced on the
    unpatched tree: compiling tcp_output.c at -O1 because of a GCC 15.2
    hang, and disabling USB_OHCI_HCD because of an sm501-usb boot failure.

 include/linux/slab.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/include/linux/slab.h b/include/linux/slab.h
index 32c9f8ed7ae20..0798a714da87f 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -259,13 +259,16 @@ enum _slab_flag_bits {
 
 /*
  * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
+ * It satisfies the alignment promised by __assume_kmalloc_alignment
+ * and keeps the historic value 16 where that is already aligned.
  *
  * Dereferencing ZERO_SIZE_PTR will lead to a distinct access fault.
  *
  * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can.
  * Both make kfree a no-op.
  */
-#define ZERO_SIZE_PTR ((void *)16)
+#define ZERO_SIZE_PTR ((void *)(ARCH_KMALLOC_MINALIGN > 16 ? \
+				ARCH_KMALLOC_MINALIGN : 16))
 
 #define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
 				(unsigned long)ZERO_SIZE_PTR)
@@ -622,6 +625,12 @@ static inline bool kmem_dump_obj(void *object) { return false; }
 #define KMALLOC_SHIFT_LOW ilog2(KMALLOC_MIN_SIZE)
 #endif
 
+/*
+ * Keep ZERO_SIZE_PTR below PAGE_SIZE and the low pointer poison values.
+ * 128 is the largest in-tree ARCH_KMALLOC_MINALIGN.
+ */
+static_assert(ARCH_KMALLOC_MINALIGN <= 128);
+
 /*
  * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
  * Intended for arches that get misalignment faults even for 64 bit integer
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.