diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -72,6 +72,12 @@ Calls to these functions where the template argument was deduced by the compiler are unaffected by this change. +- The functions ``std::allocator::allocate`` and + ``std::experimental::pmr::polymorphic_allocator::allocate`` now throw + an exception of type ``std::bad_array_new_length`` when the requested size + exceeds the maximum supported size, as required by the C++ standard. + Previously the type ``std::length_error`` was used. + Build System Changes -------------------- diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -108,7 +108,7 @@ "`3025 `__","Map-like container deduction guides should use ``pair``\ , not ``pair``\ ","San Diego","|Complete|","" "`3031 `__","Algorithms and predicates with non-const reference arguments","San Diego","","" "`3037 `__","``polymorphic_allocator``\ and incomplete types","San Diego","","" -"`3038 `__","``polymorphic_allocator::allocate``\ should not allow integer overflow to create vulnerabilities","San Diego","","" +"`3038 `__","``polymorphic_allocator::allocate``\ should not allow integer overflow to create vulnerabilities","San Diego","|Complete|","14.0" "`3054 `__","``uninitialized_copy``\ appears to not be able to meet its exception-safety guarantee","San Diego","","" "`3065 `__","LWG 2989 missed that all ``path``\ 's other operators should be hidden friends as well","San Diego","|Complete|","" "`3096 `__","``path::lexically_relative``\ is confused by trailing slashes","San Diego","|Complete|","" @@ -162,7 +162,7 @@ "","","","","" "`3231 `__","``year_month_day_last::day``\ specification does not cover ``!ok()``\ values","Belfast","|Nothing To Do|","" "`3225 `__","``zoned_time``\ converting constructor shall not be ``noexcept``\ ","Belfast","","","|chrono|" -"`3190 `__","``std::allocator::allocate``\ sometimes returns too little storage","Belfast","","" +"`3190 `__","``std::allocator::allocate``\ sometimes returns too little storage","Belfast","|Complete|","14.0" "`3218 `__","Modifier for ``%d``\ parse flag does not match POSIX and ``format``\ specification","Belfast","","","|chrono| |format|" "`3224 `__","``zoned_time``\ constructor from ``TimeZonePtr``\ does not specify initialization of ``tp_``\ ","Belfast","","","|chrono|" "`3230 `__","Format specifier ``%y/%Y``\ is missing locale alternative versions","Belfast","","","|chrono| |format|" @@ -200,7 +200,7 @@ "`3201 `__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|","" "`3226 `__","``zoned_time``\ constructor from ``string_view``\ should accept ``zoned_time``\ ","Prague","","","|chrono|" "`3233 `__","Broken requirements for ``shared_ptr``\ converting constructors","Prague","","" -"`3237 `__","LWG 3038 and 3190 have inconsistent PRs","Prague","","" +"`3237 `__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0" "`3238 `__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","","" "`3242 `__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","Clang 14","|format|" "`3243 `__","``std::format``\ and negative zeroes","Prague","","","|format|" diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h --- a/libcxx/include/__memory/allocator.h +++ b/libcxx/include/__memory/allocator.h @@ -98,8 +98,7 @@ _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _Tp* allocate(size_t __n) { if (__n > allocator_traits::max_size(*this)) - __throw_length_error("allocator::allocate(size_t n)" - " 'n' exceeds maximum supported size"); + __throw_bad_array_new_length(); if (__libcpp_is_constant_evaluated()) { return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); } else { @@ -181,8 +180,7 @@ _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 const _Tp* allocate(size_t __n) { if (__n > allocator_traits::max_size(*this)) - __throw_length_error("allocator::allocate(size_t n)" - " 'n' exceeds maximum supported size"); + __throw_bad_array_new_length(); if (__libcpp_is_constant_evaluated()) { return static_cast(::operator new(__n * sizeof(_Tp))); } else { diff --git a/libcxx/include/experimental/memory_resource b/libcxx/include/experimental/memory_resource --- a/libcxx/include/experimental/memory_resource +++ b/libcxx/include/experimental/memory_resource @@ -183,11 +183,8 @@ // 8.6.3, memory.polymorphic.allocator.mem _LIBCPP_INLINE_VISIBILITY _ValueType* allocate(size_t __n) { - if (__n > __max_size()) { - __throw_length_error( - "std::experimental::pmr::polymorphic_allocator::allocate(size_t n)" - " 'n' exceeds maximum supported size"); - } + if (__n > __max_size()) + __throw_bad_array_new_length(); return static_cast<_ValueType*>( __res_->allocate(__n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType)) ); @@ -384,11 +381,8 @@ private: virtual void * do_allocate(size_t __bytes, size_t) { - if (__bytes > __max_size()) { - __throw_length_error( - "std::experimental::pmr::resource_adaptor::do_allocate(size_t bytes, size_t align)" - " 'bytes' exceeds maximum supported size"); - } + if (__bytes > __max_size()) + __throw_bad_array_new_length(); size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; return __alloc_.allocate(__s); } diff --git a/libcxx/include/new b/libcxx/include/new --- a/libcxx/include/new +++ b/libcxx/include/new @@ -149,6 +149,16 @@ _LIBCPP_NORETURN _LIBCPP_FUNC_VIS void __throw_bad_alloc(); // not in C++ spec +_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY +void __throw_bad_array_new_length() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw bad_array_new_length(); +#else + _VSTD::abort(); +#endif +} + #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) && \ !defined(_LIBCPP_ABI_VCRUNTIME) #ifndef _LIBCPP_CXX03_LANG diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist --- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist +++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist @@ -7,6 +7,8 @@ {'is_defined': False, 'name': '_ZNSt13runtime_errorD2Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt14overflow_errorD1Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt16invalid_argumentD1Ev', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZNSt20bad_array_new_lengthC1Ev', 'type': 'FUNC'} +{'is_defined': False, 'name': '_ZNSt20bad_array_new_lengthD1Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt8bad_castC1Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt8bad_castD1Ev', 'type': 'FUNC'} {'is_defined': False, 'name': '_ZNSt8bad_castD2Ev', 'type': 'FUNC'} @@ -20,6 +22,7 @@ {'is_defined': False, 'name': '_ZTISt13runtime_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTISt14overflow_error', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTISt16invalid_argument', 'size': 0, 'type': 'OBJECT'} +{'is_defined': False, 'name': '_ZTISt20bad_array_new_length', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTISt8bad_cast', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTISt9bad_alloc', 'size': 0, 'type': 'OBJECT'} {'is_defined': False, 'name': '_ZTISt9exception', 'size': 0, 'type': 'OBJECT'} diff --git a/libcxx/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp b/libcxx/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp --- a/libcxx/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp +++ b/libcxx/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp @@ -61,11 +61,11 @@ size_t sizeTypeMax = std::numeric_limits::max(); if (maxSize != sizeTypeMax) { - // Test that allocating size_t(~0) throws bad alloc. + // Test that allocating size_t(~0) throws bad_array_new_length. try { a.allocate(sizeTypeMax); assert(false); - } catch (std::exception const&) { + } catch (std::bad_array_new_length const&) { } // Test that allocating even one more than the max size does throw. @@ -73,7 +73,7 @@ try { a.allocate(overSize); assert(false); - } catch (std::exception const&) { + } catch (std::bad_array_new_length const&) { } } } diff --git a/libcxx/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp b/libcxx/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp --- a/libcxx/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp +++ b/libcxx/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp @@ -99,7 +99,7 @@ try { m1.allocate(size); assert(false); - } catch (std::exception const&) { + } catch (std::bad_array_new_length const&) { } } #endif diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp @@ -24,7 +24,7 @@ try { TEST_IGNORE_NODISCARD a.allocate(count); assert(false); - } catch (const std::exception &) { + } catch (const std::bad_array_new_length &) { } }