Wagner Landgraf 43 Posted March 5, 2023 Considering the following code: try except on E: Exception do begin DoSomething; raise; end; end; Is it possible, in "real" applications (*), that in the case of something bad happens, DoSomething method does not execute? (*) I know that any object can be raised as an exception, so I understand that in theory, you can have exception objects that do not inherit from Exception class. But my question is more in this way: I know that my code doesn't raise any exception object that does not inherit from Exception. Also consider that third party libraries used do not do that. Is it still possible that DoSomething method doesn't execute? Say, for example, if some really low level error happen, Windows API calls, DLLs, etc.? Share this post Link to post
FPiette 382 Posted March 5, 2023 Probably if the process is aborted, DoSomething will not execute. Same if power turned off. Same if fatal system error. Share this post Link to post
Wagner Landgraf 43 Posted March 5, 2023 9 minutes ago, FPiette said: Probably if the process is aborted, DoSomething will not execute. Same if power turned off. Same if fatal system error. Assuming this is not sarcasm, as English is not my main language: my question refers to a situation where the application continues executing. Share this post Link to post
Uwe Raabe 2057 Posted March 5, 2023 I am reluctant to write the trivial case, but it won't execute if just no exception bubbles up to that point, perhaps because it is caught (not necessary handled properly) at some deeper level. Just curious: What problem are you actually trying to solve? 1 Share this post Link to post
Wagner Landgraf 43 Posted March 5, 2023 (edited) 6 minutes ago, Uwe Raabe said: Just curious: What problem are you actually trying to solve? I've detected an odd behavior in an application that I can't explain yet why it happened. I searched for database transaction management as I felt it was related to it. All the transaction-related code has the usually pattern try..except, having a Rollback in the except block followed by a raise. Then I found there was only a single try..except which was constructed the way in my first post. DoSomething would be the rollback. All the other transaction-handling in the application code had the rollback just directly in the except block, not inside the "on E: Exception do". Interestingly enough, the different try..except was in a place that is somehow involved with the error. So I wondered if there might be a remote chance that some error happened, a non Exception object was raised, the rollback was not called, the exception was re-raised and everything continued as usual, but without the call to the rollback. Edited March 5, 2023 by Wagner Landgraf Share this post Link to post
programmerdelphi2k 237 Posted March 5, 2023 (edited) maybe this can happens because the many languages use a "CLR" as proxy (between original language and platform target) then, I think that can happens in rare case... Quote The C# language's exception handling features help you deal with any unexpected or exceptional situations that occur when a program is running. Exception handling uses the try, catch, and finally keywords to try actions that may not succeed, to handle failures when you decide that it's reasonable to do so, and to clean up resources afterward. Exceptions can be generated by the common language runtime (CLR), by .NET or third-party libraries, or by application code. Exceptions are created by using the throw keyword. https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/exceptions/ Quote 20.3 The System.Exception class The System.Exception class is the base type of all exceptions. This class has a few notable properties that all exceptions share: Message is a read-only property of type string that contains a human-readable description of the reason for the exception. InnerException is a read-only property of type Exception. If its value is non-null, it refers to the exception that caused the current exception. (That is, the current exception was raised in a catch block handling the InnerException.) Otherwise, its value is null, indicating that this exception was not caused by another exception. The number of exception objects chained together in this manner can be arbitrary. The value of these properties can be specified in calls to the instance constructor for System.Exception. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/exceptions Edited March 5, 2023 by programmerdelphi2k 1 Share this post Link to post
Marco V 3 Posted March 5, 2023 Corruption of the stack can mess up SEH I guess. 2 Share this post Link to post
SwiftExpat 65 Posted March 5, 2023 You could try to write the except statement with the else syntax to see if it gets caught. I had to do this in web core, null items will raise an exception that are a special exception. try ... except on E: Exception do Logger.Warn('Failed app tool init : ' + E.Message, self); else // handle everything else Logger.Warn('Failed app tool init', self); end; 4 Share this post Link to post
David Heffernan 2345 Posted March 6, 2023 (edited) 16 hours ago, Wagner Landgraf said: Then I found there was only a single try..except which was constructed the way in my first post. DoSomething would be the rollback. All the other transaction-handling in the application code had the rollback just directly in the except block, not inside the "on E: Exception do". Interestingly enough, the different try..except was in a place that is somehow involved with the error. So I wondered if there might be a remote chance that some error happened, a non Exception object was raised, the rollback was not called, the exception was re-raised and everything continued as usual, but without the call to the rollback. Its simple to check this by changing the code to handle all exceptions, not just ones that derive from Delphi's Exception class. I wonder, how would a language exception raised by another module in your process appear as when it reach your exception handler? Edited March 6, 2023 by David Heffernan Share this post Link to post
Cristian Peța 103 Posted March 6, 2023 (edited) 16 hours ago, Wagner Landgraf said: All the transaction-related code has the usually pattern try..except, having a Rollback in the except block followed by a raise. I use this construct and this will go well with any exceptions but there is a weakness if the library will not set InTransaction how it should. try StartTransaction; .... Commit; finally if InTransaction then Rollback; end; Edited March 6, 2023 by Cristian Peța Share this post Link to post
Der schöne Günther 316 Posted March 6, 2023 That's an interesting approach, never seen it before. 🤔 To this day, I also go with try .. except Rollback; raise; end 1 Share this post Link to post
SwiftExpat 65 Posted March 6, 2023 2 hours ago, David Heffernan said: I wonder, how would a language exception raised by another module in your process appear as when it reach your exception handler? I believe this is what your asking for, something like this, focused on the else clause, adjusted for the faulting module. "You can access the current except value via JSExceptValue in unit JS." "Note that this is only valid inside the catch-block. The compiler will not warn, if you use it outside. " Unit MyModule; Interface Uses SysUtils, Math, JS; Function DoIt(n: integer): double; Implementation Function DoIt(n: integer): double; var E: Exception; Begin try Result:=double(7.0)/n; if not IsFinite(Result) then if n=0 then raise EZeroDivide.Create else raise EOverflow.Create; except on EZeroDivide do Result:=0.0; on E2: EOverflow do Result:=0.0; else raise EAbort.Create('Something other: '+String(JS.JSExceptObject)); end; End; End. Reference : https://wiki.freepascal.org/Pas2js_Transpiler#Translating_try..except Share this post Link to post
Wagner Landgraf 43 Posted March 6, 2023 3 hours ago, David Heffernan said: Its simple to check this by changing the code to handle all exceptions, not just ones that derive from Delphi's Exception class. Sure, that is already done. I was just wondering if that was a possible thing to happen. But it looks like that's not the case. Share this post Link to post
programmerdelphi2k 237 Posted March 6, 2023 (edited) as rule, the "order" help you when exception can occurs... but it's a paranoic way not? type ENotRelated = exception; procedure TForm1.Button1Click(Sender: TObject); begin try raise ENotRelated.Create('help help'); except on E: EDivByZero do // a specific exception ShowMessage('Ok, Im Specific'); // on E:XXXX do .... on E: exception do // a generic exception ShowMessage('Ok, Im Generic'); // by default, these line will be called... else // anyother not related... ShowMessage('Ok, Im ELSE'); end; end; Edited March 6, 2023 by programmerdelphi2k Share this post Link to post
PeterBelow 238 Posted March 6, 2023 5 hours ago, Wagner Landgraf said: Sure, that is already done. I was just wondering if that was a possible thing to happen. But it looks like that's not the case. There is a case, though: if the code inside the try block calls something in a DLL and that DLL function does not trap any exceptions raised inside the DLL code these would bubble up the exception handler stack into your try except block, be trapped there but not recognized as deriving from the Exception class. This would even be the case if the DLL is written in Delphi, unless DLL and EXE are build with the same Delphi version and with run-time packages enabled for both projects. 1 Share this post Link to post
Wagner Landgraf 43 Posted March 6, 2023 2 minutes ago, PeterBelow said: There is a case, though: if the code inside the try block calls something in a DLL and that DLL function does not trap any exceptions raised inside the DLL code these would bubble up the exception handler stack into your try except block, be trapped there but not recognized as deriving from the Exception class. This would even be the case if the DLL is written in Delphi, unless DLL and EXE are build with the same Delphi version and with run-time packages enabled for both projects. Thank you very much. That's the kind of situation I was wondering. So it's possible, especially because in the end Delphi apps are calling DLLs often. I just don't know the odds of such situation to happen. Share this post Link to post
David Heffernan 2345 Posted March 6, 2023 14 hours ago, David Heffernan said: I wonder, how would a language exception raised by another module in your process appear as when it reach your exception handler? Indeed 4 hours ago, PeterBelow said: There is a case, though: if the code inside the try block calls something in a DLL and that DLL function does not trap any exceptions raised inside the DLL code these would bubble up the exception handler stack into your try except block, be trapped there but not recognized as deriving from the Exception class. This would even be the case if the DLL is written in Delphi, unless DLL and EXE are build with the same Delphi version and with run-time packages enabled for both projects. Share this post Link to post
Rollo62 536 Posted March 7, 2023 Dont know if Mobile is relevant for your case too, but I know that some systen exceptions may be untrapped. A solution was to extract try-except into separate method and implement a kindof double try-except to ensure to catch them all. Share this post Link to post
Wagner Landgraf 43 Posted March 7, 2023 Mobile is not the case here. But for all intents and purposes, it's clear, from the responses of some helpful gentlemen here, that "on E: Exception" is not a 100% safe approach. Share this post Link to post
Lars Fosdal 1792 Posted March 8, 2023 13 hours ago, Wagner Landgraf said: Mobile is not the case here. But for all intents and purposes, it's clear, from the responses of some helpful gentlemen here, that "on E: Exception" is not a 100% safe approach. That is extremely significant. I have countless numbers of these and I am starting to wonder if they should be rewritten to try // ... except on E: Exception do begin end else raise; end; and then have a general handler for those further out. Or.... just log "An unidentified terrible event happened." Share this post Link to post
David Heffernan 2345 Posted March 8, 2023 21 minutes ago, Lars Fosdal said: I have countless numbers of these Don't you just have a small number of top level exception handlers? Share this post Link to post
Lars Fosdal 1792 Posted March 8, 2023 33 minutes ago, David Heffernan said: Don't you just have a small number of top level exception handlers? When dealing with live data, there is no end to what can go wrong - so no - I do not have a small number of top level exception handlers. Share this post Link to post
David Heffernan 2345 Posted March 8, 2023 2 minutes ago, Lars Fosdal said: When dealing with live data, there is no end to what can go wrong - so no - I do not have a small number of top level exception handlers. Sounds like the worst of all worlds. The noise of try / except blocks everywhere, and old school checking for errors at all steps! Share this post Link to post
Lars Fosdal 1792 Posted March 8, 2023 With TCP/UDP/Serial, JsonRPC, REST, Databases and conversions and partial data transfers possible - you tend to accumulate a number of these. Share this post Link to post
Wagner Landgraf 43 Posted March 8, 2023 1 hour ago, Lars Fosdal said: I have countless numbers of these and I am starting to wonder if they should be rewritten to That is not needed. The else is implicit in the try..except block, if an exception is not trapped in the "on" clause, it's re-raised. The point here is if you have code that needs to be executed, like a transaction rollback, or a log message that needs to be generated, etc. 1 Share this post Link to post