Not understood mem leak with TTree::Draw

Hello

I’m seeing something i don"t really understand: iwth 5.34.32, when i do a Ttree::Draw to produce TEventList, i got a mem leak when doing a valgrind check, for a new(long) done in TStorage…

I’ve able to get it with a dummy example as follow :

#include "TTree.h"
#include <iostream>

using namespace std;

int main(void)
{

  TTree *tt = new TTree("tt","");
  double pouet;
  tt->Branch("pouet",&pouet,"pouet/D");

  for(unsigned int i=0; i<100; i++)
    {
      pouet=i;
      tt->Fill();
    }

  int nbEnt =   tt->Draw(">>evList","","goff");
  cout<<"NoSelection :: "<<nbEnt<<endl;
  int nbEnt2 =  tt->Draw(">>evList","pouet>50","goff");
  cout<<"greater than 50 :: "<<nbEnt2<<endl;
  int nbEnt3 =   tt->Draw(">>evList","","goff");
  cout<<"NoSelection :: "<<nbEnt3<<endl;

  delete tt;
  
}

which i compile with

Here is the result of valgrind --suppressions=${ROOTSYS}/etc/valgrind-root.supp --leak-check=full ./pouet

==15349== 29 bytes in 1 blocks are possibly lost in loss record 11,903 of 26,274
==15349==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==15349==    by 0x35038CF258: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x35038CF376: ??? (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x35038D10F5: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x5279131: TClassRef::TClassRef(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==15349==    by 0x92C8DBB: TTreePlayer::TTreePlayer() (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92F5BD4: ROOTDict::new_TTreePlayer(void*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x5292E57: TClass::New(TClass::ENewType) const (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==15349==    by 0x4CA0EEF: TVirtualTreePlayer::TreePlayer(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==15349==    by 0x4CC7688: TTree::GetPlayer() (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==15349==    by 0x4CC7784: TTree::Draw(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==15349==    by 0x400D10: main (Memory.C:19)
==15349== 
==15349== 34 bytes in 1 blocks are possibly lost in loss record 13,947 of 26,274
==15349==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==15349==    by 0x35038CF258: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x35038CF376: ??? (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x35038D10F5: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==15349==    by 0x5AB2B87: G__add_setup_func (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x5A1772B: G__pragma (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x5A7CC59: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x59C428D: G__loadfile (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x59C4A19: G__include_file (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x5A81E9C: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x5B0A62A: G__define_struct (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349==    by 0x5A81A83: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==15349== 
==15349== 360 (232 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 26,124 of 26,274
==15349==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==15349==    by 0x52465B8: TStorage::ObjectAlloc(unsigned long) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==15349==    by 0x92EAD4B: TSelectorDraw::CompileVariables(char const*, char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92E6CDE: TSelectorDraw::Begin(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C5645: TTreePlayer::Process(TSelector*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C7D27: TTreePlayer::DrawSelect(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x400D10: main (Memory.C:19)
==15349== 
==15349== 360 (232 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 26,125 of 26,274
==15349==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==15349==    by 0x52465B8: TStorage::ObjectAlloc(unsigned long) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==15349==    by 0x92EAD4B: TSelectorDraw::CompileVariables(char const*, char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92E6CDE: TSelectorDraw::Begin(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C5645: TTreePlayer::Process(TSelector*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C7D27: TTreePlayer::DrawSelect(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x400DD0: main (Memory.C:23)
==15349== 
==15349== 8,096 (96 direct, 8,000 indirect) bytes in 1 blocks are definitely lost in loss record 26,246 of 26,274
==15349==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==15349==    by 0x52465B8: TStorage::ObjectAlloc(unsigned long) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==15349==    by 0x92E7A4B: TSelectorDraw::Begin(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C5645: TTreePlayer::Process(TSelector*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x92C7D27: TTreePlayer::DrawSelect(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==15349==    by 0x400D10: main (Memory.C:19)
==15349== 
==15349== LEAK SUMMARY:
==15349==    definitely lost: 560 bytes in 3 blocks
==15349==    indirectly lost: 8,256 bytes in 3 blocks
==15349==      possibly lost: 63 bytes in 2 blocks
==15349==    still reachable: 4,102,777 bytes in 52,764 blocks
==15349==         suppressed: 1,268,166 bytes in 9,511 blocks
==15349== Reachable blocks (those to which a pointer was found) are not shown.
==15349== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==15349== 
==15349== For counts of detected and suppressed errors, rerun with: -v
==15349== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 1004 from 63)

Is this known ? Should it be added to the valgrind suppressions list or, more likely i guess, am I doing something stupid ?

thanks in advance
jbb

changing the 2nd argument of the Draw method from “” to “1>0” get rid of most of these lines.
But I have a new one, now when i call GetV1()…

the code is the following

#include "TTree.h"
#include "TROOT.h"
#include "TDirectory.h"
#include <iostream>

using namespace std;

int main(void)
{

  TTree *tt = new TTree("tt","");
  double pouet;
  tt->Branch("pouet",&pouet,"pouet/D");

  for(unsigned int i=0; i<100; i++)
    {
      pouet=i;
      tt->Fill();
    }

  int nbEnt =   tt->Draw(">>evList","1>0","goff");
  gROOT->Delete("evList;*");
  int nbEnt2 =  tt->Draw(">>evList","pouet>50","goff");
  gROOT->Delete("evList;*");
  int nbEnt3 =   tt->Draw(">>evList","1>0","goff");
  gROOT->Delete("evList;*");

  int np=tt->Draw("pouet","1>0","goff");
  double *foo = tt->GetV1();
  
  int np2=tt->Draw("pouet","pouet>50","goff");
  double *foo2 = tt->GetV1();

  delete tt;
  
}

and the result from valgrind is

==19959== 6 bytes in 1 blocks are definitely lost in loss record 2,878 of 27,875
==19959==    at 0x4A077BC: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==19959==    by 0x92E6C03: TSelectorDraw::Begin(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x92C5645: TTreePlayer::Process(TSelector*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x92C7D27: TTreePlayer::DrawSelect(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x400C62: main (Memory.C:28)
==19959== 
==19959== 6 bytes in 1 blocks are definitely lost in loss record 2,879 of 27,875
==19959==    at 0x4A077BC: operator new[](unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==19959==    by 0x92E6C03: TSelectorDraw::Begin(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x92C5645: TTreePlayer::Process(TSelector*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x92C7D27: TTreePlayer::DrawSelect(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x400CB3: main (Memory.C:31)
==19959== 
==19959== 29 bytes in 1 blocks are possibly lost in loss record 12,594 of 27,875
==19959==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==19959==    by 0x35038CF258: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x35038CF376: ??? (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x35038D10F5: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x5279131: TClassRef::TClassRef(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==19959==    by 0x92C8DBB: TTreePlayer::TTreePlayer() (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x92F5BD4: ROOTDict::new_TTreePlayer(void*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==19959==    by 0x5292E57: TClass::New(TClass::ENewType) const (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==19959==    by 0x4CA0EEF: TVirtualTreePlayer::TreePlayer(TTree*) (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==19959==    by 0x4CC7688: TTree::GetPlayer() (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==19959==    by 0x4CC7784: TTree::Draw(char const*, char const*, char const*, long long, long long) (in /export/home/jb232551/root_v5.34.32/lib/libTree.so.5.34)
==19959==    by 0x400B60: main (Memory.C:21)
==19959== 
==19959== 34 bytes in 1 blocks are possibly lost in loss record 14,661 of 27,875
==19959==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==19959==    by 0x35038CF258: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x35038CF376: ??? (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x35038D10F5: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.21)
==19959==    by 0x5AB2B87: G__add_setup_func (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x5A1772B: G__pragma (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x5A7CC59: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x59C428D: G__loadfile (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x59C4A19: G__include_file (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x5A81E9C: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x5B0A62A: G__define_struct (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959==    by 0x5A81A83: G__exec_statement (in /export/home/jb232551/root_v5.34.32/lib/libCint.so.5.34)
==19959== 
==19959== LEAK SUMMARY:
==19959==    definitely lost: 12 bytes in 2 blocks
==19959==    indirectly lost: 0 bytes in 0 blocks
==19959==      possibly lost: 63 bytes in 2 blocks
==19959==    still reachable: 8,334,047 bytes in 53,360 blocks
==19959==         suppressed: 1,365,673 bytes in 10,947 blocks
==19959== Reachable blocks (those to which a pointer was found) are not shown.
==19959== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==19959== 
==19959== For counts of detected and suppressed errors, rerun with: -v
==19959== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 1025 from 73)

all ideas are welcome
cheers
jb

Hi,

This is a real leak. I am updating the code to resolved it.

Cheers,
Philippe.

Thanks for the quick answer

I don’t know if this is related (all coming from TreePlayer ?) but when i call GetEntries with a cut, i also get mem leaks. Adding these three lines in the same code (right before the delete)

  int nentcut1 = tt->GetEntries("pouet>50");
  int nentfull = tt->GetEntries();
  int nentcut2 = tt->GetEntries("pouet<30");

Valgrind add to the previous log these lines

=11679== 176 (80 direct, 96 indirect) bytes in 1 blocks are definitely lost in loss record 22,027 of 28,046
==11679==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==11679==    by 0x52465B8: TStorage::ObjectAlloc(unsigned long) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==11679==    by 0x92C4A89: TSelectorEntries::SetSelection(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x92C4C15: TSelectorEntries::TSelectorEntries(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x92CE223: TTreePlayer::GetEntries(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x400CF1: main (Memory.C:34)
==11679== 
==11679== 176 (80 direct, 96 indirect) bytes in 1 blocks are definitely lost in loss record 22,028 of 28,046
==11679==    at 0x4A07117: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==11679==    by 0x52465B8: TStorage::ObjectAlloc(unsigned long) (in /export/home/jb232551/root_v5.34.32/lib/libCore.so.5.34)
==11679==    by 0x92C4A89: TSelectorEntries::SetSelection(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x92C4C15: TSelectorEntries::TSelectorEntries(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x92CE223: TTreePlayer::GetEntries(char const*) (in /export/home/jb232551/root_v5.34.32/lib/libTreePlayer.so.5.34)
==11679==    by 0x400D2E: main (Memory.C:36)

showing that only the middle one without argument is probem free. Am I doing something wrong ?

Thanks anyway for the quick feedback
regards
Jean-Baptiste Blanchard

Hi Jean-Baptiste,

Indeed there was a (small) leak whenever TTree::Draw was called without any formula at all (which seems a bit odd to do anyway :slight_smile: ). This is fixed in the master.

I will now investigate the one for GetEntries.

Cheers,
Philippe.

The other two issues (including GetEntries) are resolved in the master.

Cheers,
Philippe.

Thanks a lot for your answer…

I’ll make our own suppression file including these issues, to mask them with the 5.34.32 and I’ll remove it as soon as i’ll move to v6.

Thanks again
Cheers
jb