Hi!

As described in the PR, if two argument erase is removing the last
element of one bucket (i.e. the one referenced in _M_buckets array
for the next bucket) and then at least one element from the
following bucket, but not all elements from that next bucket,
__is_bucket_begin is initially false and in the second for (;;) iteration,
while it is already true, __n_bkt == __bkt and thus _M_remove_bucket_begin
doesn't do anything, and following if (__n && __n_bkt != __bkt) is
false as well (1 && 0), thus nothing is changed in the _M_buckets array
and we end up referencing there a removed element.  We might crash if we
read it and if we modify it, we usually corrupt malloc data structures.

Fixed thusly, if __is_bucket_begin is true, then we know __n is the first
item in its bucket and thus __prev_n should be in the _M_buckets array.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2012-01-18  Jakub Jelinek  <ja...@redhat.com>

        PR libstdc++/51845
        * include/bits/hashtable.h
        (_Hashtable<>::erase(const_iterator, const_iterator)): Also update
        _M_buckets[__n_bkt] if __is_bucket_begin.

--- libstdc++-v3/include/bits/hashtable.h       2012-01-15 20:59:53.765526939 
+0100
+++ libstdc++-v3/include/bits/hashtable.h       2012-01-18 19:49:39.222388730 
+0100
@@ -1541,7 +1541,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          __bkt = __n_bkt;
        }
 
-      if (__n && __n_bkt != __bkt)
+      if (__n && (__n_bkt != __bkt || __is_bucket_begin))
        _M_buckets[__n_bkt] = __prev_n;
       __prev_n->_M_nxt = __n;
       return iterator(__n);

        Jakub

Reply via email to