[omniORB] MSVC 5.0 bug: throw in ctor with virtual base class calls virtual
base with wrong 'this'
Randy Shoup
rshoup@tumbleweed.com
Fri, 04 Sep 1998 08:19:17 -0700
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