Skip to content

Commit 05a2d17

Browse files
committed
[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
1 parent 49be23a commit 05a2d17

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

libcxx/include/vector

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,8 @@ vector<_Tp, _Allocator>::reserve(size_type __n)
15901590
{
15911591
if (__n > capacity())
15921592
{
1593+
if (__n > max_size())
1594+
this->__throw_length_error();
15931595
allocator_type& __a = this->__alloc();
15941596
__split_buffer<value_type, allocator_type&> __v(__n, size(), __a);
15951597
__swap_out_circular_buffer(__v);
@@ -3018,6 +3020,8 @@ vector<bool, _Allocator>::reserve(size_type __n)
30183020
{
30193021
if (__n > capacity())
30203022
{
3023+
if (__n > max_size())
3024+
this->__throw_length_error();
30213025
vector __v(this->get_allocator());
30223026
__v.__vallocate(__n);
30233027
__v.__construct_at_end(this->begin(), this->end());

libcxx/test/std/containers/sequences/vector.bool/reserve.pass.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "test_macros.h"
1818
#include "min_allocator.h"
19+
#include "test_allocator.h"
1920

2021
int main(int, char**)
2122
{
@@ -56,6 +57,23 @@ int main(int, char**)
5657
assert(v.capacity() >= 150);
5758
}
5859
#endif
60+
#ifndef TEST_HAS_NO_EXCEPTIONS
61+
{
62+
std::vector<bool, limited_allocator<bool, 10> > v;
63+
v.reserve(5);
64+
try {
65+
// A typical implementation would allocate chunks of bits.
66+
// In libc++ the chunk has the same size as the machine word. It is
67+
// reasonable to assume that in practice no implementation would use
68+
// 64 kB or larger chunks.
69+
v.reserve(10 * 65536);
70+
assert(false);
71+
} catch (const std::length_error&) {
72+
// no-op
73+
}
74+
assert(v.capacity() >= 5);
75+
}
76+
#endif
5977

6078
return 0;
6179
}

libcxx/test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,22 @@ int main(int, char**)
6767
assert(is_contiguous_container_asan_correct(v));
6868
}
6969
#endif
70+
#ifndef TEST_HAS_NO_EXCEPTIONS
71+
{
72+
std::vector<int, limited_allocator<int, 100> > v;
73+
v.reserve(50);
74+
assert(v.capacity() == 50);
75+
assert(is_contiguous_container_asan_correct(v));
76+
try {
77+
v.reserve(101);
78+
assert(false);
79+
} catch (const std::length_error&) {
80+
// no-op
81+
}
82+
assert(v.capacity() == 50);
83+
assert(is_contiguous_container_asan_correct(v));
84+
}
85+
#endif
7086

7187
return 0;
7288
}

0 commit comments

Comments
 (0)