[libcxx-commits] [libcxx] [libc++] Fix std::pmr::new_delete_resource() returning underaligned pointers (PR #219166)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 27 04:22:25 PDT 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/219166
>From 7848eda2af8e7a1c98121c18dada8e9039ed1c37 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 27 Aug 2026 12:18:05 +0200
Subject: [PATCH] [libc++] Fix std::pmr::new_delete_resource() returning
underaligned pointers
---
libcxx/src/memory_resource.cpp | 14 +++--
.../new_delete_resource.align.pass.cpp | 59 +++++++++++++++++++
.../allocate_overaligned_request.pass.cpp | 2 +-
3 files changed, 69 insertions(+), 6 deletions(-)
create mode 100644 libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp
diff --git a/libcxx/src/memory_resource.cpp b/libcxx/src/memory_resource.cpp
index c58e4a3790b25..4930942e0b12f 100644
--- a/libcxx/src/memory_resource.cpp
+++ b/libcxx/src/memory_resource.cpp
@@ -34,11 +34,11 @@ static bool is_aligned_to(void* ptr, size_t align) {
class _LIBCPP_HIDDEN __new_delete_memory_resource_imp : public memory_resource {
void* do_allocate(size_t bytes, size_t align) override {
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
- return std::__libcpp_allocate<std::byte>(__element_count(bytes), align);
+ return ::operator new(bytes, std::align_val_t(align));
#else
- if (bytes == 0)
- bytes = 1;
- std::byte* result = std::__libcpp_allocate<std::byte>(__element_count(bytes), align);
+ if (bytes < align)
+ bytes = align;
+ std::byte* result = ::operator new(bytes);
if (!is_aligned_to(result, align)) {
std::__libcpp_deallocate<std::byte>(result, __element_count(bytes), align);
std::__throw_bad_alloc();
@@ -48,7 +48,11 @@ class _LIBCPP_HIDDEN __new_delete_memory_resource_imp : public memory_resource {
}
void do_deallocate(void* p, size_t bytes, size_t align) override {
- std::__libcpp_deallocate<std::byte>(static_cast<std::byte*>(p), __element_count(bytes), align);
+#if _LIBCPP_HAS_ALIGNED_ALLOCATION
+ ::operator delete(p, align_val_t(align));
+#else
+ ::operator delete(p);
+#endif
}
bool do_is_equal(const memory_resource& other) const noexcept override { return &other == this; }
diff --git a/libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp
new file mode 100644
index 0000000000000..57a0ee37546de
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// TODO: Change to XFAIL once https://llvm.org/PR40995 is fixed
+// UNSUPPORTED: availability-pmr-missing
+
+// <memory_resource>
+
+// memory_resource *new_delete_resource()
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory_resource>
+#include <new>
+
+alignas(128) char buffer[128];
+bool allocated = false;
+
+void* operator new(std::size_t size) {
+ if (allocated)
+ throw std::bad_alloc();
+
+ allocated = true;
+ if (size <= 4)
+ return buffer + 4;
+ if (size <= 8)
+ return buffer + 8;
+ if (size <= 16)
+ return buffer + 16;
+ if (size <= 128)
+ return buffer + 128;
+ throw std::bad_alloc();
+}
+
+void operator delete(void*) noexcept { allocated = false; }
+
+void* operator new(std::size_t size, std::align_val_t align) {
+ if (static_cast<size_t>(align) > 128)
+ throw std::bad_alloc();
+ return operator new(std::max(size, static_cast<size_t>(align)));
+}
+
+void operator delete(void*, std::align_val_t) noexcept { allocated = false; }
+
+int main(int, char**) {
+ std::pmr::memory_resource* res = std::pmr::new_delete_resource();
+ void* ptr = res->allocate(1, __STDCPP_DEFAULT_NEW_ALIGNMENT__);
+ assert((reinterpret_cast<uintptr_t>(ptr) & (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) == 0);
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_overaligned_request.pass.cpp b/libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
index 95c6b36b71f98..479b0f87215b2 100644
--- a/libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
@@ -42,7 +42,7 @@ int main(int, char**) {
ret = r1.allocate(globalMemCounter.last_new_size, 4);
assert(ret != nullptr);
ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkNewCalledEq(2));
- ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkAlignedNewCalledEq(1));
+ ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkAlignedNewCalledEq(2));
return 0;
}
More information about the libcxx-commits
mailing list