[libcxx-commits] [libcxx] 4006059 - [libc++] Fix std::pmr::new_delete_resource() returning underaligned pointers (#219166)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Sep 3 02:35:14 PDT 2026
Author: Nikolas Klauser
Date: 2026-09-03T11:35:08+02:00
New Revision: 4006059d2d07add782dbe8575afacb075601749a
URL: https://github.com/llvm/llvm-project/commit/4006059d2d07add782dbe8575afacb075601749a
DIFF: https://github.com/llvm/llvm-project/commit/4006059d2d07add782dbe8575afacb075601749a.diff
LOG: [libc++] Fix std::pmr::new_delete_resource() returning underaligned pointers (#219166)
We're currently using `__libcpp_allocate` inside
`std::pmr::new_delete_resource`. `__libcpp_allocate` calls `operator
new` without an alignment argument if the alignment is small enough.
This, however, violates the requirement that `new_delete_resource` needs
to return a pointer with an alignment greater or equal to the alignment
argument, since `operator new` without an alignment argument only has to
return "suitably aligned storage", which basically assumes that `size >=
alignment`. To fix that we can simply call the aligned operator new
unconditionally.
Added:
libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp
Modified:
libcxx/src/memory_resource.cpp
libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/src/memory_resource.cpp b/libcxx/src/memory_resource.cpp
index c58e4a3790b25..7e57be5d064bc 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, bytes, align_val_t(align));
+#else
+ ::operator delete(p, bytes);
+#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..8c77fb8c9e653
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/mem.res/mem.res.global/new_delete_resource.align.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// UNSUPPORTED: sanitizer-new-delete
+
+// XFAIL: using-built-library-before-llvm-24
+
+// <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) {
+ assert(!allocated);
+
+ 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;
+
+ assert(false && "Unexpected allocation size");
+ return buffer;
+}
+
+void operator delete(void*) noexcept { allocated = false; }
+
+void* operator new(std::size_t size, std::align_val_t align) {
+ assert(static_cast<size_t>(align) <= 128);
+ 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..96fcbaf47540b 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
@@ -10,6 +10,8 @@
// TODO: Change to XFAIL once https://llvm.org/PR40995 is fixed
// UNSUPPORTED: availability-pmr-missing
+// XFAIL: using-built-library-before-llvm-24
+
// <memory_resource>
// class monotonic_buffer_resource
@@ -42,7 +44,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