Interception of exceptions by root in compiled program

Dear All,

I’m new to this forum.
We are building a C++ recontruction program for the Borexino experiment that includes a root file writer at the end of the event processing queue.
Therefore we link against a lot of root libraries.
On some but not all working enviroments within our collaboration we encounter the following problem: every exception, even if not thrown in a root context, is cought by root and in most of the cases root recovers and the program doesn’t exit (i.e. our main exception handler is never called).
Is it a known issue? Is there a way to control root exception handlers?
Thank you for the attention.

Best Regards

Davide D’angelo

Hi,

CINT has a feature where it catch every exception thrown during the execution of a command that it launched. This seems to be reasonable default behavior, since you would really want the program to completely exit while you are doing interactive work.
To disable this behavior execute the cint command

.exception or
gROOT->ProcessLine(".exception");
Cheers,
Philippe

Dear Philippe,

thank you very much for your fast reply.

Our program is compiled so we don’t go through CINT.
This is also no interactive application, it runs in batch and writes a root file.
Our event class inherits from TObject, so while compiling we generate dictionary and library.
We don’t create explicitly a TROOT object, we simply use TFile and ClassDef dor dictionary generation.

I’m spending some trying to understand it better myself and I’ll see if your suggestion can apply.
Should you have a more specific one, it would be of course very welcome.
Thanks again.

Best regards,
Davide D’Angelo

Can you send me an example?

Cheers,
Philippe

Dear Philippe,

I think our is a fairly standard way to use root in a reconstruction program
I paste here the 2 classes where root is involved:

[code]#ifndef _BX_ROOT_EVENT_H
#define _BX_ROOT_EVENT_H
#include <TROOT.h>
#include <TObject.h>

class bx_root_event: public TObject {
public:
bx_root_event ();
virtual ~bx_root_event ();

// all variables clean up
void clear ();

ClassDef (bx_root_event, 1)    

private:
};

#endif
[/code]

and this is the other

[code]#ifndef _BX_WRITER_H
#define _BX_WRITER_H

#include “TFile.h”
#include “TTree.h”

#include “bx_base_module.hh”
#include “bx_rec_general.hh”
#include “bx_root_event.hh”

// base class for root event filler
class bx_base_root_event_filler {
public:
bx_base_root_event_filler () {}
virtual ~bx_base_root_event_filler () {}

virtual void fill (bx_root_event*) = 0;

};

// one implemetation of a root event filler
class bx_root_event_filler : public bx_base_root_event_filler {
public:
bx_root_event_filler (const bx_reco_event* p) : p_reco_event§ {}
virtual ~bx_root_event_filler () {}

// fill root event
virtual void fill (bx_root_event*);

private:
inline const bx_reco_event& reco () const { return *p_reco_event; }
const bx_reco_event *p_reco_event;
};

class bx_event_writer: public bx_base_module {
public:
bx_event_writer ();
virtual ~bx_event_writer () {}

virtual void begin ();
virtual bx_reco_event* doit (bx_reco_event *ev);
virtual void end ();

private:
TFile *p_root_file;
TTree *p_root_tree;
bx_root_event *p_root_event;
};
[/code]

as you see, there is really nothing special in it.

I suspect that whenever one uses a root object, this somehow initializes a the TROOT singleton that plays the trick.
We could call ->ProcessLine(".exception") on this one if we could get a pointer to it. I just gave a look at the TROOT reference page but could not find a static method that returns a TROOT*
Any idea?

thanks again, bye
Davide

P.S.: uhm, it’s 8.30 pm here in Italy, my stomach really wants me to leave. I’ll check replies again tomorrow hopefully. have a nice evening.

Hi,

I don’t specifically see any C++ exceptions in your code.
Are you really talking about C++ exceptions (i.e. result of a C++ throw) or are you talking about unix signal (like seg fault)?

Can you send me the result on the screen of root ‘catching’ your exceptions?

Cheers,
Philippe

Hi,

well, the code is over 3000 lines. I sent you only the recently added parts where root is involved.
The program has a message handler that throws the exception when he recieves a message with level==critic. So every module indirectly throws the exception by sending a critic message. There is also a single exception handler at top level (in the main) which sould exit with some info and this is never called due to root interception.

Also signals could be involved, though the program runs a single process with no threads, I will explore this better.

The screen output is not very significant:

[code]Error in TFile::TFile: file test.root already exists

critic: module bx_event_writer: root file test.root already exists
Warning in TFile::Write: file test.root not opened in write mode

info: Echidna NORMAL END[/code]

lines starting with ‘>>>’ are printed by our message handler.
Before root was introduced, after the critic there was a line sent by exception handler and the program used to exit. Here it goes until its normal end.

This is where exception are thrown within the exception handler:

if (msg.check_exception ()) { log.close (); throw std::runtime_error (msg.str ()); }

And this is our main with the exception handler:

[code]int main(int argc, char *argv[]) {
try {
bx_options::get ()->set_command_line (argc, argv);

bx_reco_framework frame;
frame.run();

} catch (std::exception& ex) {
std::cout << ">>> exception: " << ex.what() << std::endl;
} catch (…) {
std::cout << “>>> exception: unknown type” << std::endl;
}
messenger::get ()->flush ();
}[/code]

Again, this is rather ordinary code as far as I know.

I think that, if there is a way to access the TROOT singleton from within the code, it is worth trying your original suggestion. Do you know any way to do this?

Thanks, bye
Davide

Include the header file TROOT.h and use

ROOT::GetROOT()->xxx(); if you are using a newer version of ROOT, otherwise use:

gROOT->xxx();

Could you send me the code from this method?
Cheers,
Philippe.

PS. If the code is only 3000 lines of code, can you send me a complete tar file?

Dear Philippe,

Unfortunately it didn’t seem to work. I tried to add:

gROOT->ProcessLine(".exceptions"); 

in the main but the behaviour was unchanged, apart from the following message that confirms the operation (I guess):

G__catchexception=0

I send you the tar file. The method you were interested in is in Echidna/framework/bx_reco_framework.cc and is the main event processor.

You should be able to compile if you have postgres libraries installed, but for running, you’ll need a rawdata file and an authorized access to our database.

Perheaps I must say here that this beahaviour happens on machines running gcc 3.2.2 or gcc 3.3.1. On other machines where gcc is 2.95 this does not occur.

Root version is 3.05/07 in both cases and has been installed from binaries, compiled with gcc3.2 in the first 2 cases and with 2.95 in the other case.

Thanks again for your help,
bye
Davide
echidna_4_5_04.tar.gz (60.5 KB)

Hi,

This issues is not related to ROOT but to your usage of iostream.

The iostream is design to not throw any exception (by default).
Hence operator<< catches any exception and set the fail bit.
If you need a different behavior you have to set what they call the stream’s exception mask:

bx_message msg; msg.exceptions (std::ios_base::badbit); msg.set_level (bx_message::critic); msg.set_log_level (bx_message::info); msg.set_print_level (bx_message::info); msg << "start framework run" << dispatch;

Alternatively you could call msg.dispatch() directly;

Cheers,
Philippe.

Also a few notes about your makefiles. When building C++ libraries you have to use g++ as your library builder. ‘ar’ is insufficient in some repesct (initialization of global objects for example).

When using static library (as opposed to shared library) you have to link you application directly against the dictionary object file. This is because there is no unresolved reference to force the linker to pull the dictionary .o file out of the static library (you could also play trick with defining unresolved references).

[quote=“pcanal”]Hi,

This issues is not related to ROOT but to your usage of iostream.
[/quote]
You are definitely wrong :slight_smile:

The way the exception are thrown is perfectly legal: the dispatch call make a dynamic cast to a bx_message which call the messanger which generate a runtime_exception. The iostream library HAS not to intercept exception which are not generated by itself.
Here the << syntax for dispatch is fine since it correspond to the dispact function call; the failbi|badbitt syntax is irrelevant since I’m not using iostream to launche the exception itself but a devoted set of classes.
Calling directly bx_message::dispatch shouldn’t change.
The problem I think is the compiler/library Davide is using, since on other machine it works perfectly.
I think the problem arised when root was added to the project but maybe it was present even before in the Davide’s machine. How knows?
Davide, can you please try to remove root libraries and test for such problems?

[quote=“pcanal”]
Also a few notes about your makefiles. When building C++ libraries you have to use g++ as your library builder. ‘ar’ is insufficient in some repesct (initialization of global objects for example).

When using static library (as opposed to shared library) you have to link you application directly against the dictionary object file. This is because there is no unresolved reference to force the linker to pull the dictionary .o file out of the static library (you could also play trick with defining unresolved references).[/quote]
I’m the principal author of Echidna, the makefiles are just tmp, and a version creating a global dynamic library is on schedule.
BTW using ar for collecting .o file is fine since I remember the one pass rule of the linker.
The global object are then inited by the final linker and set in the RSS zone of the binary. Would be even fine to use ar to simply have a collection of .o compiled with fPIC (normali called .la archives) from which to build the dynamic library with g++ or ld. This is the standard way libtool works.

[quote=“pcanal”]Hi,

I don’t specifically see any C++ exceptions in your code.
Are you really talking about C++ exceptions (i.e. result of a C++ throw) or are you talking about unix signal (like seg fault)?

Cheers,
Philippe[/quote]

I would be very usefull for me to avoid root libraries to install signal handlers for most signals; I prefer to have a core which I can debug instead of a root message complainaining of a “segmentation violation”.
How can I solve this?

Thanks
Alessamdro

The list of signals that are handled by default by ROOT:

[ul]kSigChild
kSigBus
kSigSegmentationViolation
kSigIllegalInstruction
kSigSystem
kSigPipe
kSigAlarm
kSigUrgent
kSigFloatingException
kSigWindowChanged[/ul]

You can reset any of them using:

Cheers,
Philippe.

Dear Philippe,

you are definitely right :wink:

I made some more investigation and these are some results:
[ul]

  1. The problem with C++ exceptions is NOT ROOT related. I tried a version where root was cleaned up everywhere and the behaviour is the same. I erronously convinced myself that root was causing it for 2 reasons:

[list]
a) It showed up roughly when root was introduced, but actually also this smart shortcut of calling dispatch() through the << operator was not introduced long before (or maybe I personally didn’t work with the code in the meantime).
b) The problem with unix signals was known to some peole in our group and I thought the 2 problems were the same, while in fact they are not.
[/ul]

Sorry for this, I should have checked better.

  1. Calling dispatch() directly or raising the exception in another way does not encounter the problem.

  2. The badbit of the stream IS SET, if << dispatch is used, while the strem retains its ios_base::goodbit state otherwise.

  3. Adding msg.exceptions (std::ios_base::badbit); allows to use the << operator smoothly.

[/list:u]

So for some reason on some machines (Debian) the iostream does not catch the exception as Alessandro said, while on other s (Mandrake) it does exactly what Philippe wrote.
It does not depend on the compiler because 2.95, 3.0, 3.2, 3.3 they all work in Debian.
Could it be that the implementation of STL iostream has a different deafault behaviour in different linux distributions?
Can I change this behaviour on my machines?

I’m not a C++ guru like You or Alessandro so the discussion on the makefile issues is beyond my knowledge for the moment, but thanks for the help.

Thank you very much also for the help on the signal handlers (I haven’t tried it yet).

Have a nice evening,
Davide

P.S. Alessandro may sound a bit sharp when someone is questioning his code, but it doesn’t mean he really has the badbit set, nor that people are not allowed to do it, expecially if they are just kindly trying to help.

[quote=“ddangelo”]Dear Philippe,

you are definitely right :wink:

I made some more investigation and these are some results:
[ul]

  1. The problem with C++ exceptions is NOT ROOT related. I tried a version where root was cleaned up everywhere and the behaviour is the same. I erronously convinced myself that root was causing it for 2 reasons:

  2. Calling dispatch() directly or raising the exception in another way does not encounter the problem.

  3. The badbit of the stream IS SET, if << dispatch is used, while the strem retains its ios_base::goodbit state otherwise.

    [/ul]
    [/quote]
    The question is that iostream is not allowed to intercept every exception a sublayer throws; It can handle some “predefined ones” like bad_alloc.
    But of custom classes exceptions should not; this means that even if a catch(…) is allowed, the exception has to be thrown again after setting some internal status (at list this says the iso inforamtions I found on web).

[quote=“ddangelo”]Can I change this behaviour on my machines?
[/quote]
simply you can add the following line to the bx_message constructor

this->exceptions (std::ios_base::badbit)

Hi,

[quote]
The question is that iostream is not allowed to intercept every exception a sublayer throws; It can handle some “predefined ones” like bad_alloc.
But of custom classes exceptions should not; this means that even if a catch(…) is allowed, the exception has to be thrown again after setting some internal status (at list this says the iso inforamtions I found on web). [/quote]

According to the C++ standard paragraphe 27.6.2.5.1:

Hence the behavior of the Debian iostream is not standard conforming.

Cheers,
Philippe

You are referring to:

I interpreted that only referring to the sentry procedure.
I will look more deeply with the debian developers to this question, btw to solve the problem adding the line I quoted before to the bx_message ctor is enought.