On 2015.01.06 at 03:18 -0500, Paul Smith wrote: > Hi all. It's possible my code is doing something illegal, but it's also > possible I've found a problem with -O3 optimization in GCC 4.9.2. I've > built this same code with GCC 4.8.2 -O3 on GNU/Linux and it works fine. > It also works with GCC 4.9.2 with lower -O (-O2 for example). > > When I try a build with GCC 4.9.2 -O3 I'm seeing a segfault, because we > get confused and invoke code that we should be skipping. > > I've compressed the test down to a self-contained sample file that I've > attached here. Save it and run: > > g++-4.9.2 -g -O3 -o mystring mystring.cpp > > Then: > > ./mystring > Segmentation fault > > You can also add -fno-strict-aliasing etc. and it doesn't make any > difference. > > The seg fault happens in the implementation of operator +=() where we're > appending to an empty string, so this->data is NULL. That method starts > like this (after the standard pushes etc.): > > 0x0000000000400a51 <+17>: mov (%rdi),%r14 > > which puts this->data (null) into %r14. Later on, with no intervening > reset of r14, we see this: > > 0x0000000000400ac5 <+133>: cmp %r12,%r14 > 0x0000000000400ac8 <+136>: je 0x400b18 <String::operator+=(char > const*)+216> > 0x0000000000400aca <+138>: subl $0x1,-0x8(%r14) > > We don't take the jump, and this (+138) is where we get the segfault > because r14 is still 0. This is in the if-statement in the release() > method where it subtracts 1 from count... but it should never get here > because this->data (r14) is NULL! > > (gdb) i r rip > rip 0x400aca 0x400aca <String::operator+=(char const*)+138> > (gdb) i r r14 > r14 0x0 0 > > Anyone have any thoughts about this? I know the inline new/delete is > weird but it's required to repro the bug, and we need our own new/delete > because we're using our own allocator.
gcc-help is more appropriate for this kind of question. If you compile with gcc-5 and -fsanitize=undefined you'll get: mystring.cpp:104:26: runtime error: null pointer passed as argument 2, which is declared to never be null So you should guard the memcpy() call. -- Markus