The polymorphic_allocator::construct functions create dangling
pointers to rvalues of type memory_resource* and then dereference
them, leading to undefined behaviour.

This fixes those functions to use lvalues, and then adds a deleted
overload of __use_alloc to prevent this happening again.

This means __use_alloc can't be used like:

 f( __use_alloc<T, Alloc>(c.get_allocator()) );

because get_allocator() returns an rvalue, but it's an internal-only
helper and we can just do this instead:

 auto alloc = c.get_allocator();
 f( __use_alloc<T, Alloc>(alloc) );
        * include/bits/uses_allocator.h (__use_alloc(const _Alloc&&)): Add
        deleted overload to prevent dangling references to rvalues.
        * include/experimental/memory_resource
        (polymorphic_allocator::construct): Do not call __use_alloc with
        rvalue arguments.

Tested powerpc64le-linux, committed to trunk.

commit 072946c11b40cb13f709cb31ff5ef4a998d41f96
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Thu Jul 6 12:22:49 2017 +0100

    Prevent __uses_alloc from holding dangling references
    
        * include/bits/uses_allocator.h (__use_alloc(const _Alloc&&)): Add
        deleted overload to prevent dangling references to rvalues.
        * include/experimental/memory_resource
        (polymorphic_allocator::construct): Do not call __use_alloc with
        rvalue arguments.

diff --git a/libstdc++-v3/include/bits/uses_allocator.h 
b/libstdc++-v3/include/bits/uses_allocator.h
index 89d4e43..4d60716 100644
--- a/libstdc++-v3/include/bits/uses_allocator.h
+++ b/libstdc++-v3/include/bits/uses_allocator.h
@@ -109,6 +109,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __ret._M_a = std::__addressof(__a);
       return __ret;
     }
+
+  template<typename _Tp, typename _Alloc, typename... _Args>
+    void
+    __use_alloc(const _Alloc&&) = delete;
+
 #if __cplusplus > 201402L
   template <typename _Tp, typename _Alloc>
     inline constexpr bool uses_allocator_v =
diff --git a/libstdc++-v3/include/experimental/memory_resource 
b/libstdc++-v3/include/experimental/memory_resource
index 653189c..99ace7a 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -168,8 +168,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template <typename _Tp1, typename... _Args> //used here
        void construct(_Tp1* __p, _Args&&... __args)
        {
-         auto __use_tag = __use_alloc<_Tp1, memory_resource*,
-              _Args...>(this->resource());
+         memory_resource* const __resource = this->resource();
+         auto __use_tag
+           = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource);
          _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
        }
 
@@ -180,10 +181,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                       tuple<_Args1...> __x,
                       tuple<_Args2...> __y)
        {
+         memory_resource* const __resource = this->resource();
          auto __x_use_tag =
-           __use_alloc<_Tp1, memory_resource*, _Args1...>(this->resource());
+           __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource);
          auto __y_use_tag =
-           __use_alloc<_Tp2, memory_resource*, _Args2...>(this->resource());
+           __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource);
 
          ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct,
                                           _M_construct_p(__x_use_tag, __x),

Reply via email to