This patch fixes a problem with the old hashtable::erase code when the caller passes a reference to an element in the table, the element is not the first in the bucket, but it is equal to the first in the bucket. This is PR 49060, and the patch and test case are from that PR with minor tweaks. Bootstrapped and ran libstdc++ testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian 2011-05-25 David Tardon <dtar...@redhat.com> PR libstdc++/49060 * include/backward/hashtable.h (hashtable::erase): Don't crash if erasing first and another element with a reference to the other element. * testsuite/backward/hash_set/49060.cc: New.
Index: include/backward/hashtable.h =================================================================== --- include/backward/hashtable.h (revision 173685) +++ include/backward/hashtable.h (working copy) @@ -898,13 +898,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __next = __cur->_M_next; } } - if (_M_equals(_M_get_key(__first->_M_val), __key)) - { - _M_buckets[__n] = __first->_M_next; - _M_delete_node(__first); - ++__erased; - --_M_num_elements; - } + bool __delete_first = _M_equals(_M_get_key(__first->_M_val), __key); if (__saved_slot) { __next = __saved_slot->_M_next; @@ -913,6 +907,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ++__erased; --_M_num_elements; } + if (__delete_first) + { + _M_buckets[__n] = __first->_M_next; + _M_delete_node(__first); + ++__erased; + --_M_num_elements; + } } return __erased; } Index: testsuite/backward/hash_set/49060.cc =================================================================== --- testsuite/backward/hash_set/49060.cc (revision 0) +++ testsuite/backward/hash_set/49060.cc (revision 0) @@ -0,0 +1,35 @@ +// { dg-options "-Wno-deprecated" } + +#include <backward/hashtable.h> +#include <utility> + +struct modulo2_hash +{ + size_t operator()(int const key) const + { + return key % 2; + } +}; + +struct modulo2_eq +{ + bool operator()(int const left, int const right) const + { + return left % 2 == right % 2; + } +}; + +int main() +{ + typedef std::_Select1st<std::pair<int const, int> > extract_type; + typedef + __gnu_cxx::hashtable<std::pair<int const, int>, int, modulo2_hash, + extract_type, modulo2_eq, std::allocator<int> > + table_type; + table_type table(4, modulo2_hash(), modulo2_eq(), extract_type(), + std::allocator<int>()); + + table.insert_equal(std::make_pair(2, 1)); + table_type::iterator it(table.insert_equal(std::make_pair(4, 2))); + table.erase(it->first); +}