PR65122 extended alignment support in allocators
authorJonathan Wakely <redi@gcc.gnu.org>
Fri, 14 Oct 2016 12:03:47 +0000 (13:03 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 14 Oct 2016 12:03:47 +0000 (13:03 +0100)
PR libstdc++/65122
* include/ext/malloc_allocator.h (malloc_allocator::allocate): Use
aligned_alloc for types with extended alignment if available,
otherwise throw bad_alloc if malloc doesn't return a suitable value.
* include/ext/bitmap_allocator.h (bitmap_allocator::allocate)
(bitmap_allocator::deallocate): Use aligned new/delete for types with
extended alignment.
* include/ext/mt_allocator.h (__mt_alloc::allocate)
(__mt_alloc::deallocate): Likewise.
* include/ext/new_allocator.h (new_allocator::allocate)
(new_allocator::deallocate): Likewise.
* include/ext/pool_allocator.h (__pool_alloc::allocate)
(__pool_alloc::deallocate): Likewise.
* testsuite/20_util/allocator/overaligned.cc: New test.
* testsuite/ext/bitmap_allocator/overaligned.cc: New test.
* testsuite/ext/malloc_allocator/overaligned.cc: New test.
* testsuite/ext/mt_allocator/overaligned.cc: New test.
* testsuite/ext/new_allocator/overaligned.cc: New test.
* testsuite/ext/pool_allocator/overaligned.cc: New test.

From-SVN: r241158

12 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/ext/bitmap_allocator.h
libstdc++-v3/include/ext/malloc_allocator.h
libstdc++-v3/include/ext/mt_allocator.h
libstdc++-v3/include/ext/new_allocator.h
libstdc++-v3/include/ext/pool_allocator.h
libstdc++-v3/testsuite/20_util/allocator/overaligned.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc [new file with mode: 0644]
libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc [new file with mode: 0644]

index 4a052f4dd5309323997aa96f14ab2450d5043778..a401ee0b84ae2fa777bbc19ae7136cec4f323d79 100644 (file)
@@ -1,7 +1,30 @@
+2016-10-14  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/65122
+       * include/ext/malloc_allocator.h (malloc_allocator::allocate): Use
+       aligned_alloc for types with extended alignment if available,
+       otherwise throw bad_alloc if malloc doesn't return a suitable value.
+       * include/ext/bitmap_allocator.h (bitmap_allocator::allocate)
+       (bitmap_allocator::deallocate): Use aligned new/delete for types with
+       extended alignment.
+       * include/ext/mt_allocator.h (__mt_alloc::allocate)
+       (__mt_alloc::deallocate): Likewise.
+       * include/ext/new_allocator.h (new_allocator::allocate)
+       (new_allocator::deallocate): Likewise.
+       * include/ext/pool_allocator.h (__pool_alloc::allocate)
+       (__pool_alloc::deallocate): Likewise.
+       * testsuite/20_util/allocator/overaligned.cc: New test.
+       * testsuite/ext/bitmap_allocator/overaligned.cc: New test.
+       * testsuite/ext/malloc_allocator/overaligned.cc: New test.
+       * testsuite/ext/mt_allocator/overaligned.cc: New test.
+       * testsuite/ext/new_allocator/overaligned.cc: New test.
+       * testsuite/ext/pool_allocator/overaligned.cc: New test.
+
 2016-10-14  Tim Shen  <timshen@google.com>
 
        PR libstdc++/77944
-       * include/std/variant: include <bits/funcexcept.h> for __try and __catch.
+       * include/std/variant: Include <bits/funcexcept.h> for __try and
+       __catch.
 
 2016-10-14  Jonathan Wakely  <jwakely@redhat.com>
 
index c7fbd3e20c720ae7b957fd35d1896ec7001f99f8..836abc8c53027fc3fd8e915940ec57ac3d75d943 100644 (file)
@@ -1018,6 +1018,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        if (__n > this->max_size())
          std::__throw_bad_alloc();
 
+#if __cpp_aligned_new
+       if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+         {
+           const size_type __b = __n * sizeof(value_type);
+           std::align_val_t __al = std::align_val_t(alignof(value_type));
+           return static_cast<pointer>(::operator new(__b, __al));
+         }
+#endif
+
        if (__builtin_expect(__n == 1, true))
          return this->_M_allocate_single_object();
        else
@@ -1036,6 +1045,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
        if (__builtin_expect(__p != 0, true))
          {
+#if __cpp_aligned_new
+           // Types with extended alignment are handled by operator delete.
+           if (alignof(value_type) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+             {
+               ::operator delete(__p, std::align_val_t(alignof(value_type)));
+               return;
+             }
+#endif
+
            if (__builtin_expect(__n == 1, true))
              this->_M_deallocate_single_object(__p);
            else
index 5c32eab70c3aa97c7b9dbb9a876d7251f9e04dff..acb60a2a3cf7bb1ed3bf9e0a825546abdea2be91 100644 (file)
@@ -30,6 +30,7 @@
 #define _MALLOC_ALLOCATOR_H 1
 
 #include <cstdlib>
+#include <cstddef>
 #include <new>
 #include <bits/functexcept.h>
 #include <bits/move.h>
@@ -100,9 +101,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        if (__n > this->max_size())
          std::__throw_bad_alloc();
 
-       pointer __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp)));
+       pointer __ret;
+#if __cpp_aligned_new
+#if __cplusplus > 201402L && _GLIBCXX_HAVE_ALIGNED_ALLOC
+       if (alignof(_Tp) > alignof(std::max_align_t))
+         {
+           __ret = static_cast<_Tp*>(::aligned_alloc(alignof(_Tp),
+                                                     __n * sizeof(_Tp)));
+         }
+#else
+# define _GLIBCXX_CHECK_MALLOC_RESULT
+#endif
+#endif
+       if (!__ret)
+         __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp)));
        if (!__ret)
          std::__throw_bad_alloc();
+#ifdef _GLIBCXX_CHECK_MALLOC_RESULT
+#undef _GLIBCXX_CHECK_MALLOC_RESULT
+         if (reinterpret_cast<std::size_t>(__ret) % alignof(_Tp))
+           {
+             // Memory returned by malloc is not suitably aligned for _Tp.
+             deallocate(__ret, __n);
+             std::__throw_bad_alloc();
+           }
+#endif
        return __ret;
       }
 
index 7016e489d417ae1b668882a5146c15cf119c0ce3..d7ea7c1a8c37cc062e331c9fc77a2c0d8d1f6834 100644 (file)
@@ -691,6 +691,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       if (__n > this->max_size())
        std::__throw_bad_alloc();
 
+#if __cpp_aligned_new
+      // Types with extended alignment are handled by operator new/delete.
+      if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+       {
+         std::align_val_t __al = std::align_val_t(alignof(_Tp));
+         return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al));
+       }
+#endif
+
       __policy_type::_S_initialize_once();
 
       // Requests larger than _M_max_bytes are handled by operator
@@ -737,6 +746,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       if (__builtin_expect(__p != 0, true))
        {
+#if __cpp_aligned_new
+         // Types with extended alignment are handled by operator new/delete.
+         if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+           {
+             ::operator delete(__p, std::align_val_t(alignof(_Tp)));
+             return;
+           }
+#endif
+
          // Requests larger than _M_max_bytes are handled by
          // operators new/delete directly.
          __pool_type& __pool = __policy_type::_S_get_pool();
index dd00b7384aa2e628d2db5082a20d8b512a06f735..2ff4780f0e0db248bff22eecc6dcf264c1fbac49 100644 (file)
@@ -101,13 +101,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        if (__n > this->max_size())
          std::__throw_bad_alloc();
 
+#if __cpp_aligned_new
+       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+         {
+           std::align_val_t __al = std::align_val_t(alignof(_Tp));
+           return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al));
+         }
+#endif
        return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
       }
 
       // __p is not permitted to be a null pointer.
       void
       deallocate(pointer __p, size_type)
-      { ::operator delete(__p); }
+      {
+#if __cpp_aligned_new
+       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+         {
+           ::operator delete(__p, std::align_val_t(alignof(_Tp)));
+           return;
+         }
+#endif
+       ::operator delete(__p);
+      }
 
       size_type
       max_size() const _GLIBCXX_USE_NOEXCEPT
index ee60e90166e94a190b0f392cc09adef70b425a5b..9e0511de19a27884d51c77fc4cab1968b6ad616f 100644 (file)
@@ -219,6 +219,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          if (__n > this->max_size())
            std::__throw_bad_alloc();
 
+         const size_t __bytes = __n * sizeof(_Tp);
+
+#if __cpp_aligned_new
+         if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+           {
+             std::align_val_t __al = std::align_val_t(alignof(_Tp));
+             return static_cast<_Tp*>(::operator new(__bytes, __al));
+           }
+#endif
+
          // If there is a race through here, assume answer from getenv
          // will resolve in same direction.  Inspired by techniques
          // to efficiently support threading found in basic_string.h.
@@ -230,7 +240,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                __atomic_add_dispatch(&_S_force_new, -1);
            }
 
-         const size_t __bytes = __n * sizeof(_Tp);           
          if (__bytes > size_t(_S_max_bytes) || _S_force_new > 0)
            __ret = static_cast<_Tp*>(::operator new(__bytes));
          else
@@ -259,6 +268,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       if (__builtin_expect(__n != 0 && __p != 0, true))
        {
+#if __cpp_aligned_new
+         if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+           {
+             ::operator delete(__p, std::align_val_t(alignof(_Tp)));
+             return;
+           }
+#endif
          const size_t __bytes = __n * sizeof(_Tp);
          if (__bytes > static_cast<size_t>(_S_max_bytes) || _S_force_new > 0)
            ::operator delete(__p);
diff --git a/libstdc++-v3/testsuite/20_util/allocator/overaligned.cc b/libstdc++-v3/testsuite/20_util/allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..384d1d2
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <memory>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 4;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  std::allocator<X> a;
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/bitmap_allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..7d365de
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <ext/bitmap_allocator.h>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 4;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  __gnu_cxx::bitmap_allocator<X> a;
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/malloc_allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..87182f1
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <ext/malloc_allocator.h>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 2;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  __gnu_cxx::malloc_allocator<X> a;
+#if __cplusplus > 201402L && _GLIBCXX_HAVE_ALIGNED_ALLOC
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+#else
+  // Allocating for extended alignment is unreliable without aligned_alloc()
+  try
+  {
+    X* p1 = a.allocate(1);
+    VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+    a.deallocate(p1, 1);
+  }
+  catch (const std::bad_alloc&)
+  { }
+  try
+  {
+    X* p2 = a.allocate(20);
+    VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+    a.deallocate(p2, 20);
+  }
+  catch (const std::bad_alloc&)
+  { }
+#endif
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/mt_allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..41b8b46
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <ext/mt_allocator.h>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 4;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  __gnu_cxx::__mt_alloc<X> a;
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/new_allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..27413cf
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <ext/new_allocator.h>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 4;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  __gnu_cxx::new_allocator<X> a;
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc b/libstdc++-v3/testsuite/ext/pool_allocator/overaligned.cc
new file mode 100644 (file)
index 0000000..b509b79
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-faligned-new" }
+// { dg-do run { target c++11 } }
+
+#include <ext/pool_allocator.h>
+#include <cstddef>
+#include <cstdint>
+#include <testsuite_hooks.h>
+
+constexpr std::size_t align = alignof(std::max_align_t) * 4;
+
+struct X {
+  alignas(align) char c;
+};
+
+void
+test01()
+{
+  __gnu_cxx::__pool_alloc<X> a;
+  X* p1 = a.allocate(1);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p1) % align) == 0 );
+  a.deallocate(p1, 1);
+  X* p2 = a.allocate(20);
+  VERIFY( (reinterpret_cast<std::uintptr_t>(p2) % align) == 0 );
+  a.deallocate(p2, 20);
+}
+
+int
+main()
+{
+  test01();
+}