Crash when reading new root files

Hi Wim,

I’m a bit in a predicament here.
I have generated a new set of tuples with my event class. When trying to read the new ROOT files with the new Event class, python crashes. Now the funny thing is this: When reading the old files with the newevent class, I get a warning, but can process the read the tuples alright.
I had noticed crashes like that in earlier versions of ROOT, but I thought PyRoot just isn’t ready and didn’t bother with it further. The fact that this happens now concerns me, because I have set up everything in Python already.

Please run the following code (after making the new dictionary from the attached files – you’ll have to rename the extensions to .cc and .hh.)

from ROOT import TTree, TFile, gSystem
gSystem.Load('JansEvent_cc')
from ROOT import JansEvent
f = TFile('bug.root')
t = f.Get('evtTree2')
j = JansEvent()
t.SetBranchAddress('event', j)
t.GetEvent(0)
j.bList.GetEntries() #yes, there are entries
j.bList[0].gamma #crash

Cheers,
Jan

The traceback is this:
*** Break *** segmentation violation
Generating stack trace…
0x0185038f in TClass::GetActualClass(void const*) const + 0x55 from /u1/local/root/lib/root/libCore.so
0x00f8da19 in PyROOT::BindRootObject(void*, TClass*, bool) + 0x69 from /u1/local/root/lib/root/libPyROOT.so
0x00f77f4a in PyROOT::TRootObjectConverter::FromMemory(void*) + 0x3a from /u1/local/root/lib/root/libPyROOT.so
0x00f82652 in _ZN6PyROOT45_GLOBAL__N_pyroot_src_PropertyProxy.cxxHOIKob6pp_getEPNS_13PropertyProxyEPNS_11ObjectPro + 0x62 from /u1/local/root/lib/root/libPyROOT.so
0x0807908d in PyObject_GenericGetAttr + 0x1a9 from /u1/local/bin/python
0x08078d23 in PyObject_GetAttr + 0xab from /u1/local/bin/python
0x080a6f17 in PyEval_EvalFrame + 0x1d9f from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080aa2c4 in from /u1/local/bin/python
0x080a6977 in PyEval_EvalFrame + 0x17ff from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080a913d in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080a913d in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a91b9 in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080a913d in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080a913d in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080a913d in from /u1/local/bin/python
0x080a8da7 in from /u1/local/bin/python
0x080a73b3 in PyEval_EvalFrame + 0x223b from /u1/local/bin/python
0x080a7e6e in PyEval_EvalCodeEx + 0x40a from /u1/local/bin/python
0x080aa8ca in PyEval_EvalCode + 0x22 from /u1/local/bin/python
0x080d22a5 in from /u1/local/bin/python
0x080d1b09 in PyRun_SimpleFileExFlags + 0x191 from /u1/local/bin/python
0x080554cb in Py_Main + 0x56b from /u1/local/bin/python
0x08054f5b in main + 0x17 from /u1/local/bin/python
0x0023678a in __libc_start_main + 0xda from /lib/tls/libc.so.6
0x08054eb9 in ldexp + 0x61 from /u1/local/bin/python
Aborted
JansEvent.h (5.32 KB)
JansEvent.c (3.59 KB)
bug.root (18.1 KB)

Jan,

still have to look into your example, but here are some initial thoughts:

TTree::SetBranchAddress() is a template, and when used without class, the CINT class deduction doesn’t work (I have to write something by hand, as is done for TTree::Branch()): it’ll actually think you’re handing over a Long_t. Can you use the longer version instead, the one that explicitly takes a TClass*?

virtual void SetBranchAddress(const char* bname, void* add, TClass* realClass, EDataType datatype, Bool_t ptr)
Note that it’ll require AddressOf(). Internally, the templated code will just call the one above, after having deduced “realClass.”

Alternatively (you’re using PyROOT HEAD, no?) can you start accessing the event directly, like so:

t = f.Get('evtTree2')
t.GetEvent(0) 
t.Event.bList[0].gamma

and give feedback on that?

In general, the problem of combining python and TTree/TClonesArray is that the latter use a lot of pointer magic, whereas the former supports none. Iow., I have to write most everything out explicitly. Contrary to what people believe, pyroot doesn’t solve the pointer/memory-mgmt problems of C++, it just shifts the burden.

It would be easier on me if I can handle TTree’s by proxy (as per above through psuedo-datamember access), rather than figuring out how to get all the pointer magic of all the various parts of the TTree library properly translated from python (I’ll get there, to be sure, but it’ll just take longer). Thanks!

More later when I’ve looked into your example in detail.

Cheers,
Wim

Hi Wim,

thanks for your quick reply.
I’m sorry, but I need more information to call the long version of SetBranchAddress
I have figured out what TClass is, but where do I get EDataType from, what is it and what does the Bool_t parameter do ?
Ah. just found out about the inherent brilliance of the Bool_t parameter. But I still don’t know where to get EDataType from.

I’m using ROOT CVS as of one hour ago, but unfortunately, there is no t.Event available.

Thanks for your help. Please keep at it. I like PyRoot.
:smiley:
Jan

Jan,

sorry about the “t.Event”; it is of course “t.event” (the name that you gave to the object when creating the tree). It will still crash at that point, though: I’m playing with the problem at this moment and it has something to do with the inheritance tructure of the B_Parameters class.

More in a moment,
Wim

Jan,

since your inheritance hiearchy is one of the cases mentioned as not to be supported in the docs of TClass::GetActualClass, I’m giving a workaround here that you can apply. Later I’ll try to see whether I can “detect” cases like yours and simply not use TClass::GetActualClass when applicable.

Anyway, to continue working, please add this:

    TClass* IsA() {
       return B_GammaParameters::Class();
    }

as a method to struct B_GammaParameters (and likewise B_Proton… etc.).

That IsA() will then be called, instead of the virtual const version from the ClassDef, and then it’ll work. Does for me, that is. :slight_smile:

More when I have more,
Wim

Wim,

I thought that you meant t.event, but it didn’t show up in the list of completions (ipython is sooo nice…) and I didn’t try. It works after the first Tree::GetEvent().

As for your workaround. This looks like a solution I can live with. And it works like a charm. I think this is something that could be advertised as a proper solution, rather than trying to figure out every eventuality. (Diamond inheritance pattern, anyone ?)

Thanks so much.
Jan
=D>

Jan,

no, it can’t be put out there as a general solution, as there still is something more going wrong. Consider this .C macro: gROOT->LoadMacro( "JansEvent.c+" ); TFile* f = new TFile("bug.root"); TTree* t = f->Get("evtTree2"); JansEvent* j = new JansEvent(); t->SetBranchAddress("event", &j); t->GetEvent(0); j->bList.GetEntries(); std::cout << ((B_Parameters*)j->bList[0])->gamma->minTrackDTheta << std::endl; std::cout << ((B_Parameters*)j->bList[0])->gamma->uid << std::endl; std::cout << ((B_Parameters*)j->bList[0])->gamma->GetName() << std::endl; }
which shows that the gamma part looks ok (except for the uid part, which is different than what a TBrowser shows), but when accessing a virtual function, it crashes.

Something went wrong when you moved from the old event to the new one; it is not python related; and I can’t put my finger on it (lack of understanding of ROOT I/O, I’m afraid), as looking at the StreamerInfo’s and counting bytes doesn’t show me anything obviously wrong. :frowning:

What I think that happes (but I can’t “prove” it), is that the vtable gets overwritten. Why, I don’t know, but if you add 12 bytes or more worth of data members before uid in CandidateParameters, you’ll see the same values pop up in the first 4 as visible from the TBrowser for uid. The TVector3 is unaffected in all cases.

Cheers,
Wim

OK,
I have made four new files.
Two with the old Tuples from this other thread.
One each with python and CINT.
And the same for Tuples from this thread.
I have also attached the scripts that I used to make the Tuples.
One thing that is peculiar about the CINT script is that it crashes when I close the file at the end. The traceback says something about TAttLine…
Actually I don’t want to know.
Anyways, these are the files.
newTupleCINT.root (17.5 KB)
oldTuplePy.root (16.1 KB)
oldTupleCINT.root (16.1 KB)

And the rest
makeSmallerTuple.c (462 Bytes)
makeSmallerTuple.py (422 Bytes)
newTuplePy.root (17.5 KB)

Create fout and t in the heap (not in the stack) to avoid possible problems with the order of objects destructions.
see attached script

Rene
makeSmallerTuple.c (613 Bytes)

I think this problem is now fixed in CVS.

The problem appeared in TBranch::SetAddress when we are dealing with a
TClonesArray containing an object containing an object inheriting
from a non-virtual base class and from TObject. The address of the
basic type data members of the base class was not calculated properly.

Cheers,
Philippe.