Jump to content
A.M. Hoornweg

ReleaseExceptionObject not working?

Recommended Posts

Hello all,

 

I have the impression that Sysutils.ReleaseExceptionObject is not working as advertized.

I see that it's just a dummy procedure. Please find a testcase below.

 

Calling TestCase(True) causes a memory leak whereas TestCase(false) works correctly. The memory leak is gone when I free the exception object manually.

 


procedure AnalyzeException(ReRaise: Boolean);
var e: Exception;
begin
  e := Exception(AcquireExceptionObject);
   // ...Do something with the object ...

  if ReRaise then
    raise (e) at ExceptAddr
  else
    ReleaseExceptionObject ; //This should work but is a dummy procedure...
    //FreeAndNil(e);  --> this works though
end;



Procedure TestCase (SwallowException:Boolean);
var OneThousand, Zero: integer; d: double;
begin
  Zero := 0;
  OneThousand := 1000;
  try
    d := OneThousand / Zero;
  except
    AnalyzeException(SwallowException);
  end;
end;

 

Share this post


Link to post

We recently discussed this in https://quality.embarcadero.com/browse/RSP-18259 - even after reading the comment in System.pas I cannot imagine what the idea behind ReleaseExceptionObject was given that AcquireExceptionObject returns a reference and thus also passes ownership to the caller. Thus the parameterless ReleaseExceptionObject cannot work by design given that it does not have any parameter where you might pass the previous result of AcquireExceptionObject.

 

Even the documentation tells that this routine is just there for backwards compatibility and should not be used (I would have marked it as deprecated long ago so people that might still have it in their code would remove it)

https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.ReleaseExceptionObject

Edited by Stefan Glienke

Share this post


Link to post

I question the design of the code shown.  I would have opted to implement it more like this instead:

procedure AnalyzeException(const E: Exception);
begin
  // ...Do something with the object ...
end;

procedure TestCase (ReRaiseException {or: SwallowException}: Boolean);
var
  OneThousand, Zero: integer;
  d: double;
begin
  Zero := 0;
  OneThousand := 1000;
  try
    d := OneThousand / Zero;
  except
    on E: Exception do
    begin
      AnalyzeException(E);
      if ReRaiseException {or: not SwallowException} then raise;
    end;
  end;
end;

 

Share this post


Link to post
On 6/30/2023 at 7:17 PM, Remy Lebeau said:

I question the design of the code shown.  I would have opted to implement it more like this instead:


procedure AnalyzeException(const E: Exception);
begin
  // ...Do something with the object ...
end;

procedure TestCase (ReRaiseException {or: SwallowException}: Boolean);
var
  OneThousand, Zero: integer;
  d: double;
begin
  Zero := 0;
  OneThousand := 1000;
  try
    d := OneThousand / Zero;
  except
    on E: Exception do
    begin
      AnalyzeException(E);
      if ReRaiseException {or: not SwallowException} then raise;
    end;
  end;
end;

 

 

Remy, this was just a tiny test case to reproduce the memory leak caused by the non-functionality of ReleaseExceptionObject. 

 

I was just trying to get a better understanding of the inner workings and lifetime management of exceptions. One such exercise was to detect if an exception was active (hence not passing it as a parameter), then to analyze it (and log the information somewhere) and to conditionally re-raise it based on the information gathered.  Ideally I'd like to hook into the system before "except" even fires.

 

 

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×