Memory leak in TFile?

Hello ROOTers,

Consider the following, very simple test program:

[code]#include “TFile.h”
#include “TH1F.h”

int main() {
TFile f(“test.root”,“RECREATE”);
TH1F *h = new TH1F(“h”,“h”,10,0.,1.);
f.Write();
f.Close();

return 0;
}[/code]

I compile this as

Valgrind sees a memory leak, although I use the ROOT suppressions file:

$ valgrind --leak-check=full --suppressions=/etc/root/valgrind-root.supp --num-callers=50 ./testROOT ==6291== Memcheck, a memory error detector ==6291== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==6291== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==6291== Command: ./testROOT ==6291== ==6291== ==6291== HEAP SUMMARY: ==6291== in use at exit: 3,691,202 bytes in 41,980 blocks ==6291== total heap usage: 97,194 allocs, 55,214 frees, 7,567,580 bytes allocated ==6291== ==6291== 32 bytes in 1 blocks are possibly lost in loss record 16,436 of 31,402 ==6291== at 0x4C28147: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==6291== by 0x4FF5D5C: TString::Replace(int, int, char const*, int) (in /usr/lib/x86_64-linux-gnu/root5.34/libCore.so.5.34) ==6291== by 0x61E61FC: TStreamerInfo::Compile() (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x61D6CC6: TStreamerInfo::Build() (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x5050356: TClass::GetStreamerInfo(int) const (in /usr/lib/x86_64-linux-gnu/root5.34/libCore.so.5.34) ==6291== by 0x61D78AA: TStreamerInfo::Build() (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x618BD50: TBufferFile::WriteClassBuffer(TClass const*, void*) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x61C5D11: TKey::TKey(TObject const*, char const*, int, TDirectory*) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x61A04A9: TFile::CreateKey(TDirectory*, TObject const*, char const*, int) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x619A9A9: TDirectoryFile::WriteTObject(TObject const*, char const*, char const*, int) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x4FD8D35: TObject::Write(char const*, int, int) const (in /usr/lib/x86_64-linux-gnu/root5.34/libCore.so.5.34) ==6291== by 0x6198AF0: TDirectoryFile::Write(char const*, int, int) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x61A0F74: TFile::Write(char const*, int, int) (in /usr/lib/x86_64-linux-gnu/root5.34/libRIO.so.5.34) ==6291== by 0x400D6F: main (testROOT.cc:7) ==6291== ==6291== LEAK SUMMARY: ==6291== definitely lost: 0 bytes in 0 blocks ==6291== indirectly lost: 0 bytes in 0 blocks ==6291== possibly lost: 32 bytes in 1 blocks ==6291== still reachable: 2,715,667 bytes in 30,748 blocks ==6291== suppressed: 975,503 bytes in 11,231 blocks ==6291== Reachable blocks (those to which a pointer was found) are not shown. ==6291== To see them, rerun with: --leak-check=full --show-reachable=yes ==6291== ==6291== For counts of detected and suppressed errors, rerun with: -v ==6291== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 73 from 73)

Is this a bug, or am I incorrectly handling my TFile?

I’m using ROOT v5.34.

Thanks in advance,
Davide

Hi Davide,

Neither. The memory that is reported by valgrind is allocated only once (per StreamerInfo, not per file) and is global memory that is intentionally not release at the end of the process (to save some run-time). Consider using the file etc/valgrind-root.supp (with --suppressions=…) to hide intentional ‘leak’.

Cheers,
Philippe.

Philippe, he already uses “–suppressions=/etc/root/valgrind-root.supp” (see the first line in his “memory leak” report -> it’s his full valgrind command line). I think it’s the “–leak-check=full” option which makes these “errors” appear (just try to valgrind the standard “root.exe -l -q” with this option present).

Thanks Pepe,

Indeed, I had missed the valgrind option on the command line. I updated the trunk and the v5.34 patch branch to suppress also this report.

Cheers,
Philippe.

Hi Pepe,

I can not reproduce on my machine the valgrind output you get on Ubuntu. Can you send me the result of --gen-suppressions=all so that I can add them as needed in the valgrind suppression … or better yet, can you send me a patch for valgrind-root.supp that add them.

Thanks,
Philippe.

Here’s the new file (again, delete after downloaded).

This is somehow strange … with the “–suppressions” option I get 79 errors, without it I get 80. How can this be?
The only difference is:

< ==3714== 160 (40 direct, 120 indirect) bytes in 1 blocks are definitely lost in loss record 13,625 of 14,936 < ==3714== at 0x4024F20: malloc (vg_replace_malloc.c:236) < ==3714== by 0x49F64C3: nss_parse_service_list (nsswitch.c:622) < ==3714== by 0x49F6C06: __nss_database_lookup (nsswitch.c:164) < ==3714== by 0x54E5EAB: ??? < ==3714== by 0x54E6B6C: ??? < ==3714== by 0x49AEC14: getpwuid_r@@GLIBC_2.1.2 (getXXbyYY_r.c:253) < ==3714== by 0x49AE57E: getpwuid (getXXbyYY.c:117) < ==3714== by 0x424142C: TUnixSystem::UnixHomedirectory(char const*) (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x42414FC: TUnixSystem::HomeDirectory(char const*) (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x418CF77: TROOT::InitSystem() (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x41917E9: TROOT::TROOT(char const*, char const*, void (**)()) (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x4192EDD: ROOT::GetROOT() (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x4192F77: global constructors keyed to TROOT.cxx (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x45D1A0C: ??? (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x412364F: ??? (in /ROOTSYS/lib/root/libCore.so.5.34) < ==3714== by 0x400DC0B: call_init (dl-init.c:70) < ==3714== by 0x400DD28: _dl_init (dl-init.c:134) < ==3714== by 0x400088E: ??? (in /lib/ld-2.11.1.so) < ==3714== < { < <insert_a_suppression_name_here> < Memcheck:Leak < fun:malloc < fun:nss_parse_service_list < fun:__nss_database_lookup < obj:* < obj:* < fun:getpwuid_r@@GLIBC_2.1.2 < fun:getpwuid < fun:_ZN11TUnixSystem17UnixHomedirectoryEPKc < fun:_ZN11TUnixSystem13HomeDirectoryEPKc < fun:_ZN5TROOT10InitSystemEv < fun:_ZN5TROOTC1EPKcS1_PPFvvE < fun:_ZN4ROOT7GetROOTEv < fun:_GLOBAL__I_TROOT.cxx < obj:/ROOTSYS/lib/root/libCore.so.5.34 < obj:/ROOTSYS/lib/root/libCore.so.5.34 < fun:call_init < fun:_dl_init < obj:/lib/ld-2.11.1.so < }

There is another strange problem … when I ran valgrind for the first time today (just to try the original post) … I got more than 2000 errors … but now I get 79 (i.e. I cannot reproduce these 2000).

Maybe on can ask someone to run the same command on Ubuntu 12.04?

Can it be that … the problem is that in “valgrind-root.supp” I find “fun:_Znwm” and “fun:_Znam” but my valgrind reports “fun:_Znwj” and “fun:_Znaj” … and so no rule is recognized?

Same with “fun:_ZN8TStorage11ObjectAllocEm” versus “fun:_ZN8TStorage11ObjectAllocEj”, “fun:_ZN7TObjectnwEm” versus “fun:_ZN7TObjectnwEj”, … “fun:_ZNSs4_Rep9_S_createEmmRKSaIcE” versus “fun:_ZNSs4_Rep9_S_createEjjRKSaIcE”

I think I am right …
In many places … “m” <-> “j” … once I start to replace

Hi Pepe,

Yes, as you were typing your answer I uploaded in the trunk and the v5.34 patch branch, an update to the suppression file that should make it valid/useful both on 32 and 64 bits platform (the issue here with _Znwj vs _Znwm, etc.).

Thanks,
Philippe.

I needed to modify some more entries … new “valgrind-root.supp” file attached (please commit it) …
I still get 6 errors. Have a look at the attached “ROOT.v5-34-00-patches.valgrind.out.txt” file.

One question … up to now only the “ROOT’s RTTI” section has been modified. However, in another sections there are 7 more cases of “m” / “mm” which one might consider … fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeIiEE8allocateEmPKv fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPKcSt3setIiSt4lessIiESaIiEEEEE8allocateEmPKv fun:_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKPKcSt3setIiSt4lessIiESaIiEEEEE8allocateEmPKv fun:_ZN5TGX1113GetWindowSizeEmRiS0_RjS1_ fun:_ZN8TGX11TTF10DrawStringEmmiiPKci fun:_ZN5TGX1110CheckEventEm11EGEventTypeR7Event_t fun:_ZN5TGX1113SetWindowNameEmPc
valgrind-root.supp.txt (13.7 KB)
ROOT.v5-34-00-patches.valgrind.out.txt (18.4 KB)

Attached, a modified “valgrind-root.supp” file with ALL “m” fixed (i.e. including these 7 mentioned in the previous post).
I still get the same 6 errors, though.
valgrind-root.supp.txt (13.7 KB)

Hi Pepe,

I uploaded the fixes to the trunk and the v5.34 patch branches except for the routine that should (and intended to) be the same (always a long) on both 32 and 64 bits platforms namely (DrawString, GetWindowSize, CheckEvent).

Thanks,
Philippe.

Hi Pepe,

And now, I updated the trunk and patch branches to cover the last 6 issue you were seeing.

Cheers,
Philippe.

Still one error left (see attachment) :stuck_out_tongue:

What concerns these last four functions (GetWindowSize, DrawString, CheckEvent, SetWindowName), I can confirm that their “exact” names with “m” appear in libraries on my i686 system.
ROOT.v5-34-00-patches.valgrind.out.txt (4.54 KB)

Just from curiosity I tried to “valgrind --leak-check=full” the “${ROOTSYS}/bin/rootn.exe -l -q” …
==6737== ERROR SUMMARY: 6110 errors from 6110 contexts (suppressed: 83 from 46)

Hi Pepe,

The last one should also be covered in the trunk and v5.34 patch branch.

As far as rootn is concerned, I will leave it alone for now, as it is very seldom used.

Cheers,
Philippe.

==9572== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 123 from 88) =D>

Just for completeness … if I try “–leak-check=full --show-reachable=yes”, I get extremely many “reachable blocks” found.

Anyhow, as this issue is “closed” for now - maybe you could delete all posts here so that they do not generate unnecessary disturbance in the search engine.