Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARM64 crash when using static block allocator with small types #171

Open
kevin-- opened this issue Nov 13, 2023 · 2 comments
Open

ARM64 crash when using static block allocator with small types #171

kevin-- opened this issue Nov 13, 2023 · 2 comments

Comments

@kevin--
Copy link

kevin-- commented Nov 13, 2023

Crash when deallocating shared_ptr building for arm64 -- Xcode Apple clang version 14.0.3 (clang-1403.0.22.14.1)

Has been happening for a couple major Xcode versions so far.

Example program

using StaticMemoryPoolAllocator =
    foonathan::memory::memory_pool<foonathan::memory::node_pool, foonathan::memory::static_block_allocator>

size_t Capacity = 20;
using TestType = int;
using NodeSize = shared_ptr_stateful_node_size<TestType>;

constexpr size_t storage_size_bytes = StaticMemoryPoolAllocator::min_block_size( NodeSize::value, Capacity );

// setup storage & pool
foonathan::memory::static_allocator_storage<storage_size_bytes> storage;
StaticMemoryPoolAllocator pool( NodeSize::value, storage_size_bytes, storage );

// test case

std::list<std::shared_ptr<TestType>> retain;
for ( size_t i = 0; i < capacity; ++i ) {
    retain.push_back( foonathan::memory::allocate_shared<TestType>( pool ) );
}
retain.clear(); // < crash here

In fact, resetting the shared_ptr of the 2nd created item can cause a crash.

In my experimenting, the only thing that alleviated the crash was to use TestType with a sizeof 8 or higher.

@foonathan
Copy link
Owner

I don't have access to XCode, can you please give me the following information:

  1. shared_ptr_stateful_node_size<TestType>::value
  2. How many bytes are allocated by memory::allocate_shared<TestType>(pool) (you can find it out by setting a breakpoint in std_allocator::allocate, the value is n * sizeof(T) of whatever allocator instantiation was being used.
  3. If there is a mismatch between 1 and 2, the output of nodesize_dbg --verbose

Thank you.

@kevin--
Copy link
Author

kevin-- commented Apr 22, 2024

Sorry for the long delay, here is the info

using TestType = int;

  1. sizeof(int) = 4, alignof(int) = 4
  2. shared_ptr_stateful_node_size<int>::value = 44
  3. memory::allocate_shared<TestType>(pool) -> std_allocator::allocate = n = 1
    • std::allocator::allocate_impl:
          void* allocate_impl(std::false_type, size_type n)
          {
              if (n == 1)
                  return this->allocate_node(sizeof(T), alignof(T));
              else
                  return this->allocate_array(n, sizeof(T), alignof(T));
          }
      
      taking the n == 1 branch here, sizeof(T) = 40, alignof(T) = 8.
    • so I think therefore it is allocating 48, but the determined size is 44 from (1) above
  4. see attached nodesize_dbg_verbose.txt

It seems the discrepancy in (1) is that detail::shared_ptr_stateful_node_size<alignof(T)>::value + sizeof(T) here we take the alignof(int)
BUT in (2) the allocator impl is taking the alignof(shared_ptr_stateful_node_size<int>)

The type of the std_allocator is

foonathan::memory::std_allocator<
    std::__shared_ptr_emplace<
        int,
        foonathan::memory::std_allocator<
            int,
            rt::StaticMemoryPool<
                20,
                shared_ptr_stateful_node_size<int>,
                rt::container_overhead::None
            >
        >
    >,
    rt::StaticMemoryPool<
        20,
        shared_ptr_stateful_node_size<int>,
        rt::container_overhead::None
    >
> 

The rt::StaticMemoryPool is my implementation of an allocator-- the 1st argument is the capacity, the 2nd template argument is used to determine the size of the nodes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants