[gcc/devel/omp/gcc-9] PR libstdc++/89164 enforce constraints for uninitialized algos

Tobias Burnus burnus@gcc.gnu.org
Thu Mar 5 14:15:00 GMT 2020


https://gcc.gnu.org/g:f061d690d8e15512540127dd43eb6f0bcf37cbb3

commit f061d690d8e15512540127dd43eb6f0bcf37cbb3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 24 13:54:58 2019 +0100

    PR libstdc++/89164 enforce constraints for uninitialized algos
    
    The memmove optimizations for std::uninitialized_copy/fill/_n will
    compile even if the type is not copy constructible, because std::copy
    doesn't require copy construction to work. But the uninitialized
    algorithms do require it.
    
    This adds explicit static assertions to ensure we don't allow ill-formed
    initializations.
    
    Backport from mainline
    2019-08-30  Jonathan Wakely  <jwakely@redhat.com>
    
    	PR libstdc++/89164
    	* include/bits/stl_algobase.h (__copy_move): Give descriptive names
    	to template parameters.
    	* include/bits/stl_uninitialized.h (uninitialized_copy)
    	(uninitialized_fill, uninitialized_fill_n): Add static assertions to
    	diagnose invalid uses.
    	* testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc:
    	Adjust expected error.
    	* testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc:
    	New test.
    	* testsuite/20_util/specialized_algorithms/uninitialized_copy_n/
    	89164.cc: New test.
    	* testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc:
    	New test.
    	* testsuite/20_util/specialized_algorithms/uninitialized_fill_n/
    	89164.cc: New test.
    	* testsuite/23_containers/vector/cons/89164.cc: New test.
    	* testsuite/23_containers/vector/cons/89164_c++17.cc: New test.
    
    From-SVN: r277388

Diff:
---
 libstdc++-v3/ChangeLog                             | 22 ++++++++++
 libstdc++-v3/include/bits/stl_algobase.h           |  2 +-
 libstdc++-v3/include/bits/stl_uninitialized.h      | 24 +++++++++--
 .../specialized_algorithms/uninitialized_copy/1.cc |  2 +-
 .../uninitialized_copy/89164.cc                    | 38 ++++++++++++++++
 .../uninitialized_copy_n/89164.cc                  | 35 +++++++++++++++
 .../uninitialized_fill/89164.cc                    | 35 +++++++++++++++
 .../uninitialized_fill_n/89164.cc                  | 35 +++++++++++++++
 .../testsuite/23_containers/vector/cons/89164.cc   | 40 +++++++++++++++++
 .../23_containers/vector/cons/89164_c++17.cc       | 50 ++++++++++++++++++++++
 10 files changed, 278 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index fe6c649..65b3873 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,6 +1,28 @@
 2019-10-24  Jonathan Wakely  <jwakely@redhat.com>
 
 	Backport from mainline
+	2019-08-30  Jonathan Wakely  <jwakely@redhat.com>
+
+	PR libstdc++/89164
+	* include/bits/stl_algobase.h (__copy_move): Give descriptive names
+	to template parameters.
+	* include/bits/stl_uninitialized.h (uninitialized_copy)
+	(uninitialized_fill, uninitialized_fill_n): Add static assertions to
+	diagnose invalid uses.
+	* testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc:
+	Adjust expected error.
+	* testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc:
+	New test.
+	* testsuite/20_util/specialized_algorithms/uninitialized_copy_n/
+	89164.cc: New test.
+	* testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc:
+	New test.
+	* testsuite/20_util/specialized_algorithms/uninitialized_fill_n/
+	89164.cc: New test.
+	* testsuite/23_containers/vector/cons/89164.cc: New test.
+	* testsuite/23_containers/vector/cons/89164_c++17.cc: New test.
+
+	Backport from mainline
 	2019-10-22  Jonathan Wakely  <jwakely@redhat.com>
 
 	* include/bits/memoryfwd.h (uses_allocator): Do not declare for C++98.
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index 3b11394..6e9316a 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -301,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // (2) If we're using random access iterators, then write the loop as
   // a for loop with an explicit count.
 
-  template<bool, bool, typename>
+  template<bool _IsMove, bool _IsSimple, typename _Category>
     struct __copy_move
     {
       template<typename _II, typename _OI>
diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h
index 0d42b25..f5ca743 100644
--- a/libstdc++-v3/include/bits/stl_uninitialized.h
+++ b/libstdc++-v3/include/bits/stl_uninitialized.h
@@ -122,9 +122,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus < 201103L
       const bool __assignable = true;
 #else
-      // trivial types can have deleted assignment
+      // Trivial types can have deleted copy constructor, but the std::copy
+      // optimization that uses memmove would happily "copy" them anyway.
+      static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
+	  "result type must be constructible from value type of input range");
+
       typedef typename iterator_traits<_InputIterator>::reference _RefType1;
       typedef typename iterator_traits<_ForwardIterator>::reference _RefType2;
+      // Trivial types can have deleted assignment, so using std::copy
+      // would be ill-formed. Require assignability before using std::copy:
       const bool __assignable = is_assignable<_RefType2, _RefType1>::value;
 #endif
 
@@ -186,7 +192,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus < 201103L
       const bool __assignable = true;
 #else
-      // trivial types can have deleted assignment
+      // Trivial types can have deleted copy constructor, but the std::fill
+      // optimization that uses memmove would happily "copy" them anyway.
+      static_assert(is_constructible<_ValueType, const _Tp&>::value,
+	  "result type must be constructible from input type");
+
+      // Trivial types can have deleted assignment, so using std::fill
+      // would be ill-formed. Require assignability before using std::fill:
       const bool __assignable = is_copy_assignable<_ValueType>::value;
 #endif
 
@@ -248,7 +260,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus < 201103L
       const bool __assignable = true;
 #else
-      // trivial types can have deleted assignment
+      // Trivial types can have deleted copy constructor, but the std::fill
+      // optimization that uses memmove would happily "copy" them anyway.
+      static_assert(is_constructible<_ValueType, const _Tp&>::value,
+	  "result type must be constructible from input type");
+
+      // Trivial types can have deleted assignment, so using std::fill
+      // would be ill-formed. Require assignability before using std::fill:
       const bool __assignable = is_copy_assignable<_ValueType>::value;
 #endif
       return __uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>::
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc
index d3b8210..22b9805 100644
--- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/1.cc
@@ -34,4 +34,4 @@ test01(T* result)
   T t[1];
   std::uninitialized_copy(t, t+1, result); // { dg-error "here" }
 }
-// { dg-prune-output "use of deleted function" }
+// { dg-error "constructible from value" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc
new file mode 100644
index 0000000..fa1ae59
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy/89164.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2019 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 compile { target c++11 } }
+
+#include <vector>
+
+// PR libstdc++/89164
+
+struct X
+{
+  X() = default;
+  X(const X&) = delete;
+};
+
+void test01()
+{
+  X x[1];
+  alignas(X) unsigned char buf[sizeof(X)];
+  X* p = (X*)buf;
+
+  std::uninitialized_copy(x, x+1, p); // { dg-error "here" }
+}
+// { dg-error "must be constructible" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc
new file mode 100644
index 0000000..361a798
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_copy_n/89164.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 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 compile { target c++11 } }
+
+#include <vector>
+
+struct X {
+  X() = default;
+  X(const X&) = delete;
+};
+
+void test01()
+{
+  X x[1];
+  alignas(X) unsigned char buf[sizeof(X)];
+  X* p = (X*)buf;
+
+  std::uninitialized_copy_n(x, 1, p); // { dg-error "here" }
+}
+// { dg-error "must be constructible" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc
new file mode 100644
index 0000000..8634c80
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill/89164.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 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 compile { target c++11 } }
+
+#include <vector>
+
+struct X {
+  X() = default;
+  X(const X&) = delete;
+};
+
+void f()
+{
+  X x;
+  alignas(X) unsigned char buf[sizeof(X)];
+  X* p = (X*)buf;
+
+  std::uninitialized_fill(p, p+1, x); // { dg-error "here" }
+}
+// { dg-error "must be constructible" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc
new file mode 100644
index 0000000..a2d7dc7
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/uninitialized_fill_n/89164.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 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 compile { target c++11 } }
+
+#include <vector>
+
+struct X {
+  X() = default;
+  X(const X&) = delete;
+};
+
+void test01()
+{
+  X x;
+  alignas(X) unsigned char buf[sizeof(X)];
+  X* p = (X*)buf;
+
+  std::uninitialized_fill_n(p, 1, x); // { dg-error "here" }
+}
+// { dg-error "must be constructible" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc
new file mode 100644
index 0000000..e280731
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2019 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 compile { target c++11 } }
+
+#include <vector>
+
+// PR libstdc++/89164
+
+struct X
+{
+  X() = default;
+  X(const X&) = delete;
+};
+
+void test01()
+{
+  X x[1];
+  // Should not be able to create vector using uninitialized_copy:
+  std::vector<X> v1{x, x+1};	// { dg-error "here" }
+
+  // Should not be able to create vector using uninitialized_fill_n:
+  std::vector<X> v2{2u, X{}};	// { dg-error "here" }
+}
+// { dg-error "constructible from value" "" { target *-*-* } 0 }
+// { dg-error "constructible from input" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc
new file mode 100644
index 0000000..db7d8d5
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc
@@ -0,0 +1,50 @@
+// Copyright (C) 2019 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 "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <vector>
+
+// PR libstdc++/89164
+
+struct X
+{
+  X() = default;
+  X(const X&) = delete;
+};
+
+void test01()
+{
+  X x[1];
+  // Should not be able to create vector using uninitialized_copy:
+  std::vector<X> v1{x, x+1};	// { dg-error "here" }
+
+  // Should not be able to create vector using uninitialized_fill_n:
+  std::vector<X> v2{2u, X{}};	// { dg-error "here" }
+}
+
+void test02()
+{
+#if __cplusplus >= 201703L
+  // Can create initializer_list<X> with C++17 guaranteed copy elision,
+  // but shouldn't be able to copy from it with uninitialized_copy:
+  std::vector<X> v3{X{}, X{}, X{}};   // { dg-error "here" }
+#endif
+}
+// { dg-error "constructible from value" "" { target *-*-* } 0 }
+// { dg-error "constructible from input" "" { target *-*-* } 0 }



More information about the Libstdc++-cvs mailing list