Skip to content

Commit

Permalink
libstdc++: Make allocators throw bad_array_new_length on overflow [LW…
Browse files Browse the repository at this point in the history
…G 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.
  • Loading branch information
jwakely committed Oct 5, 2020
1 parent 717e402 commit f92a504
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 7 deletions.
3 changes: 3 additions & 0 deletions libstdc++-v3/config/abi/pre/gnu.ver
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions libstdc++-v3/include/bits/functexcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__));
Expand Down
10 changes: 8 additions & 2 deletions libstdc++-v3/include/ext/malloc_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions libstdc++-v3/include/ext/new_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down
6 changes: 3 additions & 3 deletions libstdc++-v3/include/std/memory_resource
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}
Expand All @@ -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)));
}
Expand Down
4 changes: 4 additions & 0 deletions libstdc++-v3/src/c++11/functexcept.cc
Original file line number Diff line number Diff line change
Expand 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()); }
Expand Down
53 changes: 53 additions & 0 deletions libstdc++-v3/testsuite/20_util/allocator/lwg3190.cc
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit f92a504

Please sign in to comment.