[libcxx-commits] [libcxx] 05a2d17 - [libcxx] Throw correct exception from std::vector::reserve

Mikhail Maltsev via libcxx-commits libcxx-commits at lists.llvm.org
Thu Oct 21 02:41:16 PDT 2021


Author: Mikhail Maltsev
Date: 2021-10-21T10:40:48+01:00
New Revision: 05a2d1766864f60210d8f337a7ea709fa0707b53

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

LOG: [libcxx] Throw correct exception from std::vector::reserve

According to the standard [vector.capacity]/5, std::vector<T>::reserve
shall throw an exception of type std::length_error when the requested
capacity exceeds max_size().

This behavior is not implemented correctly: the function 'reserve'
simply propagates the exception from allocator<T>::allocate. Before
D110846 that exception used to be of type std::length_error (which is
correct for vector<T>::reserve, but incorrect for
allocator<T>::allocate).

This patch fixes the issue and adds regression tests.

Reviewed By: Quuxplusone, ldionne, #libc

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

Added: 
    

Modified: 
    libcxx/include/vector
    libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
    libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/vector b/libcxx/include/vector
index eeca81dfabc1..c9b121b3177d 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -1590,6 +1590,8 @@ vector<_Tp, _Allocator>::reserve(size_type __n)
 {
     if (__n > capacity())
     {
+        if (__n > max_size())
+            this->__throw_length_error();
         allocator_type& __a = this->__alloc();
         __split_buffer<value_type, allocator_type&> __v(__n, size(), __a);
         __swap_out_circular_buffer(__v);
@@ -3018,6 +3020,8 @@ vector<bool, _Allocator>::reserve(size_type __n)
 {
     if (__n > capacity())
     {
+        if (__n > max_size())
+            this->__throw_length_error();
         vector __v(this->get_allocator());
         __v.__vallocate(__n);
         __v.__construct_at_end(this->begin(), this->end());

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
index c36a779bdc14..e1f2344bdff1 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp
@@ -16,6 +16,7 @@
 
 #include "test_macros.h"
 #include "min_allocator.h"
+#include "test_allocator.h"
 
 int main(int, char**)
 {
@@ -56,6 +57,23 @@ int main(int, char**)
         assert(v.capacity() >= 150);
     }
 #endif
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    {
+        std::vector<bool, limited_allocator<bool, 10> > v;
+        v.reserve(5);
+        try {
+            // A typical implementation would allocate chunks of bits.
+            // In libc++ the chunk has the same size as the machine word. It is
+            // reasonable to assume that in practice no implementation would use
+            // 64 kB or larger chunks.
+            v.reserve(10 * 65536);
+            assert(false);
+        } catch (const std::length_error&) {
+            // no-op
+        }
+        assert(v.capacity() >= 5);
+    }
+#endif
 
   return 0;
 }

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
index 78cfcc3422cb..378a67c96ce5 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
@@ -67,6 +67,22 @@ int main(int, char**)
         assert(is_contiguous_container_asan_correct(v));
     }
 #endif
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    {
+        std::vector<int, limited_allocator<int, 100> > v;
+        v.reserve(50);
+        assert(v.capacity() == 50);
+        assert(is_contiguous_container_asan_correct(v));
+        try {
+            v.reserve(101);
+            assert(false);
+        } catch (const std::length_error&) {
+            // no-op
+        }
+        assert(v.capacity() == 50);
+        assert(is_contiguous_container_asan_correct(v));
+    }
+#endif
 
   return 0;
 }


        


More information about the libcxx-commits mailing list