[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