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.
This commit is contained in:
parent
717e402dbf
commit
f92a504fdd
|
@ -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.
|
||||
|
|
|
@ -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__));
|
||||
|
|
|
@ -102,8 +102,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_Tp*
|
||||
allocate(size_type __n, const void* = 0)
|
||||
{
|
||||
if (__n > this->_M_max_size())
|
||||
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
|
||||
|
|
|
@ -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())
|
||||
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__)
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__throw_bad_alloc()
|
||||
{ _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()); }
|
||||
|
|
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue