This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Runtime crashes when mixing _GLIBCXX_DEBUG settings


On 11 October 2012 00:15, Jonathan Wakely wrote:
> On 10 October 2012 23:39, Evan Driscoll wrote:
>> I have a library (builds to a shared library) and a client program, both
>> under "my" control. I built a debug version of the library, forgetting
>> that doing so turns on _GLIBCXX_DEBUG to get the debug version of the
>> STL and such. (Doing this implicitly is probably a mistake, but that's
>> somewhat beside the point.) I then built the client program without
>> _GLIBCXX_DEBUG. It complied and linked successfully, but experienced
>> runtime crashes. Compiling the library without _GLIBCXX_DEBUG set or
>> compiling the client program with it set will cause it to work properly.
>>
>> My understanding from the documentation of the debug feature of the
>> library is that this shouldn't be able to happen: mixed _GLIBCXX_DEBUG
>> settings should either work or cause a linker error. Is this true? If
>
> Mangled names don't include function return types, so it's entirely
> possible to get crashes still, the system isn't foolproof.

Also, if you have code such as:

struct Foo
{
  std::vector<int> v;
  int* i = 0;
};

int f(const Foo& foo);

Then the mangled name of f(const Foo&) won't change depending on
whether _GLIBCXX_DEBUG is defined, but the offset of Foo::i will be
different, so accessing the member will be done at the wrong offset if
the code doing the access and the code that defined the object don't
agree on the object layout.

Here's a complete example showing no linker errors, but the program
prints two different addresses for the same variable, and valgrind
shows an invalid read.

$ cat d.h
// d.h
#ifndef D_H
#define D_H

#include <vector>
#include <iostream>

struct Foo
{
  std::vector<int> v;
  int i;
};

int f(const Foo& foo);

#endif
$ cat d1.cc
// d1.cc
#include "d.h"

int main()
{
  Foo* foo = new Foo();
  std::cout << &foo->i << '\n';
  return f(*foo);
}
$ cat d2.cc
// d2.cc
#include "d.h"

std::vector<int> v;
int f(const Foo& foo)
{
  std::cout << &foo.i << '\n';
  return foo.i;
}

$ cat Makefile
# Makefile
a.out: d1.o d2.o
        $(CXX) $^ -o $@
d2.o: CPPFLAGS = -D_GLIBCXX_DEBUG
$
$ make
g++    -c -o d1.o d1.cc
g++  -D_GLIBCXX_DEBUG  -c -o d2.o d2.cc
g++ d1.o d2.o -o a.out
$
$ ./a.out
0x2555028
0x2555048
$
$ valgrind ./a.out
==25882== Memcheck, a memory error detector
==25882== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==25882== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==25882== Command: ./a.out
==25882==
0x4c3a058
0x4c3a078
==25882== Invalid read of size 4
==25882==    at 0x4015BA: f(Foo const&) (in /dev/shm/a.out)
==25882==    by 0x401463: main (in /dev/shm/a.out)
==25882==  Address 0x4c3a078 is not stack'd, malloc'd or (recently) free'd
==25882==
==25882==
==25882== HEAP SUMMARY:
==25882==     in use at exit: 32 bytes in 1 blocks
==25882==   total heap usage: 1 allocs, 0 frees, 32 bytes allocated
==25882==
==25882== LEAK SUMMARY:
==25882==    definitely lost: 32 bytes in 1 blocks
==25882==    indirectly lost: 0 bytes in 0 blocks
==25882==      possibly lost: 0 bytes in 0 blocks
==25882==    still reachable: 0 bytes in 0 blocks
==25882==         suppressed: 0 bytes in 0 blocks
==25882== Rerun with --leak-check=full to see details of leaked memory
==25882==
==25882== For counts of detected and suppressed errors, rerun with: -v
==25882== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]