This is the mail archive of the mailing list for the GCC project.

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

Error with vtable thunks in EGCS under Linux

This message describes my unsuccessful attempts to work around the
vtable-thunks bug in EGCS v1.1.1 on Linux (RedHat 5.1).  This is a very
serious bug for us any anyone considering using virtual inheritance, EGCS,
and Linux.  In summary, -fvtable-thunks are known to be broken, and it
seems impossible to use -fno-vtable-thunks under Linux. Does anyone have
any idea how to get code to compile with -fno-vtable-thunks on Linux?

Thanks in advance,

Rick Lerner, Ph.D.				20 Industrial Drive East
Senior Principal Software Engineer		Northampton, MA 01060
Amerinex Applied Imaging			(413) 582-9600

EGCS v1.1.1 on Linux sets -fvtable-thunks by default.  Unfortunately, the
generated thunks are incorrect when using virtual dispatch from a virtual
base class.  To avoid this problem, we tried to compile our application
libraries with -fno-vtable-thunks.  This fixed the virtual dispatch
but we now get a segmentation fault during a delete of an ofstream as shown
in the following program:

// segfaults at delete if compiled with:
// c++ -fno-vtable-thunks -o foo

#include <fstream.h>

int main ()
  char *fileName = "foo.txt";
  ostream* strm;
  strm = new ofstream(fileName);
  delete strm;
  return 0;

I first tried to recompile the EGCS release with -fno-vtable-thunks as the
default.  I made the following changes:

	change -fvtable-thunks to -fno-vtable-thunks

	replace #define DEFAULT_VTABLE_THUNKS 1
	with    #define DEFAULT_VTABLE_THUNKS 0
After rebuilding EGCS from scratch:
        mkdir /usr/gnu/Linux2/egcs-1.1.1
	cd /usr/gnu/Linux2/egcs-1.1.1
	/usr/gnu/src/egcs-1.1.1/configure --prefix=/usr/gnu
	make bootstrap
	make install

I was unable to link the above program because stdstrbufs.o contained the
following undefined symbol, which is still using thunk naming conventions:

nm stdstrbufs.o | grep vt
         U __vt_7filebuf

nm filebuf.o | grep vt     
         U _vt.7filebuf

nm streambuf.o | grep vt | grep filebuf
00000000 R _vt.7filebuf

I traced this back to the fact that libio under Linux uses
/usr/include/_G_config.h rather than one created within EGCS.
the file libio/config/ contains the following lines:

# Use the libio which comes with the local libc.

# Comment this out to avoid including the stdio functions in libiostream.a:

# Comment the above and uncomment the below to use the code in the Linux
# We have _G_config.h in /usr/include.

# We must not see the libio.h file from this library.

I then hacked the asm statement in stdstrbufs.C to use the proper non-thunk
symbol.  This resulted in a segfault as shown in the following backtrace:

(gdb) bt
#0  0x4006666d in __libc_free (mem=0x80545c0) at malloc.c:2866
#1  0x8051241 in __builtin_delete (ptr=0x80545c0)
#2  0x804de56 in streambuf::~streambuf (this=0x80545c0, __in_chrg=-1)
    at /usr/gnu/src/egcs-1.1.1/libio/
#3  0x804ec61 in filebuf::~filebuf (this=0x80545c0, __in_chrg=-1)
    at /usr/gnu/src/egcs-1.1.1/libio/
#4  0x40063da0 in __overflow (f=0x80545c0, ch=-1) at genops.c:162
#5  0x40063ae7 in _IO_file_xsputn (f=0x80545c0, data=0x8052e6b, n=4)
    at fileops.c:681
#6  0x804eea4 in filebuf::xsputn (this=0x80545c0, s=0x8052e6b "mid ", n=4)
    at /usr/gnu/src/egcs-1.1.1/libio/
#7  0x804bd7b in ostream::operator<< (this=0x80546c0, s=0x8052e6b "mid ")
    at /usr/gnu/src/egcs-1.1.1/libio/
#8  0x804a235 in mid::mid (this=0x8058508, __in_chrg=0) at
#9  0x804a2b5 in leaf::leaf (this=0x8058508, __in_chrg=1) at
#10 0x804a35a in main () at

I then attempted to have EGCS use its own _G_config.h and stdio files by
swapping the commented sections in libio/config/  This had two
ill-effects, first the libio makefile did not find a rule to make
and the generated _G_config.h file used the undefined type sigset_t.  At
point I gave up and commented out the offending "delete strm" statement
my program.

The following program demonstrates the vtable-thunk bug.
// compile this file with c++ -fvtable-thunks -o fred
// note the different values of this in the last call to doit.
// In a larger program all but the first call to doit exhibit
// the erroneous behavior.
#include <iostream.h>

class super
  virtual void doit(const char*) =0;

class top : virtual public super
  virtual void doit(const char*);

class mid : public top

class leaf : public mid
  int i;

void top::doit(const char* msg)
  cout << "top::doit (from " << msg << ")- \tthis: " << this << endl;

  cout << "mid- \t\t\t\t\tthis: " << this << endl;
  top::doit("mid top::doit");
  doit("mid       doit");
  this->doit("mid this->doit");
  top* hackptr = this;
  cout << "mid- \t\t\t\t\thackptr: " << hackptr << endl;
  hackptr->doit("mid hackptr->doit");	// <<<<<******** incorrectly adjusts
"this" by size of leaf

  cout << "leaf- \t\t\t\t\tthis: " << this << endl;

int main ()
  leaf* l = new leaf();
  return 0;

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