mirror of
https://github.com/boostorg/container.git
synced 2026-01-19 04:02:17 +00:00
Add overalignment support for new_delete_resource for newer (__cpp_aligned_new) and older standards, including some workaround for targets where __STDCPP_DEFAULT_NEW_ALIGNMENT__ value is not correctly aligned between GCC and the malloc implementation (Win32)
This commit is contained in:
@@ -1451,8 +1451,9 @@ use [*Boost.Container]? There are several reasons for that:
|
||||
* Implemented C++20's [funcref boost::container::uninitialized_construct_using_allocator uninitialized_construct_using_allocator]
|
||||
and [funcref boost::container::make_obj_using_allocator make_obj_using_allocator].
|
||||
* Added `[[nodiscard]]` to several allocator and PMR utilities.
|
||||
* Implemented overaligned operator new/delete support for `new_allocator` and `pmr::new_delete_resource()`
|
||||
when C++17's `cpp_aligned_new` is available.
|
||||
* Implemented overaligned operator new/delete support for `new_allocator` and `pmr::new_delete_resource()`:
|
||||
* Uses C++17's `cpp_aligned_new` if available.
|
||||
* Uses alternative aligned allocation functions for Win32/Unix otherwise.
|
||||
* Fixed bugs/issues:
|
||||
* [@https://github.com/boostorg/container/issues/323 GitHub #323: ['"flat_tree::try_emplace UB"]].
|
||||
|
||||
|
||||
152
include/boost/container/detail/aligned_alloc.hpp
Normal file
152
include/boost/container/detail/aligned_alloc.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2025-2025. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/container for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef BOOST_CONTAINER_DETAIL_ALIGNED_ALLOC_HPP
|
||||
#define BOOST_CONTAINER_DETAIL_ALIGNED_ALLOC_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
# include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
// Platform detection
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#define BOOST_CONTAINER_HAS_ALIGNED_MALLOC
|
||||
#else
|
||||
#include <unistd.h> //Include it to detect POSIX features
|
||||
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
|
||||
#define BOOST_CONTAINER_HAS_POSIX_MEMALIGN
|
||||
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)
|
||||
#define BOOST_CONTAINER_HAS_POSIX_MEMALIGN
|
||||
#elif defined(__APPLE__)
|
||||
#include <Availability.h>
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500
|
||||
#define BOOST_CONTAINER_HAS_ALIGNED_ALLOC
|
||||
#else
|
||||
#define BOOST_CONTAINER_HAS_POSIX_MEMALIGN
|
||||
#endif
|
||||
#elif defined(__ANDROID__)
|
||||
#if (__ANDROID_API__ >= 28)
|
||||
#define BOOST_CONTAINER_HAS_ALIGNED_ALLOC
|
||||
#else
|
||||
#define BOOST_CONTAINER_HAS_POSIX_MEMALIGN
|
||||
#endif
|
||||
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||
#define BOOST_CONTAINER_HAS_ALIGNED_ALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Include
|
||||
#if defined(BOOST_CONTAINER_HAS_ALIGNED_MALLOC)
|
||||
#include <malloc.h>
|
||||
#elif defined(BOOST_CONTAINER_HAS_POSIX_MEMALIGN)
|
||||
#include <stdlib.h>
|
||||
#elif defined(BOOST_CONTAINER_HAS_ALIGNED_ALLOC)
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <stdlib.h> //for malloc
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
namespace dtl {
|
||||
|
||||
#if defined(BOOST_CONTAINER_HAS_POSIX_MEMALIGN)
|
||||
|
||||
inline void* aligned_allocate(std::size_t al, std::size_t sz)
|
||||
{
|
||||
void *ptr;
|
||||
// posix_memalign requires aligned multiple of void*
|
||||
if (al < sizeof(void*))
|
||||
al = sizeof(void*);
|
||||
int ret = posix_memalign(&ptr, al, sz);
|
||||
if (ret != 0)
|
||||
return 0;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_CONTAINER_HAS_ALIGNED_ALLOC)
|
||||
|
||||
inline void* aligned_allocate(std::size_t al, std::size_t sz)
|
||||
{
|
||||
// Some aligned_allocate are based on posix_memalign so require also minimal alignment
|
||||
if (al < sizeof(void*))
|
||||
al = sizeof(void*);
|
||||
|
||||
// aligned_allocate requires size to be a multiple of alignment
|
||||
std::size_t rounded_size = std::size_t(sz + al - 1u) & ~std::size_t(al - 1);
|
||||
|
||||
//Check for rounded size overflow
|
||||
return rounded_size ? aligned_allocate(al, rounded_size) : 0;
|
||||
}
|
||||
|
||||
#elif defined(BOOST_CONTAINER_HAS_ALIGNED_MALLOC)
|
||||
|
||||
inline void* aligned_allocate(std::size_t al, std::size_t sz)
|
||||
{
|
||||
return _aligned_malloc(sz, al);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void* aligned_allocate(std::size_t al, std::size_t sz)
|
||||
{
|
||||
//Make room for a back pointer metadata
|
||||
void* const mptr = malloc(sz + sizeof(void*) + al);
|
||||
if (!mptr)
|
||||
return 0;
|
||||
|
||||
//Now align the returned pointer (which will be aligned at least to sizeof(void*)
|
||||
std::size_t raw_addr = reinterpret_cast<std::size_t>(mptr);
|
||||
std::size_t offset = sizeof(void*);
|
||||
void *const ptr = reinterpret_cast<void*>((raw_addr + offset + al - 1u) & ~(al - 1u));
|
||||
|
||||
// Store the original pointer just before the aligned address
|
||||
void** backpointer = reinterpret_cast<void**>(ptr) - 1;
|
||||
*backpointer = mptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_CONTAINER_HAS_ALIGNED_ALLOC) || defined(BOOST_CONTAINER_HAS_POSIX_MEMALIGN)
|
||||
|
||||
inline void aligned_deallocate(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#elif defined(BOOST_CONTAINER_HAS_ALIGNED_MALLOC)
|
||||
|
||||
inline void aligned_deallocate(void* ptr)
|
||||
{
|
||||
_aligned_free(ptr); //_aligned_free supports NULL ptr
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void aligned_deallocate(void* ptr)
|
||||
{
|
||||
// Obtain backpointer data and free it
|
||||
void** storage = reinterpret_cast<void**>(ptr) - 1;
|
||||
free(*storage);
|
||||
}
|
||||
|
||||
#endif//
|
||||
|
||||
} //namespace dtl {
|
||||
} //namespace container {
|
||||
} //namespace boost {
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DETAIL_ALIGNED_ALLOC_HPP
|
||||
@@ -22,19 +22,50 @@
|
||||
#include <boost/container/throw_exception.hpp>
|
||||
#include <boost/container/detail/type_traits.hpp>
|
||||
|
||||
#if !defined(__cpp_aligned_new)
|
||||
#include <boost/container/detail/aligned_alloc.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace container {
|
||||
namespace dtl {
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE bool operator_new_raw_overaligned(std::size_t alignment)
|
||||
{
|
||||
//GCC-clang on Mingw-w64 has problems with malloc (MSVCRT / UCRT) alignment not matching
|
||||
//__STDCPP_DEFAULT_NEW_ALIGNMENT__, since HeapAlloc alignment is 8 for 32 bit targets
|
||||
#if !defined(__cpp_aligned_new) || (defined(_WIN32) && !defined(_WIN64) && !defined(_MSC_VER))
|
||||
return alignment > 2u*sizeof(void*);
|
||||
#else
|
||||
return alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE bool operator_new_raw_overaligned_tricky()
|
||||
{
|
||||
//GCC-clang on Mingw-w64 has problems with malloc (MSVCRT / UCRT) alignment not matching
|
||||
//__STDCPP_DEFAULT_NEW_ALIGNMENT__, since HeapAlloc alignment is 8 for 32 bit targets
|
||||
#if !defined(__cpp_aligned_new) || (defined(_WIN32) && !defined(_WIN64) && !defined(_MSC_VER))
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE void* operator_new_raw_allocate(const std::size_t size, const std::size_t alignment)
|
||||
{
|
||||
(void)alignment;
|
||||
#if defined(__cpp_aligned_new)
|
||||
if(__STDCPP_DEFAULT_NEW_ALIGNMENT__ < alignment) {
|
||||
if(operator_new_raw_overaligned(alignment)) {
|
||||
#if defined(__cpp_aligned_new)
|
||||
return ::operator new(size, std::align_val_t(alignment));
|
||||
#else
|
||||
//C++ requires zero-sized allocations to return a non-null pointer
|
||||
return aligned_allocate(alignment, !size ? 1 : size);
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
return ::operator new(size);
|
||||
}
|
||||
#endif
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
BOOST_CONTAINER_FORCEINLINE void operator_delete_raw_deallocate
|
||||
@@ -42,22 +73,24 @@ BOOST_CONTAINER_FORCEINLINE void operator_delete_raw_deallocate
|
||||
{
|
||||
(void)size;
|
||||
(void)alignment;
|
||||
#ifdef __cpp_aligned_new
|
||||
if(__STDCPP_DEFAULT_NEW_ALIGNMENT__ < alignment) {
|
||||
# if defined(__cpp_sized_deallocation)
|
||||
::operator delete(ptr, size, std::align_val_t(alignment));
|
||||
if(operator_new_raw_overaligned(alignment)) {
|
||||
#if defined(__cpp_aligned_new)
|
||||
# if defined(__cpp_sized_deallocation)
|
||||
::operator delete(ptr, size, std::align_val_t(alignment));
|
||||
#else
|
||||
::operator delete(ptr, std::align_val_t(alignment));
|
||||
# endif
|
||||
#else
|
||||
::operator delete(ptr, std::align_val_t(alignment));
|
||||
# endif
|
||||
return;
|
||||
aligned_deallocate(ptr);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
# if defined(__cpp_sized_deallocation)
|
||||
::operator delete(ptr, size);
|
||||
#else
|
||||
::operator delete(ptr);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined(__cpp_sized_deallocation)
|
||||
::operator delete(ptr, size);
|
||||
#else
|
||||
::operator delete(ptr);
|
||||
# endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
Reference in New Issue
Block a user