Bug 326091

Summary: False positive in libstdc++ std::string::_S_construct (gcc 4.7.2)
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:

Description ewirch 2013-10-16 11:11:05 UTC
Run this test case (sorry for the length, was not able to make it smaller):

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

char* list2byteArray() {
	// count data amount
	size_t data_size = 24;

	// copy data
	char *data = new char[data_size];

	for (size_t i = 0; i < data_size; i++) {
		data[i] = 'a';
	}
	data[data_size - 1] = 0;

	char *ret = strdup(data);
	delete[] data;
	return ret;
}

int addRecord() {
	char *data = list2byteArray();

	usleep(100);

	free(data);

	return 0;
}

void *fillTable(void *ptr) {
	for (int i = 0; i < 100; i++) {
		string id("000");
		id.append(1, 'a' + i);
		list<string> record;
		record.push_back("some data");

		addRecord();
	}
	usleep(1000 * 1000);

	return NULL;
}

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

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

	err = pthread_create(&thread2, NULL, &fillTable, NULL);
	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.");
}



Compiled with
> g++ -std=c++11 -O0 -g  test.cpp  -lpthread -o test
analysed with
> valgrind --tool=drd ./test

GCC-Information: g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Valgrind SVN revision r13645. Compiled using default configuration.

Reproducible: Always

Steps to Reproduce:
1. Compile as described
2. Run as described

Actual Results:  
Analysis result is:
==28897== drd, a thread error detector
==28897== Copyright (C) 2006-2013, and GNU GPL'd, by Bart Van Assche.
==28897== Using Valgrind-3.9.0.SVN and LibVEX; rerun with -h for copyright info
==28897== Command: ./test
==28897==
==28897== Thread 3:
==28897== Conflicting store by thread 3 at 0x0643325b size 1
==28897==    at 0x51194D8: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511BE28: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511BE72: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x4010AA: fillTable(void*) (main.cpp:38)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Address 0x643325b is at offset 27 from 0x6433240. Allocation context:
==28897==    at 0x4C2E2CB: operator new(unsigned long) (vg_replace_malloc.c:319)
==28897==    by 0x511A3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511BD94: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511BE72: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x4010AA: fillTable(void*) (main.cpp:38)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment start (thread 2)
==28897==    at 0x4C3274E: pthread_mutex_unlock (drd_pthread_intercepts.c:680)
==28897==    by 0x4C2ED5E: vgDrd_thread_wrapper (drd_pthread_intercepts.c:236)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment end (thread 2)
==28897==    at 0x563684D: ??? (syscall-template.S:82)
==28897==    by 0x5664783: usleep (usleep.c:33)
==28897==    by 0x40105D: addRecord() (main.cpp:29)
==28897==    by 0x40112A: fillTable(void*) (main.cpp:43)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897==
==28897== Thread 2:
==28897== Conflicting store by thread 2 at 0x064334ac size 1
==28897==    at 0x51194D8: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A6FE: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A9B4: std::string::_M_replace_aux(unsigned long, unsigned long, unsigned long, char) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x401731: std::string& std::string::_M_replace_dispatch<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int, std::__true_type) (basic_string.h:1699)
==28897==    by 0x40157B: std::string& std::string::replace<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int) (basic_string.h:1627)
==28897==    by 0x401488: std::string& std::string::append<int>(int, int) (basic_string.h:1042)
==28897==    by 0x4010CD: fillTable(void*) (main.cpp:39)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Address 0x64334ac is at offset 28 from 0x6433490. Allocation context:
==28897==    at 0x4C2E2CB: operator new(unsigned long) (vg_replace_malloc.c:319)
==28897==    by 0x511A3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A5B2: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A9B4: std::string::_M_replace_aux(unsigned long, unsigned long, unsigned long, char) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x401731: std::string& std::string::_M_replace_dispatch<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int, std::__true_type) (basic_string.h:1699)
==28897==    by 0x40157B: std::string& std::string::replace<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int) (basic_string.h:1627)
==28897==    by 0x401488: std::string& std::string::append<int>(int, int) (basic_string.h:1042)
==28897==    by 0x4010CD: fillTable(void*) (main.cpp:39)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment start (thread 3)
==28897==    at 0x4C3274E: pthread_mutex_unlock (drd_pthread_intercepts.c:680)
==28897==    by 0x4C2ED5E: vgDrd_thread_wrapper (drd_pthread_intercepts.c:236)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment end (thread 3)
==28897==    at 0x563684D: ??? (syscall-template.S:82)
==28897==    by 0x5664783: usleep (usleep.c:33)
==28897==    by 0x40105D: addRecord() (main.cpp:29)
==28897==    by 0x40112A: fillTable(void*) (main.cpp:43)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897==
==28897== Conflicting store by thread 2 at 0x064334ab size 1
==28897==    at 0x511AA00: std::string::_M_replace_aux(unsigned long, unsigned long, unsigned long, char) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x401731: std::string& std::string::_M_replace_dispatch<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int, std::__true_type) (basic_string.h:1699)
==28897==    by 0x40157B: std::string& std::string::replace<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int) (basic_string.h:1627)
==28897==    by 0x401488: std::string& std::string::append<int>(int, int) (basic_string.h:1042)
==28897==    by 0x4010CD: fillTable(void*) (main.cpp:39)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Address 0x64334ab is at offset 27 from 0x6433490. Allocation context:
==28897==    at 0x4C2E2CB: operator new(unsigned long) (vg_replace_malloc.c:319)
==28897==    by 0x511A3B8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A5B2: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x511A9B4: std::string::_M_replace_aux(unsigned long, unsigned long, unsigned long, char) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==28897==    by 0x401731: std::string& std::string::_M_replace_dispatch<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int, std::__true_type) (basic_string.h:1699)
==28897==    by 0x40157B: std::string& std::string::replace<int>(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, int, int) (basic_string.h:1627)
==28897==    by 0x401488: std::string& std::string::append<int>(int, int) (basic_string.h:1042)
==28897==    by 0x4010CD: fillTable(void*) (main.cpp:39)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment start (thread 3)
==28897==    at 0x4C3274E: pthread_mutex_unlock (drd_pthread_intercepts.c:680)
==28897==    by 0x4C2ED5E: vgDrd_thread_wrapper (drd_pthread_intercepts.c:236)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897== Other segment end (thread 3)
==28897==    at 0x563684D: ??? (syscall-template.S:82)
==28897==    by 0x5664783: usleep (usleep.c:33)
==28897==    by 0x40105D: addRecord() (main.cpp:29)
==28897==    by 0x40112A: fillTable(void*) (main.cpp:43)
==28897==    by 0x4C2ED64: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355)
==28897==    by 0x4E48E99: start_thread (pthread_create.c:308)
==28897==    by 0x566ACCC: clone (clone.S:112)
==28897==
==28897==
==28897== For counts of detected and suppressed errors, rerun with: -v
==28897== ERROR SUMMARY: 5 errors from 3 contexts (suppressed: 177 from 75)


Expected Results:  
No errors expected.
Comment 1 Bart Van Assche 2013-10-19 10:58:52 UTC
Thanks for the report and for the test case. It would be appreciated if you could help testing the following candidate fix:

drd: Avoid that optimized strlen() implementations trigger false positive race reports (#326091)

diff --git a/drd/drd_strmem_intercepts.c b/drd/drd_strmem_intercepts.c
index d77e824..7248907 100644
--- a/drd/drd_strmem_intercepts.c
+++ b/drd/drd_strmem_intercepts.c
@@ -70,6 +70,7 @@
  STRLEN(VG_Z_LIBC_SONAME,          strlen)
  STRLEN(VG_Z_LD_LINUX_SO_2,        strlen)
  STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
+ STRLEN(VG_Z_LIBC_SONAME,          __GI_strlen)
 #elif defined(VGO_darwin)
  STRLEN(VG_Z_LIBC_SONAME,          strlen)
 #endif
Comment 2 Bart Van Assche 2013-10-20 08:24:05 UTC
Note: the above patch has been checked in as r13664 on the trunk.
Comment 3 ewirch 2013-10-21 05:28:56 UTC
Confirmed: error is not reported any more