Issue 3150: Exceptions in servant constructors (cxx_revision) Source: Triodia Technologies Pty Ltd (Mr. Michi Henning, michi(at)triodia.com) Nature: Uncategorized Issue Severity: Summary: I think we have a defect/omission in the C++ mapping with respect to exception safety. Consider a servant class with a constructor: class FooImpl : public virtual POA_Foo { public: FooImpl(); // ... }; Consider what happens if FooImpl() throws an exception for some reason. By the time FooImpl() runs, the base class constructor POA_Foo() has run already. So, when the compiler deals with the exception, it invokes ~POA_Foo(). The problem arises because, in our implementation at least, ~POA_Foo() checks if the reference count is zero and asserts if not. Resolution: Revised Text: Actions taken: December 20, 1999: received issue Discussion: deferred in June 2011 to the next RTF End of Annotations:===== Date: Sun, 19 Dec 1999 20:52:36 +1000 (EST) From: Michi Henning To: C++ Revision Task Force Subject: Exceptions in servant constructors Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: E!a!!Pj#e9[>$!!EP&!! I think we have a defect/omission in the C++ mapping with respect to exception safety. Consider a servant class with a constructor: class FooImpl : public virtual POA_Foo { public: FooImpl(); // ... }; Consider what happens if FooImpl() throws an exception for some reason. By the time FooImpl() runs, the base class constructor POA_Foo() has run already. So, when the compiler deals with the exception, it invokes ~POA_Foo(). The problem arises because, in our implementation at least, ~POA_Foo() checks if the reference count is zero and asserts if not. The only way around this problem I can see is to write the constructor like this: FooImpl::FooImpl() { try { // whatever... } catch (...) { POA_Foo::fixup_the_mess(); } } The intent is that POA_Foo::fixup_the_mess() (or whatever more polite name you'd like to choose ;-) can undo whatever state changes were made by the constructor. So, should we add some cleanup call like this? Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Sender: jon@floorboard.com Message-ID: <385D5F8B.CBA196CA@floorboard.com> Date: Sun, 19 Dec 1999 14:43:24 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.5.1 sun4m) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: C++ Revision Task Force Subject: Re: Exceptions in servant constructors References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: m^7!!4LBe9OoF!!i_Wd9 Michi Henning wrote: > > I think we have a defect/omission in the C++ mapping with respect > to exception safety. Consider a servant class with a constructor: > > class FooImpl : public virtual POA_Foo { > public: > FooImpl(); > // ... > }; > > Consider what happens if FooImpl() throws an exception for some > reason. > By the time FooImpl() runs, the base class constructor POA_Foo() has > run > already. So, when the compiler deals with the exception, it invokes > ~POA_Foo(). > > The problem arises because, in our implementation at least, > ~POA_Foo() > checks if the reference count is zero and asserts if not. > > The only way around this problem I can see is to write the > constructor > like this: > > FooImpl::FooImpl() > { > try { > // whatever... > } catch (...) { > POA_Foo::fixup_the_mess(); > } > } > > The intent is that POA_Foo::fixup_the_mess() (or whatever more > polite name > you'd like to choose ;-) can undo whatever state changes were made > by > the constructor. > > So, should we add some cleanup call like this? Ick. I thought about just calling _remove_ref() in the try block, but that results in the servant being destroyed twice. :-( I guess we do need a special function. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Date: Wed, 5 Jan 2000 11:10:13 +1000 (EST) From: Michi Henning To: C++ Revision Task Force Subject: Proposal for 3150 Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: j!^d9-mDe9:^\d9&jPd9 Hi, the drift of this proposal is to add a function to each skeleton that can be upcalled from a derived class before it throws an exception in order to undo any side effects that have happened in base class constructors: class POA_SomeInterface : ... { public: // ... void _constructor_exception(); // ... }; Each skeleton class has that member function. A servant class is obliged to call that member function on its base class if it throws an exception from the servant constructor. This gives the ORB a chance to clean up any side effects that may have occured in the base class constructor(s). The edits that follow formalize this proposal. Page 1-128: Add the following signature to the end of the protected section of ServantBase: void _constructor_exception(); Add the following text at the end of section 1.36.1: The _constructor_exception() member function is provided to permit the ORB to perform cleanup if a derived servant class throws an exception in its constructor. The _constructor_exception() member function is generated into each skeleton class. A compliant application must call this function before throwing an exception from a servant constructor. For example: class MyInterfaceImpl : public virtual POA_MyInterface { public: MyInterfaceImpl() { if (something_bad_happens()) { POA_MyInterface::_constructor_exception(); throw SomeException; } } // ... }; Calls to _constructor_exception() from anywhere but a servant constructor have undefined behavior. Calling _constructor_exception() without following the call with an actual exception throw has undefined behavior. Add the following signature at the end of the public section of RefCountServantBase on page 1-130: void _constructor_exception(); Add the following para immediately preceding section 1.36.3: As for servants that inherit from a skeleton class, the _constructor_exception() member function is provided to permit the ORB to perform cleanup if a derived constructor throws an exception. A compliant application must call this function before throwing an exception from a servant constructor. For example: class MyInterfaceImpl : public virtual POA_MyInterface, public virtual RefCountServantBase { public: MyInterfaceImpl() { if (something_bad_happens()) { POA_MyInterface::_constructor_exception(); RefCountServantBase::_constructor_exception(); throw SomeException; } } // ... }; Change the last code example on page 1-136 to read: // C++ class A : public virtual Object { public: virtual Short op1() = 0; virtual void op2(Long val) = 0; void _constructor_exception(); // See 1.36.1 ... }; Add the following signature at the end of the public section to class DynamicImplementation on page 1-145: void _constructor_exception(); Add the following para at the end of section 1.38.3: The _constructor_exception() function must be called by servants that throw an exception from the constructor. See . Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html From: Paul Kyzivat To: "'Michi Henning'" , C++ Revision Task Force Subject: RE: Proposal for 3150 Date: Wed, 5 Jan 2000 09:49:01 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: "M;e9VaZd9mCid9b*id9 This puts an unusual and error prone requirement on each and every implementation of a servant constructor. There must be a nicer way to do this! One possible alternative: a function to be called at the end of the user's constructor, indicating successful construction. This is at least fail-safe. It can be provided as part of the reference counting mixin, something like _begin_reference_counting(). Seems like there ought to be a tricky way to do this without any intrusion on user written code, but I haven't come up with one yet. Paul > -----Original Message----- > From: Michi Henning [mailto:michi@ooc.com.au] > Sent: Tuesday, January 04, 2000 8:10 PM > To: C++ Revision Task Force > Subject: Proposal for 3150 > > > Hi, > > the drift of this proposal is to add a function to each skeleton > that can be upcalled from a derived class before it throws an > exception > in order to undo any side effects that have happened in base class > constructors: > > class POA_SomeInterface : ... { > public: > // ... > void _constructor_exception(); > // ... > }; > > Each skeleton class has that member function. A servant class > is obliged > to call that member function on its base class if it throws > an exception > from the servant constructor. This gives the ORB a chance to clean > up > any side effects that may have occured in the base class > constructor(s). > > The edits that follow formalize this proposal. > > Page 1-128: > > Add the following signature to the end of the protected section of > ServantBase: > > void _constructor_exception(); > > Add the following text at the end of section 1.36.1: > > The _constructor_exception() member function is > provided to permit > the ORB to perform cleanup if a derived servant class throws > an exception in its constructor. The > _constructor_exception() member > function is generated into each skeleton class. A compliant > application must call this function before throwing an > exception > from a servant constructor. For example: > > class MyInterfaceImpl : public virtual POA_MyInterface { > public: > MyInterfaceImpl() { > if (something_bad_happens()) { > > POA_MyInterface::_constructor_exception(); > throw SomeException; > } > } > // ... > }; > > Calls to _constructor_exception() from anywhere but a servant > constructor have undefined behavior. Calling > _constructor_exception() > without following the call with an actual exception throw has > undefined behavior. > > Add the following signature at the end of the public section of > RefCountServantBase on page 1-130: > > void _constructor_exception(); > > Add the following para immediately preceding section 1.36.3: > > As for servants that inherit from a skeleton class, the > _constructor_exception() member function is provided to permit > the ORB to perform cleanup if a derived constructor throws > an exception. A compliant application must call this function > before throwing an exception from a servant constructor. For > example: > > class MyInterfaceImpl : > public virtual POA_MyInterface, > public virtual RefCountServantBase { > public: > MyInterfaceImpl() { > if (something_bad_happens()) { > > POA_MyInterface::_constructor_exception(); > > RefCountServantBase::_constructor_exception(); > throw SomeException; > } > } > // ... > }; > > Change the last code example on page 1-136 to read: > > // C++ > class A : public virtual Object > { > public: > virtual Short op1() = 0; > virtual void op2(Long val) = 0; > void _constructor_exception(); // See 1.36.1 > ... > }; > > Add the following signature at the end of the public section to > class DynamicImplementation on page 1-145: > > void _constructor_exception(); > > Add the following para at the end of section 1.38.3: > > The _constructor_exception() function must be called by > servants > that throw an exception from the constructor. See to ServantBase > section>. > > Cheers, > > Michi. > -- > Michi Henning +61 7 3891 5744 > Object Oriented Concepts +61 4 1118 2700 (mobile) > Suite 4, 904 Stanley St +61 7 3891 5009 (fax) > East Brisbane 4169 michi@ooc.com.au > AUSTRALIA > http://www.ooc.com.au/staff/michi-henning.html > X-Sender: vinoski@mail.boston.amer.iona.com X-Mailer: QUALCOMM Windows Eudora Pro Version 4.1 Date: Wed, 05 Jan 2000 12:19:57 -0500 To: Paul Kyzivat From: Steve Vinoski Subject: RE: Proposal for 3150 Cc: C++ Revision Task Force In-Reply-To: > <9B164B713EE9D211B6DC0090273CEEA91402A1@bos1.noblenet.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" X-UIDL: Ogpd9/?H!!%&Y!!nHgd9 At 09:49 AM 1/5/00 -0500, Paul Kyzivat wrote: >Seems like there ought to be a tricky way to do this without any intrusion >on user written code, but I haven't come up with one yet. I don't think there is. Michi first raised this to me a few months ago and I've thought about it off and on since then, coming up with no better ideas. Jon has also given it some thought and has come up empty. Perhaps Kevlin Henney has some ideas that we haven't considered, but Kevlin is not one to sit quietly in the background if there's an obvious answer. :-) --steve > > Paul > >> -----Original Message----- >> From: Michi Henning [mailto:michi@ooc.com.au] >> Sent: Tuesday, January 04, 2000 8:10 PM >> To: C++ Revision Task Force >> Subject: Proposal for 3150 >> >> >> Hi, >> >> the drift of this proposal is to add a function to each skeleton >> that can be upcalled from a derived class before it throws an >> exception >> in order to undo any side effects that have happened in base class >> constructors: >> >> class POA_SomeInterface : ... { >> public: >> // ... >> void _constructor_exception(); >> // ... >> }; >> >> Each skeleton class has that member function. A servant class >> is obliged >> to call that member function on its base class if it throws >> an exception >> from the servant constructor. This gives the ORB a chance to clean up >> any side effects that may have occured in the base class >> constructor(s). >> >> The edits that follow formalize this proposal. >> >> Page 1-128: >> >> Add the following signature to the end of the protected section of >> ServantBase: >> >> void _constructor_exception(); >> >> Add the following text at the end of section 1.36.1: >> >> The _constructor_exception() member function is >> provided to permit >> the ORB to perform cleanup if a derived servant class throws >> an exception in its constructor. The >> _constructor_exception() member >> function is generated into each skeleton class. A compliant >> application must call this function before throwing an exception >> from a servant constructor. For example: >> >> class MyInterfaceImpl : public virtual POA_MyInterface { >> public: >> MyInterfaceImpl() { >> if (something_bad_happens()) { >> >> POA_MyInterface::_constructor_exception(); >> throw SomeException; >> } >> } >> // ... >> }; >> >> Calls to _constructor_exception() from anywhere but a servant >> constructor have undefined behavior. Calling >> _constructor_exception() >> without following the call with an actual exception throw has >> undefined behavior. >> >> Add the following signature at the end of the public section of >> RefCountServantBase on page 1-130: >> >> void _constructor_exception(); >> >> Add the following para immediately preceding section 1.36.3: >> >> As for servants that inherit from a skeleton class, the >> _constructor_exception() member function is provided to permit >> the ORB to perform cleanup if a derived constructor throws >> an exception. A compliant application must call this function >> before throwing an exception from a servant constructor. For >> example: >> >> class MyInterfaceImpl : >> public virtual POA_MyInterface, >> public virtual RefCountServantBase { >> public: >> MyInterfaceImpl() { >> if (something_bad_happens()) { >> >> POA_MyInterface::_constructor_exception(); >> >> RefCountServantBase::_constructor_exception(); >> throw SomeException; >> } >> } >> // ... >> }; >> >> Change the last code example on page 1-136 to read: >> >> // C++ >> class A : public virtual Object >> { >> public: >> virtual Short op1() = 0; >> virtual void op2(Long val) = 0; >> void _constructor_exception(); // See 1.36.1 >> ... >> }; >> >> Add the following signature at the end of the public section to >> class DynamicImplementation on page 1-145: >> >> void _constructor_exception(); >> >> Add the following para at the end of section 1.38.3: >> >> The _constructor_exception() function must be called by servants >> that throw an exception from the constructor. See > to ServantBase >> section>. >> >> Cheers, >> >> Michi. >> -- >> Michi Henning +61 7 3891 5744 >> Object Oriented Concepts +61 4 1118 2700 (mobile) >> Suite 4, 904 Stanley St +61 7 3891 5009 (fax) >> East Brisbane 4169 michi@ooc.com.au >> AUSTRALIA >> http://www.ooc.com.au/staff/michi-henning.html >> From: Paul Kyzivat To: "'Steve Vinoski'" , Paul Kyzivat Cc: C++ Revision Task Force Subject: RE: Proposal for 3150 Date: Wed, 5 Jan 2000 12:39:02 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: >:Sd9>B From: Steve Vinoski [mailto:vinoski@iona.com] > I don't think there is. Michi first raised this to me a few > months ago and > I've thought about it off and on since then, coming up with no > better > ideas. Jon has also given it some thought and has come up > empty. Perhaps > Kevlin Henney has some ideas that we haven't considered, but > Kevlin is not > one to sit quietly in the background if there's an obvious > answer. :-) I only saw this one recently, and haven't spent any real effort looking for a solution. The fact that several smart people have tried makes me be inclined to agree with you. Lacking something totally unintrusive, I would prefer something that fails safe and doesn't require unusual coding practices. Making a call when there is an exception in general requires the body of the user's constructor (and possibly initializers as well) to be protected with try/catch(...). The fact that often this will not be required is worse, because people will be lulled into not thinking about the case when it is needed. At least a required initialization call can be simply inserted at the end of the constructor without much thought. Still not appealing, but preferable in my opinion, especially if only needed when using the reference counting mixin. Sender: jbiggar@corvette.floorboard.com Message-ID: <3873AAD0.C55A3318@floorboard.com> Date: Wed, 05 Jan 2000 12:34:24 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.6 sun4u) X-Accept-Language: en MIME-Version: 1.0 To: Paul Kyzivat CC: "'Steve Vinoski'" , C++ Revision Task Force Subject: Re: Proposal for 3150 References: <9B164B713EE9D211B6DC0090273CEEA91402AA@bos1.noblenet.com> Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: ;Kd!!VfQ!!gl;e9YOOe9 Paul Kyzivat wrote: > > > From: Steve Vinoski [mailto:vinoski@iona.com] > > > I don't think there is. Michi first raised this to me a few > > months ago and > > I've thought about it off and on since then, coming up with no > better > > ideas. Jon has also given it some thought and has come up > > empty. Perhaps > > Kevlin Henney has some ideas that we haven't considered, but > > Kevlin is not > > one to sit quietly in the background if there's an obvious > answer. :-) > > I only saw this one recently, and haven't spent any real effort > looking for > a solution. The fact that several smart people have tried makes me > be > inclined to agree with you. > > Lacking something totally unintrusive, I would prefer something that > fails > safe and doesn't require unusual coding practices. > > Making a call when there is an exception in general requires the > body of the > user's constructor (and possibly initializers as well) to be > protected with > try/catch(...). The fact that often this will not be required is > worse, > because people will be lulled into not thinking about the case when > it is > needed. > > At least a required initialization call can be simply inserted at > the end of > the constructor without much thought. Still not appealing, but > preferable in > my opinion, especially if only needed when using the reference > counting > mixin. I've also racked my brain for a better solution, but there isn't one. Michi's proposal at least has the benefit of not breaking code that doesn't currently throw an exception out of a servant constructor, whereas your proposal breaks all current code. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org From: Paul Kyzivat To: "'Jonathan Biggar'" , Paul Kyzivat Cc: "'Steve Vinoski'" , C++ Revision Task Force Subject: RE: Proposal for 3150 Date: Wed, 5 Jan 2000 16:15:08 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: 2iNe9h$T!!a;Wd9#kEe9 > From: Jonathan Biggar [mailto:jon@floorboard.com] > I've also racked my brain for a better solution, but there isn't one. > Michi's proposal at least has the benefit of not breaking code that > doesn't currently throw an exception out of a servant constructor, > whereas your proposal breaks all current code. I'll grant you that one. But we need to be concerned about increasing the number of arcane features to the point where real people (as opposed to people like us) give up trying to use the C++ binding. Date: Thu, 6 Jan 2000 08:30:23 +1000 (EST) From: Michi Henning To: Paul Kyzivat cc: "'Jonathan Biggar'" , "'Steve Vinoski'" , C++ Revision Task Force Subject: RE: Proposal for 3150 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA91402B3@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: &JPe94`9e96/Me9;pcd9 On Wed, 5 Jan 2000, Paul Kyzivat wrote: > But we need to be concerned about increasing the number of arcane features > to the point where real people (as opposed to people like us) give up trying > to use the C++ binding. The whole problem is caused by the fact that we are deriving servants from a non-abstract base class (ServantBase). If the base class constructor has a side effect, then if the derived class constructor throws an exception, we are hosed and need such a work-around. This really is a case to support the old argument that there should be no such thing as a non-abstract base class and implementation inheritance. (However, I'm not enough of a purist to support that argument ;-) So, the problem is inherent in the inheritance from a non-abstract base class (or, if you like, the inability of C++ to tell the base class constructor that a derived constructor has thrown an exception ;-) If the fix I suggested is considered too radical or ugly, we could do something else: simply prevent the skeleton constructor from throwing any exceptions at all: class POA_Foo : ... { public: POA_Foo() throw(); // ... }; This makes the problem disappear in a puff of smoke (at the cost of preventing servants from throwing exceptions from their constructor). Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Sender: jbiggar@corvette.floorboard.com Message-ID: <3873C9CF.E572E30E@floorboard.com> Date: Wed, 05 Jan 2000 14:46:39 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.6 sun4u) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: Paul Kyzivat , "'Steve Vinoski'" , C++ Revision Task Force Subject: Re: Proposal for 3150 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: O?:!!BDLe9NH4!!p37!! Michi Henning wrote: > > On Wed, 5 Jan 2000, Paul Kyzivat wrote: > > > But we need to be concerned about increasing the number of arcane > features > > to the point where real people (as opposed to people like us) give > up trying > > to use the C++ binding. > > The whole problem is caused by the fact that we are deriving > servants from > a non-abstract base class (ServantBase). If the base class > constructor > has a side effect, then if the derived class constructor throws an > exception, > we are hosed and need such a work-around. This really is a case to > support > the old argument that there should be no such thing as a > non-abstract > base class and implementation inheritance. (However, I'm not enough > of a > purist to support that argument ;-) > > So, the problem is inherent in the inheritance from a non-abstract > base class > (or, if you like, the inability of C++ to tell the base class > constructor > that a derived constructor has thrown an exception ;-) Actually, the problem arose when OOC defined the destructor implementation for the refcounted servant to assert if the refcount wasn't zero. This isn't required by the C++ language mapping. Perhaps it would just be better to tell OOC not to do that? :-) -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Date: Thu, 6 Jan 2000 08:59:42 +1000 (EST) From: Michi Henning To: Jonathan Biggar cc: Paul Kyzivat , "'Steve Vinoski'" , C++ Revision Task Force Subject: Re: Proposal for 3150 In-Reply-To: <3873C9CF.E572E30E@floorboard.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: VXH!!([1!!*>N!!4+:!! On Wed, 5 Jan 2000, Jonathan Biggar wrote: > Actually, the problem arose when OOC defined the destructor > implementation for the refcounted servant to assert if the refcount > wasn't zero. This isn't required by the C++ language mapping. > Perhaps > it would just be better to tell OOC not to do that? :-) Well, you could argue that (and we will consider it). But it would mean to leave the reference count hanging... However, the problem goes beyond this because other implementations may have other side-effects. The mapping doesn's say that the constructor of a servant base class must be free of side-effects, does it? ;-) Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html