[PATCH] PR libstdc++/70966 make pmr::new_delete_resource() immortal

Jonathan Wakely jwakely@redhat.com
Wed Jun 20 19:34:00 GMT 2018


Construct the program-wide resource objects using placement new. This
means they have dynamic storage duration and won't be destroyed during
termination.

	PR libstdc++/70966
	* include/experimental/memory_resource (__resource_adaptor_imp): Add
	static assertions to enforce requirements on pointer types.
	(__resource_adaptor_imp::get_allocator()): Add noexcept.
	(new_delete_resource, null_memory_resource): Return address of an
	object with dynamic storage duration.
	(__null_memory_resource): Remove.
	* testsuite/experimental/memory_resource/70966.cc: New.

Tested x86_64-linux, committed to trunk. I plan to backport this to
the branches too, as it's experimental TS material.


-------------- next part --------------
commit 2a3eba3f0312c8c15f4f2fd7fe7dcc4896036797
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jun 20 20:01:04 2018 +0100

    PR libstdc++/70966 make pmr::new_delete_resource() immortal
    
    Construct the program-wide resource objects using placement new. This
    means they have dynamic storage duration and won't be destroyed during
    termination.
    
            PR libstdc++/70966
            * include/experimental/memory_resource (__resource_adaptor_imp): Add
            static assertions to enforce requirements on pointer types.
            (__resource_adaptor_imp::get_allocator()): Add noexcept.
            (new_delete_resource, null_memory_resource): Return address of an
            object with dynamic storage duration.
            (__null_memory_resource): Remove.
            * testsuite/experimental/memory_resource/70966.cc: New.

diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
index b8480c2a17b..670a2210804 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -33,7 +33,6 @@
 #include <new>
 #include <atomic>
 #include <cstddef>
-#include <bits/alloc_traits.h>
 #include <experimental/bits/lfts_config.h>
 
 namespace std {
@@ -258,6 +257,22 @@ namespace pmr {
   template <typename _Alloc>
     class __resource_adaptor_imp : public memory_resource
     {
+      static_assert(is_same<char,
+	  typename allocator_traits<_Alloc>::value_type>::value,
+	  "Allocator's value_type is char");
+      static_assert(is_same<char*,
+	  typename allocator_traits<_Alloc>::pointer>::value,
+	  "Allocator's pointer type is value_type*");
+      static_assert(is_same<const char*,
+	  typename allocator_traits<_Alloc>::const_pointer>::value,
+	  "Allocator's const_pointer type is value_type const*");
+      static_assert(is_same<void*,
+	  typename allocator_traits<_Alloc>::void_pointer>::value,
+	  "Allocator's void_pointer type is void*");
+      static_assert(is_same<const void*,
+	  typename allocator_traits<_Alloc>::const_void_pointer>::value,
+	  "Allocator's const_void_pointer type is void const*");
+
     public:
       using allocator_type = _Alloc;
 
@@ -276,7 +291,7 @@ namespace pmr {
       __resource_adaptor_imp&
       operator=(const __resource_adaptor_imp&) = default;
 
-      allocator_type get_allocator() const { return _M_alloc; }
+      allocator_type get_allocator() const noexcept { return _M_alloc; }
 
     protected:
       virtual void*
@@ -311,13 +326,13 @@ namespace pmr {
     private:
       // Calculate Aligned Size
       // Returns a size that is larger than or equal to __size and divisible
-      // by __alignment, where __alignment is required to be the power of 2.
+      // by __alignment, where __alignment is required to be a power of 2.
       static size_t
       _S_aligned_size(size_t __size, size_t __alignment)
       { return ((__size - 1)|(__alignment - 1)) + 1; }
 
       // Determine whether alignment meets one of those preconditions:
-      // 1. Equals to Zero
+      // 1. Equal to Zero
       // 2. Is power of two
       static bool
       _S_supported (size_t __x)
@@ -337,34 +352,33 @@ namespace pmr {
   inline memory_resource*
   new_delete_resource() noexcept
   {
-    static resource_adaptor<std::allocator<char>> __r;
-    return static_cast<memory_resource*>(&__r);
+    using type = resource_adaptor<std::allocator<char>>;
+    alignas(type) static unsigned char __buf[sizeof(type)];
+    static type* __r = new(__buf) type;
+    return __r;
   }
 
-  template <typename _Alloc>
-    class __null_memory_resource : private memory_resource
-    {
-    protected:
-      void*
-      do_allocate(size_t, size_t)
-      { std::__throw_bad_alloc(); }
-
-      void
-      do_deallocate(void*, size_t, size_t) noexcept
-      { }
-
-      bool
-      do_is_equal(const memory_resource& __other) const noexcept
-      { return this == &__other; }
-
-      friend memory_resource* null_memory_resource() noexcept;
-    };
-
   inline memory_resource*
   null_memory_resource() noexcept
   {
-    static __null_memory_resource<void> __r;
-    return static_cast<memory_resource*>(&__r);
+    class type final : public memory_resource
+    {
+      void*
+      do_allocate(size_t, size_t) override
+      { std::__throw_bad_alloc(); }
+
+      void
+      do_deallocate(void*, size_t, size_t) noexcept override
+      { }
+
+      bool
+      do_is_equal(const memory_resource& __other) const noexcept override
+      { return this == &__other; }
+    };
+
+    alignas(type) static unsigned char __buf[sizeof(type)];
+    static type* __r = new(__buf) type;
+    return __r;
   }
 
   // The default memory resource
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc b/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc
new file mode 100644
index 00000000000..c0173ffa7a9
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc
@@ -0,0 +1,56 @@
+// Copyright (C) 2018 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-do run { target c++14 } }
+
+#include <experimental/memory_resource>
+
+namespace pmr = std::experimental::pmr;
+
+struct X
+{
+  pmr::memory_resource* res = nullptr;
+  void* ptr = nullptr;
+  static constexpr std::size_t n = 64;
+
+  constexpr X() { }
+
+  explicit
+  X(pmr::memory_resource* r) : res(r), ptr(r->allocate(n)) { }
+
+  ~X() { if (ptr) res->deallocate(ptr, n); }
+};
+
+void
+swap(X& lhs, X& rhs) {
+    std::swap(lhs.res, rhs.res);
+    std::swap(lhs.ptr, rhs.ptr);
+}
+
+void
+test01()
+{
+  static X x1;
+  X x2(pmr::new_delete_resource());
+  swap(x1, x2);
+  // Now x1 will deallocate the memory during destruction of static objects.
+}
+
+int main()
+{
+  test01();
+}


More information about the Libstdc++ mailing list