PR 72847 Prevent double-free in std::vector<bool>
authorJonathan Wakely <jwakely@redhat.com>
Tue, 16 Aug 2016 11:33:16 +0000 (12:33 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Tue, 16 Aug 2016 11:33:16 +0000 (12:33 +0100)
PR libstdc++/72847
* include/bits/stl_bvector.h (_Bvector_base::_M_deallocate): Zero
pointers to start and end of storage.
* testsuite/23_containers/vector/bool/72847.cc: New test.
* include/bits/vector.tcc (vector<bool>::_M_reallocate): Only update
_M_finish after deallocating.
(vector<bool>::_M_fill_insert): Likewise.
(vector<bool>::_M_insert_range): Likewise.
(vector<bool>::_M_insert_aux): Likewise.

From-SVN: r239497

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_bvector.h
libstdc++-v3/include/bits/vector.tcc
libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc [new file with mode: 0644]

index 73ddaac385d54e34c96cf9c695c2c824171f4a1d..a7689f451f50502eacf60b5e2b3b2d91f97eb581 100644 (file)
@@ -1,3 +1,15 @@
+2016-08-16  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/72847
+       * include/bits/stl_bvector.h (_Bvector_base::_M_deallocate): Zero
+       pointers to start and end of storage.
+       * testsuite/23_containers/vector/bool/72847.cc: New test.
+       * include/bits/vector.tcc (vector<bool>::_M_reallocate): Only update
+       _M_finish after deallocating.
+       (vector<bool>::_M_fill_insert): Likewise.
+       (vector<bool>::_M_insert_range): Likewise.
+       (vector<bool>::_M_insert_aux): Likewise.
+
 2016-08-15  Ville Voutilainen  <ville.voutilainen@gmail.com>
 
        Implement LWG 2744 and LWG 2754.
index 629fe4dd902554687bb15bda5627b93482ef1c12..b3ac63f521fdc834063da1bdc2356f2a1842bf69 100644 (file)
@@ -500,6 +500,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
            _Bit_alloc_traits::deallocate(_M_impl,
                                          _M_impl._M_end_of_storage - __n,
                                          __n);
+           _M_impl._M_start = _M_impl._M_finish = _Bit_iterator();
+           _M_impl._M_end_of_storage = _Bit_pointer();
          }
       }
 
index 9717b74a9781f8f39bc6247060586e1641167159..6926a8b91c4d23968fab78d154a40e6522d1813f 100644 (file)
@@ -708,9 +708,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       _Bit_pointer __q = this->_M_allocate(__n);
       iterator __start(std::__addressof(*__q), 0);
-      this->_M_impl._M_finish = _M_copy_aligned(begin(), end(), __start);
+      iterator __finish(_M_copy_aligned(begin(), end(), __start));
       this->_M_deallocate();
       this->_M_impl._M_start = __start;
+      this->_M_impl._M_finish = __finish;
       this->_M_impl._M_end_of_storage = __q + _S_nword(__n);
     }
 
@@ -736,11 +737,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          iterator __start(std::__addressof(*__q), 0);
          iterator __i = _M_copy_aligned(begin(), __position, __start);
          std::fill(__i, __i + difference_type(__n), __x);
-         this->_M_impl._M_finish = std::copy(__position, end(),
-                                             __i + difference_type(__n));
+         iterator __finish = std::copy(__position, end(),
+                                       __i + difference_type(__n));
          this->_M_deallocate();
          this->_M_impl._M_end_of_storage = __q + _S_nword(__len);
          this->_M_impl._M_start = __start;
+         this->_M_impl._M_finish = __finish;
        }
     }
 
@@ -770,10 +772,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
                iterator __start(std::__addressof(*__q), 0);
                iterator __i = _M_copy_aligned(begin(), __position, __start);
                __i = std::copy(__first, __last, __i);
-               this->_M_impl._M_finish = std::copy(__position, end(), __i);
+               iterator __finish = std::copy(__position, end(), __i);
                this->_M_deallocate();
                this->_M_impl._M_end_of_storage = __q + _S_nword(__len);
                this->_M_impl._M_start = __start;
+               this->_M_impl._M_finish = __finish;
              }
          }
       }
@@ -798,10 +801,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
          iterator __start(std::__addressof(*__q), 0);
          iterator __i = _M_copy_aligned(begin(), __position, __start);
          *__i++ = __x;
-         this->_M_impl._M_finish = std::copy(__position, end(), __i);
+         iterator __finish = std::copy(__position, end(), __i);
          this->_M_deallocate();
          this->_M_impl._M_end_of_storage = __q + _S_nword(__len);
          this->_M_impl._M_start = __start;
+         this->_M_impl._M_finish = __finish;
        }
     }
 
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc
new file mode 100644 (file)
index 0000000..7bd8b39
--- /dev/null
@@ -0,0 +1,49 @@
+// 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-require-cstdint "" }
+// { dg-skip-if "" { *-*-* } { "-fno-exceptions" } }
+
+#include <vector>
+#include <ext/throw_allocator.h>
+#include <testsuite_hooks.h>
+
+// PR libstdc++/72847
+void
+test01()
+{
+  bool test __attribute((unused)) = true;
+
+  typedef bool value_type;
+  typedef __gnu_cxx::throw_allocator_limit<value_type> allocator_type;
+  typedef std::vector<value_type, allocator_type> test_type;
+  test_type v1(1, false);
+  test_type v2(v1.capacity()+1, false);
+  allocator_type::set_limit(0);
+  try {
+    v1 = v2;
+  } catch (const __gnu_cxx::forced_error&) {
+  }
+  // throw_allocator will throw if double-free happens
+}
+
+// Container requirement testing, exceptional behavior
+int main()
+{
+  test01();
+  return 0;
+}