Free(): invalid pointer:

Dear Rooters,

I have the feeling that the question is more C++ related than ROOT itself, but with the classes I handle is hard to find an answer.

I am creating a simple event display in 3D. The idea behind is read three std::vector (x,y,z information) from a rootfile, then fill a std:vector of TGraph2D which is sent to a function to plot all the graphs. Here is more or less what I am saying (I am omitting most of the lines, definitions).


vector< TGraph2D* > vGraph;
(...)
for(int j=0; j<numHits; j++)
  {
    xrec[steps] = xHits->at(j);
    yrec[steps] = yHits->at(j);
    zrec[steps] = zHits->at(j);
    steps++;
  }
vGraph.push_back(new TGraph2D(numHits, xrec, yrec, zrec) );

graph2dfile(vGraph);

(...)

void graph2dfile(vector<TGraph2D*> &vGraph)
{
TH3F *frame3d = new TH3F("frame3d","mTPC - Hits/Event",10,-0.15, 0.15, 10, -0.15, 0.15, 10,-0.28,0.28);
  
frame3d->GetXaxis()->SetTitle("X (mm)"); frame3d->GetXaxis()->SetTitleOffset(1.4); frame3d->GetXaxis()->CenterTitle() ;
frame3d->GetYaxis()->SetTitle("Y (mm)"); frame3d->GetYaxis()->SetTitleOffset(1.4); frame3d->GetYaxis()->CenterTitle() ;
frame3d->GetZaxis()->SetTitle("Z (mm)"); frame3d->GetZaxis()->SetTitleOffset(1.4); frame3d->GetZaxis()->CenterTitle() ;
  
frame3d->Draw();

for(int kk = 0; kk < NoG; kk++)
	{
	  vGraph[kk] -> SetLineColor(color_wh[kk]);
	  vGraph[kk] -> SetLineWidth(4);
	  vGraph[kk] -> SetMarkerStyle(20);
	  vGraph[kk] -> SetMarkerSize(.9);
	  vGraph[kk] -> SetMarkerColor(color_wh[kk]);
	  vGraph[kk] -> Draw("PLINE same");
	}
  cGraph->Modified();
  cGraph->Update();

  return;

}


The program works smoothly when reads several events from the rootfile, BUT selecting one event, AND NOT always, just some events, I get the error (after the call of the function, in other words, after the return):

*** Error in /home/USER/Builds/root6/bin/root.exe’: free(): invalid pointer: 0x0000000006c921c8 ***`

It bugs me that it happens with just some events which don’t have anything special and with others works fine.

If I put the whole function continuously after reading the branches instead of making a function, the error is:

*** Break *** bus error

I am running the code as a script, not compiled.

Any hint will be appreciated


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.22/03
Platform: Linux CENTOS 7
Compiler: gcc (GCC) 4.9.2


What do you mean ? does that selection may occur during the Drawing process ?
The fact it is random may suggest that the TCanvas is in some intermediate state when you “select”

Hi @McCuack ,
indeed the best way to debug these crashes is to proceed like with any C++ program: compile it with debug symbols with g++ -g -o program program.cpp $(root-config --libs --cflags) and run it in the debugger (gdb ./program) to check where the error happens and to investigate why.

Running the program under valgrind (valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp ./program) also often helps in figuring out where the invalid memory access is happening and why.

If everything fails, if you provide a small, self-contained reproducer of the issue that we can compile and run, we can try to take a look ourselves.

Cheers,
Enrico

1 Like

Thank you, Oliver, Enrico,

since I was running the code as a macro, I modified it as suggested to a compiled version and it works perfectly, no warnings, nothing. And I tested with the events which were giving me those issues.

My only guess is that the interpreter was not handling well the std::vector from function to function.

I can prepare a tarball with the code, but I don’t think it is worth the effort. I can conclude that is better to compile the code.

Thanks again for your advice and time

-Carlos

Hi,
I would still suggest to run the code under valgrind because access to bad memory or double frees or use-after-deletes may or may not result in a crash depending on how unlucky you are.

ROOT’s C++ interpreter should have no issues with std::vectors.

Cheers,
Enrico

Thank you Enrico,

sure, the interpreter should not have issues with std::vectors, that was a shoot in the dark trying to find an explanation.
I ran valgrind, and not sure how to interpret the output

valgrind --suppressions=$ROOTSYS/etc/valgrind-root.supp ./EventDisplay 
==2004== Memcheck, a memory error detector
==2004== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2004== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2004== Command: ./EventDisplay
==2004== 
vex amd64->IR: unhandled instruction bytes: 0xF 0xAE 0x64 0x24 0x40 0x48 0x8B 0x73
vex amd64->IR:   REX=0 REX.W=0 REX.R=0 REX.X=0 REX.B=0
vex amd64->IR:   VEX=0 VEX.L=0 VEX.nVVVV=0x0 ESC=0F
vex amd64->IR:   PFX.66=0 PFX.F2=0 PFX.F3=0
==2004== valgrind: Unrecognised instruction at address 0x40169d8.
==2004==    at 0x40169D8: _dl_runtime_resolve_xsave (in /usr/lib64/ld-2.17.so)
==2004== Your program just tried to execute an instruction that Valgrind
==2004== did not recognise.  There are two possible reasons for this.
==2004== 1. Your program has a bug and erroneously jumped to a non-code
==2004==    location.  If you are running Memcheck and you just saw a
==2004==    warning about a bad jump, it's probably your program's fault.
==2004== 2. The instruction is legitimate but Valgrind doesn't handle it,
==2004==    i.e. it's Valgrind's fault.  If you think this is the case or
==2004==    you are not sure, please let us know and we'll try to fix it.
==2004== Either way, Valgrind will now raise a SIGILL signal which will
==2004== probably kill your program.
==2004== 
==2004== Process terminating with default action of signal 4 (SIGILL)
==2004==  Illegal opcode at address 0x40169D8
==2004==    at 0x40169D8: _dl_runtime_resolve_xsave (in /usr/lib64/ld-2.17.so)
==2004== valgrind: Unrecognised instruction at address 0x40169d8.
==2004==    at 0x40169D8: _dl_runtime_resolve_xsave (in /usr/lib64/ld-2.17.so)
==2004== Your program just tried to execute an instruction that Valgrind
==2004== did not recognise.  There are two possible reasons for this.
==2004== 1. Your program has a bug and erroneously jumped to a non-code
==2004==    location.  If you are running Memcheck and you just saw a
==2004==    warning about a bad jump, it's probably your program's fault.
==2004== 2. The instruction is legitimate but Valgrind doesn't handle it,
==2004==    i.e. it's Valgrind's fault.  If you think this is the case or
==2004==    you are not sure, please let us know and we'll try to fix it.
==2004== Either way, Valgrind will now raise a SIGILL signal which will
==2004== probably kill your program.
==2004== 
==2004== Process terminating with default action of signal 4 (SIGILL)
==2004==  Illegal opcode at address 0x40169D8
==2004==    at 0x40169D8: _dl_runtime_resolve_xsave (in /usr/lib64/ld-2.17.so)
==2004== 
==2004== HEAP SUMMARY:
==2004==     in use at exit: 0 bytes in 0 blocks
==2004==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2004== 
==2004== All heap blocks were freed -- no leaks are possible
==2004== 
==2004== For counts of detected and suppressed errors, rerun with: -v
==2004== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
Illegal instruction (core dumped)

it indicates 0 errors but ends with a core dump… valgrind is out of my league…

-Carlos

That does not look great, but if I understand correctly you are running the program on a amd64 architecture, it could be that valgrind has some issues with it.

I would be glad to double-check if you can share a minimal reproducer.

Cheers,
Enrico

Thank you Enrico and sorry for the delay to answer. Somehow, the code below will read the data from the root file, and, in the original issue, send the read data to a graph in a function.

I include a small rootfile unit-test.root (120.4 KB). Here, instead of graph the data, I just wanted to show it in the terminal. I run this as a macro, the error is the same, so I guess it is happening within these lines here.

Enrico, you mentioned the error in Valgrind (which was the compiled version), but somehow it runs. Normally, this kind of macro didn’t give me so much trouble in Root5, is it possible to the interpreter change?

Thank you for your feedback

#include <iostream>
#include "string.h"
#include "TFile.h"
#include "TStyle.h"
#include "TTree.h"
#include "math.h"
#include <thread>
#include "TSystem.h"
#include <vector>

TTree *mTPCTree;

typedef struct{
  double  count;
  double  rate;
  double  solang;
  double  sigma;
  double  W2;
  double  xbj;
  double  Q2;
  double  th;
  double  ph;
  double  KE;
  double  sigmaELA;
  double  sigmaQE;
  double  sigmaSIDIS; 
  double  sigmaDIS;
  double  sigmaTDIS;
  double  Aperp;
  double  Apar;
  double  Pt;
  double  Pl;
  double  vx;
  double  vy;
  double  vz;
  double  ep;
  double  np;
  double  p1p;
  double  p2p;
  double  pip;
  double  epx;
  double  epy;
  double  epz;
  double  npx;
  double  npy;
  double  npz;
  double  p1px;
  double  p1py;
  double  p1pz;
  double  p2px;
  double  p2py;
  double  p2pz;
  double  pipx;
  double  pipy;
  double  pipz;
  double  nth;
  double  nph;
  double  p1th;
  double  p1ph;
  double  p2th;
  double  p2ph;
  double  pith;
  double  piph;
  double  pmperp;
  double  pmpar;
  double  pmparsm;
  double  z;
  double  phperp;
  double  phih;
  double  MX;
  double  Sx;
  double  Sy;
  double  Sz;
  double  xpi;
  double  tpi;
  double  xa;
  double  pt;
  double  nu;
  double  ya;
  double  y;
  double  f2p;
  double  f2pi;
  double  ypi;
  int  nucl;
  int  fnucl;
  int  hadr;
  int  earmaccept;
  int  harmaccept; 
} evType;

using namespace std;

void rootreader()
{
  TString fileName = TString::Format("/home/ayerbe/Analysis/TDIS/g4sbs-build/unit-test.root");
  //  TString fileName = TString::Format("../rootfiles/swif_QE_1M_20210830.root");
  TFile *file = new TFile(fileName,"READ"); 

  mTPCTree = (TTree*)file->Get("T"); 
  
  evType ev;
  mTPCTree -> SetBranchAddress("ev", &ev.count);

  // Declaration of leaf type
  std::vector<Double_t> *xHits = 0;
  std::vector<Double_t> *yHits = 0;
  std::vector<Double_t> *zHits = 0;
  std::vector<Double_t> *pid = 0;
  std::vector<Double_t> *mid = 0;
  
  TBranch *b_xHits;
  TBranch *b_yHits;
  TBranch *b_zHits;  
  TBranch *b_pid;  
  TBranch *b_mid;

  mTPCTree -> SetBranchAddress("SBS.mTPC.hit.xhitg", &xHits, &b_xHits);
  mTPCTree -> SetBranchAddress("SBS.mTPC.hit.yhitg", &yHits, &b_yHits);
  mTPCTree -> SetBranchAddress("SBS.mTPC.hit.zhitg", &zHits, &b_zHits);

  mTPCTree -> SetBranchAddress("SBS.mTPC.hit.pid", &pid, &b_pid);
  mTPCTree -> SetBranchAddress("SBS.mTPC.hit.mid", &mid, &b_mid);

  Int_t Entries = mTPCTree->GetEntries();
  cout<<"Entries: "<<Entries<<endl;
  
  for (Int_t i = 0; i < Entries; i++)
    {
      cout<<"\nEntry: "<< i<< endl;
      
      mTPCTree->GetEntry(i);

      Int_t numHits = xHits->size();
      cout<< " numHits: "<<numHits<<endl;

      cout<<"proton momentum: "<< ev.np<<endl;
      
      for(int j=0; j<numHits; j++)
	{
	  cout<<"PID: "<< pid->at(j)<<endl;
	  //		if( pid->at(j) == 2212)
	  //			if(( pid->at(j) == 0 || pid->at(j) == 2212))// && mid->at(j) == 0)
	  {
	    cout<<"Hit: "<<j<<" x: " << xHits->at(j) <<" y: " << yHits->at(j)<<" z: " << zHits->at(j)<<endl;
	  }
	  
	}
      
    }
  
}









typedef struct {
   Double_t        count;
   Double_t        rate;
   Double_t        solang;
   Double_t        sigma;
   Double_t        W2;
   Double_t        xbj;
   Double_t        Q2;
   Double_t        th;
   Double_t        ph;
   Double_t        KE;
   Double_t        sigmaELA;
   Double_t        sigmaQE;
   Double_t        sigmaSIDIS;
   Double_t        sigmaDIS;
   Double_t        sigmaTDIS;
   Double_t        Aperp;
   Double_t        Apar;
   Double_t        Pt;
   Double_t        Pl;
   Double_t        vx;
   Double_t        vy;
   Double_t        vz;
   Double_t        ep;
   Double_t        np;
   Double_t        p1p;
   Double_t        p2p;
   Double_t        pip;
   Double_t        epx;
   Double_t        epy;
   Double_t        epz;
   Double_t        npx;
   Double_t        npy;
   Double_t        npz;
   Double_t        p1px;
   Double_t        p1py;
   Double_t        p1pz;
   Double_t        p2px;
   Double_t        p2py;
   Double_t        p2pz;
   Double_t        pipx;
   Double_t        pipy;
   Double_t        pipz;
   Double_t        nth;
   Double_t        nph;
   Double_t        p1th;
   Double_t        p1ph;
   Double_t        p2th;
   Double_t        p2ph;
   Double_t        pith;
   Double_t        piph;
   Double_t        pmperp;
   Double_t        pmpar;
   Double_t        pmparsm;
   Double_t        z;
   Double_t        phperp;
   Double_t        phih;
   Double_t        phiS;
   Double_t        thetaS;
   Double_t        MX2;
   Double_t        Sx;
   Double_t        Sy;
   Double_t        Sz;
   Double_t        xpi;
   Double_t        tpi;
   Double_t        xa;
   Double_t        pt;
   Double_t        nu;
   Double_t        ya;
   Double_t        y;
   Double_t        f2p;
   Double_t        f2pi;
   Double_t        ypi;
   Double_t        s;
   Double_t        t;
   Double_t        u;
   Double_t        costhetaCM;
   Double_t        Egamma;
   Int_t           nucl;
   Int_t           fnucl;
   Int_t           hadr;
   Int_t           earmaccept;
   Int_t           harmaccept;
} evType;

BTW. In the end of your “rootreader”, add:
delete file; // automatically deletes "mTPCTree", too
or at least:
mTPCTree->ResetBranchAddresses(); // disconnect from local variables

Hi,
the crash is due to the following lines:

evType ev;
mTPCTree -> SetBranchAddress("ev", &ev.count);

You are reading all of "ev" into ev.count, which causes an out-of-bound write that overwrites some of the data in the fileName object, and that ultimately causes its destructor to crash. We are lucky that this chain of events ultimately caused a crash, it could have just as likely have silently read bogus data.

I guess what you want is:

  evType ev;
  mTPCTree -> SetBranchAddress("ev.count", &ev.count);

but then you should not trust the contents of ev.np as you are not telling TTree to read anything into it.

Higher-level reading interfaces such as TTreeReader or RDataFrame avoid these kind of problems altogether as they are type-safe: you can’t read a branch of a type into a variable of a different type using those interfaces. There are less checks when using TTree directly, it’s a more “expert-friendly” interface.

Wile E’s suggestion to delete file is also useful to avoid a memory leak (but that will cause unnecessary memory usage, not crashes).

Cheers,
Enrico

Thanks Enrico,

I tried your advice, but then I get the error:

Error in <TTree::SetBranchAddress>: unknown branch -> ev.count

which, from my understanding, I get it because ev is a struct where count is the first variable. Also, from my experience, I should set the branch ‘ev’ and give the address of the first variable. Certainly, YOUR explanation makes more sense to me (a branch address per leaf), but… you see the error.

I added Wile E’s suggestion, but without suscess. What I found (I am sorry, I discovered and not sure why) is that I was using the size of the vector as a number of elements (personally, I think it was correct), but if I use the number of hits (a variable I didn’t know I have, the rootfile was not created by me), I don’t have the error anymore.

Once again, the compiled version works fine, and I don’t know why the difference of it running as a macro or compiled with gcc.

Thank you again for all your advices.

Attach the “final” version of your macro.

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