Program crash when using RooRealVar as a structure component

I am very confused as to why the following code block is failing. Can somebody give me a hint as to why? I am running root 5.18 with RooFit version 2.31 which was bundled with it.

#include <RooRealVar.h>
#include <iostream>

using namespace std;
using namespace RooFit;

typedef struct {
  RooRealVar test;
} TestType;

void testFunction(TestType tmp);

int main(int argc, char *argv[]) {

  TestType tmp;

  testFunction(tmp);

  return(0);
}

void testFunction(TestType tmp) {
  cout << "The value of the variable was: " << tmp.test.getVal() << endl;
}

The following is the stack trace from gdb…

[code]
GNU gdb 6.8
Copyright © 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”…
(gdb) run
Starting program: /home/prophecy/Desktop/TMPWORK/BackgroundConsistency/test
[Thread debugging using libthread_db enabled]
[New Thread 0xb5a1d8e0 (LWP 5714)]

RooFit v2.31 – Developed by Wouter Verkerke and David Kirkby
Copyright © 2000-2008 NIKHEF, University of California & Stanford University
All rights reserved, please read http://roofit.sourceforge.net/license.txt

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb5a1d8e0 (LWP 5714)]
0xb5d8debc in RooRealVar::RooRealVar () from /usr/lib/root/libRooFitCore.so.5.18
(gdb) bt
#0 0xb5d8debc in RooRealVar::RooRealVar () from /usr/lib/root/libRooFitCore.so.5.18
#1 0x08048d52 in TestType (this=0xbffc417c) at test.cc:9
#2 0x08048d9c in main () at test.cc:17
[/code][/code]

I realize that I could probably get away with constructing my structs out of pointers, but I don’t really want to deal with the memory management. I guess I could try to use smart pointers, but this is starting to get too complicated. It seems to me that the above code should work just fine.

I just upgraded to the latest stable version of root and can verify that the problem is persisting.

  *******************************************
  *                                         *
  *        W E L C O M E  to  R O O T       *
  *                                         *
  *   Version   5.20/00      24 June 2008   *
  *                                         *
  *  You are welcome to visit our Web site  *
  *          http://root.cern.ch            *
  *                                         *
  *******************************************

ROOT 5.20/00 (trunk@24524, Sep 07 2008, 16:49:00 on linux)

CINT/ROOT C/C++ Interpreter version 5.16.29, Jan 08, 2008
Type ? for help. Commands must be C++ statements.
Enclose multiple statements between { }.

I have determined that the code that I pasted is not the minimal code example. The following also crashs and is much simpler:

#include <RooRealVar.h>

using namespace RooFit;

int main(int argc, char *argv[]) {

  RooRealVar test;
  test.setRange(0, 400);
  test = 0;

  return(0);
}

If I initialize the RooRealVar with something like

  RooRealVar test("blah", "blah", 0, 400, "blah");

then the problem goes away. This looks to be a bug I think. Is this correct?

Justace

Ok, sorry to be posting so much here in my own thread, but I find that it is relevant information.

In looking at the root 5.20 source tree I find the following default constructor for RooRealVar:

//_____________________________________________________________________________
RooRealVar::RooRealVar()  :  _error(0), _asymErrLo(0), _asymErrHi(0), _binning(0), _sharedProp(0)
{
  // Default constructor
}

In this constructor the RooAbsRealLValue is not explicitly instantiated like in the other constructors? Is this a problem. I would have thought that C++ would have implicitly ran the constructor for the inherited class. The code does not segfault at this point yet. It really goes crazy when you try to set something equal to it. So, when you set something equal to it the operator= is called and if it is just a value it still calls the RooAbsRealLValue::operator= method. Ohh, I think that I might have found the problem…

When the operator= method is called it uses the setVal method which checks to see if it is in a valid range. A chain of method calls eventually calls RooRealVar::getBinning() with no name, since there was not one anyway. Ok, so the getBinning method just bindly returns *_binning at this point which has not been initialized with a default value since the default constructor was used. The setVal() method then tries to dereference this which results in the segfault that I am seeing.

Another stange thing that I see is that the operator= method is not overloaded in the RooRealVar class. If this is the case then is the error not propagated in the copy? It seems from the code that the value of the variable is passed across but not the error. Is this true?

The following is the RooAbsRealLValue::operator= method that is used in the copy which I took from root/roofit/roofitcore/src/RooAbsRealLValue.cxx line 172.

//_____________________________________________________________________________
RooAbsArg& RooAbsRealLValue::operator=(const RooAbsReal& arg)
{
  // Assignment operator from other RooAbsReal
  return operator=(arg.getVal()) ;
}

It should be noted that when I try to add an explicit RooRealVar::setRange call so that something is there then it still segfaults due to a check on RooAbsRealLValue::getMin from somewhere inside the RooRealVar::getBinning method. Since this call is not explicitly in there I figure that it is coming from the return of the *binning somehow. The following is the gdb backtrace for the case where I create a RooRealVar using the default constructor and then try to explicitly call the setRange method.

GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) run
Starting program: /home/prophecy/Desktop/TMPWORK/BackgroundConsistency/test 
[Thread debugging using libthread_db enabled]
[New Thread 0xb56e56d0 (LWP 21111)]

RooFit v2.50 -- Developed by Wouter Verkerke and David Kirkby 
                Copyright (C) 2000-2008 NIKHEF, University of California & Stanford University
                All rights reserved, please read http://roofit.sourceforge.net/license.txt


Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb56e56d0 (LWP 21111)]
0xb5924ccb in RooAbsRealLValue::getMin () from /usr/lib/root/libRooFitCore.so.5.20
(gdb) bt
#0  0xb5924ccb in RooAbsRealLValue::getMin () from /usr/lib/root/libRooFitCore.so.5.20
#1  0xb5a1f267 in RooRealVar::getBinning () from /usr/lib/root/libRooFitCore.so.5.20
#2  0xb5a22a7b in RooRealVar::setRange () from /usr/lib/root/libRooFitCore.so.5.20
#3  0x08048d59 in main () at test.cc:12

Justace

Is there really no information on this?

Did I just miss-post this? If it is can a moderator shift it to the right forum please?

Justace

Hi Justace,

You should always use the full constructor to make a RooRealVar.

The default constructor does not make a functional object by itself, it exists to support ROOT persistence of RooRealVar objects (when you read such an object from file,
first the default ctor is called, then ROOT I/O fills all the data members with the information from the file).

Wouter