diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-10-05 15:16:58 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-10-05 15:18:56 +0100 |
commit | f92a504fdd943527687faf9557e0b39ff7fe6125 (patch) | |
tree | 007b6dfe3b0578c5f19eff0875b9725996def695 | |
parent | 717e402dbf55e7da83d4fc87641ab9e60d4846cb (diff) | |
download | gcc-f92a504fdd943527687faf9557e0b39ff7fe6125.zip gcc-f92a504fdd943527687faf9557e0b39ff7fe6125.tar.gz gcc-f92a504fdd943527687faf9557e0b39ff7fe6125.tar.bz2 |
libstdc++: Make allocators throw bad_array_new_length on overflow [LWG 3190]
std::allocator and std::pmr::polymorphic_allocator should throw
std::bad_array_new_length from their allocate member functions if the
number of bytes required cannot be represented in std::size_t.
libstdc++-v3/ChangeLog:
* config/abi/pre/gnu.ver: Add new symbol.
* include/bits/functexcept.h (__throw_bad_array_new_length):
Declare new function.
* include/ext/malloc_allocator.h (malloc_allocator::allocate):
Throw bad_array_new_length for impossible sizes (LWG 3190).
* include/ext/new_allocator.h (new_allocator::allocate):
Likewise.
* include/std/memory_resource (polymorphic_allocator::allocate)
(polymorphic_allocator::allocate_object): Use new function,
__throw_bad_array_new_length.
* src/c++11/functexcept.cc (__throw_bad_array_new_length):
Define.
* testsuite/20_util/allocator/lwg3190.cc: New test.
-rw-r--r-- | libstdc++-v3/config/abi/pre/gnu.ver | 3 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/functexcept.h | 3 | ||||
-rw-r--r-- | libstdc++-v3/include/ext/malloc_allocator.h | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/ext/new_allocator.h | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/std/memory_resource | 6 | ||||
-rw-r--r-- | libstdc++-v3/src/c++11/functexcept.cc | 4 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/allocator/lwg3190.cc | 53 |
7 files changed, 82 insertions, 7 deletions
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 87a48a2..6a2b2da 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -2322,6 +2322,9 @@ GLIBCXX_3.4.29 { # std::__atomic_futex_unsigned_base::_M_futex_wait_until_steady _ZNSt28__atomic_futex_unsigned_base26_M_futex_wait_until_steady*; + # std::__throw_bad_array_new_length() + _ZSt28__throw_bad_array_new_lengthv; + } GLIBCXX_3.4.28; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/include/bits/functexcept.h b/libstdc++-v3/include/bits/functexcept.h index 52eef2b..f6079e2 100644 --- a/libstdc++-v3/include/bits/functexcept.h +++ b/libstdc++-v3/include/bits/functexcept.h @@ -51,6 +51,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __throw_bad_alloc(void) __attribute__((__noreturn__)); + void + __throw_bad_array_new_length(void) __attribute__((__noreturn__)); + // Helper for exception objects in <typeinfo> void __throw_bad_cast(void) __attribute__((__noreturn__)); diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h index 366c766..dd45470 100644 --- a/libstdc++-v3/include/ext/malloc_allocator.h +++ b/libstdc++-v3/include/ext/malloc_allocator.h @@ -102,8 +102,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Tp* allocate(size_type __n, const void* = 0) { - if (__n > this->_M_max_size()) - std::__throw_bad_alloc(); + if (__builtin_expect(__n > this->_M_max_size(), false)) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3190. allocator::allocate sometimes returns too little storage + if (__n > (std::size_t(-1) / sizeof(_Tp))) + std::__throw_bad_array_new_length(); + std::__throw_bad_alloc(); + } _Tp* __ret = 0; #if __cpp_aligned_new diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 2e21a98..a43c8d9 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -102,8 +102,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD _Tp* allocate(size_type __n, const void* = static_cast<const void*>(0)) { - if (__n > this->_M_max_size()) - std::__throw_bad_alloc(); + if (__builtin_expect(__n > this->_M_max_size(), false)) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3190. allocator::allocate sometimes returns too little storage + if (__n > (std::size_t(-1) / sizeof(_Tp))) + std::__throw_bad_array_new_length(); + std::__throw_bad_alloc(); + } #if __cpp_aligned_new if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index 3db2297..6491179 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -168,8 +168,8 @@ namespace pmr allocate(size_t __n) __attribute__((__returns_nonnull__)) { - if (__n > (__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp))) - _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); + if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n) + std::__throw_bad_array_new_length(); return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), alignof(_Tp))); } @@ -195,7 +195,7 @@ namespace pmr allocate_object(size_t __n = 1) { if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n) - _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); + std::__throw_bad_array_new_length(); return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), alignof(_Up))); } diff --git a/libstdc++-v3/src/c++11/functexcept.cc b/libstdc++-v3/src/c++11/functexcept.cc index d43167d..b5da174 100644 --- a/libstdc++-v3/src/c++11/functexcept.cc +++ b/libstdc++-v3/src/c++11/functexcept.cc @@ -54,6 +54,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _GLIBCXX_THROW_OR_ABORT(bad_alloc()); } void + __throw_bad_array_new_length() + { _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); } + + void __throw_bad_cast() { _GLIBCXX_THROW_OR_ABORT(bad_cast()); } diff --git a/libstdc++-v3/testsuite/20_util/allocator/lwg3190.cc b/libstdc++-v3/testsuite/20_util/allocator/lwg3190.cc new file mode 100644 index 0000000..955f05b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/lwg3190.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2020 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 <memory> +#include <new> +#include <limits> +#include <testsuite_hooks.h> + +// LWG 3190. std::allocator::allocate sometimes returns too little storage + +void +test01() +{ + struct A { char biiiiig[1 << 16]; }; + std::allocator<A> a; + try + { + std::size_t max = std::numeric_limits<std::size_t>::max() / sizeof(A); + A* p = a.allocate(max + 1); + throw p; + } +#if __cplusplus >= 201103L + catch (const std::bad_array_new_length&) + { + } +#endif + catch (const std::bad_alloc&) + { + VERIFY( __cplusplus < 201103L ); + } +} + +int +main() +{ + test01(); +} |