AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Beware of secondary exceptions

Ein Thema von DP News-Robot · begonnen am 7. Dez 2023
Antwort Antwort
Benutzerbild von DP News-Robot
DP News-Robot

Registriert seit: 4. Jun 2010
14.979 Beiträge
 
#1

Beware of secondary exceptions

  Alt 7. Dez 2023, 18:40
We were contacted by a client who complained that EurekaLog was generating an error report in the wrong place. In fact, the client had an expected exception that he wanted to hide by showing a simple message instead. The client kindly showed his code:
try Query.Delete; // - an exception is raised hereexcept Query.Transaction.Rollback; ShowMessage('Sorry, could not delete the report'); Exit;end;What's happening? Does EurekaLog really ignore user code?

If the client code were written like this:
try Query.Delete; // - an exception is raised hereexcept Exit;end;then there would be no problem: Query.Delete raises an exception, the exception is caught by the except block, which does nothing, and execution continues further, EurekaLog does not react (*).

However, the client code looks different: its except block does some (complex) exception recovery.

In any case, such exceptions are called handled because they are handled by the user's (client's) code. A handled exception is handled by cleanup code, which performs some recovery/rollback actions, after which program execution continues and the exception itself is removed.

In general, any cleanup code (be it a destructor or a rollback/recovery code) should be written in a such way so it will not raise exceptions. It seems to me that the logic here is obvious: if your normal code raises an exception, then you can always suggest a possible recovery actions (the so-called “Plan B”). For example, if an exception occurs when opening a document - then the document needs to be closed; If an exception occurs while accessing the printer - the print job must be canceled. If there is an error opening a file - you can try to open it again after a pause or user's action. And so on.

But what will you do if an error occurs in the “Plan B” itself? You wanted to cancel the print job, but it... is not cancelled. So what now? You will not be able to offer any reasonable recovery actions. Because you don't know what happened. Your variables may be corrupted. Hell, you might not even be able to allocate a block of memory right now! The only possible clean way is to kill/restart the application.

This is why the cleanup code must NOT raise exceptions. Because you can't do anything meaningful with these exceptions. In other words: the cleanup code must handle all exceptions that it knows how to handle.

But in practice, things may not be the same as in an ideal world.

In this case, the client's code raises a second exception inside Query.Transaction.Rollback. It means that the execution of the except block is interrupted and execution moves to the exception handler higher up the stack. It turns out that there are no more try blocks higher up the stack in the client's code, so execution is transferred to the global exception handler, which calls EurekaLog to generate a bug report.

Correcting the code will involve following the rule “cleanup code must not raise exceptions” (“cleanup code must handle known exceptions”). For example, as follows:
try Query.Delete; // - an exception is raised hereexcept try Query.Transaction.Rollback; except on EDatabaseError do; // - ignore database errors end; ShowMessage('Sorry, could not delete the report'); Exit;end;In this case, the second exception will be handled in place and will not "bubble up" to the next exception handler (be it a try block or a global exception handler). It is important to write the correct code - i.e. so that it doesn't block exceptions that you don't know how to handle. For example, the following code is incorrect:
try Query.Transaction.Rollback; except // - ignore ALL errors end;It is incorrect because you do not know how to properly handle/rollback/recover from, for example, an EAccessViolation exception. It is best to write the code so that it takes into account the most narrow conditions for exceptions - only those that you know exactly how to handle. For example, if you know a specific type/code of the error when canceling a transaction - then write like this:
try Query.Transaction.Rollback; except on E: ESomeSpecificDatabaseException do if E.ErrorCode = 1234 then begin // - ignore only this specific error end else raise; end;


Remarks:
Weiterlesen...
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:16 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz