[fpc-pascal] FPCUnit test + raise E;

Marcos Douglas md at delfire.net
Sun Sep 15 13:05:30 CEST 2013


On Sun, Sep 15, 2013 at 6:56 AM, Sven Barth <pascaldragon at googlemail.com> wrote:
> On 15.09.2013 03:21, Marcos Douglas wrote:
>>
>> Hi,
>>
>> 1) I have a code like that:
>>
>> procedure TghSQLConnector.Connect;
>> begin
>>    try
>>      FLib.Connect;
>>    except
>>      on E: Exception do
>>        DoOnException(E);
>>    end;
>> end;
>>
>>   https://github.com/mdbs99/Greyhound/blob/0.1.8/src/ghsql.pas#L1565
>>
>>
>> 2) DoOnException was implemented so:
>>
>> procedure TghSQLHandler.DoOnException(E: Exception);
>> begin
>>    if Assigned(FOnException) then
>>      FOnException(Self, E)
>>    else
>>      raise E;
>> end;
>>
>> https://github.com/mdbs99/Greyhound/blob/0.1.8/src/ghsql.pas#L443
>>
>>
>> So, as you see, if occurs a Exception the code checks if the event
>> (OnException) was setted. If yes, call user implementation; if no,
>> call raise E;
>> It works... but not when I uses in FPCUnit tests.
>>
>> See a simple test (this works):
>>
>> procedure TghSQLConnectorTest.TestOnException;
>> begin
>>    // catch
>>    FConn.OnException := @DoOnException;
>>    FConn.Script.Text := 'foo';
>>    FConn.Execute;
>> end;
>>
>> https://github.com/mdbs99/Greyhound/blob/0.1.8/test/ghsqltest.pas#L246
>>
>>
>> The code DoOnException is:
>>
>> procedure TghSQLTest.DoOnException(Sender: TObject; E: Exception);
>> begin
>>    AssertTrue(Assigned(E));
>> end;
>>
>> https://github.com/mdbs99/Greyhound/blob/0.1.8/test/ghsqltest.pas#L141
>>
>> So, if I change the test like bellow... BUM! SIGSEGV!!
>>
>> procedure TghSQLConnectorTest.TestOnException;
>> begin
>>    // removed >>> FConn.OnException := @DoOnException;
>>    FConn.Script.Text := 'foo';
>>    FConn.Execute;
>> end;
>>
>>
>> The ERROR is:
>> [Content]
>> Project test raised exception class 'External: SIGSEGV'.
>>
>>   At address 40B758
>
>
> Could you as a test replace the
>
> raise E
>
> with
>
> raise E at get_caller_addr(get_frame), get_caller_frame(get_frame);
>
> and check whether this makes a difference?

I tried. No makes difference.
(could you explain which the difference to call "raise" using "raise E
at [...]"?)

I implemented -- but not up to Git yet -- some like that:
procedure TghSQLHandler.DoOnException(E: Exception);
var
  NewEx: EghSQLError;
begin
  if Assigned(FOnException) then
    FOnException(Self, E)
  else
  begin
    NewEx := EghSQLError.Create(Self, E.Message);   // <<<
    NewEx.InnerException := E;                                  // <<<
    raise NewEx;
  end;
end;

So, if I recreate the Exception, it works in any cases. As you see, I
created a new property (InnerException) to save the original
exception to know what the real Exception happened...
But I think this introduces much more overhead to processing.

In my code I have classes that inherited from TghSQLHandler. This
class have the DoOnException method.
So DoOnException can be call many times in override methods. Maybe the
program "broke" the stack because "raise E" can be call and raise an
exception; the next "level" raise another; and next call again.  :/

> Could you also compile the RTL with debug information and maybe also without
> optimizations (CROSSOPT="-gl -O-") and rerun your test and display the stack
> trace (you'll need to enable "-gl" for your test as well)?
>
> Regards,
> Sven

I will try too.

Marcos Douglas



More information about the fpc-pascal mailing list