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