This is the mail archive of the gcc-bugs@gcc.gnu.org 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

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


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
problem,
but we now get a segmentation fault during a delete of an ofstream as shown
in the following program:

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

#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:

    config/mt-linux:
	change -fvtable-thunks to -fno-vtable-thunks

    gcc/config/linux.h:
	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.
Specifically,
the file libio/config/linux.mt 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:
# LIBIOSTREAM_OBJECTS = $(IO_OBJECTS) $(IOSTREAM_OBJECTS)
$(STDIO_WRAP_OBJECTS) $(OSPRIM_OBJECTS)
# LIBIOSTREAM_DEP = $(LIBIOSTREAM_OBJECTS) stdio.list
# LIBIOSTREAM_USE = $(LIBIOSTREAM_OBJECTS) `cat stdio.list`

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

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


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/streambuf.cc:224
#3  0x804ec61 in filebuf::~filebuf (this=0x80545c0, __in_chrg=-1)
    at /usr/gnu/src/egcs-1.1.1/libio/filebuf.cc:76
#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/filebuf.cc:205
#7  0x804bd7b in ostream::operator<< (this=0x80546c0, s=0x8052e6b "mid ")
    at /usr/gnu/src/egcs-1.1.1/libio/iostream.cc:784
#8  0x804a235 in mid::mid (this=0x8058508, __in_chrg=0) at fred.cc:37
#9  0x804a2b5 in leaf::leaf (this=0x8058508, __in_chrg=1) at fred.cc:44
#10 0x804a35a in main () at fred.cc:50


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




The following program demonstrates the vtable-thunk bug.
----------------------------------------------------------------------
	fred.cc
----------------------------------------------------------------------
// compile this file with c++ -fvtable-thunks -o fred fred.cc
// 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
{
public:
  virtual void doit(const char*) =0;
};

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

class mid : public top
{
public:
  mid();
};

class leaf : public mid
{
public:
  leaf();
  int i;
};



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

mid::mid()
{
  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
}

leaf::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]