Error persisting array of pointers

Hello,

I might be overlooking something obvious here, but could someone please tell me why the following segfaults?

std::array<TObject*, 2> arr;
arr[0] = new TObject();
arr[1] = new TObject();

TFile f("foo.root", "RECREATE");
f.WriteObject(&arr, "array");
f.Close();

TFile ff("foo.root");
std::array<TObject*, 2> *arr2 = nullptr;
ff.GetObject("array", arr2);  // Segfaults here
std::cout << arr2 << std::endl;

Output:

 *** Break *** segmentation violation

===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007f6613dd107a in __GI___waitpid (pid=27546, stat_loc=stat_loc
entry=0x7ffe0ac4b380, options=options
entry=0) at ../sysdeps/unix/sysv/linux/waitpid.c:29
#1  0x00007f6613d49fbb in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:148
#2  0x00007f6615002a92 in TUnixSystem::StackTrace() () from /home/ahmad/biodynamo/build/third_party/root/lib/libCore.so
#3  0x00007f6615005383 in TUnixSystem::DispatchSignals(ESignals) () from /home/ahmad/biodynamo/build/third_party/root/lib/libCore.so
#4  <signal handler called>
#5  0x0000000000000002 in ?? ()
#6  0x00007f6614fa5521 in TClass::Destructor(void*, bool) () from /home/ahmad/biodynamo/build/third_party/root/lib/libCore.so
#7  0x00007f661479b9e6 in TBufferFile::ReadFastArray(void**, TClass const*, int, bool, TMemberStreamer*, TClass const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#8  0x00007f6614a13c6e in int TStreamerInfo::ReadBuffer<char**>(TBuffer&, char** const&, TStreamerInfo::TCompInfo* const*, int, int, int, int, int) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#9  0x00007f6614863403 in TStreamerInfoActions::GenericReadAction(TBuffer&, void*, TStreamerInfoActions::TConfiguration const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#10 0x00007f66147a1d9e in TBufferFile::ReadClassBuffer(TClass const*, void*, TClass const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#11 0x00007f661483b05f in TKey::ReadObjectAny(TClass const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#12 0x00007f66147de69e in TDirectoryFile::GetObjectChecked(char const*, TClass const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#13 0x0000000000401f6d in void TDirectory::GetObject<std::array<TObject*, 2ul> >(char const*, std::array<TObject*, 2ul>*&) ()
#14 0x0000000000401c69 in main ()
===========================================================

Using std::vector<TObject*> and adding this to my selection.xml for genreflex seems to work fine. If I try to add std::array<TObject*, 2> to my selection.xml I get an error saying that this should be working “transparently” and therefore should not have it in my selection.xml

Any ideas what is going wrong?

Best,
Ahmad


ROOT Version: v6.18/04
Platform: Ubuntu 16.04
Compiler: GCC 5.5


Indeed, storing std::array of pointers directly in a TDirectory is not working at the moment (the element are not properly initialized to zero). To work around the problem use either an std::vector or wrap the std::array in a class/struct.

Cheers,
Philippe.

Thanks for your reply.

I tried to wrap the array in a class as such:

class Foo {
public:
  Foo() {}
  // Foo(TRootIOCtor*) {
  //   foo_[0] = nullptr;
  //   foo_[1] = nullptr;
  // }

  void Create() {
    foo_[0] = new TObject();
    foo_[1] = new TObject();
  }

  std::array<TObject*, 2> foo_;
  ClassDefNV(Foo, 1);
};

Foo foo;
foo.Create();
TFile f("foo.root", "RECREATE");
f.WriteObject(&foo, "foo_object");   // segfault here

This results in:

 *** Break *** segmentation violation



===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007efc379d507a in __GI___waitpid (pid=27238, stat_loc=stat_loc
entry=0x7ffc632ac280, options=options
entry=0) at ../sysdeps/unix/sysv/linux/waitpid.c:29
#1  0x00007efc3794dfbb in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:148
#2  0x00007efc38627a92 in TUnixSystem::StackTrace() () from /home/ahmad/biodynamo/build/third_party/root/lib/libCore.so
#3  0x00007efc3862a383 in TUnixSystem::DispatchSignals(ESignals) () from /home/ahmad/biodynamo/build/third_party/root/lib/libCore.so
#4  <signal handler called>
#5  0x0000000000000000 in ?? ()
#6  0x00007efc35de4e25 in TBufferFile::WriteFastArray(void*, TClass const*, int, TMemberStreamer*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#7  0x00007efc36072a1d in int TStreamerInfo::WriteBufferAux<char**>(TBuffer&, char** const&, TStreamerInfo::TCompInfo* const*, int, int, int, int, int) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#8  0x00007efc35ead483 in TStreamerInfoActions::GenericWriteAction(TBuffer&, void*, TStreamerInfoActions::TConfiguration const*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#9  0x00007efc35deb12e in TBufferFile::WriteClassBuffer(TClass const*, void*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#10 0x00007efc35e873a3 in TKey::TKey(void const*, TClass const*, char const*, int, TDirectory*) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#11 0x00007efc35e39491 in TFile::CreateKey(TDirectory*, void const*, TClass const*, char const*, int) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so
#12 0x00007efc35e2bac7 in TDirectoryFile::WriteObjectAny(void const*, TClass const*, char const*, char const*, int) () from /home/ahmad/biodynamo/build/third_party/root/lib/libRIO.so

I tried initializing the array elements to null in the TRootIOCtor but that has no effect.
Using std::vector is unfortunately not an option, since I’m trying to avoid heap allocations.

Best,
Ahmad

Edit: my colleague tried the above snippet out with the master branch, and got the same segfault.

There is indeed a fatal bug … The system currently does not recognize that this is an array of pointers :frowning: and treats it as an array object (obviously with disastrous result).

A workaround would be to use an std::array<DerivedClass, 2> (which would also reduce the number of heap allocation :slight_smile: ).

There is unfortunately a performance reason as to why we want to have an array of pointers, and not a vector of pointers or an array of objects.

My colleague and I found a workaround that is a bit more suitable for our use case. We implemented a custom streamer for the class (containing an array of pointers), in which we use a temporary vector object to place our pointers in and stream that in and out of the ROOT buffer. Since we don’t do IO in any of our software’s hotspots, we don’t mind if this costs us a bit extra IO-time.

I created a JIRA ticket for the bug: https://sft.its.cern.ch/jira/browse/ROOT-10581

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.