https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127675
--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
The other bug is here in ext/pb_ds/detail/ov_tree_map_/erase_fn_imps.hpp
value_vector a_new_values = s_value_alloc.allocate(new_size);
iterator target_it = a_new_values;
cond_dtor<size_type> cd(a_new_values, target_it, new_size); // #1
_GLIBCXX_DEBUG_ONLY(debug_base::clear()); // #2
for (iterator source_it = begin(); source_it != m_end_it; ++source_it)
{
if (!pred(*source_it))
{
new (const_cast<void*>(static_cast<const void*>(target_it)))
value_type(*source_it);
_GLIBCXX_DEBUG_ONLY(debug_base::insert_new(PB_DS_V2F(*source_it)));
// #3
++target_it;
}
}
reallocate_metadata((node_update*)this, new_size); // #4
cd.set_no_action(); // #5
At the line marked #1 we create an RAII type that will clean up the new
allocation, a_new_values. At #5 that RAII type is disarmed so that it won't do
the clean up.
The idea is to allocate new storage, copy the values we are not erasing, and
then only replace the existing storage if that all happens without throwing an
exception. If anything throws, the RAII object 'cd' will clean up and there are
no changes to *this.
Except that at #2 and #3 we make modifications directly to the
this->debug_base::m_keys list. If an exception is thrown at #4 (which happens
randomly, via the __throw_allocator which injects random failures into the test
code) then we rollback the new allocation but the changes to
this->debug_base::m_keys remain. This leaves m_size and m_keys.size()
inconsistent. On the next call to any member function the
PB_DS_ASSERT_VALID((*this)) check fails and aborts.
The reason it only happens in debug mode is because the m_keys list is only
populated in debug mode and the PB_DS_ASSERT_VALID check is a no-op without
debug mode:
#define PB_DS_ASSERT_VALID(X) \
_GLIBCXX_DEBUG_ONLY(X.assert_valid(__FILE__, __LINE__);)
I think this is only a bug in the tests, not the real containers. The
debug_base only exists in the test code.