return pools;
}
+ static inline size_t
+ choose_block_size(size_t bytes, size_t alignment)
+ {
+ if (bytes == 0) [[unlikely]]
+ return alignment;
+
+ // Use bit_ceil in case alignment is invalid (i.e. not a power of two).
+ size_t mask = std::__bit_ceil(alignment) - 1;
+ // Round up to a multiple of alignment.
+ size_t block_size = (bytes + mask) & ~mask;
+
+ if (block_size >= bytes) [[likely]]
+ return block_size;
+
+ // Wrapped around to zero, bytes must have been impossibly large.
+ return numeric_limits<size_t>::max();
+ }
+
// Override for memory_resource::do_allocate
void*
synchronized_pool_resource::
do_allocate(size_t bytes, size_t alignment)
{
- const auto block_size = std::max(bytes, alignment);
+ const auto block_size = choose_block_size(bytes, alignment);
const pool_options opts = _M_impl._M_opts;
if (block_size <= opts.largest_required_pool_block)
{
synchronized_pool_resource::
do_deallocate(void* p, size_t bytes, size_t alignment)
{
- size_t block_size = std::max(bytes, alignment);
+ size_t block_size = choose_block_size(bytes, alignment);
if (block_size <= _M_impl._M_opts.largest_required_pool_block)
{
const ptrdiff_t index = pool_index(block_size, _M_impl._M_npools);
void*
unsynchronized_pool_resource::do_allocate(size_t bytes, size_t alignment)
{
- const auto block_size = std::max(bytes, alignment);
+ const auto block_size = choose_block_size(bytes, alignment);
if (block_size <= _M_impl._M_opts.largest_required_pool_block)
{
// Recreate pools if release() has been called:
unsynchronized_pool_resource::
do_deallocate(void* p, size_t bytes, size_t alignment)
{
- size_t block_size = std::max(bytes, alignment);
+ size_t block_size = choose_block_size(bytes, alignment);
if (block_size <= _M_impl._M_opts.largest_required_pool_block)
{
if (auto pool = _M_find_pool(block_size))
--- /dev/null
+// { dg-do run { target c++17 } }
+// Bug 118681 - unsynchronized_pool_resource may fail to respect alignment
+
+#include <memory_resource>
+#include <cstdio>
+#include <testsuite_hooks.h>
+
+#ifndef RESOURCE
+# define RESOURCE std::pmr::unsynchronized_pool_resource
+#endif
+
+bool any_misaligned = false;
+
+bool
+is_aligned(void* p, [[maybe_unused]] std::size_t size, std::size_t alignment)
+{
+ const bool misaligned = reinterpret_cast<std::uintptr_t>(p) % alignment;
+#ifdef DEBUG
+ std::printf("allocate(%2zu, %2zu): %p is aligned %scorrectly\n",
+ size, alignment, p, misaligned ? "in" : "");
+ any_misaligned |= misaligned;
+ return true;
+#endif
+ return ! misaligned;
+}
+
+void
+test_alignment(std::pmr::memory_resource& res, bool dealloc)
+{
+ for (std::size_t alignment : { 8, 16, 32, 64 })
+ {
+ for (std::size_t size : { 9, 12, 24, 40, 48, 56, 72 })
+ {
+ void* p1 = res.allocate(size, alignment);
+ void* p2 = res.allocate(size, alignment);
+
+ VERIFY( is_aligned(p1, size, alignment) );
+ VERIFY( is_aligned(p2, size, alignment) );
+
+ if (dealloc)
+ {
+ res.deallocate(p2, size, alignment);
+ res.deallocate(p2, size, alignment);
+ }
+ }
+ }
+}
+
+int main()
+{
+ RESOURCE res;
+ test_alignment(res, true);
+ res.release();
+ test_alignment(res, false);
+ res.release();
+
+ VERIFY( ! any_misaligned );
+}