On Fri, Oct 24, 2025 at 8:08 PM Jonathan Wakely <[email protected]> wrote:

> Switch std::valarray<T> memory allocation to use std::__new_allocator<T>
> 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<T> 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.
> ---
>
> Tested powerpc64le-linux.
>
LGTM.

>
> I don't know why the allocating function is "get_storage" and the
> deallocating one is "release_memory" rather than "release_storage".
>
We are changing the signature, and mangled name anyway, so we could rename
it to release_storage. I am OK either way.

>
>  libstdc++-v3/include/bits/valarray_array.h    | 10 +++++----
>  libstdc++-v3/include/std/valarray             | 12 +++++-----
>  .../testsuite/26_numerics/valarray/108951.cc  | 22 +++++++++++++++++++
>  3 files changed, 34 insertions(+), 10 deletions(-)
>  create mode 100644 libstdc++-v3/testsuite/26_numerics/valarray/108951.cc
>
> 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 <bits/c++config.h>
>  #include <bits/cpp_type_traits.h>
> +#include <bits/new_allocator.h>
>  #include <cstdlib>
>  #include <new>
>
> @@ -57,12 +58,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    template<typename _Tp>
>      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<typename _Tp>
> +    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<typename _Tp>
> @@ -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 <valarray>
> +#include <cstdint>
> +#include <testsuite_hooks.h>
> +
> +struct alignas(64) Num
> +{
> +  Num()
> +  {
> +    VERIFY(reinterpret_cast<std::uintptr_t>(this) % alignof(*this) == 0);
> +  }
> +
> +  double val{};
> +};
> +
> +int main()
> +{
> +  std::valarray<Num> v(2);
> +  v.resize(4, {});
> +}
> --
> 2.51.0
>
>

Reply via email to