[omniORB] VC++ 5: omniORB client: Destructor called twice a fter throw!!!

Dietmar May dcmay@object-workshops.com
Thu, 15 Oct 1998 09:46:10 -0700


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------ =_NextPart_000_01BDF85B.519A0430
Content-Type: text/plain

Dave,

This appears to be similar to a problem which was reported back in
September. Essentially, if an exception is thrown from within an
incompletely constructed object (ie., in the constructor), the
destructor of the object is called twice, in our case once with an
INVALID pointer. Details of our report, and Randy Stroup's response are
attached.

Don't know whether this is applicable to your case or not, but just in
case ...

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

> I'm using omniORB 2.5 for both my CORBA client & server.  The client
is
> implemented using Visual C++ 5.0, under Win95.  I've encountered what
appears
> to be a VERY serious compiler bug in the client, as shown in the
excerpts 
> below from the actual code.
> 
> I've confirmed the double destructor call.  Is this really a VC++ bug?
Any
> suggestions for a workaround?

Regards,
Dietmar May

------ =_NextPart_000_01BDF85B.519A0430
Content-Type: message/rfc822
Content-Description: MSVC 5.0 bug: throw in ctor with virtual base class calls virtual base with wrong 'this'

Message-ID: <D45DD6430E16D211B7D1204C4F4F5020345E@OAK>
From: Dietmar May <dcmay@object-workshops.com>
To: "'omniORB (E-mail)'" <omniorb-list@orl.co.uk>
Subject: MSVC 5.0 bug: throw in ctor with virtual base class calls virtual
	 base with wrong 'this'
Date: Thu, 3 Sep 1998 22:02:02 -0700 
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.0.1459.74)
Content-Type: text/plain

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


------ =_NextPart_000_01BDF85B.519A0430
Content-Type: message/rfc822
Content-Description: Re: [omniORB] MSVC 5.0 bug: throw in ctor with virtual base class calls virtual base with wrong 'this'

Message-ID: <D45DD6430E16D211B7D1204C4F4F5020345F@OAK>
From: rshoup@tumbleweed.com
To: Dietmar May <dcmay@object-workshops.com>
Cc: "omniORB (E-mail)" <omniorb-list@orl.co.uk>
Subject: Re: [omniORB] MSVC 5.0 bug: throw in ctor with virtual base class
	 calls virtual base with wrong 'this'
Date: Fri, 4 Sep 1998 08:19:17 -0700 
MIME-Version: 1.0
X-Mailer: Internet Mail Service (5.0.1459.74)
Content-Type: text/plain;
	charset="iso-8859-1"

Dietmar -- 

We have experienced this problem for a while on NT, but never did the
research in the KnowledgeBase to find out if it had been reported :-) 
Thanks.

Our interim solution to this problem has been the following ugliness:

+ publicly derive all implementations from an ExceptionRethrower class
+ catch all exceptions in the outermost constructor, and store the
exception inside the ExceptionRethrower base class.
+ immediately after the constructor call in the calling method, call
object->RethrowCtorException().

This works best, of course, when all or most of your exceptions derive
from a single base class.  ExceptionRethrower is an auto_ptr-like
template which takes the exception type as a template argument, stores a
pointer to the exception, and exposes a method to rethrow the exception
if it exists.

Dietmar May wrote:
> 
> 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

-- 

-- Randy
_________________________________________________________________  
Randy Shoup                                     (650)569-3682  
Principal Engineer                              rshoup@tumbleweed.com  
Tumbleweed Software Corporation

------ =_NextPart_000_01BDF85B.519A0430--