Bug 326436

Summary: False positive in libstdc++ std::list::push_back
Product: [Developer tools] valgrind Reporter: ewirch <wirch.eduard>
Component: drdAssignee: Bart Van Assche <bart.vanassche+kde>
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: 3.9.0.SVN   
Target Milestone: ---   
Platform: Ubuntu   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: drd r13688 conflict trace for 0x64341a8

Description ewirch 2013-10-22 11:52:17 UTC
Valgrind r13670 Compiled using default configuration.
GCC-Information: g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

Reproducible: 8 out of 10 runs

Reproducible: Sometimes

Steps to Reproduce:
1. Compile test case:  g++ -std=c++11 -O0 -g  test.cpp -lpthread -o test
2. Test it: valgrind --tool=drd  ./test
3. Two errors are being reported:
Actual Results:  
==3334== Thread 2:
==3334== Conflicting store by thread 2 at 0x06433548 size 8
==3334==    at 0x401803: std::_List_node<int*>::_List_node<int*>(int*&&) (stl_list.h:115)
==3334==    by 0x401786: _ZN9__gnu_cxx13new_allocatorISt10_List_nodeIPiEE9constructIS3_IS2_EEEvPT_DpOT0_ (in /home/factfinder/edu/ff-lib-test/test)
==3334==    by 0x4016A1: std::_List_node<int*>* std::list<int*, std::allocator<int*> >::_M_create_node<int*>(int*&&) (stl_list.h:503)
==3334==    by 0x40157B: void std::list<int*, std::allocator<int*> >::_M_insert<int*>(std::_List_iterator<int*>, int*&&) (stl_list.h:1533)
==3334==    by 0x40137E: std::list<int*, std::allocator<int*> >::push_back(int*&&) (stl_list.h:1002)
==3334==    by 0x40114D: SubTest::subTest() (test.cpp:25)
==3334==    by 0x40129C: Test::func1() (test.cpp:49)
==3334==    by 0x400D97: func1(void*) (test.cpp:62)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Address 0x6433548 is at offset 8 from 0x6433540. Allocation context:
==3334==    at 0x4C2E30B: operator new(unsigned long) (vg_replace_malloc.c:319)
==3334==    by 0x4017E0: __gnu_cxx::new_allocator<std::_List_node<int*> >::allocate(unsigned long, void const*) (new_allocator.h:94)
==3334==    by 0x40173F: std::_List_base<int*, std::allocator<int*> >::_M_get_node() (stl_list.h:335)
==3334==    by 0x401670: std::_List_node<int*>* std::list<int*, std::allocator<int*> >::_M_create_node<int*>(int*&&) (stl_list.h:500)
==3334==    by 0x40157B: void std::list<int*, std::allocator<int*> >::_M_insert<int*>(std::_List_iterator<int*>, int*&&) (stl_list.h:1533)
==3334==    by 0x40137E: std::list<int*, std::allocator<int*> >::push_back(int*&&) (stl_list.h:1002)
==3334==    by 0x40114D: SubTest::subTest() (test.cpp:25)
==3334==    by 0x40129C: Test::func1() (test.cpp:49)
==3334==    by 0x400D97: func1(void*) (test.cpp:62)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Other segment start (thread 3)
==3334==    at 0x4C39C82: pthread_rwlock_wrlock (drd_pthread_intercepts.c:1150)
==3334==    by 0x55A35DC: setlocale (setlocale.c:208)
==3334==    by 0x401237: Test::setUp() (test.cpp:40)
==3334==    by 0x400DCA: func2(void*) (test.cpp:69)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Other segment end (thread 3)
==3334==    at 0x4C3B242: pthread_rwlock_unlock (drd_pthread_intercepts.c:1237)
==3334==    by 0x55A37C6: setlocale (setlocale.c:364)
==3334==    by 0x401237: Test::setUp() (test.cpp:40)
==3334==    by 0x400DCA: func2(void*) (test.cpp:69)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334==
==3334== Conflicting store by thread 2 at 0x06433548 size 8
==3334==    at 0x50CC8E7: std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==3334==    by 0x401592: void std::list<int*, std::allocator<int*> >::_M_insert<int*>(std::_List_iterator<int*>, int*&&) (stl_list.h:1534)
==3334==    by 0x40137E: std::list<int*, std::allocator<int*> >::push_back(int*&&) (stl_list.h:1002)
==3334==    by 0x40114D: SubTest::subTest() (test.cpp:25)
==3334==    by 0x40129C: Test::func1() (test.cpp:49)
==3334==    by 0x400D97: func1(void*) (test.cpp:62)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Address 0x6433548 is at offset 8 from 0x6433540. Allocation context:
==3334==    at 0x4C2E30B: operator new(unsigned long) (vg_replace_malloc.c:319)
==3334==    by 0x4017E0: __gnu_cxx::new_allocator<std::_List_node<int*> >::allocate(unsigned long, void const*) (new_allocator.h:94)
==3334==    by 0x40173F: std::_List_base<int*, std::allocator<int*> >::_M_get_node() (stl_list.h:335)
==3334==    by 0x401670: std::_List_node<int*>* std::list<int*, std::allocator<int*> >::_M_create_node<int*>(int*&&) (stl_list.h:500)
==3334==    by 0x40157B: void std::list<int*, std::allocator<int*> >::_M_insert<int*>(std::_List_iterator<int*>, int*&&) (stl_list.h:1533)
==3334==    by 0x40137E: std::list<int*, std::allocator<int*> >::push_back(int*&&) (stl_list.h:1002)
==3334==    by 0x40114D: SubTest::subTest() (test.cpp:25)
==3334==    by 0x40129C: Test::func1() (test.cpp:49)
==3334==    by 0x400D97: func1(void*) (test.cpp:62)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Other segment start (thread 3)
==3334==    at 0x4C39C82: pthread_rwlock_wrlock (drd_pthread_intercepts.c:1150)
==3334==    by 0x55A35DC: setlocale (setlocale.c:208)
==3334==    by 0x401237: Test::setUp() (test.cpp:40)
==3334==    by 0x400DCA: func2(void*) (test.cpp:69)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334== Other segment end (thread 3)
==3334==    at 0x4C3B242: pthread_rwlock_unlock (drd_pthread_intercepts.c:1237)
==3334==    by 0x55A37C6: setlocale (setlocale.c:364)
==3334==    by 0x401237: Test::setUp() (test.cpp:40)
==3334==    by 0x400DCA: func2(void*) (test.cpp:69)
==3334==    by 0x4C2EDA4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==3334==    by 0x4E48E99: start_thread (pthread_create.c:308)
==3334==    by 0x566ACCC: clone (clone.S:112)
==3334==

Expected Results:  
No errors reported.

Test case:

#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <string>
#include <sstream>
#include <list>
using namespace std;

class SubTest {
public:
        SubTest() {
                list<int *> ffList;
                ffList.push_back((int *) NULL);

                for (list<int*>::iterator ff = ffList.begin(); ff != ffList.end(); ff++) {
                        usleep(1000);
                }

        }

        void subTest() {
                list<int *> ffList;
                ffList.push_back((int *) NULL);

                for (list<int*>::const_iterator ff = ffList.begin(); ff != ffList.end(); ff++) {
                        usleep(1000);
                }

        }
};

class Test {
        SubTest *subTest;

public:
        void setUp() {
                subTest = new SubTest();
                setlocale(LC_ALL, "English");
        }

        void tearDown() {
                delete subTest;
        }

        void func1() {
                for (size_t i = 0; i < 10000; i++) {
                        subTest->subTest();
                        usleep(1000);
                }
        }

        void func2() {
                usleep(1000);
        }
};

void *func1(void *instance) {
        Test *casted = reinterpret_cast<Test*>(instance);
        casted->setUp();
        casted->func1();
        casted->tearDown();
        return NULL;
}

void *func2(void *instance) {
        Test *casted = reinterpret_cast<Test*>(instance);
        casted->setUp();
        casted->func2();
        casted->tearDown();
        return NULL;
}

int main(int argc, char* argv[]) {
        int err;
        pthread_t thread1;
        pthread_t thread2;
        Test instance1;
        Test instance2;

        // create
        err = pthread_create(&thread1, NULL, &func1, &instance1);
        if (err != 0) throw string("failed to create a thread.");

        err = pthread_create(&thread2, NULL, &func2, &instance2);
        if (err != 0) throw string("failed to create a thread.");

        // join
        err = pthread_join(thread1, NULL);
        if (err != 0) throw string("Thread::join(): failed to join.");

        err = pthread_join(thread2, NULL);
        if (err != 0) throw string("Thread::join(): failed to join.");
}
Comment 1 Bart Van Assche 2013-10-22 15:21:27 UTC
Can you tell me the version number of the Linaro distribution that you are using ? I'd like to install Linaro myself in order to reproduce this. So far I have not yet been able to reproduce this issue with the test program provided above neither on Ubuntu 13.04 nor on openSUSE 12.3.
Comment 2 ewirch 2013-10-23 07:31:20 UTC
> lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 12.10
Release:        12.10
Codename:       quantal

Ubuntu package versions:
gcc 4:4.7.2-1ubuntu2
g++ 4:4.7.2-1ubuntu2
libstdc++6 4.7.2-2ubuntu1
libc6 2.15-0ubuntu20.2

It looks like setlocale plays an important role. When I change the setlocale line in the test case to:
setlocale(LC_ALL, NULL);
OR
setlocale(LC_ALL, "C");
OR something invalid. DRD will not report any errors. 

I found a second value, which will also trigger the error: "German". Both values are reported by 
locale -a -v
in the "language" fields on my system. So maybe you first check the locales installed on your test system.
Comment 3 Bart Van Assche 2013-10-23 12:20:08 UTC
A candidate fix has been checked in on the trunk as r13679. Does that help ?
Comment 4 Bart Van Assche 2013-10-23 13:10:01 UTC
Update: the real fix for this issue is in trunk r13686.
Comment 5 ewirch 2013-10-24 05:57:15 UTC
Sorry, the same errors are being reported.
Comment 6 Bart Van Assche 2013-10-24 07:16:31 UTC
Eduard, it would help a lot if you could do the following:
* Double check that your local copy of the Valgrind Subversion repository is up to date and that Valgrind has been rebuilt and reinstalled properly after the most recent update.
* Reproduce this issue.
* Copy the first address for which DRD reports a conflicting access.
* Rerun the test with the following additional DRD options (where ${addr} is the address that has been copied in the previous step): --read-var-info=yes --ptrace-addr=${addr}
* If the new run reports a conflicting access on the same address, store the DRD output in a text file and attach it to this bug ticket.
* If the new run reported a conflicting access on a different address, try a few times more until the first reported conflicting access is for the address specified via --ptrace-addr.
Comment 7 ewirch 2013-10-24 08:14:31 UTC
Created attachment 83073 [details]
drd r13688 conflict trace for 0x64341a8
Comment 8 ewirch 2013-10-24 08:14:44 UTC
Sure thing.

I made sure I'm using the current code by invoking "svn status -u" and by modifying the version number in configure.ac.

After building and installing valgrind --version reports: valgrind-3.9.0.SVN.r13688

Error reports strill occur. Created a trace and attached.
Comment 9 Bart Van Assche 2013-10-24 10:02:24 UTC
Thanks. Apparently an stpcpy() intercept was missing in drd. Such an intercept has been added in r13694. Does that help ?
Comment 10 ewirch 2013-10-24 11:29:41 UTC
Nice, errors are gone. For future bug reports: is a trace of the conflicting address is enough, or do you need a test case?
Comment 11 Bart Van Assche 2013-10-24 13:59:58 UTC
A test case is preferred. The trick with --ptrace-addr only works if a false positive report is caused by a missing intercept.