[gnu.g++.bug] BUG in dtor derived from abstract

jj@idris.id.dk (Jesper Joergensen [ris]) (01/17/90)

ATTN: Michael Tiemann


I've just come accross another BUG, which bites in the destructor for a class
derived from an abstract base class with a pure virtual destructor. The
destructors for the other base classes, however, seems to be called quite
normally before the program fails. The below sample session contains a complete
executable example with trace output on the  cout  ostream:

***** SAMPLE SESSION START *****
% pwd
/usr/users/jj/GNUmail/g++errs
% cat virtdtortest.cc
#include <stream.h>

class Abstract {
public:
  virtual ~Abstract() =  0 ;
} ;

class Base {
  int *member ;
public:
  Base() {
    member = new int ; *member = 0 ;
    (cout << "Base::Base() executed\n").flush() ;
  }
  Base(int member1) {
    member = new int ; *member = member1 ;
    (cout << "Base::Base(int) executed\n").flush() ;
  }
  ~Base() {
    delete member ;
    (cout << "Base::~Base() executed\n").flush() ;
  }
} ;

class Derived : public Abstract, public Base {
public:
  Derived() {
    (cout << "Derived::Derived() executed\n").flush() ;
  }
  Derived(int x) : Base(x) {
    (cout << "Derived::Derived(int) executed\n").flush() ;
  }
  ~Derived() {
    (cout << "Derived::~Derived() executed\n").flush() ;
  }
} ;


int main(int argc, const char *argv) {
  (cout << "Derived d ;\n").flush() ;
  Derived d ;
  (cout << "Derived d1 = d ;\n").flush() ;
  Derived d1 = d ;
  (cout << "Derived d2 = 12 ;\n").flush() ;
  Derived d2 = 12 ;
  (cout << "Abstract *aptr = new Derived(12) ;\n").flush() ;
  Abstract *aptr = new Derived(12) ;
  (cout << "delete aptr ;\n").flush() ;
  delete aptr ;
  (cout << "return 0 ;\n").flush() ;
  return 0 ;
}
% g++ -v virtdtortest.cc -o virtdtortest
g++ version 1.36.3- (based on GCC 1.36)
 /usr/local/lib/gcc-cpp -+ -v -undef -D__GNUC__ -D__GNUG__ -D__cplusplus -Dvax -Dunix -D__vax__ -D__unix__ virtdtortest.cc /usr/tmp/cc018935.cpp
GNU CPP version 1.36
 /usr/local/lib/gcc-cc1plus /usr/tmp/cc018935.cpp -quiet -dumpbase virtdtortest.cc -version -o /usr/tmp/cc018935.s
GNU C++ version 1.36.3- (based on GCC 1.36) (vax) compiled by GNU C version 1.36.
default target switches: -munix
 /usr/local/lib/gcc-as -o virtdtortest.o /usr/tmp/cc018935.s
 /usr/local/lib/gcc-ld -o virtdtortest /lib/crt0.o virtdtortest.o -lg++ /usr/local/lib/gcc-gnulib -lc
% virtdtortest
Derived d ;
Base::Base() executed
Derived::Derived() executed
Derived d1 = d ;
Derived d2 = 12 ;
Base::Base(int) executed
Derived::Derived(int) executed
Abstract *aptr = new Derived(12) ;
Base::Base(int) executed
Derived::Derived(int) executed
delete aptr ;
Derived::~Derived() executed
Base::~Base() executed
Illegal instruction (core dumped)
****** SAMPLE SESSION END ******

I have analyzed the assembler code generated for the failing destructor, which
is contained in the above example in  Derived::~Derived(). After doing the body
of  Derived::~Derived()  itself and called  Base::~Base()  then some condition,
which is always true, causes a call to  abort(), hence the core is dumped. The
condition, as far as I can decifer the code, simply says:

	if (this != 0) abort() ;

and  this  will never be 0 within a destructor, so we'll always get an abort.

Having looked at the virtual function table for the abstract base class
Abstract, which contains abort instead of the destructor that doesn't exist, I
assume that this illegal-destructor-call-check is expanded unconditionally into
the destructor for the derived class. The idea of having abort in the virtual
function table is a simple and ellegant runtime check, but it should never go
into the destructor for the derived class.

It seems to me that something has been forgotten here, another of those special
cases (dealing with those destructors in a compiler, must be a pain in the ...
hhrrmm, sorry ... output stream :^).


Hope my explanation will help you on the right track to the error faster.

	Please resond, thanks in advance

	Jesper Jorgensen	jj@idris.id.dk

	Research associate
	Department of Computer Science
	Technical University of Denmark
	DK-2800 Lyngby
	DENMARK

PS: I should never have praised the new version of the compiler, now the BUGs
    seems to be queuing to bite (good old Murphy :^).