diff --git a/test/boost/chunked_vector_test.cc b/test/boost/chunked_vector_test.cc index ead989fb02..7aacacd5a5 100644 --- a/test/boost/chunked_vector_test.cc +++ b/test/boost/chunked_vector_test.cc @@ -178,3 +178,32 @@ BOOST_AUTO_TEST_CASE(tests_reserve_partial) { BOOST_REQUIRE_EQUAL(v.capacity(), orig_size); } } + +// Tests the case of make_room() invoked with last_chunk_capacity_deficit but _size not in +// the last reserved chunk. +BOOST_AUTO_TEST_CASE(test_shrinking_and_expansion_involving_chunk_boundary) { + using vector_type = utils::chunked_vector>; + vector_type v; + + // Fill two chunks + v.reserve(vector_type::max_chunk_capacity() * 3 / 2); + for (uint64_t i = 0; i < vector_type::max_chunk_capacity() * 3 / 2; ++i) { + v.emplace_back(std::make_unique(i)); + } + + // Make the last chunk smaller than max size to trigger the last_chunk_capacity_deficit path in make_room() + v.shrink_to_fit(); + + // Leave the last chunk reserved but empty + for (uint64_t i = 0; i < vector_type::max_chunk_capacity(); ++i) { + v.pop_back(); + } + + // Try to reserve more than the currently reserved capacity and trigger last_chunk_capacity_deficit path + // with _size not in the last chunk. Should not sigsegv. + v.reserve(vector_type::max_chunk_capacity() * 4); + + for (uint64_t i = 0; i < vector_type::max_chunk_capacity() * 2; ++i) { + v.emplace_back(std::make_unique(i)); + } +} diff --git a/utils/chunked_vector.hh b/utils/chunked_vector.hh index dca542167e..ce20881680 100644 --- a/utils/chunked_vector.hh +++ b/utils/chunked_vector.hh @@ -376,7 +376,9 @@ chunked_vector::make_room(size_t n, bool stop_afte auto new_last_chunk_capacity = last_chunk_capacity + capacity_increase; // FIXME: realloc? maybe not worth the complication; only works for PODs auto new_last_chunk = new_chunk(new_last_chunk_capacity); - migrate(addr(_capacity - last_chunk_capacity), addr(_size), new_last_chunk.get()); + if (_size > _capacity - last_chunk_capacity) { + migrate(addr(_capacity - last_chunk_capacity), addr(_size), new_last_chunk.get()); + } _chunks.back() = std::move(new_last_chunk); _capacity += capacity_increase; }