PR libstdc++/83860 avoid dangling references in valarray closure types
authorJonathan Wakely <jwakely@redhat.com>
Wed, 2 May 2018 16:41:46 +0000 (17:41 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 2 May 2018 16:41:46 +0000 (17:41 +0100)
Store nested closures by value not by reference, to prevent holding
invalid references to temporaries that have been destroyed. This
changes the layout of the closure types, so change their linkage names,
but moving them to a different namespace.

PR libstdc++/57997
PR libstdc++/83860
* include/bits/gslice_array.h (gslice_array): Define default
constructor as deleted, as per C++11 standard.
* include/bits/mask_array.h (mask_array): Likewise.
* include/bits/slice_array.h (slice_array): Likewise.
* include/bits/valarray_after.h (_GBase, _GClos, _IBase, _IClos): Move
to namespace __detail.
(_GBase::_M_expr, _IBase::_M_expr): Use _ValArrayRef for type of data
members.
* include/bits/valarray_before.h (_ValArrayRef): New helper for type
of data members in closure objects.
(_FunBase, _ValFunClos, _RefFunClos, _UnBase, _UnClos, _BinBase)
(_BinBase2, _BinBase1, _BinClos, _SBase, _SClos): Move to namespace
__detail.
(_FunBase::_M_expr, _UnBase::_M_expr, _BinBase::_M_expr1)
(_BinBase::_M_expr2, _BinBase2::_M_expr1, _BinBase1::_M_expr2)
(_SBase::_M_expr): Use _ValArrayRef for type of data members.
* include/std/valarray (_UnClos, _BinClos, _SClos, _GClos, _IClos)
(_ValFunClos, _RefFunClos): Move to namespace __detail and add
using-declarations to namespace std.
* testsuite/26_numerics/valarray/83860.cc: New.

From-SVN: r259844

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/gslice_array.h
libstdc++-v3/include/bits/mask_array.h
libstdc++-v3/include/bits/slice_array.h
libstdc++-v3/include/bits/valarray_after.h
libstdc++-v3/include/bits/valarray_before.h
libstdc++-v3/include/std/valarray
libstdc++-v3/testsuite/26_numerics/valarray/83860.cc [new file with mode: 0644]

index 8aca0a34c785bb6c371b822100913dae0824fd11..7b17bd2f8b43782c62744791d75b99b634209f55 100644 (file)
@@ -1,5 +1,28 @@
 2018-05-02  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/57997
+       PR libstdc++/83860
+       * include/bits/gslice_array.h (gslice_array): Define default
+       constructor as deleted, as per C++11 standard.
+       * include/bits/mask_array.h (mask_array): Likewise.
+       * include/bits/slice_array.h (slice_array): Likewise.
+       * include/bits/valarray_after.h (_GBase, _GClos, _IBase, _IClos): Move
+       to namespace __detail.
+       (_GBase::_M_expr, _IBase::_M_expr): Use _ValArrayRef for type of data
+       members.
+       * include/bits/valarray_before.h (_ValArrayRef): New helper for type
+       of data members in closure objects.
+       (_FunBase, _ValFunClos, _RefFunClos, _UnBase, _UnClos, _BinBase)
+       (_BinBase2, _BinBase1, _BinClos, _SBase, _SClos): Move to namespace
+       __detail.
+       (_FunBase::_M_expr, _UnBase::_M_expr, _BinBase::_M_expr1)
+       (_BinBase::_M_expr2, _BinBase2::_M_expr1, _BinBase1::_M_expr2)
+       (_SBase::_M_expr): Use _ValArrayRef for type of data members.
+       * include/std/valarray (_UnClos, _BinClos, _SClos, _GClos, _IClos)
+       (_ValFunClos, _RefFunClos): Move to namespace __detail and add
+       using-declarations to namespace std.
+       * testsuite/26_numerics/valarray/83860.cc: New.
+
        * testsuite/backward/strstream_move.cc: Remove duplicate function
        call.
 
index 2da7e0442bbe4bc7aea73080f2e404f2ab6db743..715c53bd616aa9f399e87b0d2044525f8701dff5 100644 (file)
@@ -128,8 +128,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       gslice_array(_Array<_Tp>, const valarray<size_t>&);
 
+#if __cplusplus < 201103L
       // not implemented
       gslice_array();
+#else
+    public:
+      gslice_array() = delete;
+#endif
     };
 
   template<typename _Tp>
index 84671cb43d64c128144e1fea2c35069aad31504b..c11691a243aaa8cc235b576e744c39a874ab5b28 100644 (file)
@@ -131,8 +131,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       const _Array<bool> _M_mask;
       const _Array<_Tp>  _M_array;
 
+#if __cplusplus < 201103L
       // not implemented
       mask_array();
+#else
+    public:
+      mask_array() = delete;
+#endif
     };
 
   template<typename _Tp>
index 05b096bb5a91af29ce42b65db724cc88e3aa2f83..b025373180f5c6f957f822fb041f9278ca2a49a3 100644 (file)
@@ -192,8 +192,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       const size_t      _M_stride;
       const _Array<_Tp> _M_array;
 
+#if __cplusplus < 201103L
       // not implemented
       slice_array();
+#else
+    public:
+      slice_array() = delete;
+#endif
     };
 
   template<typename _Tp>
index 7f62b292ed506f366620dccf9e235c7ffa1e7e79..bb1a3c9b513547953fa029d4eaa1219080f4cb0a 100644 (file)
@@ -38,6 +38,8 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+namespace __detail
+{
   //
   // gslice_array closure.
   //
@@ -59,8 +61,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return _M_index.size(); }
 
     private:
-      const _Dom&            _M_expr;
-      const valarray<size_t>& _M_index;
+      typename _ValArrayRef<_Dom>::__type      _M_expr;
+      const valarray<size_t>&                  _M_index;
     };
 
   template<typename _Tp>
@@ -128,8 +130,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return _M_index.size(); }
 
     private:
-      const _Dom&            _M_expr;
-      const valarray<size_t>& _M_index;
+      typename _ValArrayRef<_Dom>::__type      _M_expr;
+      const valarray<size_t>&                  _M_index;
     };
 
   template<class _Dom>
@@ -153,6 +155,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _IClos (const valarray<_Tp>& __a, const valarray<size_t>& __i)
       : _Base (__a, __i) {}
     };
+} // namespace __detail
   
   //
   // class _Expr
index a77fdf203b245fac00a053592190f2086259dea5..fe41787c19f7c4720307fa98a8caf36e90b267fb 100644 (file)
@@ -406,6 +406,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       typedef bool result_type;
     };
 
+namespace __detail
+{
+  // Closure types already have reference semantics and are often short-lived,
+  // so store them by value to avoid (some cases of) dangling references to
+  // out-of-scope temporaries.
+  template<typename _Tp>
+    struct _ValArrayRef
+    { typedef const _Tp __type; };
+
+  // Use real references for std::valarray objects.
+  template<typename _Tp>
+    struct _ValArrayRef< valarray<_Tp> >
+    { typedef const valarray<_Tp>& __type; };
+
   //
   // Apply function taking a value/const reference closure
   //
@@ -425,7 +439,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       size_t size() const { return _M_expr.size ();}
 
     private:
-      const _Dom& _M_expr;
+      typename _ValArrayRef<_Dom>::__type _M_expr;
       value_type (*_M_func)(_Arg);
     };
 
@@ -490,7 +504,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       size_t size() const { return _M_expr.size(); }
       
     private:
-      const _Arg& _M_expr;
+      typename _ValArrayRef<_Arg>::__type _M_expr;
     };
 
   template<class _Oper, class _Dom>
@@ -536,8 +550,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       size_t size() const { return _M_expr1.size(); }
 
     private:
-      const _FirstArg& _M_expr1;
-      const _SecondArg& _M_expr2;
+      typename _ValArrayRef<_FirstArg>::__type _M_expr1;
+      typename _ValArrayRef<_SecondArg>::__type _M_expr2;
     };
 
 
@@ -557,8 +571,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       size_t size() const { return _M_expr1.size(); }
 
     private:
-      const _Clos& _M_expr1;
-      const _Vt& _M_expr2;
+      typename _ValArrayRef<_Clos>::__type _M_expr1;
+      _Vt _M_expr2;
     };
 
   template<class _Oper, class _Clos>
@@ -577,8 +591,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       size_t size() const { return _M_expr2.size(); }
 
     private:
-      const _Vt& _M_expr1;
-      const _Clos& _M_expr2;
+      _Vt _M_expr1;
+      typename _ValArrayRef<_Clos>::__type _M_expr2;
     };
 
   template<class _Oper, class _Dom1, class _Dom2>
@@ -592,7 +606,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<class _Oper, typename _Tp>
-    struct _BinClos<_Oper,_ValArray, _ValArray, _Tp, _Tp>
+    struct _BinClos<_Oper, _ValArray, _ValArray, _Tp, _Tp>
     : _BinBase<_Oper, valarray<_Tp>, valarray<_Tp> >
     {
       typedef _BinBase<_Oper, valarray<_Tp>, valarray<_Tp> > _Base;
@@ -668,10 +682,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _BinClos(const _Tp& __t, const valarray<_Tp>& __v) : _Base(__t, __v) {}
     };
 
-    //
-    // slice_array closure.
-    //
-  template<typename _Dom> 
+  //
+  // slice_array closure.
+  //
+  template<typename _Dom>
     class _SBase
     {
     public:
@@ -689,7 +703,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return _M_slice.size (); }
 
     private:
-      const _Dom& _M_expr;
+      typename _ValArrayRef<_Dom>::__type _M_expr;
       const slice& _M_slice;
     };
 
@@ -736,6 +750,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       
       _SClos (_Array<_Tp> __a, const slice& __s) : _Base (__a, __s) {}
     };
+} // namespace __detail
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
index 761a2fc98be339cbbda34d3b40ab7bbd9ead7ca3..03e0badfc53d299aff44ce01146b1532d5968c03 100644 (file)
@@ -51,6 +51,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Tp1, typename _Tp2>
     class _ValArray;
 
+namespace __detail
+{
   template<class _Oper, template<class, class> class _Meta, class _Dom>
     struct _UnClos;
 
@@ -74,6 +76,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<template<class, class> class _Meta, class _Dom>
     class _RefFunClos;
+} // namespace __detail
+
+  using __detail::_UnClos;
+  using __detail::_BinClos;
+  using __detail::_SClos;
+  using __detail::_GClos;
+  using __detail::_IClos;
+  using __detail::_ValFunClos;
+  using __detail::_RefFunClos;
 
   template<class _Tp> class valarray;   // An array of type _Tp
   class slice;                          // BLAS-like slice out of an array
diff --git a/libstdc++-v3/testsuite/26_numerics/valarray/83860.cc b/libstdc++-v3/testsuite/26_numerics/valarray/83860.cc
new file mode 100644 (file)
index 0000000..6d82ef5
--- /dev/null
@@ -0,0 +1,110 @@
+// 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++11 } }
+
+#include <valarray>
+#include <testsuite_hooks.h>
+
+const std::valarray<int> v{
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+bool
+all_of(const std::valarray<bool>& vals)
+{
+  for (bool b : vals)
+    if (!b)
+      return false;
+  return true;
+}
+
+void
+test01()
+{
+  // PR libstdc++/83860
+  const std::valarray<int> va(v), vb(v), vc(v);
+  auto sum = va + vb + vc;
+  std::valarray<int> vsum = sum;
+  VERIFY( all_of( vsum == (3 * v) ) );
+}
+
+void
+test02()
+{
+  auto neg = -(-v);
+  std::valarray<int> vneg = neg;
+  VERIFY( all_of( vneg == v ) );
+}
+
+void
+test03()
+{
+  const std::valarray<int> va(v), vb(v);
+  auto diff = va + -vb;
+  std::valarray<int> vdiff = diff;
+  VERIFY( all_of( vdiff == (va - vb) ) );
+}
+
+void
+test04()
+{
+  const std::valarray<int> va(v), vb(v);
+  auto sum = -va + -vb;
+  std::valarray<int> vsum = sum;
+  VERIFY( all_of( vsum == (-2 * v) ) );
+}
+
+void
+test05()
+{
+  const std::valarray<int> va(v), vb(v);
+  auto sum = -(-va + -vb);
+  std::valarray<int> vsum = sum;
+  VERIFY( all_of( vsum == (2 * v) ) );
+}
+
+void
+test06()
+{
+  auto prod = 3 * +v * 2;
+  std::valarray<int> vprod = prod;
+  VERIFY( all_of( vprod == (6 * v) ) );
+}
+
+void
+test07()
+{
+  const std::valarray<int> va(v), vb(v);
+  auto valfun = [](int i) { return i; };
+  auto reffun = [](const int& i) { return i; };
+  auto sum = (va.apply(valfun) + vb.apply(reffun));
+  std::valarray<int> vsum = sum;
+  VERIFY( all_of( vsum == (va + vb) ) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+  test06();
+  test07();
+}