Just a quick exception management tip for today.
I was debugging a weird cascade of exceptions in an application today — it started with an EOleException from a database connection issue, and rapidly degenerated into a series of EAccessViolation and EInvalidPointer exceptions: often a good sign of Use-After-Free or Double-Free scenarios. Problem was, I could not see any place where we could be using a object after freeing it, even in the error case.
Here’s a shortened version of the code:
procedure ConnectToDatabase; begin try CauseADatabaseException; // yeah... bear with me here. except on E: EDatabaseError do begin E.Message := 'Failed to connect to database; the '+ 'error message was: ' + E.Message; raise(E); end; end; end;
Can you spot the bug?
I must admit I read through the code quite a few times before I spotted it. It’s not an in-your-face-look-at-me type of bug! In fact, the line in question appears to be completely logical and plausible.
Okay, enough waffle. The bug is in the last line of the exception handler:
When we call raise(E) we are telling Delphi that here is a shiny brand new exception object that we want to raise. After Delphi raises the exception object, the original exception object is freed, and … wait a minute, that’s the exception object we were raising! One delicious serve of Use-After-Free or Double-Free coming right up!
We should be doing this instead:
raise; // don't reference E here!
Another thing to take away from this is: remember that you don’t control the lifetime of the exception object. Don’t store references to it and expect it to survive. If you want to maintain knowledge of an inner exception object, use Delphi’s own nested exception management, available since Delphi 2009.
5 thoughts on “How not to re-raise an exception in Delphi”
The code above changes the message of the exception object. Just using raise does not re-raise the exception with the new, changed error message in Delphi 7. Is there a way to accomplish that?
That code should update the Message member of the Exception object in Delphi 7. If you are debugging the code, you will first see the original message in the debugger when the exception is initially raised, but your final exception handler should see the modified message.
You can also always raise a new exception, e.g. raise Exception.Create(‘New Error Message’);
I know this is a 5 year old blog post, but I just wanted to say thanks because you probably saved me a ton of trouble. Google led me here when I was searching for my re-raised exceptions question, and your solution is spot-on.
Yay! Glad I was able to help 🙂