User Class TF1 member double delete

I have a simple user defined class that inherits from TObjects
It simply holds a TF1 and a std::vector
I think my problem is to do with having a TObject as a member variable.

Class is compiled in an external library which is loaded at ROOT run time.
Dictionary generated with the following pragma
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ nestedclasses;
#pragma link C++ defined_in “include/james_utility.h”;

When I save and later load an instance of the class from a .root file it behaves as intended, however at root quit time I get a memory error:
root [1] .q
*** Error in `/opt/root_v6.04.12/bin/root.exe’: free(): invalid pointer: 0x00000000040de4b8 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7d023)[0x7f0340225023]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN5TList6DeleteEPKc+0x2b5)[0x7f03410ff705]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN5TROOT20EndOfProcessCleanupsEv+0x38)[0x7f03410d65c8]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN11TUnixSystem4ExitEib+0x21)[0x7f0341152f31]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN12TApplication11ProcessLineEPKcbPi+0x7f)[0x7f03410e0c4f]
/opt/root_v6.04.12/lib/root/libRint.so(_ZN5TRint13ProcessLineNrEPKcS1_Pi+0x125)[0x7f0340cbea95]
/opt/root_v6.04.12/lib/root/libRint.so(_ZN5TRint15HandleTermInputEv+0x211)[0x7f0340cbecf1]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN11TUnixSystem16CheckDescriptorsEv+0x155)[0x7f0341157d05]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN11TUnixSystem16DispatchOneEventEb+0xca)[0x7f0341158c9a]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN7TSystem9InnerLoopEv+0x16)[0x7f03410ae716]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN7TSystem3RunEv+0x70)[0x7f03410af2c0]
/opt/root_v6.04.12/lib/root/libCore.so(_ZN12TApplication3RunEb+0x1f)[0x7f03410df45f]
/opt/root_v6.04.12/lib/root/libRint.so(_ZN5TRint3RunEb+0x4f7)[0x7f0340cc01a7]
/opt/root_v6.04.12/bin/root.exe(main+0x4c)[0x40103c]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f03401c9b15]
/opt/root_v6.04.12/bin/root.exe[0x4010ad]

The invalid pointer (In this run instance 0x00000000040de4b8) I have confirmed is the memory address of the TF1 member of the class.

Is this an issue in that the system is trying to delete the TF1 as a TObject in memory but it is already deleted as a member of my class? Is there a way around this?

I only have this issue upon loading an instance from a .root file, I dont get any such issues when quitting from a sessions in which instances of the class are created live.

Hi,

it’s no problem at all to have such classes. The best would be to share here:

  1. The class header and implementation
  2. The recipe you used to generate dictionaries and compile the library
  3. The code you have to write and the one you use to read the instances from disk
  4. The root version you use

Danilo

Hi,

You can try to avoid registering the function in the gROOT ( the global list of functions).
Just call at the beginning of your program

TF1::DefaultAddToGlobalList(false)

Lorenzo

Thanks for the swift replies, I’ve boiled it down to minimal working example, attached.

I’m using ROOT 6.04/12

My version seems to be missing TF1::DefaultAddToGlobalList, was this a recent addition? I would prefer not to go this route as it has wider effects and I’d like to understand what I’m doing wrong as Danilo says such classes should be possible.

James S
minimalworking.zip (1.73 KB)

Hi,

The problem is that your class is deleting a TF1 object that ROOT has deleted as well. So either you check that
when deleting the TF1 or better you avoid registering the TF1 object in the list.
If you are using one of the latest ROOT, it is better to use this solution to create the TF1:

 TF1 func("func","[0]*x+[1]",0,1,TF1::EAddToList::kNo);

I have checked with your example, modifying your create.C macro and it works fine for me

Cheers

Lorenzo

Hi,

as lorenzo says, there is a way to detach the function from the list also after creating it with the AddToGlobalList too (root.cern.ch/doc/master/classTF … 704e1423e5).

I took the freedom of modifying your makefile in order to be able to run your two macros without the macro loading the library and steering them

ROOT_LIBS = `root-config --glibs`
ROOT_GCC_FLAGS = `root-config --cflags`

CC = g++
CFLAGS = -std=c++11 -g -fPIC -Wall $(ROOT_GCC_FLAGS)

TARG = libjutility.so
	
$(TARG): j_utility.cpp j_utility.h
	rootcint -f  DictOutput.cxx -rml $(TARG) -rmf al.rootmap j_utility.h Linkdef.h
	$(CC) $(CFLAGS) -o $@ -shared DictOutput.cxx j_utility.cpp -I. $(ROOT_LIBS)

clean:
	rm $(TARG)
	rm -rf DictOutput*

The difference is that now you generate also a rootmap file which allows ROOT to automatically load the library you create. I hope this helps.

Cheers,
D

Thank you for your responses, I didnt know about the rootmap files. I would rather not go the route of removing the TF1 and creation time as this doesnt actually fix the class, also “EAddToList” is not recognised in my ROOT version.
I instead tried calling AddToGlobalList within the class, this didnt work and I also noticed it always returned false, but should return true the first time it is called on a TF1 as the global default is to add them to the global list.

“your class is deleting a TF1 object that ROOT has deleted as well. So either you check that when deleting the TF1 or better you avoid registering the TF1 object in the list.” - I dont see what I can do in regard to “check when deleting” it is a member variable, its destructor gets called no matter what I do.

Although I am now very confused, I noticed after adding a cout my objects destructor was never called, so I dont understand how IT can be guilty of the double delete.

After calling:
"FitHolder* LoadOb=(FitHolder*)LoadFile.Get(“TestOb”);"
LoadOb was still in scope even after calling:
"LoadFile.Close()"
and calling “delete LoadOb” fixed the TF1 invalid pointer problem.

Also calling
"gROOT->GetListOfFunctions()->Remove(&(LoadOb->cFit));"
before program exit (without the destructor being called) worked.

Although I have 2 ways of making the error go away in this example now, I’m still not sure I agree/understand the diagnosis of the problem and I would like to write a class that works rather than one that needs workarounds to use.

Hi,

Your both solution makes sense. In the first case you are deleting the TF1 object before ROOT and this is fine, in the second one you remove it from the list of functions kept by ROOT.
These are not workaround, it is just the way the TF1 classes are managed by the framework.
Either you want to manage them, then call TF1.AddToGLobalList(false) or you need to be careful to not double delete them.

It is strange that the first time, TF1::AddToGLobalList returns false. It does not for me.

Cheers

Lorenzo

I say workaround as they require external intervention. Ideally I would make the TF1 a private member and then de-register it when it enters the class.

My problems currently are not understanding where the double delete happens as the destructor is never called except for when I have done it manually (I dont think I really understand the state of an object pointer got with TFile->Get or TFile->GetObject).

and also having strange behaviour of TF1.AddToGLobalList(false).
Only “GetListOfFunctions()->Remove” seems to work.
It seems the member TF1 is always created not on the list, function of the TF1 copy assignment operator?
When the object is loaded from a TFile the TF1 reverts to being tracked on the global list

In creation macro"

[code]TF1 func(“func”,"[0]*x+[1]",0,1);
FitHolder TestObA(&func)

gROOT->GetListOfFunctions()->FindObject(&(func)) 0x7f9f33b2c0d8
func.AddToGlobalList(false) 0
gROOT->GetListOfFunctions()->FindObject(&(func)) 0x7f9f33b2c0d8
gROOT->GetListOfFunctions()->Remove(&(func)) 0x7f9f33b2c0d8
gROOT->GetListOfFunctions()->FindObject(&(func)) 0

FitHolder TestObB(&func)
gROOT->GetListOfFunctions()->FindObject(&(TestObA.cFit)) 0
gROOT->GetListOfFunctions()->FindObject(&(TestObB.cFit)) 0[/code]
In loading macro

FitHolder* LoadOb=(FitHolder*)LoadFile.Get("TestOb"); gROOT->GetListOfFunctions()->FindObject(&( LoadOb->cFit)) 0x3bfefe8