- Modify dlmalloc_allocation_command to use alignment info, this requires modifying the dlmalloc_ext wrapper library.

- Replace all dlmalloc_malloc uses with dlmalloc_allocation_command to support overaligned types in array allocations.
This commit is contained in:
Ion Gaztañaga
2026-01-19 01:06:56 +01:00
parent 1e1741ce63
commit 9201bbf83b
10 changed files with 49 additions and 29 deletions

View File

@@ -14,6 +14,7 @@
#include <boost/container/detail/dlmalloc.hpp> #include <boost/container/detail/dlmalloc.hpp>
#include <boost/container/throw_exception.hpp> #include <boost/container/throw_exception.hpp>
#include <boost/container/detail/type_traits.hpp>
#define BOOST_INTERPROCESS_VECTOR_ALLOC_STATS #define BOOST_INTERPROCESS_VECTOR_ALLOC_STATS
@@ -71,7 +72,7 @@ void allocation_timing_test(std::size_t num_iterations, std::size_t num_elements
if(min > max) if(min > max)
max = min; max = min;
ret = dlmalloc_allocation_command ret = dlmalloc_allocation_command
( m_mode, sizeof(POD) (m_mode, sizeof(POD), dtl::alignment_of<POD>::value
, min, max, &received_size, addr); , min, max, &received_size, addr);
if(!ret.first){ if(!ret.first){
throw_runtime_error("!ret.first)"); throw_runtime_error("!ret.first)");

View File

@@ -169,7 +169,7 @@ class adaptive_pool
return pointer(static_cast<T*>(singleton_t::instance().allocate_node())); return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
} }
else{ else{
return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T))); return static_cast<pointer>(dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value));
} }
} }
@@ -346,7 +346,8 @@ class adaptive_pool
std::size_t r_size; std::size_t r_size;
{ {
void* reuse_ptr_void = reuse_ptr; void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
} }
prefer_in_recvd_out_size = r_size/sizeof(T); prefer_in_recvd_out_size = r_size/sizeof(T);
@@ -470,7 +471,7 @@ class private_adaptive_pool
return pointer(static_cast<T*>(m_pool.allocate_node())); return pointer(static_cast<T*>(m_pool.allocate_node()));
} }
else{ else{
return static_cast<pointer>(dlmalloc_malloc(count*sizeof(T))); return static_cast<pointer>(dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value));
} }
} }
@@ -600,7 +601,8 @@ class private_adaptive_pool
std::size_t r_size; std::size_t r_size;
{ {
void* reuse_ptr_void = reuse_ptr; void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
} }
prefer_in_recvd_out_size = r_size/sizeof(T); prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -184,7 +184,7 @@ class allocator
(void)hint; (void)hint;
if(count > size_type(-1)/(2u*sizeof(T))) if(count > size_type(-1)/(2u*sizeof(T)))
boost::container::throw_bad_alloc(); boost::container::throw_bad_alloc();
void *ret = dlmalloc_malloc(count*sizeof(T)); void *ret = dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value);
if(!ret) if(!ret)
boost::container::throw_bad_alloc(); boost::container::throw_bad_alloc();
return static_cast<pointer>(ret); return static_cast<pointer>(ret);
@@ -359,7 +359,8 @@ class allocator
std::size_t r_size; std::size_t r_size;
{ {
void* reuse_ptr_void = reuse_ptr; void* reuse_ptr_void = reuse_ptr;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0; reuse_ptr = ret.second ? static_cast<T*>(reuse_ptr_void) : 0;
} }
prefer_in_recvd_out_size = r_size/sizeof(T); prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -284,6 +284,7 @@ int boost_cont_malloc_check(void);
boost_cont_command_ret_t boost_cont_allocation_command boost_cont_command_ret_t boost_cont_allocation_command
( allocation_type command ( allocation_type command
, size_t sizeof_object , size_t sizeof_object
, size_t alignof_object
, size_t limit_objects , size_t limit_objects
, size_t preferred_objects , size_t preferred_objects
, size_t *received_objects , size_t *received_objects

View File

@@ -75,6 +75,7 @@ BOOST_CONTAINER_DECL int dlmalloc_malloc_check();
BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command
( allocation_type command ( allocation_type command
, size_t sizeof_object , size_t sizeof_object
, size_t alignof_object
, size_t limit_objects , size_t limit_objects
, size_t preferred_objects , size_t preferred_objects
, size_t *received_objects , size_t *received_objects

View File

@@ -156,7 +156,7 @@ class node_allocator
return pointer(static_cast<T*>(singleton_t::instance().allocate_node())); return pointer(static_cast<T*>(singleton_t::instance().allocate_node()));
} }
else{ else{
void *ret = dlmalloc_malloc(count*sizeof(T)); void *ret = dlmalloc_memalign(count*sizeof(T), dtl::alignment_of<T>::value);
if(BOOST_UNLIKELY(!ret)) if(BOOST_UNLIKELY(!ret))
boost::container::throw_bad_alloc(); boost::container::throw_bad_alloc();
return static_cast<pointer>(ret); return static_cast<pointer>(ret);
@@ -338,7 +338,8 @@ class node_allocator
std::size_t r_size; std::size_t r_size;
{ {
void* reuse_ptr_void = reuse; void* reuse_ptr_void = reuse;
ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); ret = dlmalloc_allocation_command( command, sizeof(T), dtl::alignment_of<T>::value
, l_size, p_size, &r_size, reuse_ptr_void);
reuse = static_cast<T*>(reuse_ptr_void); reuse = static_cast<T*>(reuse_ptr_void);
} }
prefer_in_recvd_out_size = r_size/sizeof(T); prefer_in_recvd_out_size = r_size/sizeof(T);

View File

@@ -79,12 +79,13 @@ BOOST_CONTAINER_DECL int dlmalloc_malloc_check()
BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command BOOST_CONTAINER_DECL boost_cont_command_ret_t dlmalloc_allocation_command
( allocation_type command ( allocation_type command
, size_t sizeof_object , size_t sizeof_object
, size_t alignof_object
, size_t limit_objects , size_t limit_objects
, size_t preferred_objects , size_t preferred_objects
, size_t *received_objects , size_t *received_objects
, void *reuse_ptr , void *reuse_ptr
) )
{ return boost_cont_allocation_command(command, sizeof_object, limit_objects, preferred_objects, received_objects, reuse_ptr); } { return boost_cont_allocation_command(command, sizeof_object, alignof_object, limit_objects, preferred_objects, received_objects, reuse_ptr); }
BOOST_CONTAINER_DECL void *dlmalloc_sync_create() BOOST_CONTAINER_DECL void *dlmalloc_sync_create()
{ return boost_cont_sync_create(); } { return boost_cont_sync_create(); }

View File

@@ -1174,7 +1174,7 @@ void* boost_cont_malloc(size_t bytes)
size_t received_bytes; size_t received_bytes;
ensure_initialization(); ensure_initialization();
return boost_cont_allocation_command return boost_cont_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1, bytes, bytes, &received_bytes, 0).first; (BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, bytes, bytes, &received_bytes, 0).first;
} }
void boost_cont_free(void* mem) void boost_cont_free(void* mem)
@@ -1341,7 +1341,7 @@ void* boost_cont_alloc
{ {
//ensure_initialization provided by boost_cont_allocation_command //ensure_initialization provided by boost_cont_allocation_command
return boost_cont_allocation_command return boost_cont_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1, minbytes, preferred_bytes, received_bytes, 0).first; (BOOST_CONTAINER_ALLOCATE_NEW, 1, 1, minbytes, preferred_bytes, received_bytes, 0).first;
} }
void boost_cont_multidealloc(boost_cont_memchain *pchain) void boost_cont_multidealloc(boost_cont_memchain *pchain)
@@ -1373,7 +1373,7 @@ int boost_cont_malloc_check(void)
boost_cont_command_ret_t boost_cont_allocation_command boost_cont_command_ret_t boost_cont_allocation_command
(allocation_type command, size_t sizeof_object, size_t limit_size (allocation_type command, size_t sizeof_object, size_t alignof_object, size_t limit_size
, size_t preferred_size, size_t *received_size, void *reuse_ptr) , size_t preferred_size, size_t *received_size, void *reuse_ptr)
{ {
boost_cont_command_ret_t ret = { 0, 0 }; boost_cont_command_ret_t ret = { 0, 0 };
@@ -1416,12 +1416,15 @@ boost_cont_command_ret_t boost_cont_allocation_command
} }
if(command & BOOST_CONTAINER_ALLOCATE_NEW){ if(command & BOOST_CONTAINER_ALLOCATE_NEW){
void *addr = mspace_malloc_lockless(ms, preferred_size); disable_lock(ms);
if(!addr) addr = mspace_malloc_lockless(ms, limit_size); void *addr = mspace_memalign(ms, alignof_object, preferred_size);
if(!addr) addr = mspace_memalign(ms, alignof_object, limit_size);
if(addr){ if(addr){
s_allocated_memory += chunksize(mem2chunk(addr)); s_allocated_memory += chunksize(mem2chunk(addr));
*received_size = DL_SIZE_IMPL(addr); *received_size = DL_SIZE_IMPL(addr);
} }
enable_lock(ms);
ret.first = addr; ret.first = addr;
ret.second = 0; ret.second = 0;
if(addr){ if(addr){

View File

@@ -112,12 +112,12 @@ bool test_allocation_shrink()
; ++i){ ; ++i){
std::size_t try_received_size = 0; std::size_t try_received_size = 0;
void* try_result = dlmalloc_allocation_command void* try_result = dlmalloc_allocation_command
( BOOST_CONTAINER_TRY_SHRINK_IN_PLACE, 1, i*2 ( BOOST_CONTAINER_TRY_SHRINK_IN_PLACE, 1, 1, i*2
, i, &try_received_size, (char*)buffers[i]).first; , i, &try_received_size, (char*)buffers[i]).first;
std::size_t received_size = 0; std::size_t received_size = 0;
void* result = dlmalloc_allocation_command void* result = dlmalloc_allocation_command
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, i*2 ( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, 1, i*2
, i, &received_size, (char*)buffers[i]).first; , i, &received_size, (char*)buffers[i]).first;
if(result != try_result) if(result != try_result)
@@ -174,7 +174,7 @@ bool test_allocation_expand()
std::size_t preferred_size = i*2; std::size_t preferred_size = i*2;
preferred_size = min_size > preferred_size ? min_size : preferred_size; preferred_size = min_size > preferred_size ? min_size : preferred_size;
while(dlmalloc_allocation_command while(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, min_size ( BOOST_CONTAINER_EXPAND_FWD, 1, 1, min_size
, preferred_size, &received_size, (char*)buffers[i]).first){ , preferred_size, &received_size, (char*)buffers[i]).first){
//Check received size is bigger than minimum //Check received size is bigger than minimum
if(received_size < min_size){ if(received_size < min_size){
@@ -211,10 +211,10 @@ bool test_allocation_shrink_and_expand()
for(std::size_t i = 0; i != NumIt; ++i){ for(std::size_t i = 0; i != NumIt; ++i){
std::size_t received_size = 0; std::size_t received_size = 0;
void *ptr = dlmalloc_allocation_command void *ptr = dlmalloc_allocation_command
(BOOST_CONTAINER_ALLOCATE_NEW, 1u, i, i*2u, &received_size, 0).first; (BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, i, i*2u, &received_size, 0).first;
if(!ptr){ if(!ptr){
ptr = dlmalloc_allocation_command ptr = dlmalloc_allocation_command
( BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, i*2, &received_size, 0).first; ( BOOST_CONTAINER_ALLOCATE_NEW, 1u, 1u, 1u, i*2, &received_size, 0).first;
if(!ptr) if(!ptr)
break; break;
} }
@@ -230,7 +230,7 @@ bool test_allocation_shrink_and_expand()
bool size_reduced_flag; bool size_reduced_flag;
if(true == (size_reduced_flag = !! if(true == (size_reduced_flag = !!
dlmalloc_allocation_command dlmalloc_allocation_command
( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, received_sizes[i] ( BOOST_CONTAINER_SHRINK_IN_PLACE, 1, 1, received_sizes[i]
, i, &received_size, (char*)buffers[i]).first)){ , i, &received_size, (char*)buffers[i]).first)){
if(received_size > std::size_t(received_sizes[i])){ if(received_size > std::size_t(received_sizes[i])){
return false; return false;
@@ -250,7 +250,7 @@ bool test_allocation_shrink_and_expand()
std::size_t received_size = 0; std::size_t received_size = 0;
std::size_t request_size = received_sizes[i]; std::size_t request_size = received_sizes[i];
if(dlmalloc_allocation_command if(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, request_size ( BOOST_CONTAINER_EXPAND_FWD, 1, 1, request_size
, request_size, &received_size, (char*)buffers[i]).first){ , request_size, &received_size, (char*)buffers[i]).first){
if(received_size != request_size){ if(received_size != request_size){
return false; return false;
@@ -314,7 +314,7 @@ bool test_allocation_deallocation_expand()
preferred_size = min_size > preferred_size ? min_size : preferred_size; preferred_size = min_size > preferred_size ? min_size : preferred_size;
while(dlmalloc_allocation_command while(dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_FWD, 1, min_size ( BOOST_CONTAINER_EXPAND_FWD, 1, 1, min_size
, preferred_size, &received_size, (char*)buffers[i]).first){ , preferred_size, &received_size, (char*)buffers[i]).first){
//Check received size is bigger than minimum //Check received size is bigger than minimum
if(received_size < min_size){ if(received_size < min_size){
@@ -383,7 +383,7 @@ bool test_allocation_with_reuse()
std::size_t min_size = (received_size/sizeof_object + 1u)*sizeof_object; std::size_t min_size = (received_size/sizeof_object + 1u)*sizeof_object;
std::size_t prf_size = (received_size/sizeof_object + (i+1u)*2u)*sizeof_object; std::size_t prf_size = (received_size/sizeof_object + (i+1u)*2u)*sizeof_object;
dlmalloc_command_ret_t ret = dlmalloc_allocation_command dlmalloc_command_ret_t ret = dlmalloc_allocation_command
( BOOST_CONTAINER_EXPAND_BWD, sizeof_object, min_size ( BOOST_CONTAINER_EXPAND_BWD, sizeof_object, 1u, min_size
, prf_size, &received_size, (char*)ptr); , prf_size, &received_size, (char*)ptr);
//If we have memory, this must be a buffer reuse //If we have memory, this must be a buffer reuse
if(!ret.first) if(!ret.first)

View File

@@ -112,10 +112,9 @@ struct GetAllocatorCont
template<class ValueType> template<class ValueType>
struct apply struct apply
{ {
typedef vector< ValueType typedef typename allocator_traits<VoidAllocator>
, typename allocator_traits<VoidAllocator> ::template portable_rebind_alloc<ValueType>::type rebound_allocator_type;
::template portable_rebind_alloc<ValueType>::type typedef vector< ValueType, rebound_allocator_type> type;
> type;
}; };
}; };
@@ -127,6 +126,7 @@ int test_cont_variants()
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont; typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::movable_and_copyable_int>::type MyCopyMoveCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont; typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::copyable_int>::type MyCopyCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::moveconstruct_int>::type MyMoveConstructCont; typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::moveconstruct_int>::type MyMoveConstructCont;
typedef typename GetAllocatorCont<VoidAllocator>::template apply<test::overaligned_copyable_int>::type MyOverAlignCont;
if (test::vector_test<MyCont>()) if (test::vector_test<MyCont>())
return 1; return 1;
@@ -138,7 +138,11 @@ int test_cont_variants()
return 1; return 1;
if (test::vector_test<MyMoveConstructCont>()) if (test::vector_test<MyMoveConstructCont>())
return 1; return 1;
#if !defined(__cpp_aligned_new) //old std::allocators don't support overaligned types
BOOST_IF_CONSTEXPR(!dtl::is_same<typename MyCont::allocator_type, std::allocator<int> >::value)
#endif
if (test::vector_test<MyOverAlignCont>())
return 1;
return 0; return 0;
} }
@@ -276,6 +280,11 @@ int main()
std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl; std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
return 1; return 1;
} }
// boost::container::new_allocator
if(test_cont_variants< new_allocator<void> >()){
std::cerr << "test_cont_variants< allocator<void> > failed" << std::endl;
return 1;
}
{ //Test enum container { //Test enum container
typedef vector<Test, std::allocator<Test> > MyEnumCont; typedef vector<Test, std::allocator<Test> > MyEnumCont;