]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Make std::valarray support overaligned types [PR108951]
authorJonathan Wakely <jwakely@redhat.com>
Fri, 24 Oct 2025 11:56:04 +0000 (12:56 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 27 Oct 2025 09:54:55 +0000 (09:54 +0000)
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.

Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
libstdc++-v3/include/bits/valarray_array.h
libstdc++-v3/include/std/valarray
libstdc++-v3/testsuite/26_numerics/valarray/108951.cc [new file with mode: 0644]

index b5c02b77b105126009d73785a15362f7648ba3df..d1b712c3485a9d5ea419342c9087863ba1b3e030 100644 (file)
@@ -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
index 82b58efad8caffd36e19a77184c965ba187eb222..ac15e79d040e2cccd73ffb376398f3a5208623cf 100644 (file)
@@ -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 (file)
index 0000000..929a1d4
--- /dev/null
@@ -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, {});
+}