Infinite Loop in TH1::FitPanel

I am running into an infinite loop when starting the FitEditor. It seems to be connected to the existence of a custom subclass of TF1, but I can’t see anything out of the ordinary with the subclass. A minimum example that reproduces the issue is as follows, using root6.06/02.

In GGaus.hh, I define a subclass of TF1. This is a stripped down example, as my main code has more features to it.

#ifndef GGAUS_H
#define GGAUS_H

#include "TF1.h"

class GGaus : public TF1 {
public:
  GGaus() : TF1("gausbg","gaus(0)+pol1(3)") { }

  GGaus(double xlow, double xhigh)
    : TF1(Form("gausbg_%d_to_%d", (int)xlow, (int)xhigh),
          "gaus(0) + pol1(3)", xlow, xhigh) {
  }

private:
  ClassDef(GGaus,1)
};


#endif

In my LinkDef.h,

#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class GGaus+;

#endif

To compile this, I run the following commands.

rootcling -f Dictionary.cc -c -I. GGaus.hh LinkDef.h
g++ `shell root-config --cflags` -I. -fPIC -shared -o libAnalysis.so Dictionary.cc

I have a test script that I can run as follows.

username@hostname ~/temp $ cat test.C
void test(){
  // Generate a reasonable histogram for the fit function.
  TH1* hist = new TH1F("hist","hist",200,0,200);
  for(int i=0; i<2e4; i++) {
    hist->Fill(gRandom->Uniform(0,200));
    hist->Fill(gRandom->Gaus(70, 15));
  }
  hist->Draw();

  // Construct my custom class, set default parameters.
  GGaus* gaus = new GGaus(0,200);
  gaus->SetParameters(100,70,15,15,0);

  // Fit the histogram
  hist->Fit(gaus);

  // Open the fit panel
  std::cout << "before" << std::endl;
  hist->FitPanel();
  std::cout << "after" << std::endl;
}
username@hostname ~/temp $ root -n
root [0] gSystem->Load("libHist.so");
root [1] gSystem->Load("libAnalysis.so");
root [2] .x test.C
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
 FCN=199.125 FROM MIGRAD    STATUS=CONVERGED     184 CALLS         185 TOTAL
                     EDM=4.84367e-10    STRATEGY= 1  ERROR MATRIX UNCERTAINTY   1.8 per cent
  EXT PARAMETER                                   STEP         FIRST
  NO.   NAME      VALUE            ERROR          SIZE      DERIVATIVE
   1  p0           5.31126e+02   5.42544e+00  -6.92829e-03   1.60535e-06
   2  p1           6.96843e+01   1.45362e-01   1.80876e-04  -1.31359e-04
   3  p2           1.51326e+01   1.42370e-01   3.77597e-04  -4.82442e-05
   4  p3           9.75654e+01   1.97032e+00   2.43662e-03   3.41978e-05
   5  p4           7.06457e-03   1.41665e-02   1.72091e-06   3.59065e-03
before

I expect to see both print messages occur. Instead, I see only the print message from before the call to TH1::FitPanel. The program hangs, and must be stopped with Ctrl-C. During this time, CPU usage is at 100%, and I see a steady increase in memory usage.

I realized that there were a number of steps needed to reproduce the error, and so I have attached a tarball here to quickly reproduce the error. Running “make test” will compile the shared library and run the commands necessary to start the infinite loop. I have tested this under versions 5.34/32, 5.34/36, 6.04/02, and 6.06/02, and I observe the same issue in each version.
fitpanel_infinite_loop.tar.gz (21.4 KB)

Hi,

I cannot reproduce the problem with the master version of ROOT. Either by hand:

[bellenot@bbcc7x64 fitpanel_infinite_loop]$ root -l root [0] gSystem->Load("libGui"); root [1] gSystem->Load("libAnalysis"); root [2] .x test.C Info in <TCanvas::MakeDefCanvas>: created default TCanvas with name c1 FCN=199.125 FROM MIGRAD STATUS=CONVERGED 184 CALLS 185 TOTAL EDM=4.84367e-10 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 1.8 per cent EXT PARAMETER STEP FIRST NO. NAME VALUE ERROR SIZE DERIVATIVE 1 p0 5.31126e+02 5.42544e+00 -6.92829e-03 1.60535e-06 2 p1 6.96843e+01 1.45362e-01 1.80876e-04 -1.31359e-04 3 p2 1.51326e+01 1.42370e-01 3.77597e-04 -4.82442e-05 4 p3 9.75654e+01 1.97032e+00 2.43662e-03 3.41978e-05 5 p4 7.06457e-03 1.41665e-02 1.72091e-06 3.59065e-03 before after root [3]
or with “make test”:

[bellenot@bbcc7x64 fitpanel_infinite_loop]$ make test printf "gSystem->Load(\"libHist.so\");\ngSystem->Load(\"libAnalysis.so\");\n.x test.C\n" | root -l -n Info in <TCanvas::MakeDefCanvas>: created default TCanvas with name c1 FCN=199.125 FROM MIGRAD STATUS=CONVERGED 184 CALLS 185 TOTAL EDM=4.84367e-10 STRATEGY= 1 ERROR MATRIX UNCERTAINTY 1.8 per cent EXT PARAMETER STEP FIRST NO. NAME VALUE ERROR SIZE DERIVATIVE 1 p0 5.31126e+02 5.42544e+00 -6.92829e-03 1.60535e-06 2 p1 6.96843e+01 1.45362e-01 1.80876e-04 -1.31359e-04 3 p2 1.51326e+01 1.42370e-01 3.77597e-04 -4.82442e-05 4 p3 9.75654e+01 1.97032e+00 2.43662e-03 3.41978e-05 5 p4 7.06457e-03 1.41665e-02 1.72091e-06 3.59065e-03 before after [bellenot@bbcc7x64 fitpanel_infinite_loop]$
On which platform (and with which compiler) do you see this issue?

P.S. It works also with ROOT v5-34-00-patches on Windows…

Cheers, Bertrand.

Thank you for looking into it. I have tested this on both Debian 7 (wheezy) 64-bit, and Debian 8 (jessie) 64-bit. I don’t have a Windows machine with ROOT available, so I can’t test it there. The Debian 7 machine is using g++ v4.7.2, and the Debian 8 machine is using g++ v4.9.2.

username@hostname ~ $ uname -a
Linux hostname 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u6 x86_64 GNU/Linux
username@hostname ~ $ g++ --version
g++ (Debian 4.7.2-5) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
username@hostname ~ $ uname -a
Linux hostname 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u6 (2015-11-09) x86_64 GNU/Linux
username@hostname ~ $ g++ --version
g++ (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Unfortunately, I don’t seem to be able to compile the latest version of root from the master branch of the repository, because it requires a newer version of cmake than I have installed. I am currently compiling the latest release version, 6.06/06, as that is closer to your version than any of the ones that I previously tested.

The compilation finished, and I am still seeing the same infinite loop with root6.06/06. The was again done on Debian 8, under g++ 4.9.2.

OK, I’ll try with 6.06/06

Hi,

OK, I see the problem with 6.06.06… It looks the infinite loop is in TFormula::ExtractFunctors. We will investigate.
The good news is that the master version of ROOT seems to be working just fine…

Cheers, Bertrand.

Thank you, and I look forward to hearing what the difference between 6.06/06 and master is.

I did take a short dive at it through gdb, and figured out some of the reasons, but don’t know how to fix it at the moment.

  • The default constructor for TF1 will not add itself to gROOT->GetListOfFunctions().
  • The non-default constructors for TF1 will add itself to gROOT->GetListOfFunctions().
  • GGaus’s default constructor calls a non-default constructor of TF1.
  • TFitEditor’s constructor loops over gROOT->GetListOfFunctions(), calling “fit->IsA()->New()” on each element, which calls the default constructor for that class.

As a result, while TFitEditor is looping over gROOT->GetListOfFunctions(), it is continuously growing, and so the loop never ends.

Hi,

We are about to release v6.08, could you confirm that this problem is fixed in the master (and thus in v6.08)?

Thanks,
Philippe.