Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #4956

Re: g++ unordered_multimap buggy?

From Kai-Uwe Bux <jkherciueh@gmx.net>
Newsgroups comp.lang.c++
Subject Re: g++ unordered_multimap buggy?
Followup-To comp.lang.c++
Date 2011-05-14 16:32 +0200
Organization University of Bielefeld
Message-ID <iqm3qi$rb9$1@hoshi.visyn.net> (permalink)
References <4dcd42b1$0$6981$9b4e6d93@newsspool4.arcor-online.net> <iqjlqe$32v$1@hoshi.visyn.net> <4dce8c91$0$6972$9b4e6d93@newsspool4.arcor-online.net>

Followups directed to: comp.lang.c++

Show all headers | View raw


Ralf Goertz wrote:

> Kai-Uwe Bux wrote:
> 
>> Ralf Goertz wrote:
>> 
>>> Hi,
>>> 
>>> I have now spent a day to track down a segmentation fault in a program
>>> of mine that used to work. This time it crashed always exactly at the
>>> same place (I was running it with new data). The program uses
>>> unordered_multimap<string, SomeClass> and I repeatedly call a subroutine
>>> with two const SomeClass & elements obtained from iterators of that map.
>>> gdb told me that the segfault occured at the line where I called the
>>> subroutine.
>> 
>> Hm, that sounds like you could be invalidating the references somewhere
>> between obtaining them and passing them to the subroutine. But without
>> seeing the code, we are limited to guesswork.
>> 
>> 
>>> Only after switching off optimization (which in this case is
>>> very expensive because the map contains millions of elements and
>>> execution time increased from 20 minutes to over an hour) I got a
>>> different source line where the error occured:
>>> 
>>> Program terminated with signal 11, Segmentation fault.
>>> #0  0x000000000041f642 in std::_Rb_tree<std::string, std::string,
>>> #std::_Identity<std::string>, std::less<std::string>,
>>> std::allocator<std::string> >::_M_insert_unique (
>>>     this=0x7fff600cf070, linknodes=...) at
>>>     /usr/include/c++/4.5/bits/stl_tree.h:1181
>>> 
>>> In that file we have
>>> 
>>> 1171   template<typename _Key, typename _Val, typename _KeyOfValue,
>>> 1172            typename _Compare, typename _Alloc>
>>> 1173     pair<typename _Rb_tree<_Key, _Val, _KeyOfValue,
>>> 1174                _Compare, _Alloc>::iterator, bool>
>>> 1175     _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
>>> 1176     _M_insert_unique(const _Val& __v)
>>> 1177     {
>>> 1178       _Link_type __x = _M_begin();
>>> 1179       _Link_type __y = _M_end();
>>> 1180       bool __comp = true;
>>> 1181       while (__x != 0)
>>> 1182     {
>>> 1183       __y = __x;
>>> 1184       __comp = _M_impl._M_key_compare(_KeyOfValue()(__v),
>>> _S_key(__x));
>>> 1185       __x = __comp ? _S_left(__x) : _S_right(__x);
>>> 1186     }
>>> 1187       iterator __j = iterator(__y);
>>> 1188       if (__comp)
>>> 1189     {
>>> 1190       if (__j == begin())
>>> 1191         return pair<iterator, bool>(_M_insert_(__x, __y, __v),
>>> true);
>>> 1192       else
>>> 1193         --__j;
>>> 1194     }
>>> 1195       if (_M_impl._M_key_compare(_S_key(__j._M_node),
>>> _KeyOfValue()(__v)))
>>> 1196     return pair<iterator, bool>(_M_insert_(__x, __y, __v), true);
>>> 1197       return pair<iterator, bool>(__j, false);
>>> 1198     }
>>> 
>>> 
>>> I still don't see where there should be a problem but after switching to
>>> boost::unordered_multimap every thing works fine again.
>>> 
>>> I don't want to exclude the possibility that my program is buggy but
>>> given that
>>> 
>>> * it had worked previously,
>>> * works fine with boost,
>>> * crashes only with specific input after many executions of that line
>>> * doesn't use any pointers at all
>>>
>>> what are the odds that the g++ implementation is the culprit?
>> 
>> Close to 0 :-)
>> 
> 
> :(
>  
> Thanks for taking a look.
> 
>>> Maybe there is something wrong with the hashing?
>> 
>> I would rather suspect that your code has undefined behavior:
>> 
>> a) it crashes
>> b) randomly
>> c) and at different places depending on the optimization level
> 
> No that is not true. It crashes at the same point regardless of
> optimization. The reason I see a different sourceline is ? I suppose ?
> that some calls are optimized away.
> 
>> d) swapping the implementation of unordered_multimap changes the behavior
>> 
>> and, as mentioned above, invalidation of references seems a probable
>> cause of undefined behavior; in particular as your program does not use
>> pointers.
> 
> How can that be? This is the relevant part of the code
>  
>  for (;ii!=itp.first;){
>      AIterator a1=nodes.getIterator(ii->second,0);
>      AIterator a2=nodes.getIterator(ii->second,1);
>      AIterator const &ai1(ii->second < itp.first->second ? a2 : a1),
>                           &ai2(ii->second > itp.first->second ? a2 : a1);
>      if(isEqual(ai1->second, ai2->second) && merge(ai2,ai1)) {
>      }
> 
> So I declare AIterators a1 and a2 (getIterator returns a valid
> iterator!=end()) and then I declare ai1 and ai2 to be const references
> to a1 and a2 repectively depending on some sort criterion. The program
> crashes at isEqual (when compiled with -O3) but in the stl-header
> without optimization. But in both cases it is the same run in the loop.

Hm, indeed: there is nothing invalidating references that jumps right at me. 
Here are some suggestions / observations:

a) If the AIterator objects are small, it probably does not pay off to use 
AIterator const references. So, I would try:

  AIterator ai1 = ii->second < itp.first->second ? a2 : a1;
  AIterator ai2 = ii->second > itp.first->second ? a2 : a1;

and see if that changes anything.

b) Also: the cases

  ii->second < itp.first->second

and

  ii->second > itp.first->second

have the common false ii->second == itp.first->second. I cannot see whether 
that is intentional, but it sure would be a _rare_ condition, and I would 
check whether the spurious crashed might be related to that case.

c) A remark on style: Is the short circuit evaluation

      if(isEqual(ai1->second, ai2->second) && merge(ai2,ai1)) {
      }

just a result of trimming down the example? I would condent that

      if( isEqual(ai1->second, ai2->second) ) {
         merge(ai2,ai1);
      }

expresses more clearly what happens.


Best,

Kai-Uwe Bux

Back to comp.lang.c++ | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

g++ unordered_multimap buggy? Ralf Goertz <r_goertz@usenet.arcornews.de> - 2011-05-13 16:40 +0200
  Re: g++ unordered_multimap buggy? Leigh Johnston <leigh@i42.co.uk> - 2011-05-13 16:14 +0100
    Re: g++ unordered_multimap buggy? Ralf Goertz <r_goertz@usenet.arcornews.de> - 2011-05-13 17:35 +0200
  Re: g++ unordered_multimap buggy? Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-05-13 18:21 +0200
    Re: g++ unordered_multimap buggy? Ralf Goertz <r_goertz@usenet.arcornews.de> - 2011-05-14 16:07 +0200
      Re: g++ unordered_multimap buggy? Kai-Uwe Bux <jkherciueh@gmx.net> - 2011-05-14 16:32 +0200
        Re: g++ unordered_multimap buggy? Ralf Goertz <r_goertz@usenet.arcornews.de> - 2011-05-15 10:29 +0200
          Re: g++ unordered_multimap buggy? "Balog Pal" <pasa@lib.hu> - 2011-05-15 11:11 +0200
      Re: g++ unordered_multimap buggy? Ralf Goertz <r_goertz@usenet.arcornews.de> - 2011-05-17 09:17 +0200
      Re: g++ unordered_multimap buggy? Ruben Safir <mrbrklyn@panix.com> - 2011-06-09 18:26 +0000

csiph-web