You are not logged in.

#1 2011-07-24 01:18:56

neuront
Member
Registered: 2010-06-05
Posts: 9

[x64][libc++]valgrind compains when using std::string::replace

This sample code

#include <string>
#include <iostream>

int main ()
{
    std::string str("this is a test std::string.");
    str.replace(9, 5, "n example of");
    std::cout << str << std::endl;
    str.replace(8, 2, "a short");
    std::cout << str << std::endl;
    return 0;
}

run it with

$ g++ sample.cpp && valgrind ./a.out

then valgrind says

==8297== Source and destination overlap in memcpy(0x592f0e7, 0x592f0e2, 24)
==8297==    at 0x4C27B46: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8297==    by 0x4ED27A8: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/libstdc++.so.6.0.16)
==8297==    by 0x4ED284B: std::string::_M_replace_safe(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/libstdc++.so.6.0.16)
==8297==    by 0x4ED40DD: std::string::replace(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/libstdc++.so.6.0.16)
==8297==    by 0x400B7D: main

Have I done anything bad?

Following is my system and g++ info:

$ uname -a
Linux 2.6.39-ARCH #1 SMP PREEMPT Sat Jul 9 14:57:41 CEST 2011 x86_64 Intel(R) Core(TM) i5 CPU M 460 @ 2.53GHz GenuineIntel GNU/Linux

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/src/gcc-4.6.1/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --enable-gnu-unique-object --enable-linker-build-id --with-ppl --enable-cloog-backend=isl --enable-lto --enable-gold --enable-ld=default --enable-plugin --with-plugin-ld=ld.gold --disable-multilib --disable-libstdcxx-pch --enable-checking=release
Thread model: posix
gcc version 4.6.1 (GCC)

Offline

#2 2011-07-24 08:52:40

lunar
Member
Registered: 2010-10-04
Posts: 95

Re: [x64][libc++]valgrind compains when using std::string::replace

No, you haven't done anything wrong.  This is a bogus warning triggered by the standard library.  Just ignore it.

Last edited by lunar (2011-07-24 08:52:55)

Offline

#3 2011-07-25 15:37:13

tavianator
Member
From: Waterloo, ON, Canada
Registered: 2007-08-21
Posts: 859
Website

Re: [x64][libc++]valgrind compains when using std::string::replace

That actually looks like a pretty terrible bug in libstdc++.

EDIT: If you change the code to this:

#include <string>
#include <iostream>

namespace std
{
  template class basic_string<char>;
}

int main ()
{
    std::string str("this is a test std::string.");
    str.replace(9, 5, "n example of");
    std::cout << str << std::endl;
    str.replace(8, 2, "a short");
    std::cout << str << std::endl;
    return 0;
}

then g++ will instantiate std::string in your code instead of libstdc++.  Then running "g++ -Wall -g foo.cpp && valgrind ./a.out" gives

==16000== Source and destination overlap in memcpy(0x592f0e7, 0x592f0e2, 24)
==16000==    at 0x4C27B46: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==16000==    by 0x403D29: std::char_traits<char>::move(char*, char const*, unsigned long) (char_traits.h:269)
==16000==    by 0x4040AD: std::string::_M_move(char*, char const*, unsigned long) (basic_string.h:363)
==16000==    by 0x404443: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (basic_string.tcc:495)
==16000==    by 0x406735: std::string::_M_replace_safe(unsigned long, unsigned long, char const*, unsigned long) (basic_string.tcc:686)
==16000==    by 0x40601C: std::string::replace(unsigned long, unsigned long, char const*, unsigned long) (basic_string.tcc:425)
==16000==    by 0x4061F5: std::string::replace(unsigned long, unsigned long, char const*) (basic_string.h:1470)
==16000==    by 0x403B60: main (foo.cpp:14)
==16000== 

But line 269 of /usr/include/c++/4.6.1/bits/char_traits.h says

{ return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n)); }

and the disassembly clearly shows a call to memmove():

(gdb) disas
Dump of assembler code for function std::char_traits<char>::move(std::char_traits<char>::char_type*, std::char_traits<char>::char_type const*, std::size_t):
   0x0000000000403cff <+0>:    push   %rbp
   0x0000000000403d00 <+1>:    mov    %rsp,%rbp
   0x0000000000403d03 <+4>:    sub    $0x20,%rsp
   0x0000000000403d07 <+8>:    mov    %rdi,-0x8(%rbp)
   0x0000000000403d0b <+12>:    mov    %rsi,-0x10(%rbp)
   0x0000000000403d0f <+16>:    mov    %rdx,-0x18(%rbp)
   0x0000000000403d13 <+20>:    mov    -0x18(%rbp),%rdx
   0x0000000000403d17 <+24>:    mov    -0x10(%rbp),%rcx
   0x0000000000403d1b <+28>:    mov    -0x8(%rbp),%rax
   0x0000000000403d1f <+32>:    mov    %rcx,%rsi
   0x0000000000403d22 <+35>:    mov    %rax,%rdi
=> 0x0000000000403d25 <+38>:    callq  0x4037f0 <memmove@plt>
   0x0000000000403d2a <+43>:    leaveq 
   0x0000000000403d2b <+44>:    retq   
End of assembler dump.

So clearly this is a valgrind bug, where it's intercepting calls to memmove() as to memcpy() for some reason.  Reproducer:

#include <string.h>
#include <stdio.h>

int
main()
{
  char test[] = " This is a test.";
  memmove(test, test + 1, 5);
  printf("%s\n", test);
  return 0;
}

Valgrind complains about the parameters to memcpy() when there obviously isn't a call to it!  And, if you change the call to memcpy(), the warning goes away!  Valgrind has confused memmove() and memcpy().

EDIT 2: I've reported it here: https://bugs.kde.org/show_bug.cgi?id=278502

Last edited by tavianator (2011-07-25 20:49:42)

Offline

Board footer

Powered by FluxBB