Memory leak in TCanvas::DrawClonePad

Dear all,

I am trying to make a picture containing multiple canvases. Basically, I create a TCanvas, divide it wisely, loop over the canvases and for each I “drawclonepad” it on one of the subpad. However, doing so I have a memory leak.

I made a very small program (in attachment) that shows the problem. Despite the deletion of the returned TObject pointer, valgrind complains about a memory leak.

DrawClonePad usage:

TObject *o = c1->DrawClonePad(); summary->SaveAs("test4.ps"); // ok but memory leak delete o;

Valgrind:

[code]
valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp --log-file=valgrind-drawclonepaddelete.output --leak-check=full --tool=memcheck --show-reachable=no ./a.out

==19176== 3,160 (336 direct, 2,824 indirect) bytes in 1 blocks are definitely lost in loss record 35,048 of 35,126
==19176== at 0x4A0695E: operator new(unsigned long) (vg_replace_malloc.c:220)
==19176== by 0x806549C: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:328)
==19176== by 0x401C14: TObject::operator new(unsigned long) (TObject.h:156)
==19176== by 0xACBE2C8: ROOT::new_THistPainter(void*) (in /opt/root-5.30.03/lib/libHistPainter.so.5.30)
==19176== by 0x80E299F: TClass::New(TClass::ENewType) const (TClass.cxx:3689)
==19176== by 0x51F50E0: TVirtualHistPainter::HistPainter(TH1*) (TVirtualHistPainter.cxx:46)
==19176== by 0x5119415: TH1::GetPainter(char const*) (TH1.cxx:3762)
==19176== by 0x5119453: TH1::Paint(char const*) (TH1.cxx:5411)
==19176== by 0x4C82DAC: TPad::PaintModified() (TPad.cxx:3095)
==19176== by 0x4C576B7: TCanvas::Update() (TCanvas.cxx:2125)
==19176== by 0x4C588EC: TCanvas::DrawClonePad() (TCanvas.cxx:886)
==19176== by 0x4018F4: main (ex_drawclonepad.cpp:32)[/code]

I have several questions :

  1. Why do I have a memory leak ?
  2. Why the use of Draw() or DrawClone() results in an empty TCanvas ? (see attached code)
  3. Why valgrind reports a dozen memory problem even though I use the root suppression file ? (see attached output)

Thank you very much in advance for your help,
Barth
valgrind.txt (19.2 KB)
ex_drawclonepad.cpp (1.42 KB)

A standalone aplpication should have a TApplication call.
See for instance $ROOTSYS/text/stressGraphics.cxx

Hello,

I have added the TApplication call that was indeed missing. I attach a new version of the example code.

Running valgrind still reports a memory leak when calling DrawClonePad (see attachment).

Moreover, I now have a memory error reported as well :

==32148== Syscall param writev(vector[...]) points to uninitialised byte(s) ==32148== at 0x306C4CD20C: writev (in /lib64/libc-2.5.so) ==32148== by 0x306DC4624B: ??? (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0x306DC4ACCE: _XSend (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0x306DC3CCCF: XQueryExtension (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0x306DC31543: XInitExtension (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0x3070C03A89: XFixesFindDisplay (in /usr/lib64/libXfixes.so.3.1.0) ==32148== by 0x3070C01D9A: XFixesSetCursorName (in /usr/lib64/libXfixes.so.3.1.0) ==32148== by 0x3071004578: XcursorImagesLoadCursor (in /usr/lib64/libXcursor.so.1.0.2) ==32148== by 0x30710078DE: XcursorTryShapeCursor (in /usr/lib64/libXcursor.so.1.0.2) ==32148== by 0x306DC24E13: XCreateGlyphCursor (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0x306DC25370: XCreateFontCursor (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0xA84C353: TGX11::OpenDisplay(_XDisplay*) (TGX11.cxx:1136) ==32148== by 0xA84C91A: TGX11::Init(void*) (TGX11.cxx:313) ==32148== by 0xB8D0C9E: TGX11TTF::Init(void*) (TGX11TTF.cxx:169) ==32148== by 0xA83FC87: TGX11::OpenDisplay(char const*) (GX11Gui.cxx:833) ==32148== by 0xB092BC0: TGClient::TGClient(char const*) (TGClient.cxx:118) ==32148== by 0xB1E349D: TRootApplication::TRootApplication(char const*, int*, char**) (TRootApplication.cxx:46) ==32148== by 0xB2131FB: TRootGuiFactory::CreateApplicationImp(char const*, int*, char**) (TRootGuiFactory.cxx:46) ==32148== by 0x7FFD311: TApplication::InitializeGraphics() (TApplication.cxx:287) ==32148== by 0x7FFEF78: TApplication::TApplication(char const*, int*, char**, void*, int) (TApplication.cxx:189) ==32148== by 0x401F91: main (ex_drawclonepad.cpp:25) ==32148== Address 0xabd2fa6 is 262 bytes inside a block of size 16,384 alloc'd ==32148== at 0x4A05430: calloc (vg_replace_malloc.c:418) ==32148== by 0x306DC36DC6: XOpenDisplay (in /usr/lib64/libX11.so.6.2.0) ==32148== by 0xA83FBF4: TGX11::OpenDisplay(char const*) (GX11Gui.cxx:822) ==32148== by 0xB092BC0: TGClient::TGClient(char const*) (TGClient.cxx:118) ==32148== by 0xB1E349D: TRootApplication::TRootApplication(char const*, int*, char**) (TRootApplication.cxx:46) ==32148== by 0xB2131FB: TRootGuiFactory::CreateApplicationImp(char const*, int*, char**) (TRootGuiFactory.cxx:46) ==32148== by 0x7FFD311: TApplication::InitializeGraphics() (TApplication.cxx:287) ==32148== by 0x7FFEF78: TApplication::TApplication(char const*, int*, char**, void*, int) (TApplication.cxx:189) ==32148== by 0x401F91: main (ex_drawclonepad.cpp:25)

Thank you very much for your help,
Barth
valgrind.txt (568 KB)
ex_drawclonepad.cpp (1.61 KB)

i get :

++ g++ -O2 -pipe -Wall -W -Woverloaded-virtual -fPIC -Iinclude -pthread -I /Users/couet/root/include -o ex_drawclonepad.o -c ex_drawclonepad.cxx
ex_drawclonepad.cxx: In function ‘int main(int, char**)’:
ex_drawclonepad.cxx:25: error: no matching function for call to ‘TApplication::TApplication(const char [4], int*, char***)’
/Users/couet/root/include/TApplication.h:103: note: candidates are: TApplication::TApplication(const char*, Int_t*, char**, void*, Int_t)
/Users/couet/root/include/TApplication.h:87: note:                 TApplication::TApplication()
/Users/couet/root/include/TApplication.h:79: note:                 TApplication::TApplication(const TApplication&)

I apologize, I screwed the first line. Here is the correct one. :blush:
ex_drawclonepad.cpp (1.61 KB)

on Mac with the latest root I get different figues with your program:

==69000== LEAK SUMMARY:
==69000==    definitely lost: 1,376 bytes in 4 blocks
==69000==    indirectly lost: 3,648 bytes in 26 blocks
==69000==      possibly lost: 15,412 bytes in 190 blocks
==69000==    still reachable: 2,164,262 bytes in 28,821 blocks
==69000==         suppressed: 0 bytes in 0 blocks

I am on SLC5, 64 bits, ROOT 5.30/03. I don’t understand why i get a different output.

To have an impartial evaluation, I did it on lxplus :

. /afs/cern.ch/sw/lcg/app/releases/ROOT/5.30.04/x86_64-slc5-gcc43-dbg/root/bin/thisroot.sh g++ -g -I/afs/cern.ch/sw/lcg/app/releases/ROOT/5.30.04/x86_64-slc5-gcc43-dbg/root/include -pthread -m64 -fPIC -W -Wall -Wextra -Wconversion -Wdisabled-optimization -Wno-unused -Wall -Wshadow -Wextra -Wredundant-decls -L/afs/cern.ch/sw/lcg/app/releases/ROOT/5.30.04/x86_64-slc5-gcc43-dbg/root/lib -lGpad -lHist -lGraf -lGraf3d -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lRIO -lNet -lThread -lCore -lCint -lm -ldl ex_drawclonepad.cpp -o ex_drawclonepad valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp --log-file=valgrind-drawclonepaddelete.output --leak-check=full --tool=memcheck --show-reachable=no --num-callers=35 ./ex_drawclonepad

I get the attached valgrind report. There are only 2 reported issues and they relate to DrawClonePad.
On your machine, do you get leaks relative to drawclonepad at all ?

Cheers,
Barth
valgrind.txt (5.14 KB)

no… but I am using 5.32