From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1988 invoked by alias); 30 Aug 2014 16:07:45 -0000 Mailing-List: contact gcc-bugs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-bugs-owner@gcc.gnu.org Received: (qmail 1945 invoked by uid 48); 30 Aug 2014 16:07:39 -0000 From: "dvyukov at google dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/62313] New: Data race in debug iterators Date: Sat, 30 Aug 2014 16:07:00 -0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 5.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: dvyukov at google dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-SW-Source: 2014-08/txt/msg02044.txt.bz2 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62313 Bug ID: 62313 Summary: Data race in debug iterators Product: gcc Version: 5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: dvyukov at google dot com $ g++ -v gcc version 5.0.0 20140830 (experimental) (GCC) The program is: ======= #include #include #include std::list::iterator iter, iter2; void *thread(void *arg) { for (int i = 0; i < 1000000; i++) { std::list::iterator it(iter); iter2 = it; } return 0; } int main() { std::list li; li.push_back(0); iter = li.begin(); pthread_t th; pthread_create(&th, 0, thread, 0); for (int i = 0; i < 1000000; i++) { li.push_back(1); std::list::iterator it = li.begin(); it++; li.erase(it); } pthread_join(th, 0); } ===== Build it as: $ g++ test.cc -Wall -lpthread -fsanitize=thread -pie -fPIE -D_GLIBCXX_DEBUG -g -O2 Run the program. Output is: WARNING: ThreadSanitizer: data race (pid=17058) Read of size 8 at 0x7faedc637b00 by main thread (mutexes: write M2): #0 void __gnu_debug::_Safe_sequence > >::_M_invalidate_if<__gnu_debug::_Equal_to > >(__gnu_debug::_Equal_to >) /foo/include/c++/5.0.0/debug/safe_sequence.tcc:48 (a.out+0x000000002a61) #1 std::__debug::list >::_M_erase(std::__cxx1998::_List_iterator) /foo/include/c++/5.0.0/debug/list:464 (a.out+0x000000001e21) #2 std::__debug::list >::erase(__gnu_debug::_Safe_iterator, std::__debug::list > >) /foo/include/c++/5.0.0/debug/list:477 (a.out+0x000000001e21) #3 main test.cc:27 (a.out+0x000000001e21) Previous write of size 8 at 0x7faedc637b00 by thread T1: #0 __gnu_debug::_Safe_iterator, std::__debug::list > >::operator=(__gnu_debug::_Safe_iterator, std::__debug::list > > const&) /foo/include/c++/5.0.0/debug/safe_iterator.h:223 (a.out+0x000000002460) #1 thread(void*) test.cc:11 (a.out+0x000000002460) Location is global 'iter2' of size 40 at 0x7faedc637ae0 (a.out+0x000000203b00) Mutex M2 (0x7faedb100698) created at: #0 pthread_mutex_lock ../../.././libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:2686 (libtsan.so.0+0x0000000368a6) #1 __gthread_mutex_lock /ssd/src/gcc_trunk/x86_64-unknown-linux-gnu/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:748 (libstdc++.so.6+0x0000000b284b) #2 __gnu_cxx::__mutex::lock() /ssd/src/gcc_trunk/x86_64-unknown-linux-gnu/libstdc++-v3/include/ext/concurrence.h:152 (libstdc++.so.6+0x0000000b284b) #3 __gnu_cxx::__scoped_lock::__scoped_lock(__gnu_cxx::__mutex&) /ssd/src/gcc_trunk/x86_64-unknown-linux-gnu/libstdc++-v3/include/ext/concurrence.h:244 (libstdc++.so.6+0x0000000b284b) #4 __gnu_debug::_Safe_sequence_base::_M_attach(__gnu_debug::_Safe_iterator_base*, bool) ../../../.././libstdc++-v3/src/c++11/debug.cc:268 (libstdc++.so.6+0x0000000b284b) #5 __libc_start_main :0 (libc.so.6+0x000000021ec4) Thread T1 (tid=17060, running) created by main thread at: #0 pthread_create ../../.././libsanitizer/tsan/tsan_interceptors.cc:853 (libtsan.so.0+0x000000026eb4) #1 main test.cc:22 (a.out+0x000000001aad) As far as I see the safe iterator first attaches itself to the sequence in _Safe_iterator_base ctor: _Safe_iterator(const _Safe_iterator& __x) : _Safe_iterator_base(__x, _M_constant()), _M_current(__x._M_current) After that point it's accessible from other threads (in particular that invalidate other iterators). Only then it sets _M_current. But _M_current is already read from another thread that invalidates a different iterator. There can be a similar race in dtor. They usually come together. It can make sense to run some extensive test suite (if one exists) for debug iterators with -fsanitize=thread -O{0,1,2}.