implicit exception frames? [Re: [fpc-pascal] If an Assert fails in constructor, then destructor called (?)]

Michael Van Canneyt michael at freepascal.org
Thu Jul 2 16:41:01 CEST 2009



On Thu, 2 Jul 2009, Martin Friebe wrote:

> Inoussa OUEDRAOGO wrote:
>> 2009/6/29 Tom Verhoeff <T.Verhoeff at tue.nl>:
>> 
>>> While tracing a nasty bug (?), I discovered the hard way that when
>>> an Assert is done in a constructor, and it fails, then the destructor
>>> (Destroy) is automatically called.
>>> 
>> 
>> Indeed, when an exception is raised in the constructor, be it an
>> "assert" exception or not, the destructor is called to allow the
>> developer to clean up the "in-construction" instance's members he has
>> already initialized.
>> 
> I just cam across this thread. While I am not opposing the behaviour as it's 
> stand (it could be useful anyway), it raises another question.
>
> Does that mean that an implicit exception-frame (or whatever this is called) 
> is inserted *each* time you create/instantiate an object?
>
> Now I understand, object instantiation comes at a cost anyway (memory 
> allocation), this does add to the cost of instantiation. And the only 
> error/exception, which really *all* classes can encounter in a constructor, 
> is out of memory for the object itself => In which case create is never 
> called (because NewInstance fails), and Destroy should not be called (as 
> there is no instance that could be passed to destroy).
> So There could be calls to create where a developer does not want (and not 
> need) any exception stack frame.
>
> I also wonder why this special kind of "garbage collector"? Pascal has 
> automatic behaviour to handle/free resources for:
> - strings
> - open array
> - apparently classes/objects, but only inside the constructor ?
>
> The last one does of course not apply to objects hold by the failed object, 
> but I assume that, if Destroy is called, the instance is also freed?
> So why are objects handled special in the constructor? If they raise an 
> exception anywhere else in there live, then you need to care yourself about 
> catching it, and freeing them?

Because you cannot handle it yourself. Assume the following statement:

   MyClass:=TSomeClass.Create;

if an exception happens inside the constructor, then no instance pointer is 
assigned to MyClass, since execution after the exception is raised is 
continued at the next except/finally block.

That means you cannot handle destruction in the except block (assuming you
wrote one) since you have no pointer to work with.

Therefor the constructor code must call the destructor in case of an error.

Construction is handled very specially by the compiler. 
The special exception frame is in the constructor helper code. 
Your own routine does not get an extra exception frame.

For instance:

procedure DOCreate;

begin
  TMyObject.Create;
end;

Results in the following (64-bit) assembler:

.globl  P$TESTCF_DOCREATE
         .type   P$TESTCF_DOCREATE, at function
P$TESTCF_DOCREATE:
         pushq   %rbp
         movq    %rsp,%rbp
         movq    $VMT_P$TESTCF_TMYOBJECT,%rsi
         movq    $0,%rdi
         call    P$TESTCF_TMYOBJECT_$__CREATE$$TMYOBJECT
         leave
         ret

As you can see, there is no extra exception frame.

Michael.



More information about the fpc-pascal mailing list