[libcxx-commits] [libcxx] be10b1f - [libcxx] Make allocator<T>:allocate throw bad_array_new_length

Mikhail Maltsev via libcxx-commits libcxx-commits at lists.llvm.org
Mon Oct 18 11:13:37 PDT 2021


Author: Mikhail Maltsev
Date: 2021-10-18T19:12:42+01:00
New Revision: be10b1f1cc5fc621c378da97810ffc13b2a9af71

URL: https://github.com/llvm/llvm-project/commit/be10b1f1cc5fc621c378da97810ffc13b2a9af71
DIFF: https://github.com/llvm/llvm-project/commit/be10b1f1cc5fc621c378da97810ffc13b2a9af71.diff

LOG: [libcxx] Make allocator<T>:allocate throw bad_array_new_length

Currently the member functions std::allocator<T>::allocate,
std::experimental::pmr::polymorphic_allocator::allocate and
std::resource_adaptor<T>::do_allocate throw an exception of type
std::length_error when the requested size exceeds the maximum size.

According to the C++ standard ([allocator.members]/4,
[mem.poly.allocator.mem]/1), std::allocator<T>::allocate and
std::pmr::polymorphic_allocator::allocate must throw a
std::bad_array_new_length exception in this case.

The patch fixes the issue with std::allocator<T>::allocate and changes
the type the exception thrown by
std::experimental::pmr::resource_adaptor<T>::do_allocate to
std::bad_array_new_length as well for consistency.

The patch resolves LWG 3237, LWG 3038 and LWG 3190.

Reviewed By: ldionne, #libc, Quuxplusone

Differential Revision: https://reviews.llvm.org/D110846

Added: 
    

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Issues.csv
    libcxx/include/__memory/allocator.h
    libcxx/include/experimental/memory_resource
    libcxx/include/new
    libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
    libcxx/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp
    libcxx/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp
    libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 8d01a49a7efb9..7ad192361b09c 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -72,6 +72,12 @@ API Changes
   Calls to these functions where the template argument was deduced by the
   compiler are unaffected by this change.
 
+- The functions ``std::allocator<T>::allocate`` and
+  ``std::experimental::pmr::polymorphic_allocator<T>::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
index e2c994019424c..410cedcaa53de 100644
--- a/libcxx/docs/Status/Cxx20Issues.csv
+++ b/libcxx/docs/Status/Cxx20Issues.csv
@@ -108,7 +108,7 @@
 "`3025 <https://wg21.link/LWG3025>`__","Map-like container deduction guides should use ``pair<Key, T>``\ , not ``pair<const Key, T>``\ ","San Diego","|Complete|",""
 "`3031 <https://wg21.link/LWG3031>`__","Algorithms and predicates with non-const reference arguments","San Diego","",""
 "`3037 <https://wg21.link/LWG3037>`__","``polymorphic_allocator``\  and incomplete types","San Diego","",""
-"`3038 <https://wg21.link/LWG3038>`__","``polymorphic_allocator::allocate``\  should not allow integer overflow to create vulnerabilities","San Diego","",""
+"`3038 <https://wg21.link/LWG3038>`__","``polymorphic_allocator::allocate``\  should not allow integer overflow to create vulnerabilities","San Diego","|Complete|","14.0"
 "`3054 <https://wg21.link/LWG3054>`__","``uninitialized_copy``\  appears to not be able to meet its exception-safety guarantee","San Diego","",""
 "`3065 <https://wg21.link/LWG3065>`__","LWG 2989 missed that all ``path``\ 's other operators should be hidden friends as well","San Diego","|Complete|",""
 "`3096 <https://wg21.link/LWG3096>`__","``path::lexically_relative``\  is confused by trailing slashes","San Diego","|Complete|",""
@@ -162,7 +162,7 @@
 "","","","",""
 "`3231 <https://wg21.link/LWG3231>`__","``year_month_day_last::day``\  specification does not cover ``!ok()``\  values","Belfast","|Nothing To Do|",""
 "`3225 <https://wg21.link/LWG3225>`__","``zoned_time``\  converting constructor shall not be ``noexcept``\ ","Belfast","","","|chrono|"
-"`3190 <https://wg21.link/LWG3190>`__","``std::allocator::allocate``\  sometimes returns too little storage","Belfast","",""
+"`3190 <https://wg21.link/LWG3190>`__","``std::allocator::allocate``\  sometimes returns too little storage","Belfast","|Complete|","14.0"
 "`3218 <https://wg21.link/LWG3218>`__","Modifier for ``%d``\  parse flag does not match POSIX and ``format``\  specification","Belfast","","","|chrono| |format|"
 "`3224 <https://wg21.link/LWG3224>`__","``zoned_time``\  constructor from ``TimeZonePtr``\  does not specify initialization of ``tp_``\ ","Belfast","","","|chrono|"
 "`3230 <https://wg21.link/LWG3230>`__","Format specifier ``%y/%Y``\  is missing locale alternative versions","Belfast","","","|chrono| |format|"
@@ -200,7 +200,7 @@
 "`3201 <https://wg21.link/LWG3201>`__","``lerp``\  should be marked as ``noexcept``\ ","Prague","|Complete|",""
 "`3226 <https://wg21.link/LWG3226>`__","``zoned_time``\  constructor from ``string_view``\  should accept ``zoned_time<Duration2, TimeZonePtr2>``\ ","Prague","","","|chrono|"
 "`3233 <https://wg21.link/LWG3233>`__","Broken requirements for ``shared_ptr``\  converting constructors","Prague","",""
-"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","",""
+"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0"
 "`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\  deduction guides","Prague","",""
 "`3242 <https://wg21.link/LWG3242>`__","``std::format``\ : missing rules for ``arg-id``\  in ``width``\  and ``precision``\ ","Prague","|Complete|","Clang 14","|format|"
 "`3243 <https://wg21.link/LWG3243>`__","``std::format``\  and negative zeroes","Prague","","","|format|"

diff  --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h
index f99bee2b8f1b9..283212fb703dd 100644
--- a/libcxx/include/__memory/allocator.h
+++ b/libcxx/include/__memory/allocator.h
@@ -98,8 +98,7 @@ class _LIBCPP_TEMPLATE_VIS allocator
     _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     _Tp* allocate(size_t __n) {
         if (__n > allocator_traits<allocator>::max_size(*this))
-            __throw_length_error("allocator<T>::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 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
     _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     const _Tp* allocate(size_t __n) {
         if (__n > allocator_traits<allocator>::max_size(*this))
-            __throw_length_error("allocator<const T>::allocate(size_t n)"
-                                 " 'n' exceeds maximum supported size");
+            __throw_bad_array_new_length();
         if (__libcpp_is_constant_evaluated()) {
             return static_cast<const _Tp*>(::operator new(__n * sizeof(_Tp)));
         } else {

diff  --git a/libcxx/include/experimental/memory_resource b/libcxx/include/experimental/memory_resource
index 816d21f513681..75e502d78c2db 100644
--- a/libcxx/include/experimental/memory_resource
+++ b/libcxx/include/experimental/memory_resource
@@ -183,11 +183,8 @@ public:
     // 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<T>::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 @@ public:
 private:
     virtual void * do_allocate(size_t __bytes, size_t)
     {
-        if (__bytes > __max_size()) {
-            __throw_length_error(
-                "std::experimental::pmr::resource_adaptor<T>::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
index 2d1417a97586d..711b3ccd225fd 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -149,6 +149,16 @@ _LIBCPP_FUNC_VIS new_handler get_new_handler() _NOEXCEPT;
 
 _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
index 927b36f594511..fd20a7d97fda1 100644
--- 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
index 53c7c31443d34..779c0eb231c64 100644
--- 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 @@ void testAllocForSizeThrows() {
     size_t sizeTypeMax = std::numeric_limits<std::size_t>::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 @@ void testAllocForSizeThrows() {
         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
index 40ffbb1cbdbb1..3c17520aeff2e 100644
--- 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 @@ void check_alloc_max_size() {
         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
index 42013de1ccdf6..6b9b12c822424 100644
--- 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 @@ void test_max(size_t count)
     try {
         TEST_IGNORE_NODISCARD a.allocate(count);
         assert(false);
-    } catch (const std::exception &) {
+    } catch (const std::bad_array_new_length &) {
     }
 }
 


        


More information about the libcxx-commits mailing list