Segfault when accessing root object obtained via helper function

I note that opening a TFile in a helper function and returning an object from the file, and then accessing the object in the calling context, causes a segmentation fault. Can I assume that this is a bug? At very least it seems like it could fail more gently (it took me quite a while to figure out what the problem was), though it would be nice to be able to use helper functions like this. Here is a Python script to reproduce the error :

import ROOT
import sys

print "Python version:", sys.version
print "ROOT version  :", ROOT.gROOT.GetVersion()

def getTobj(filename,objname):
  tfile = ROOT.TFile(filename,"READ")
  tobj = tfile.Get(objname)
  return tobj

th1 = ROOT.TH1F("testhist","Test 1D histogram",10,1,10)
[th1.SetBinContent(i,i**2) for i in range(10)]
print [th1.GetBinContent(i) for i in range(10)]

tfile = ROOT.TFile("testhist.root","RECREATE")
th1.Write()
tfile.Close()

print "Opening root file 'manually'"
tfile = ROOT.TFile("testhist.root","READ")
th1_read = tfile.Get("testhist")
print th1_read.GetBinContent(1) # fine

print "Opening root file via helper function"
tobj = getTobj("testhist.root","testhist")
print type(tobj)
print tobj.GetBinContent(1) # segfault

OUTPUT:

[code]Python version: 2.7.11 (default, Jan 11 2016, 21:04:40)
[GCC 5.3.1 20160101]
ROOT version : 6.07/07
[0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0, 49.0, 64.0, 81.0]
Opening root file 'manually’
1.0
Opening root file via helper function
<class ‘ROOT.TH1F’>

*** Break *** segmentation violation

===========================================================
There was a crash.
This is the entire stack trace of all threads:

Thread 2 (Thread 0x7fd2898cf700 (LWP 12073)):
#0 0x00007fd2a0077b09 in futex_abstimed_wait (cancel=true, private=, abstime=0x0, expected=0, futex=0x2439340) at sem_waitcommon.c:42
#1 do_futex_wait (sem=sem
entry=0x2439340, abstime=0x0) at sem_waitcommon.c:208
#2 0x00007fd2a0077ba4 in __new_sem_wait_slow (sem=0x2439340, abstime=0x0) at sem_waitcommon.c:277
#3 0x000000000058a5ff in ?? ()
#4 0x00000000004bbc2a in PyEval_EvalFrameEx ()
#5 0x00000000004b9416 in PyEval_EvalCodeEx ()
#6 0x00000000004d53a3 in ?? ()
#7 0x00000000004a5eee in PyObject_Call ()
#8 0x00000000004c2858 in PyEval_EvalFrameEx ()
#9 0x00000000004c0bef in PyEval_EvalFrameEx ()
#10 0x00000000004c0bef in PyEval_EvalFrameEx ()
#11 0x00000000004b9416 in PyEval_EvalCodeEx ()
#12 0x00000000004d5269 in ?? ()
#13 0x00000000004edbce in ?? ()
#14 0x00000000004a5eee in PyObject_Call ()
#15 0x00000000004c5810 in PyEval_CallObjectWithKeywords ()
#16 0x000000000058a112 in ?? ()
#17 0x00007fd2a0070284 in start_thread (arg=0x7fd2898cf700) at pthread_create.c:333
#18 0x00007fd29f48697d in clone () at …/sysdeps/unix/sysv/linux/x86_64/clone.S:109

Thread 1 (Thread 0x7fd2a047e700 (LWP 12053)):
#0 0x00007fd29f45600b in _GI___waitpid (pid=12076, stat_loc=stat_loc
entry=0x7ffe759b2d70, options=options
entry=0) at …/sysdeps/unix/sysv/linux/waitpid.c:40
#1 0x00007fd29f3dd49b in do_system (line=) at …/sysdeps/posix/system.c:148
#2 0x00007fd29d3c4ab3 in TUnixSystem::Exec (shellcmd=, this=0x2344c50) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:2116
#3 TUnixSystem::StackTrace (this=0x2344c50) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:2403
#4 0x00007fd29d3c711c in TUnixSystem::DispatchSignals (this=0x2344c50, sig=kSigSegmentationViolation) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:3661
#5
#6 0x0000000000000000 in ?? ()
#7 0x00007fd2a048a045 in ?? ()
#8 0x00000000041158b0 in ?? ()
#9 0x00007ffe759b5488 in ?? ()
#10 0x00007ffe759b5488 in ?? ()
#11 0x00007ffe759b53c0 in ?? ()
#12 0x000000019f212a28 in ?? ()
#13 0x00000000041158b0 in ?? ()
#14 0x00007ffe759b5470 in ?? ()
#15 0x00007fd29efb3319 in FastCall (method=, args
=, self=, result=) at /home/farmer/repos/root/bindings/pyroot/src/Cppyy.cxx:381

The lines below might hint at the cause of the crash.
You may get help by asking at the ROOT forum http://root.cern.ch/forum.
Only if you are really convinced it is a bug in ROOT then please submit a
report at http://root.cern.ch/bugs. Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.

#6 0x0000000000000000 in ?? ()
#7 0x00007fd2a048a045 in ?? ()
#8 0x00000000041158b0 in ?? ()
#9 0x00007ffe759b5488 in ?? ()
#10 0x00007ffe759b5488 in ?? ()
#11 0x00007ffe759b53c0 in ?? ()
#12 0x000000019f212a28 in ?? ()
#13 0x00000000041158b0 in ?? ()
#14 0x00007ffe759b5470 in ?? ()
#15 0x00007fd29efb3319 in FastCall (method=, args_=, self=, result=) at /home/farmer/repos/root/bindings/pyroot/src/Cppyy.cxx:381

*** Break *** segmentation violation

===========================================================
There was a crash.
This is the entire stack trace of all threads:

Thread 2 (Thread 0x7fd2898cf700 (LWP 12073)):
#0 0x00007fd2a0077b09 in futex_abstimed_wait (cancel=true, private=, abstime=0x0, expected=0, futex=0x2439340) at sem_waitcommon.c:42
#1 do_futex_wait (sem=sem
entry=0x2439340, abstime=0x0) at sem_waitcommon.c:208
#2 0x00007fd2a0077ba4 in __new_sem_wait_slow (sem=0x2439340, abstime=0x0) at sem_waitcommon.c:277
#3 0x000000000058a5ff in ?? ()
#4 0x00000000004bbc2a in PyEval_EvalFrameEx ()
#5 0x00000000004b9416 in PyEval_EvalCodeEx ()
#6 0x00000000004d53a3 in ?? ()
#7 0x00000000004a5eee in PyObject_Call ()
#8 0x00000000004c2858 in PyEval_EvalFrameEx ()
#9 0x00000000004c0bef in PyEval_EvalFrameEx ()
#10 0x00000000004c0bef in PyEval_EvalFrameEx ()
#11 0x00000000004b9416 in PyEval_EvalCodeEx ()
#12 0x00000000004d5269 in ?? ()
#13 0x00000000004edbce in ?? ()
#14 0x00000000004a5eee in PyObject_Call ()
#15 0x00000000004c5810 in PyEval_CallObjectWithKeywords ()
#16 0x000000000058a112 in ?? ()
#17 0x00007fd2a0070284 in start_thread (arg=0x7fd2898cf700) at pthread_create.c:333
#18 0x00007fd29f48697d in clone () at …/sysdeps/unix/sysv/linux/x86_64/clone.S:109

Thread 1 (Thread 0x7fd2a047e700 (LWP 12053)):
#0 0x00007fd29f45600b in _GI___waitpid (pid=12222, stat_loc=stat_loc
entry=0x7ffe759b2d70, options=options
entry=0) at …/sysdeps/unix/sysv/linux/waitpid.c:40
#1 0x00007fd29f3dd49b in do_system (line=) at …/sysdeps/posix/system.c:148
#2 0x00007fd29d3c4ab3 in TUnixSystem::Exec (shellcmd=, this=0x2344c50) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:2116
#3 TUnixSystem::StackTrace (this=0x2344c50) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:2403
#4 0x00007fd29d3c711c in TUnixSystem::DispatchSignals (this=0x2344c50, sig=kSigSegmentationViolation) at /home/farmer/repos/root/core/unix/src/TUnixSystem.cxx:3661
#5
#6 0x0000000000000000 in ?? ()
#7 0x00007fd2a048a045 in ?? ()
#8 0x00000000041158b0 in ?? ()
#9 0x00007ffe759b5488 in ?? ()
#10 0x00007ffe759b5488 in ?? ()
#11 0x00007ffe759b53c0 in ?? ()
#12 0x000000019f212a28 in ?? ()
#13 0x00000000041158b0 in ?? ()
#14 0x00007ffe759b5470 in ?? ()
#15 0x00007fd29efb3319 in FastCall (method=, args
=, self=, result=) at /home/farmer/repos/root/bindings/pyroot/src/Cppyy.cxx:381

The lines below might hint at the cause of the crash.
You may get help by asking at the ROOT forum http://root.cern.ch/forum.
Only if you are really convinced it is a bug in ROOT then please submit a
report at http://root.cern.ch/bugs. Please post the ENTIRE stack trace
from above as an attachment in addition to anything else
that might help us fixing this issue.

#6 0x0000000000000000 in ?? ()
#7 0x00007fd2a048a045 in ?? ()
#8 0x00000000041158b0 in ?? ()
#9 0x00007ffe759b5488 in ?? ()
#10 0x00007ffe759b5488 in ?? ()
#11 0x00007ffe759b53c0 in ?? ()
#12 0x000000019f212a28 in ?? ()
#13 0x00000000041158b0 in ?? ()
#14 0x00007ffe759b5470 in ?? ()
#15 0x00007fd29efb3319 in FastCall (method=, args_=, self=, result=) at /home/farmer/repos/root/bindings/pyroot/src/Cppyy.cxx:381

Traceback (most recent call last):
File “pyroot_hist_test.py”, line 31, in
print tobj.GetBinContent(1) # segfault
TypeError: none of the 3 overloaded methods succeeded. Full details:
double TH1::GetBinContent(int bin) =>
problem in C++; program state has been reset
double TH1::GetBinContent(int bin, int) =>
takes at least 2 arguments (1 given)
double TH1::GetBinContent(int bin, int, int) =>
takes at least 3 arguments (1 given)[/code]

Hi,

the histogram is attached to the file, as the file goes out of scope, the histogram follows it. You can undo this behaviour like this

def getTobj(filename,objname):
  tfile = ROOT.TFile(filename,"READ")
  tobj = tfile.Get(objname)
  tobj.SetDirectory(0)
  return tobj

Note that opening a file to get out a single object may be less then optimal in presence of many calls…

Cheers,
Danilo

Ahh, handy workaround, thanks! I presume one can detect this happening though right? So it could throw a python error rather than segfaulting?

Hi,

we certainly will consider your suggestion but note this is a well known ROOT behaviour.

Cheers,
D