Problem with schema evolution, SegFault reading previous ver

Hi,

I created a new version of my class which is stored in a TTree (splitlevel=1) and the new version SegFaults when reading the data of the old version. This happens for all ROOT versions >= 5.10/00 regardless of the used compiler (gcc 3.3.3, 4.0.3 & 4.1.1). The default constructor sets all pointers to NULL.

Version v3 of the class has the form:

class TEyeEvent : public TObject {
public:
    TEyeEvent();

protected:
    UInt_t                  fDataPresentBits;  // Bit vector for sub-data

private:
    TEyeEventHeader        *fEventHeader;  // Eye event header
    TEyeFADCData           *fFADCData;     // container of FADC traces
    TEyePixelList          *fPixelList;    // (compressed) list ofpixels
    TEyePixelData          *fPixelData;    // container of TMirrorPixelData
   
    TEyeWeatherData        *fWeatherData;  // old weather station data (unused)

    TEyeTriggerData        *fTriggerData;  // optional trigger info (unused)
    TEyeT3Data             *fT3Data;       // optional T3 info (used)
   
    static unsigned int     fgPrintLevel;  //! print/verbosity level for TEye* classes
   
    ClassDef(TEyeEvent,(int)EyeEVENTVERSIONv3)
};

Version v4 has fWeatherData removed and v3 replaced by v4.

I managed to create a simple code example which reproduces the error and which is contained in the attachment.
[ul]
mathes@ikauger3:~/src/test/root> ./TestData1 100 1 Data1.root
./TestData1: Writing 100 events to file Data1.root
mathes@ikauger3:~/src/test/root> ./TestData1 0 0 Data1.root
./TestData1: Reading from file Data1.root
… 100 entries found!
mathes@ikauger3:~/src/test/root> ./TestData2 0 0 Data1.root
./TestData2: Reading from file Data1.root
Warning in TClass::TClass: no dictionary for class MData2 is available
… 100 entries found!

*** Break *** segmentation violation
Generating stack trace…
0xb77902c4 in TBuffer::MapObject(TObject const*, unsigned int) + 0xcc from /usr/local/root-5.13.02/lib/libCore.so.5.13
0xb68fbfc9 in TBranchElement::ReadLeaves(TBuffer&) at TBranchElement.cxx:0 from /usr/local/root-5.13.02/lib/libTree.so.5.13
0xb68f298f in TBranch::GetEntry(long long, int) + 0x27b from /usr/local/root-5.13.02/lib/libTree.so.5.13
0xb68f7c6a in TBranchElement::GetEntry(long long, int) + 0x1ac from /usr/local/root-5.13.02/lib/libTree.so.5.13
0xb68f7bef in TBranchElement::GetEntry(long long, int) + 0x131 from /usr/local/root-5.13.02/lib/libTree.so.5.13
0xb693a281 in TTree::GetEntry(long long, int) + 0xc9 from /usr/local/root-5.13.02/lib/libTree.so.5.13
0x0804cf9b in main + 0x325 from ./TestData2
0xb62dc87c in __libc_start_main + 0xdc from /lib/libc.so.6
0x0804cb81 in __gxx_personality_v0 + 0x105 from ./TestData2
Aborted
[/ul]

One possible work-around I found is to check if the pointer passed to TBuffer::MapObject() (or TBufferFile::MapObject()) is aligned or not:

      fClassMap->Add(offset,
             (obj && obj != (TObject*)-1 && ((((int)obj) % sizeof(void*)) == 0)) ? (Long_t)((TObject*)obj)->IsA() : 0);

instead of

      fClassMap->Add(offset,
             (obj && obj != (TObject*)-1) ? (Long_t)((TObject*)obj)->IsA() : 0);

But this seems to be a very dirty hack.

Sorry for this lengthy post and probably I have overlooked something in the corresponding release notes :blush:
Is there any other, recommended way to overcome this problem ?
Thanks
Hermann-Josef
root-test.tar.gz (3.5 KB)

Hi,

I can reproduce the problem. I am looking into it.

Cheers,
Philippe

Hi,

As a side note, in your example code you need to replace branch->SetAddress( data );with branch->SetAddress( &data );In your example, since data is null, the SetAddress is a nop (and you r ‘data’ pointer would never be updated).

Also I saw: tree->SetAutoSave( 100 );The parameter to AutoSave is a number of bytes (so in your case you actually got 100 autosave (one per events).

Cheers,
Philippe

Hello Philippe,

    branch->SetAddress( &data );

Uuups, you are right, a typical fault of mine. I have corrected it in the test example.

And instead of the TTree::SetAutoSave() which doesn’t make really sense here, one has to add a file->Write() just before the file->Close(). Obviously not all important lines from the real code made it into the test example.

But the SegFault is still there…

By the way another fix would be:

    TBranch *branch = tree->GetBranch( "data" );
    // disable reading from obsolete branch ?
    tree->SetBranchStatus( "fMData2", 0 ); // --> works !!!

Thanks and regards
Hermann-Josef

Hi,

Yes, disabling the branch is the best work-around (until I find a proper fix).

The test on the alignment does not work since the memory being passed/tested in this case is mostly random (so sometimes it would still pass this test!).

Cheers,
Philippe.

Hi,

I fixed the problem in the ROOT svn trunk (by avoiding the call to MapObject in this case).

Cheers,
Philippe.