A.M. Hoornweg 144 Posted June 30, 2023 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
Stefan Glienke 2003 Posted June 30, 2023 (edited) 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 June 30, 2023 by Stefan Glienke Share this post Link to post
Der schöne Günther 316 Posted June 30, 2023 3 hours ago, Stefan Glienke said: We recently discussed this in https://quality.embarcadero.com/browse/RSP-18259 of course, I still haven't created the promised follow-up ticket 😓 Quote I suppose I will accept that this ticket has been closed and open a new one Share this post Link to post
Remy Lebeau 1397 Posted June 30, 2023 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
A.M. Hoornweg 144 Posted July 3, 2023 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