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:
Jonathan Wakely 2020-10-05 15:16:58 +01:00
parent 717e402dbf
commit f92a504fdd
7 changed files with 82 additions and 7 deletions

View File

@ -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.

View File

@ -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__));

View File

@ -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

View File

@ -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__)

View File

@ -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)));
}

View File

@ -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()); }

View File

@ -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();
}