This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
Re: g++ 4.0.0: hash_map hangs when compiled with -O3 on AMD64
Hi,
I've isolated the problem to some extent. See below.
Best regards, Paul Leopardi
On Wed, 4 May 2005 09:57 am, Paul C. Leopardi wrote:
> I'm seeing the following behaviour with GluCat 0.1.8 on AMD64.
> ( http://glucat.sf.net )
...
> ./configure --with-hash-map --enable-debug=no: compiled program hangs
> (this uses __gnu_cxx::hash_map and -O3)
> gdb on the compiled program: bt results in hundreds of stack frames.
> Looks like the stack has been corrupted.
>
> Also it looks like the hang or corruption happens when using iterators with
> hash_map. I've looked at the test suite and I don't see a test where
> iterators are used with hash_map.
I've now done extensive testing with the optimization options of g++ 4.0.0,
and see that the problem only happens when both of the following flags are
used: -fstrict-aliasing -finline-functions.
The -O2 flag implies -fstrict-aliasing and
the -O3 flag implies -fstrict-aliasing -finline-functions.
See http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Optimize-Options.html
Since it seems that these flags are incompatible when used with GluCat and
__gnu_cxx::hash_map, I did some performance testing and found that the GluCat
gfft_test is faster with -O3 -fno-inline-functions than it is with
-O3 -fno-strict-aliasing.
In gdb, using GluCat gfft_test compiled with -O3, I do not get stack
corruption. I don't understand this. The test programs test02, test03 and
test04 do get stack corruption.
What I see instead with gfft_test is that in a for loop which compares an
iterator of type __gnu_cxx::hash_map::const_iterator with end(), the loop
runs forever.
It looks like for __gnu_cxx::hash_map::const_iterator, operator++ no longer
works correctly when both -fstrict-aliasing -finline-functions are used.
In particular, the following routine in hashtable.h looks like it is failing
to incement the const_iterator.
operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur)
{
size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
_M_cur = _M_ht->_M_buckets[__bucket];
}
return *this;
}
I tried changing the routine to the following
operator++()
{
const _Node* __old = _M_cur;
_M_cur = _M_cur->_M_next;
if (!_M_cur)
for( size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val) + 1;
!_M_cur && __bucket < _M_ht->_M_buckets.size();
++__bucket)
_M_cur = _M_ht->_M_buckets[__bucket];
return *this;
}
In gdb it looks like the same error is happening, but it is now a little
easier to see what happens to __bucket. In my particular case, at the
initialization of the for loop, the expression
_M_ht->_M_bkt_num(__old->_M_val) should have the value 1, but when I examine
__bucket, I see that it has the value 1, not 2 as I expected.
Unfortunately, I still don't have a short test case. I tried adding a loop
with __gnu_cxx::hash_map::const_iterator to the libstdc++/14648 test program,
and failed to reproduce the problem.
Do I have enough info to file a bug report or do I still need to try to create
a short test case?