From: jeffw@cs.tamu.EDU (Jeffrey A Waller)
Subject: Data member overwritten in virtual base class
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 8 Apr 1992 23:19:03 GMT

I sent this once before, but it never showed up
one the newsgroup (for me).  So assuming that it
was lost somehow I am resending it.

These tests were done on a Sparcstation 1.
running SunOS 4.1.1 (also doesn't work under
4.1.2).  Version of gcc/g++: 2.1

The symptom:  Repeated new's and deletes of
a class AB (see below) results in virtual 
memory being exahusted. 

The immediate reason:  The (char*) class member
is being overwritten before the
memory allocated with new char[] can be
deleted.

I have attempted to provide the minimum amount
of code to produce the problem, yet there are
a fair number of things.

1)  The class hierarchy looks like the following:

         AB
        /  \
       /    \
      /      \
     A        B
     \       /
      \     / 
       \   /
         V

class AB: public A,public B
class A: public virtual V
class B: public virtual V

2) All classes have both a constructor and
   a VIRTUAL destructor.
     ^^^^^^^

3) The char* data member (see above) is
   the LAST data member in the class definition 
       ^^^^
   of V.


When the problem doesn't arise:

1)  If V, A, or B is repeatedly new'ed and deleted;
    moreover if AB singly inherits from A or B
    (not both at once) the problem does not occur 
    either.

2)  If the destructors are not virtual--I have not
    expirimented with if any member function
    (not necessarily the destructor) being virtual.

3)  If the data member is not the last in the class
    --it is not overwriten.
    
   
The CODE:


class V
{  protected:

      int a_variable;
      int another_variable;
      char *some_data;
  
   public:

      V()
      {  some_data = new char[100];
      }
  
      virtual ~V()
      {  delete some_data;
      }
};

class A: public virtual V
{  public:

      A():V() {}

      virtual ~A() {}
};

class B: public virtual V
{  public:

      B():V() {}

      virtual ~B() {}
};

class AB: public A,public B
{  public:

      AB():A(),B() {}

      virtual ~AB() {}
};

int main()
{  while(1) delete new AB();
}

If we add some printf statements the problem becomes apparent:

      V()
      {  some_data = new char[100];
         printf("V(): some_data = %d a_variable = %d another_variable = %d\n",some_data,a_variable,another_variable);
      }


      virtual ~V()
      {  printf("~V(): some_data = %d a_variable = %d another_variable = %d\n",some_data,a_variable,another_variable);
         delete some_data;
      }

      AB():A(),B()
      {  printf("AB(): some_data = %d a_variable = %d another_variable = %d\n",some_data,a_variable,another_variable);
      }

      virtual ~AB()
      {  printf("~AB(): some_data = %d a_variable = %d another_variable = %d\n",some_data,a_variable,another_variable);
      }

***************************************************************
trial 1 order of variables in V (leaks memory like a sieve)

int a_variable;
int another_variable;
char *some_data;

sparc47% make
rm -f test4
gcc -Wall -o test4 test4.C
sparc47% test4 | more
V(): some_data = 24976 a_variable = 0 another_variable = 0
AB(): some_data = 24976 a_variable = 0 another_variable = 0
~AB(): some_data = 24976 a_variable = 0 another_variable = 0
~V(): some_data = 16640 a_variable = 0 another_variable = 0
***************************************************************

***************************************************************
trial 2 order of variables in V (memory probs go away, but...):

int a_variable;
char *some_data;
int another_variable;

sparc47% make
rm -f test4
gcc -Wall -o test4 test4.C
sparc47% test4 | more
V(): some_data = 24976 a_variable = 0 another_variable = 0
AB(): some_data = 24976 a_variable = 0 another_variable = 0
~AB(): some_data = 24976 a_variable = 0 another_variable = 0
~V(): some_data = 24976 a_variable = 0 another_variable = 16640
***************************************************************


						-Jeff


Newsgroups: gnu.gcc.bug