[Bug libstdc++/23244] New: __gnu_cxx::hash_map inconsistent iterator behavior
jzampier at gmail dot com
gcc-bugzilla@gcc.gnu.org
Fri Aug 5 02:57:00 GMT 2005
The iterators over hash_map behave in a manner inconsistent with the other
std::map, std::list, etc... data structures. This can cause segfaults which are
hard to root-cause. Sample Code Included with additional information:
Specifically, the iterators over hash_map require the 'first' datamember to
be valid until the iterator has advanced past that point. (see code for clarity)
The iterator operator++ should not depend on being able to call the
hash functor on that data member to advance. Because, as in the example,
you can't call the functor when the pointer has been deleted.
This behavior happens on other hosts of g++ (tested on 3.4.3, linux). (I just
have cygwin on here...)
The offending code is placed in #if 0 and #endif directives.
While this isn't a bug per se, it is a problem with the behavior of
hash_map that should at least be documented in LARGE letters
in the hash_map, if not fixed to work like the rest of the stl.
// $Id$
// Program: hashbroke
// Purpose: To demonstrate how __gnu_cxx::hash_map is broken. (sorta)
// Author: Jeffrey Zampieron
// License: GPL.
#include <iostream>
#include <ext/hash_map>
#include <map>
using namespace std;
using namespace __gnu_cxx;
typedef struct {
size_t operator()( const string* str ) const {
return __gnu_cxx::__stl_hash_string( str->c_str() );
}
} strptrhash;
typedef struct {
bool operator()( const string* lhs, const string* rhs ) const {
return *lhs == *rhs;
}
} strptrequal;
typedef struct {
bool operator()( const string* lhs, const string* rhs ) const {
return *lhs < *rhs;
}
} strptrless;
typedef hash_map< string*, string*, strptrhash, strptrequal > StringPtrHash;
typedef std::map< string*, string*, strptrless > StringPtrMap;
int main() {
StringPtrHash testhash;
// test keys
string* k1 = new string( "key1" );
string* k2 = new string( "key2" );
string* k3 = new string( "key3" );
string* k4 = new string( "key4" );
string* k5 = new string( "key5" );
string* k6 = new string( "key6" );
// test vals
string* v1 = new string( "val1" );
string* v2 = new string( "val2" );
string* v3 = new string( "val3" );
string* v4 = new string( "val4" );
string* v5 = new string( "val5" );
string* v6 = new string( "val6" );
testhash[ k1 ] = v1;
testhash[ k2 ] = v2;
testhash[ k3 ] = v3;
testhash[ k4 ] = v4;
testhash[ k5 ] = v5;
testhash[ k6 ] = v6;
cout << "Hash:\n";
for( StringPtrHash::iterator iter = testhash.begin();
iter != testhash.end();
iter++ ) {
cout << "Key: " << *( iter->first ) << endl;
cout << "Val: " << *( iter->second ) << endl;
}
// this SHOULD be valid.
// and is for std::map
// but causes a segfault here.
#if 0
for( StringPtrHash::iterator iter = testhash.begin();
iter != testhash.end();
iter++ ) {
delete( iter->first );
delete( iter->second );
}
#endif
// Work around:
string* prev = __null;
for( StringPtrHash::iterator iter = testhash.begin();
iter != testhash.end();
iter++ ) {
delete( prev );
delete( iter->second );
prev = iter->first;
}
delete( prev );
// That this works with map:
StringPtrMap testmap;
k1 = new string( "key1" );
k2 = new string( "key2" );
k3 = new string( "key3" );
k4 = new string( "key4" );
k5 = new string( "key5" );
k6 = new string( "key6" );
// test vals
v1 = new string( "val1" );
v2 = new string( "val2" );
v3 = new string( "val3" );
v4 = new string( "val4" );
v5 = new string( "val5" );
v6 = new string( "val6" );
testmap[ k1 ] = v1;
testmap[ k2 ] = v2;
testmap[ k3 ] = v3;
testmap[ k4 ] = v4;
testmap[ k5 ] = v5;
testmap[ k6 ] = v6;
cout << "\nMap:\n";
for( StringPtrMap::iterator iter = testmap.begin();
iter != testmap.end();
iter++ ) {
cout << "Key: " << *( iter->first ) << endl;
cout << "Val: " << *( iter->second ) << endl;
}
// works like map should.
for( StringPtrMap::iterator iter = testmap.begin();
iter != testmap.end();
iter++ ) {
delete( iter->first );
delete( iter->second );
}
// The problem seems to be that the
// operator++ in the hash_map iterator
// needs to call the function provided
// by strptrhash in order to advance...
// but in my example that pointer has been deleted...
// hence the segfault.
// This is apparent if you run valgrind on the exec.
// (I don't have it on this machine, or I'd include the output)
// Why is this the case? Iterating over a map
// should not require computation of a hash key.
// While not really a bug, this is a caveat that should
// be documented somewhere, or ideally fixed
// Notice that map does not call strptrcmp to advance the iterator
}
--
Summary: __gnu_cxx::hash_map inconsistent iterator behavior
Product: gcc
Version: 3.4.4
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: libstdc++
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: jzampier at gmail dot com
CC: gcc-bugs at gcc dot gnu dot org
GCC build triplet: i686-pc-cygwin
GCC host triplet: i686-pc-cygwin
GCC target triplet: i686-pc-cygwin
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23244
More information about the Gcc-bugs
mailing list