[omniORB] MSVC 5.0 bug: throw in ctor with virtual base class calls virtual base with wrong 'this'

Dietmar May dcmay@object-workshops.com
Thu, 3 Sep 1998 22:02:02 -0700


Ran across this bug while debugging a program. Since it deals with
calling the destructor of a virtual base class, which CORBA uses a
little bit :-), thought it might be of interest to others.

Essentially, if an exception is thrown by the constructor of a derived
class (where apparently there is at least one level of intermediate
derivation), the virtual base class' destructor is called with a 'this'
pointer that is offset by 4 or more bytes. A second side effect, at
least in the test program below, is that the virtual base class'
destructor is called a second time with the correct this pointer! This,
of course, is a problem if the virtual base class has any data to clean
up, because integers may become pointers, and pointers may reference
other objects...

Sorry, there are no known work-arounds. Also, see MS Q168936
Knowledge-base article.

=============================

#include <stdio.h>

class base
{
public:
    base ()
    {
        printf("base::base() this = 0x%lx\n", (long)(void*)this);
        i = 0;
    }
    virtual ~base ()
    {
        printf("base::~base() this = 0x%lx\n", (long)(void*)this);
        i = 0;
    }
protected:
    int i;
};

class intermed : public virtual base
{
public:
    intermed ()
    {
        printf("intermed::intermed () this = 0x%lx\n",
(long)(void*)this);
        j = 0;
        i = 1;
    }
    virtual ~intermed ()
    {
        printf("intermed::~intermed () this = 0x%lx\n",
(long)(void*)this);
        j = 0;
    }
protected:
    int j;
};

class derived : public intermed
{
public:
    derived ()
    {
        printf("derived::derived() this = 0x%lx\n", (long)(void*)this);
        k = 0;
        j = 1;
        throw int(0);
        k = 1;
    }
    ~derived ()
    {
        printf("derived::~derived() this = 0x%lx\n", (long)(void*)this);
        k = 0;
    }
protected:
    int k;
};

int main ()
{
    try
    {
        printf("creating derived object\n");
        derived d;
    }
    catch(...)
    {
        printf("caught exception from ctor\n");
    }
    printf("out of catch block\n");
    return 0;
}

=============================

Running this code results in the following output under NT 4.0 sp3:

creating derived object
base::base() this = 0x12ff68
intermed::intermed () this = 0x12ff5c
derived::derived() this = 0x12ff5c
intermed::~intermed () this = 0x12ff5c
base::~base() this = 0x12ff64
base::~base() this = 0x12ff68
caught exception from ctor
out of catch block

Regards,
Dietmar May

Software Architect
Object Workshops, Inc.
http://www.object-workshops.com
dcmay@object-workshops.com