From: Jonathan Wakely Date: Fri, 24 Oct 2025 11:56:04 +0000 (+0100) Subject: libstdc++: Make std::valarray support overaligned types [PR108951] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38a441689b0d4f3e9a712e3dde4d4fe8db474520;p=thirdparty%2Fgcc.git libstdc++: Make std::valarray support overaligned types [PR108951] Switch std::valarray memory allocation to use std::__new_allocator to allocate and deallocate memory. This adds support for extended alignment types without needing to duplicate all the logic from __new_allocator::allocate and __new_allocator::dellocate. std::__new_allocator is used instead of std::allocator because we want to ensure that the memory is still allocated with operator new, so we don't want to use any possible program-defined specialization of std::allocator which the user might have provided. To make using an allocator possible, __valarray_release_memory needs to become a function template so that it knows the type T. It also needs an additional parameter specifying the size of the allocation. This change doesn't cause an ABI change for types with fundamental alignment, because __new_allocator still uses the same operator delete function (or the sized version, which is ABI compatible) to free the memory. So if memory for a valarray is allocated in one translation unit and deallocated in another, and those TUs are compiled with different versions of GCC, we still get memory from the same operator new and release it with the same operator delete (or the compatibled sized version). For types with extended alignment this does potentially cause an ABI change on targets where the aligned version of operator delete doesn't just call free(p), but support for extended alignment types was previously just broken and had undefined behaviour. libstdc++-v3/ChangeLog: PR libstdc++/108951 * include/bits/valarray_array.h( __valarray_get_storage): Use std::__new_allocator. (__valarray_release_memory): Likewise. * include/std/valarray: Pass _M_size to __valarray_release_memory. * testsuite/26_numerics/valarray/108951.cc: New test. Reviewed-by: Tomasz KamiƄski --- diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h index b5c02b77b105..d1b712c3485a 100644 --- a/libstdc++-v3/include/bits/valarray_array.h +++ b/libstdc++-v3/include/bits/valarray_array.h @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -57,12 +58,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template inline _Tp* __valarray_get_storage(size_t __n) - { return static_cast<_Tp*>(operator new(__n * sizeof(_Tp))); } + { return std::__new_allocator<_Tp>().allocate(__n); } // Return memory to the system - inline void - __valarray_release_memory(void* __p) - { operator delete(__p); } + template + inline void + __valarray_release_memory(_Tp* __p, size_t __n) + { std::__new_allocator<_Tp>().deallocate(__p, __n); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr diff --git a/libstdc++-v3/include/std/valarray b/libstdc++-v3/include/std/valarray index 82b58efad8ca..ac15e79d040e 100644 --- a/libstdc++-v3/include/std/valarray +++ b/libstdc++-v3/include/std/valarray @@ -720,7 +720,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION valarray<_Tp>::~valarray() _GLIBCXX_NOEXCEPT { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } template @@ -736,7 +736,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __v._M_size; _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -754,7 +754,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __v._M_size; _M_data = __v._M_data; @@ -776,7 +776,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __l.size(); _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -854,7 +854,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_data) { std::__valarray_destroy_elements(_M_data, _M_data + _M_size); - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); } _M_size = __e.size(); _M_data = __valarray_get_storage<_Tp>(_M_size); @@ -1049,7 +1049,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::__valarray_destroy_elements(_M_data, _M_data + _M_size); if (_M_size != __n) { - std::__valarray_release_memory(_M_data); + std::__valarray_release_memory(_M_data, _M_size); _M_size = __n; _M_data = __valarray_get_storage<_Tp>(__n); } diff --git a/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc b/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc new file mode 100644 index 000000000000..929a1d499285 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/valarray/108951.cc @@ -0,0 +1,22 @@ +// { dg-do run { target c++11 } } +// { dg-additional-options "-faligned-new" { target c++14_down } } + +#include +#include +#include + +struct alignas(64) Num +{ + Num() + { + VERIFY(reinterpret_cast(this) % alignof(*this) == 0); + } + + double val{}; +}; + +int main() +{ + std::valarray v(2); + v.resize(4, {}); +}