[llvm] [Allocator] Don't overestimate alignment for operator new (PR #223300)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 13 21:22:14 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/223300

On many platforms with alignof(max_align_t)=16, when sizeof(T) == 24,
`std::min(llvm::bit_ceil(Size), alignof(std::max_align_t)) = min(32, 16)
= 16`. The placement new overestimates the alignment to 16 instead.


>From 0210d43ff95e8eaac1c4f4842dda0a51076f4cee Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 13 Sep 2026 21:02:12 -0700
Subject: [PATCH] [Allocator] Don't overestimate alignment for operator new

On many platforms with alignof(max_align_t)=16, when sizeof(T) == 24,
`std::min(llvm::bit_ceil(Size), alignof(std::max_align_t)) = min(32, 16)
= 16`. The placement new overestimates the alignment to 16 instead.
---
 llvm/include/llvm/Support/Allocator.h    |  6 ++++--
 llvm/unittests/Support/AllocatorTest.cpp | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index bb0ca118e20157..79e2040fcd3817 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -475,8 +475,10 @@ void *
 operator new(size_t Size,
              llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold,
                                         GrowthDelay, MinAlign> &Allocator) {
-  return Allocator.Allocate(
-      Size, std::min(llvm::bit_ceil(Size), alignof(std::max_align_t)));
+  // alignof(T) is unknown but Size%alignof(T)==0, so the lowest set bit of Size
+  // bounds it (capped at alignof(max_align_t)).
+  auto S = Size | alignof(std::max_align_t);
+  return Allocator.Allocate(Size, llvm::Align(S & -S));
 }
 
 template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
diff --git a/llvm/unittests/Support/AllocatorTest.cpp b/llvm/unittests/Support/AllocatorTest.cpp
index 744967de9004e8..eb0b2697d63418 100644
--- a/llvm/unittests/Support/AllocatorTest.cpp
+++ b/llvm/unittests/Support/AllocatorTest.cpp
@@ -99,6 +99,23 @@ TEST(AllocatorTest, TestAlignment) {
   EXPECT_EQ(0U, a & 127);
 }
 
+TEST(AllocatorTest, TestPlacementNew) {
+  struct S24 { uint64_t X[3]; };
+  struct alignas(16) S32 { uint64_t X[4]; };
+  struct S48 { uint64_t X[6]; };
+  BumpPtrAllocator Alloc;
+  Alloc.setRedZoneSize(0);
+  auto *A0 = new (Alloc) S24;
+  auto *A1 = new (Alloc) S24;
+  EXPECT_EQ(uintptr_t(A0) + sizeof(S24), uintptr_t(A1));
+  auto *B0 = new (Alloc) S32;
+  auto *B1 = new (Alloc) S32;
+  EXPECT_EQ(uintptr_t(B0) + sizeof(S32), uintptr_t(B1));
+  auto *C0 = new (Alloc) S48;
+  auto *C1 = new (Alloc) S48;
+  EXPECT_EQ(uintptr_t(C0) + sizeof(S48), uintptr_t(C1));
+}
+
 // Test zero-sized allocations.
 // In general we don't need to allocate memory for these.
 // However Allocate never returns null, so if the first allocation is zero-sized



More information about the llvm-commits mailing list