PR libstdc++/87544 limit max_size() to PTRDIFF_MAX / sizeof(T)

The C++17 standard requires the default implementation for
allocator_traits::max_size to return SIZE_MAX / sizeof(value_type).
That causes GCC to warn because the value could be larger than can
sensibly be passed to malloc. This patch changes the new_allocator and
malloc_allocator max_size() members to use PTRDIFF_MAX instead of
SIZE_MAX (and because they define it, the allocator_traits default isn't
used). This also changes vector::max_size to impose a sensible limit
using PTRDIFF_MAX for cases where the value from the allocator or
allocator_traits is not sensible.

	PR libstdc++/87544
	* include/bits/stl_vector.h (vector::_S_max_size): Limit size to
	PTRDIFF_MAX / sizeof(value_type).
	* include/ext/malloc_allocator.h (malloc_allocator::max_size):
	Likewise.
	* include/ext/new_allocator.h (new_allocator::max_size): Likewise.
	* testsuite/23_containers/vector/allocator/minimal.cc: Adjust
	expected value for max_size().
	* testsuite/23_containers/vector/capacity/87544.cc: New test.

From-SVN: r265021
This commit is contained in:
Jonathan Wakely 2018-10-10 16:39:33 +01:00 committed by Jonathan Wakely
parent d3a46ecb38
commit 422a9f7789
6 changed files with 105 additions and 4 deletions

View File

@ -1,3 +1,15 @@
2018-10-10 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/87544
* include/bits/stl_vector.h (vector::_S_max_size): Limit size to
PTRDIFF_MAX / sizeof(value_type).
* include/ext/malloc_allocator.h (malloc_allocator::max_size):
Likewise.
* include/ext/new_allocator.h (new_allocator::max_size): Likewise.
* testsuite/23_containers/vector/allocator/minimal.cc: Adjust
expected value for max_size().
* testsuite/23_containers/vector/capacity/87544.cc: New test.
2018-10-09 François Dumont <fdumont@gcc.gnu.org>
* include/bits/stl_list.h

View File

@ -1726,7 +1726,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
static size_type
_S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT
{
const size_t __diffmax = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max;
// std::distance(begin(), end()) cannot be greater than PTRDIFF_MAX,
// and realistically we can't store more than PTRDIFF_MAX/sizeof(T)
// (even if std::allocator_traits::max_size says we can).
const size_t __diffmax
= __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);
const size_t __allocmax = _Alloc_traits::max_size(__a);
return (std::min)(__diffmax, __allocmax);
}

View File

@ -139,7 +139,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
{
#if __PTRDIFF_MAX__ < __SIZE_MAX__
return size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
#else
return size_t(-1) / sizeof(_Tp);
#endif
}
#if __cplusplus >= 201103L
template<typename _Up, typename... _Args>

View File

@ -130,7 +130,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
size_type
max_size() const _GLIBCXX_USE_NOEXCEPT
{ return size_t(-1) / sizeof(_Tp); }
{
#if __PTRDIFF_MAX__ < __SIZE_MAX__
return size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
#else
return size_t(-1) / sizeof(_Tp);
#endif
}
#if __cplusplus >= 201103L
template<typename _Up, typename... _Args>

View File

@ -35,7 +35,7 @@ void test01()
typedef std::vector<T, alloc_type> test_type;
test_type v(alloc_type{});
v.push_back(T());
VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
VERIFY( v.max_size() <= traits_type::max_size(v.get_allocator()) );
}
int main()

View File

@ -0,0 +1,73 @@
// Copyright (C) 2018 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-options "-O2" }
// { dg-do compile { target c++11 } }
#include <cstdlib>
#include <vector>
template<class T>
struct Alloc : public std::allocator<T>
{
template<class U>
struct rebind { typedef Alloc<U> other; };
Alloc() : std::allocator<T>() {}
template<class U>
Alloc(const Alloc<U>& other) : std::allocator<T>(other) {}
T* allocate(std::size_t num, const void* = 0)
{
std::size_t size = num * sizeof(T);
void *result = std::malloc(size);
if(size>16 && (std::size_t(result) & 15)!=0) {
std::free(result);
return 0;
}
return static_cast<T*>( result );
}
void deallocate(T* p, std::size_t) { std::free(p); }
};
unsigned f(std::vector<int, Alloc<int> >& v)
{
v.push_back(1);
return v.size();
}
template<class T>
struct Alloc2 : public Alloc<T>
{
template<class U>
struct rebind { typedef Alloc2<U> other; };
Alloc2() : Alloc<T>() {}
template<class U>
Alloc2(const Alloc2<U>& other) : Alloc<T>(other) {}
std::size_t max_size() const { return std::size_t(-1) / sizeof(T); }
};
unsigned g(std::vector<int, Alloc2<int> >& v)
{
v.push_back(1);
return v.size();
}