Use of TObject::Error() and Fatal()

I’d like to have a possibility to break the execution of an interpreted script if some subrutine (compiled or interpreted) encounters an error and further execution of the script makes no sens. In compiled code I’d use exception handling, however this doesn’t still work in cint reliably (catching std::exception thrown in compiled code crashes root session).

What is the proper usage of TObject::Error() and Fatal()? Is there a setting so that calling TObject::Error() breaks the script execution and returns to cint prompt?
Thanks a lot.
Petr
Root 5.20_msvc8.0_debug on winxp_sp2

Hi,

We use exceptions in ALICE visualization quite extensively and it works ok.
To be more specific:

  1. Macros (cint scripts) are used to connect to data-sources and fill visulization objects.

  2. These macros call compiled code to get to the data, and these functions throw exceptions of type TEveException : public std::exception, public TString.

Macro: alisoft.cern.ch/viewvc/trunk/EVE … iew=markup

Compiled code: alisoft.cern.ch/viewvc/trunk/EVE … iew=markup
In particular see AsserRunLoader()

Example try-catch in a covering macro: alisoft.cern.ch/viewvc/trunk/EVE … iew=markup

So … I’d propose that you set up a minimal example showing your problem:

  1. exception-throwing macro to be loaded via aclic
  2. macro calling 1.

Axel and I can then help you debug the thing … and eventually fix things in ROOT.

Cheers,
Matevz

I’m sending a minimal example to reproduce my problem with exception handling using TEveException.
To reproduce run in cint:

root [1] .L except_class.cpp+
root [2] .x except_script.cpp
SomeClass constructor called
calling throw exception
Exception: Exception from SomeClass::Second - b is a null-dim vector
— crash of root.exe (cint)

The some behavior using my TNException class, defined in except_class.h (uncomment).

Running Windows XP sp2, MC VisualC++ Express (8.0),
Root 5.20 binary with debug info (for VS8.0)

Thanks a lot for helping me with the problem
Petr
except_script.cpp (416 Bytes)
except_class.h (430 Bytes)
except_class.cpp (406 Bytes)

Hi,

I modified your example so that First() and Second() return TVectorD* … then the crash does not occur. It happened while CINT was trying to initialize the return value (TVectorD).

After that I see another problem … the exeption is not propagated to the calling script, its processing is simply aborted.

This made me somewhat uneasy … so i went to recheck how this works in the ALICE code.

  1. if the exception is thrown from compiled code (or compiled macro),. it works ok … the script catches it

  2. throwing an exception from a macro does not work - it seems to be ignored.

I’ll pass this on to Axel … if nothing else to tell me what else to try.

Soon,
Matevz

Hi Matevz,
Thanks a lot for analyzing the problem. My next question is what is the purpose of TObject::Error and TObject::Fatal. This functions seem to me quite unusefull - only printing a message.

However, if TObject::Fatal forced the runtime/cint to abort execution of the running command leaving the global object in the root environment (not crashing cint), I could avoid the exception handling in most cases - I’d use the thrown exception anyhow just to report the error without catching statement.
Petr

Hi Petr,

[For context. please remember that ROOT was developed before any compiler even started to (properly) implement exception (handling)].

Fatal should be used in the case where an error that can not possibly be recovered from has occurred (i.e. clearly halting where the error happened rather than in some other remotely related place in the code).

Error should be used to indicate to the user than an Error has occurred but the program might be able to go on, possibly with result that are different from what is expected. A function that is issuing an Error usually also returns an Error code so that the caller can detect the issue.

Cheers,
Philippe.

Hi,

Just went through my problematic case with Axel … and solved it.

The problem was that my macro had:
throw (TEveException(“Foo”));
and CINT wants it to be:
throw TEveException(“Foo”); // one () less

Cheers,
Matevz

Hi,
Finally I’ve found a “good enough” solution to stop further execution of a script if an error ocured somewhere in the compiled/interpreted code and further execution of the script could be dangerous (crashes cint or so) without exception handling.
I define folloving static methods, where the DefaultErrorHandler is extended, so a global variable is set.

void MyErrorHandler(Int_t level, Bool_t abort_bool, const char *location, const char *msg) { if(level>=kError){ SomeClass::fgError = true; } DefaultErrorHandler( level, abort_bool, location, msg); } bool SomeClass::IsError() { if(fgError){ cout << "Error ocured that requires abort of script" << endl; fgError = false; return true; } else { return false } } void SomeClass::SetErrorHandling() { SetErrorHandler(MyErrorHandler); }
In the main script I periodically check by calling if(SomeClass::IsError()) return NULL; if serious error occured and allows to quit the script.
It woudl be nice to have a standard interface for such “error checking” in the root distribution

Cheers,
Petr