TTree based class with vector (CallRecursiveRemoveIfNeeded in delete)

Bonjour !

Coming back to you for an issue in my derived TTree class… I’ve a large bunch of mem leak with g++ 7.1.1 that are not shown when using g++ 5.1.1.

I’ve reproduced the behaviour thanks to a toy model. The idea is that i’m creating a tree-based class to handle our data. I’m creating branches with different types (double, string, vector). In this class I’m allocating the memory myself but when i delete an instance of this class with g++ 7.1.1 (not with 5.1.1) i got the log shown below once run with valgrind.

I’m joining to this a piece of code that reproduce this behaviour (MyTreeBasedClass.C). On g++ 7.1.1, once compiled as follow

g++ -o JBBtest MyTreeBasedClass.C `root-config --cflags --evelibs`

I run valgrind like this

valgrind --leak-check=full --suppressions=${ROOTSYS}/etc/valgrind-root.supp --show-possibly-lost=no ./JBBtest

And here is the results… Any hints will be more than welcome…
cheers
jb

==31979== Memcheck, a memory error detector
==31979== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31979== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31979== Command: ./memov6
==31979== 
==31979== Conditional jump or move depends on uninitialised value(s)
==31979==    at 0x6AC5557: CallRecursiveRemoveIfNeeded (TROOT.h:401)
==31979==    by 0x6AC5557: TObject::~TObject() (TObject.cxx:84)
==31979==    by 0x8E41EAB: ~TConfiguredAction (TStreamerInfoActions.h:107)
==31979==    by 0x8E41EAB: _Destroy<TStreamerInfoActions::TConfiguredAction> (stl_construct.h:98)
==31979==    by 0x8E41EAB: __destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:108)
==31979==    by 0x8E41EAB: _Destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:132)
==31979==    by 0x8E41EAB: _Destroy<TStreamerInfoActions::TConfiguredAction*, TStreamerInfoActions::TConfiguredAction> (stl_construct.h:196)
==31979==    by 0x8E41EAB: ~vector (stl_vector.h:434)
==31979==    by 0x8E41EAB: ~TActionSequence (TStreamerInfoActions.h:135)
==31979==    by 0x8E41EAB: ~TActionSequence (TStreamerInfoActions.h:137)
==31979==    by 0x8E41EAB: TBranchElement::SetReadActionSequence() (TBranchElement.cxx:5077)
==31979==    by 0x8E4398E: TBranchElement::InitInfo() (TBranchElement.cxx:2113)
==31979==    by 0x8E52541: TBranchElement::GetInfoImp() const (TBranchElement.cxx:981)
==31979==    by 0x8E46F25: TBranchElement::SetAddress(void*) (TBranchElement.cxx:4469)
==31979==    by 0x8E9B5B1: TTree::BronchExec(char const*, char const*, void*, bool, int, int) (TTree.cxx:2384)
==31979==    by 0x8E83BB7: TTree::Bronch(char const*, char const*, void*, int, int) (TTree.cxx:2265)
==31979==    by 0x40929D: TBranch* TTree::Branch<std::vector<double, std::allocator<double> > >(char const*, char const*, std::vector<double, std::allocator<double> >**, int, int) (TTree.h:328)
==31979==    by 0x40847C: MyClass::MyClass(char const*, char const*) (MyTreeBasedClass.C:33)
==31979==    by 0x4084C9: main (MyTreeBasedClass.C:42)
==31979== 
==31979== Conditional jump or move depends on uninitialised value(s)
==31979==    at 0x6AC5557: CallRecursiveRemoveIfNeeded (TROOT.h:401)
==31979==    by 0x6AC5557: TObject::~TObject() (TObject.cxx:84)
==31979==    by 0x8E426FB: ~TConfiguredAction (TStreamerInfoActions.h:107)
==31979==    by 0x8E426FB: _Destroy<TStreamerInfoActions::TConfiguredAction> (stl_construct.h:98)
==31979==    by 0x8E426FB: __destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:108)
==31979==    by 0x8E426FB: _Destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:132)
==31979==    by 0x8E426FB: _Destroy<TStreamerInfoActions::TConfiguredAction*, TStreamerInfoActions::TConfiguredAction> (stl_construct.h:196)
==31979==    by 0x8E426FB: ~vector (stl_vector.h:434)
==31979==    by 0x8E426FB: ~TActionSequence (TStreamerInfoActions.h:135)
==31979==    by 0x8E426FB: ~TActionSequence (TStreamerInfoActions.h:137)
==31979==    by 0x8E426FB: TBranchElement::SetFillActionSequence() (TBranchElement.cxx:5175)
==31979==    by 0x8E43996: TBranchElement::InitInfo() (TBranchElement.cxx:2114)
==31979==    by 0x8E52541: TBranchElement::GetInfoImp() const (TBranchElement.cxx:981)
==31979==    by 0x8E46F25: TBranchElement::SetAddress(void*) (TBranchElement.cxx:4469)
==31979==    by 0x8E9B5B1: TTree::BronchExec(char const*, char const*, void*, bool, int, int) (TTree.cxx:2384)
==31979==    by 0x8E83BB7: TTree::Bronch(char const*, char const*, void*, int, int) (TTree.cxx:2265)
==31979==    by 0x40929D: TBranch* TTree::Branch<std::vector<double, std::allocator<double> > >(char const*, char const*, std::vector<double, std::allocator<double> >**, int, int) (TTree.h:328)
==31979==    by 0x40847C: MyClass::MyClass(char const*, char const*) (MyTreeBasedClass.C:33)
==31979==    by 0x4084C9: main (MyTreeBasedClass.C:42)
==31979== 
Object name is Test
==31979== Conditional jump or move depends on uninitialised value(s)
==31979==    at 0x6AC5557: CallRecursiveRemoveIfNeeded (TROOT.h:401)
==31979==    by 0x6AC5557: TObject::~TObject() (TObject.cxx:84)
==31979==    by 0x8E435CC: ~TConfiguredAction (TStreamerInfoActions.h:107)
==31979==    by 0x8E435CC: _Destroy<TStreamerInfoActions::TConfiguredAction> (stl_construct.h:98)
==31979==    by 0x8E435CC: __destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:108)
==31979==    by 0x8E435CC: _Destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:132)
==31979==    by 0x8E435CC: _Destroy<TStreamerInfoActions::TConfiguredAction*, TStreamerInfoActions::TConfiguredAction> (stl_construct.h:196)
==31979==    by 0x8E435CC: ~vector (stl_vector.h:434)
==31979==    by 0x8E435CC: ~TActionSequence (TStreamerInfoActions.h:135)
==31979==    by 0x8E435CC: ~TActionSequence (TStreamerInfoActions.h:137)
==31979==    by 0x8E435CC: TBranchElement::~TBranchElement() (TBranchElement.cxx:963)
==31979==    by 0x8E43908: TBranchElement::~TBranchElement() (TBranchElement.cxx:968)
==31979==    by 0x6B45AEE: TObjArray::Delete(char const*) (TObjArray.cxx:375)
==31979==    by 0x8E960E7: TTree::~TTree() (TTree.cxx:904)
==31979==    by 0x4090DB: MyClass::~MyClass() (MyTreeBasedClass.C:18)
==31979==    by 0x409111: MyClass::~MyClass() (MyTreeBasedClass.C:18)
==31979==    by 0x40852E: main (MyTreeBasedClass.C:46)
==31979== 
==31979== Conditional jump or move depends on uninitialised value(s)
==31979==    at 0x6AC5557: CallRecursiveRemoveIfNeeded (TROOT.h:401)
==31979==    by 0x6AC5557: TObject::~TObject() (TObject.cxx:84)
==31979==    by 0x8E436AC: ~TConfiguredAction (TStreamerInfoActions.h:107)
==31979==    by 0x8E436AC: _Destroy<TStreamerInfoActions::TConfiguredAction> (stl_construct.h:98)
==31979==    by 0x8E436AC: __destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:108)
==31979==    by 0x8E436AC: _Destroy<TStreamerInfoActions::TConfiguredAction*> (stl_construct.h:132)
==31979==    by 0x8E436AC: _Destroy<TStreamerInfoActions::TConfiguredAction*, TStreamerInfoActions::TConfiguredAction> (stl_construct.h:196)
==31979==    by 0x8E436AC: ~vector (stl_vector.h:434)
==31979==    by 0x8E436AC: ~TActionSequence (TStreamerInfoActions.h:135)
==31979==    by 0x8E436AC: ~TActionSequence (TStreamerInfoActions.h:137)
==31979==    by 0x8E436AC: TBranchElement::~TBranchElement() (TBranchElement.cxx:964)
==31979==    by 0x8E43908: TBranchElement::~TBranchElement() (TBranchElement.cxx:968)
==31979==    by 0x6B45AEE: TObjArray::Delete(char const*) (TObjArray.cxx:375)
==31979==    by 0x8E960E7: TTree::~TTree() (TTree.cxx:904)
==31979==    by 0x4090DB: MyClass::~MyClass() (MyTreeBasedClass.C:18)
==31979==    by 0x409111: MyClass::~MyClass() (MyTreeBasedClass.C:18)
==31979==    by 0x40852E: main (MyTreeBasedClass.C:46)
==31979== 
==31979== 
==31979== HEAP SUMMARY:
==31979==     in use at exit: 30,401,271 bytes in 69,245 blocks
==31979==   total heap usage: 155,947 allocs, 86,702 frees, 86,539,693 bytes allocated
==31979== 
==31979== LEAK SUMMARY:
==31979==    definitely lost: 0 bytes in 0 blocks
==31979==    indirectly lost: 0 bytes in 0 blocks

MyTreeBasedClass.C (1.1 KB)


ROOT Version: 6.14.00
Platform: Fedora26
Compiler: g++ 7.1.1


Hi jb,
I don’t see memleaks reported here? :sweat_smile:

Cheers,
Enrico

Hi Enrico

agreed from my point of view :stuck_out_tongue: … It was working before hand (g++ 5.1.1), it is still working now (g++ 7.1.1) but it is complaining a lot…

Our platform is developped in a continuous integration using Cdash so every day we have several constructions/tests/coverage/mem leak checks. I’d like to understand these lines and be able to remove them without having to mask them through a valgrind-suppress file (their number is not constant so it is quite hard to monitor if we add more mem leak on top :smiley:).

If anyone has an idea of what i’m doing that coulb be considered dangerous ( Conditional jump or move depends on uninitialised value(s) )

cheers
jb

Hi jb,
these valgrind warnings are not about memory leaks, they are conditional jumps that depend on uninitialized values. A different kind of issue that valgrind-memcheck is able to detect.

So the question is whether we should be suppressing these in ${ROOTSYS}/etc/valgrind-root.supp or they are a symptom of an actual issue. I’m afraid I can’t answer that, but probably @Axel or @pcanal can.

Cheers,
Enrico

I’ve tried many different modification in my dummyexample, but I’ve got to admit this is beyond my reach I guess.

Any hints will be more than welcome

cheers
jb

In the ~MyClass(), you delete _pouet;, but _pouet is still used by the TTree which destructor is called afterwards, I think. I don’t know if anything during the deletion of the TTree (including its branch) can still use this address (maybe not). I guess @pcanal could say something more precise. I would execute ResetBranchAddresses(); right before delete _pouet;".

Thanks for your suggestion.

I tried but it remains the same

cheers
jb

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