Still: A crash when reading from a file with TTree Friends

Continuing the discussion from A crash when reading from a file with TTree Friends:

I am on ROOT 6.26.00 and it still crashes, as explained in the cited topic…

May be @pcanal can continue to help you here.

Hi,
I can reproduce this with latest master, the crash happens at line 173:

 168  TTree *TFriendElement::DisConnect()
 169  {
 170     // At this point, if the condition is not meant, fTree is usually already
 171     // deleted (hence the need for a local bit describing fTree)
 172     if (fTree)
 173        fTree->RemoveExternalFriend(this);
 174     if (fOwnFile) delete fFile;
 175     fFile = 0;
 176     fTree = 0;
 177     return 0;
 178  }

and valgrind also sees this:

root [2] .q
==527106== Invalid read of size 8
==527106==    at 0x20827BFB: TFriendElement::DisConnect() (TFriendElement.cxx:173)
==527106==    by 0x20827B37: TFriendElement::~TFriendElement() (TFriendElement.cxx:151)
==527106==    by 0x20827B6F: TFriendElement::~TFriendElement() (TFriendElement.cxx:152)
==527106==    by 0x4C22954: TCollection::GarbageCollect(TObject*) (TCollection.cxx:736)
==527106==    by 0x4C2B511: TList::Delete(char const*) (TList.cxx:537)
==527106==    by 0x2085E84B: TTree::~TTree() (TTree.cxx:986)
==527106==    by 0x2085ED15: TTree::~TTree() (TTree.cxx:1032)
==527106==    by 0x4C22954: TCollection::GarbageCollect(TObject*) (TCollection.cxx:736)
==527106==    by 0x4C2585E: THashList::Delete(char const*) (THashList.cxx:234)
==527106==    by 0x4B490CF: (anonymous namespace)::R__ListSlowDeleteContent(TList*) (TROOT.cxx:1118)
==527106==    by 0x4B4994E: TROOT::EndOfProcessCleanups() (TROOT.cxx:1222)
==527106==    by 0x4B4F53D: TROOT::ShutDown() (TROOT.cxx:3051)
==527106==  Address 0x57db050 is 0 bytes inside a block of size 712 free'd
==527106==    at 0x48488AF: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==527106==    by 0x4BBFF05: TStorage::ObjectDealloc(void*) (TStorage.cxx:362)
==527106==    by 0x4BA3E91: TObject::operator delete(void*) (TObject.cxx:1001)
==527106==    by 0x2085ED21: TTree::~TTree() (TTree.cxx:1032)
==527106==    by 0x4C22954: TCollection::GarbageCollect(TObject*) (TCollection.cxx:736)
==527106==    by 0x4C2585E: THashList::Delete(char const*) (THashList.cxx:234)
==527106==    by 0x4B490CF: (anonymous namespace)::R__ListSlowDeleteContent(TList*) (TROOT.cxx:1118)
==527106==    by 0x4B4994E: TROOT::EndOfProcessCleanups() (TROOT.cxx:1222)
==527106==    by 0x4B4F53D: TROOT::ShutDown() (TROOT.cxx:3051)
==527106==    by 0x4CF8E46: TUnixSystem::Exit(int, bool) (TUnixSystem.cxx:2142)
==527106==    by 0x4B5F27E: TApplication::Terminate(int) (TApplication.cxx:1677)
==527106==    by 0x487A0DE: TRint::Terminate(int) (TRint.cxx:740)
==527106==  Block was alloc'd at
==527106==    at 0x4846013: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==527106==    by 0x4BBFE99: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==527106==    by 0x109575: TObject::operator new(unsigned long) (TObject.h:167)
==527106==    by 0x207A932A: ROOT::new_TTree(void*) (G__Tree.cxx:4183)
==527106==    by 0x4C857DE: TClass::NewObject(TClass::ENewType, bool) const (TClass.cxx:4956)
==527106==    by 0x4C856E1: TClass::New(TClass::ENewType, bool) const (TClass.cxx:4933)
==527106==    by 0x5CDBCE3: TKey::ReadObjectAny(TClass const*) (TKey.cxx:1077)
==527106==    by 0x5C841FB: TDirectoryFile::GetObjectChecked(char const*, TClass const*) (TDirectoryFile.cxx:1098)
==527106==    by 0x20828274: void TDirectory::GetObject<TTree>(char const*, TTree*&) (TDirectory.h:205)
==527106==    by 0x20827F31: TFriendElement::GetTree() (TFriendElement.cxx:222)
==527106==    by 0x208410DB: TTreeCache::AddBranch(char const*, bool) (TTreeCache.cxx:499)
==527106==    by 0x20847D29: TTreeCache::LearnPrefill() (TTreeCache.cxx:2284)
==527106==

@pcanal it looks like TCollection::GarbageCollect deletes a/the main tree, then the friend, and the friend tries to unregister itself from the main tree that has already been deleted. Shouldn’t the main tree inform its friend that it’s being deleted?

Then I must be missing something. I reloaded the friend.C and re-run with v6.26/00 and it works for me …

Try running this in valgrind after producing test.root with the macro at the original thread:

$ valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp root.exe test.root
[0] t3->GetEntry(0)
[1] .q
// valgrind should print errors at this point

I haven’t tested intensively with the example script, but in my app it sometimes crashes, sometimes doesn’t…

That’s because it’s a use after delete, iow undefined behavior, iow if you are lucky things might work fine :confused:

right … I was missing the extra step :slight_smile:

And indeed, I still see and I still remember fixing this exact thing. So let me check what happens to the fix (either reverted and got stuck on its way to the repository)

See tree: Always register FriendElement in external list. by pcanal · Pull Request #10161 · root-project/root · GitHub which should finally fix the issue.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.