Programs segfault when deleting a pointer which refers to a virtually-derived class

Matthias Klose doko@cs.tu-berlin.de
Fri Nov 12 02:39:00 GMT 1999


[This behaviour/bug was reported on the Debian bug tracking
 system. Please CC 47992@bugs.debian.org on replies.
 Some part of this report already was reported, here is the
 complete report, including followups]

Date: Thu, 21 Oct 1999 22:09:12 -0400
From: Daniel Burrows <Daniel_Burrows@brown.edu>
To: Debian Bug Tracking System <submit@bugs.debian.org>
Subject: Programs segfault when deleting a pointer which refers to a virtually-derived class

  Hello.  I believe that I've found a g++ bug; however, I'm not sure (C++
is a big and hairy language, and I may misunderstand what is allowed and what
isn't).  The problem is with a situation such as the following:

  Class A is an abstract base class.
  Classes B and C (for whatever reason) are virtually derived from A
  Class D is derived from both B and C.

  In this situation, calling class D's destructor appears to result in a
segfault -- sometimes.  In particular, if the object is referenced by a
pointer to type A, the program will segfault.  If it is referenced by a pointer
to type B or C the behavior will vary depending on which was declared first
in the ancestor list; if D was declared as:
class D:public B, public C

  then deleting a B* pointer which refers to D will succeed but a C* pointer
will segfault.  If it was declared the other way around, the behavior will be
reversed.

  Deleting a D* pointer to the object appears to always work.

  I have attached a program which shows the above behavior in a reliable manner.
The compiler outputs no warnings (even with -Wall); the segfault occurs even
on optimization level O0.  You can try various permutations to check the other
cases.

  If this is just a Bad Thing[tm] to do, I misunderstand virtual inheritence
badly and will stop doing it :)  However, I think issuing a warning in this
case would be good then.

  Daniel


// test.cc
//
// Argh, I think I found a g++ bug.

#include <iostream.h>

class ancestor
{
public:
  virtual void foo()=0;
};

class other_child:virtual public ancestor
{
public:
  virtual void dostuff()=0;
  virtual void domorestuff()=0;
};

class danger:virtual public ancestor
{
public:
  virtual ~danger() {}
};

class danger_child:public danger, public other_child
{
public:
  void foo() {cout<<"Foo!\n";}
  void dostuff() {cout<<"Doing stuff\n";}
  void domorestuff() {cout<<"Doing more stuff\n";}

  ~danger_child() {}
};

int main(int argc, void *argv[])
{
  other_child  *tester=new danger_child;
  // Make the pointer be of type danger_child to avoid segfaulting.
  // other_child segfaults, danger doesn't doesn't.

  tester->foo();

  delete tester;

  return 0;
}



Date: Sat, 23 Oct 1999 13:05:28 -0400
From: Daniel Burrows <Daniel_Burrows@brown.edu>
To: 47992@bugs.debian.org

  I was looking around in the gcc Web pages and discovered a similar problem
(although without the multiple-inheritence stuff) -- it seems that the
definition of `ancestor' should be changed to:

class ancestor
{
public:
  virtual void foo()=0;

  virtual ~ancestor() {}
};

  -- that is, an empty virtual distructor has to be added.  This eliminates
the segfaulting (both in the test code and in my code)

  However, I still consider this to be a bug in g++; in -Wall -Werror mode
it ought to report an error when a class containing virtual methods does not
have a virtual destructor (since that's the problem here) -- in fact, it has
given me such an error for other code!  I don't see offhand why it didn't
give me an error for this, or why the code worked for some pointers but not for
others..
  I suspect a C++/g++ guru has to answer that.

  Daniel


Date: Sat, 6 Nov 1999 14:11:10 -0500
From: Daniel Burrows <Daniel_Burrows@brown.edu>
To: gcc-bugs@gcc.gnu.org
Cc: 47922@bugs.debian.org

  Ok.  After a little research, here's the problem.  The following code
segfaults unless an empty virtual destructor is added to the 'ancestor' class
or midchild's inheritence is changed to be non-virtual.  However, it compiles
without a complaint on -Wall -Werror.  I think that some sort of check for this
situation should be implemented and a warning issued.  A warning is issued
already if "ancestor" contains a non-virtual destructor, but in this code
it doesn't contain a destructor at all.

================================================================================
#include <iostream.h>

class ancestor
{
public:
  virtual void foo()=0;
};

class midchild:virtual public ancestor
{
public:
  virtual ~midchild() {}
};

class child:public midchild
{
public:
  virtual void foo() {cout<<"Foo!\n";}

  ~child() {}
};

int main(int argc, char *argv[])
{
  ancestor *obj=new child;
  obj->foo();
  delete obj;
}
================================================================================



More information about the Gcc-bugs mailing list