Read Valgrind log

Sorry, how? :see_no_evil: (Intpoint is a class, I have header and .cxx)
Thanks a lot

How did you produce Intpoint_cpp.so (i.e. a compiled version of your Intpoint.cpp file)? I don’t think root.exe -l -q ricostruzione1.cpp+g produces that file (or does it?).


We used this macro to compile all classes and macros at the same time. It produces all .so-.Aclic-.d

Uhm, the g in "kg" means that Intpoint.cpp should be compiled with debug symbols, but that does not seem to be the case, or at least valgrind can’t figure out at what line in Intpoint.cpp the problematic code resides.

You can try to re-generate the library it manually with g++ -g -fPIC -shared -o Intpoint_cpp.so Intpoint.cpp $(root-config --libs --cflags).

Hi. I’m trying using gdb (the error occurs only once in almost 30 runs on my laptop and re-generating the library gave no useful clue so I think I must try with the debugger until I come across a lucky run).
Should I use

gdb root.exe
(gdb) run ricostruzione1.cpp+g
(gdb) bt

to obtain a valuable error log? Are there better commands?
Thanks a lot

Hi, you can use gdb --args root.exe ricostruzione1.cpp+g, then inside gdb run and bt at the point of crash.

There is also a trick to run the program in a loop until you get a crash:

(gdb) run # run the program once
[Inferior 1 (process 227900) exited normally]
(gdb) break exit
Breakpoint 1 at 0x7fff6db29140 (3 locations)
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>run
>end
(gdb) run # now the program runs in a loop

This puts a breakpoint when the exit system call is called (i.e. at the end of a well-behaved execution) and then tells gdb to execute run every time that breakpoint is hit – in practice restarting the program whenever it completes successfully.

Feel free to share code and data so we can take a look directly in case this does not help either (but having some familiarity with a debugger is always useful in any case :slight_smile: )

Cheers,
Enrico

The valgrind log mentions the function UpdateIsOnHeap which had some issues that were fixed via [core/base] Clang-tidy Clazy Warnings · Issue #7412 · root-project/root · GitHub

Can you retry with the latest ROOT version?

Also, consider using this for better understanding/parsing the valgrind logs:

See also Debugging a ROOT macro

Hi. Thanks a lot. We will install the latest ROOT version and try again both valgrind and gdb and we will consult these links. If we can’t solve our problem we will cut our macro so that you must not try to read hundreds of lines of code :smiling_face:

2 Likes

Hi. Sorry for the late reply. We found the incriminated line ( but we can’t understand why).
We open a file and “link” it to hfilerec, then we do something ,finally we save a tree to the file, with hfilerec->ls we can see that the tree is in the file but the last line, hfilerec->Close(), causes the “corrupted size vs. prev_size” error on one of the laptops

image
Why? :sob: Thanks a lot

Hi @EVTO ,

hard to say without a reproducer. My educated guess is that hfilerec->Close() tries to delete some object that has already been deleted, or something similar. TFiles often own the objects contained it them (so it thinks that when it gets closed, those objects can go away), but sometimes these objects are also deleted by other code!

Cheers,
Enrico

Hi. We wrote a minimal reproducer. if you could take a look…

//root includes
#include "TH1D.h"
#include "TVirtualFFT.h"
#include "TF1.h"
#include "TMath.h"
#include "TCanvas.h"
#include <iostream>
#include "TString.h"
#include "TFile.h"
#include "TTree.h"
#include "TSystem.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TRandom3.h"
#include "TClonesArray.h"
#include "TGraph2D.h"
#include  <vector>
#include <fstream>
#include <TDirectory.h>

//headers include
#include "Vertex.h"
#include "Intpoint.h"

using namespace std;

const int limit1=17;
const int limit2=21;

void ricprova(){  
  
 //file and trees
  TFile *hfile = TFile::Open("simulazione.root", "READ");
  if(hfile==NULL){
    cout<<"Errore, non esiste il file"<<endl; 
    return;
  }	
  hfile->ls();
  TTree *treelec = (TTree*)hfile->Get("tree");
  if(treelec==NULL){ 
    cout<<"Errore, non esiste il tree"<<endl; 
    return;
  }
   
  TFile *hfilerec = TFile::Open("ricostruzione.root","RECREATE"); 
  TTree *treerec = new TTree("treerec", "ricostruzione");
  //histo
  TH1D *zintisto = new TH1D("zrec","z",12,-6,6);
  //branches
  TClonesArray *intprec1 = new TClonesArray("Intpoint", 100);
  TClonesArray *intprec2 = new TClonesArray("Intpoint", 100);
  TClonesArray &int1 = *intprec1;  
  TClonesArray &int2 = *intprec2;
 
  Vertex *verrec = NULL;
  int acceptedrec;	
  
  treerec->Branch("Vertexreal",&verrec);
    treerec->Branch("int1+noise",&intprec1);
  treerec->Branch("int2+noise",&intprec2);
  treerec->Branch("accept",&acceptedrec);
  
  //read treelec
  TClonesArray *clone1= new TClonesArray("Intpoint",100);
  TClonesArray *clone2= new TClonesArray("Intpoint",100);
  for (int i=1;i<10;i++) { 
    new (&clone1[i]) Intpoint (0,0,0); 
    new (&clone2[i]) Intpoint (0,0,0);
  } 
   
  int accepted;
  Vertex *verlec = new Vertex(); 
   
  TBranch *b3=treelec->GetBranch("accept");
  b3->SetAddress(&accepted);
  TBranch *b4=treelec->GetBranch("Vertext");
  b4->SetAddress(&verlec);
 
  //loop on events
  for(int ev=0;ev<treelec->GetEntries();ev++){
     zintisto->Reset("ICES");
    verlec->Clearvec();
    delete verrec;	  
   
    treelec->GetEntry(ev);
      
    verrec = new Vertex(*verlec);
    acceptedrec=accepted;
     for (int i=0; i<30;i++) zintisto->Fill((gRandom->Rndm()*12)-6);	  
    new TCanvas; 
    zintisto->DrawCopy(); 
      treerec->Fill();
     	
  
  }

  hfilerec-> cd(); 
  treerec->Write(); 
  hfilerec->Close();
}

If you need to run it, here are classes and file
Vertex.cpp (1.2 KB)
Vertex.h (464 Bytes)
Intpoint.h (306 Bytes)
Intpoint.cpp (870 Bytes)
simulazione.root (18.8 KB)
Thanks a lot

I do not know whether this is the problem but instead of:

  for (int i=1;i<10;i++) { 
    new (&clone1[i]) Intpoint (0,0,0); 

try

  for (int i=0;i<10;i++) { 
    new (&clone1[i]) Intpoint (0,0,0); 

I also see:

  for(int ev=0;ev<treelec->GetEntries();ev++) {
...
    new TCanvas; 
    zintisto->DrawCopy(); 
...
  }

Do you really mean to create a new TCanvas per entry and a new histogram for every single entry of the input TTree? If you have a lot of entries in the input TTree you might be running out of memory and/our computing resources.

Hi. Still crashes with for (int i=0;i<10;i++) (and we use this for cycle only to address a branch to a TClone to read the tree (if we use a void TClone, we get a valgrind warning about linking a branch to something with 0 dimension), it’s a quite useless cycle).
We need a TCanvas for every event (int ev), but we only have 20 tree entries so 1 histogram, 20 canvasses: I hope a laptop could handle that

Hi @EVTO ,

I can reproduce a crash at teardown, and I think it’s just a consequence of out of bound writes during I/O.

Here’s what valgrind has to say:

==422755== Invalid write of size 8
==422755==    at 0x4B187A5: TObject::TObject() (TObject.h:241)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b500 is 0 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 4
==422755==    at 0x4B187AC: TObject::TObject() (TObject.h:241)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b50c is 12 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid read of size 4
==422755==    at 0x4B186DE: TStorage::FilledByObjectAlloc(unsigned int const volatile*) (TStorage.h:119)
==422755==    by 0x4B18705: TStorage::UpdateIsOnHeap(unsigned int const volatile&, unsigned int volatile&) (TStorage.h:132)
==422755==    by 0x4B187CD: TObject::TObject() (TObject.h:245)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b508 is 8 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid read of size 4
==422755==    at 0x4B18723: TStorage::UpdateIsOnHeap(unsigned int const volatile&, unsigned int volatile&) (TStorage.h:135)
==422755==    by 0x4B187CD: TObject::TObject() (TObject.h:245)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b50c is 12 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 4
==422755==    at 0x4B18730: TStorage::UpdateIsOnHeap(unsigned int const volatile&, unsigned int volatile&) (TStorage.h:135)
==422755==    by 0x4B187CD: TObject::TObject() (TObject.h:245)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b50c is 12 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 4
==422755==    at 0x4B187D2: TObject::TObject() (TObject.h:247)
==422755==    by 0x70A5704: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b508 is 8 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 8
==422755==    at 0x70A5714: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:19)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b500 is 0 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 8
==422755==    at 0x70A5720: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:20)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b510 is 16 bytes after a block of size 80 alloc'd
==422755==    at 0x4846003: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==422755==    by 0x4B88CC7: TStorage::ObjectAlloc(unsigned long) (TStorage.cxx:330)
==422755==    by 0x10AC02: TObject::operator new(unsigned long) (TObject.h:167)
==422755==    by 0x10A5D4: ricprova() (ricprova.C:64)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==
==422755== Invalid write of size 8
==422755==    at 0x70A572E: Intpoint::Intpoint(double, double, double) (Intpoint.cpp:21)
==422755==    by 0x10A693: ricprova() (ricprova.C:67)
==422755==    by 0x10AB49: main (ricprova.C:103)
==422755==  Address 0x1a65b518 is 24 bytes after a block of size 80 in arena "client"
==422755==

@pcanal it looks like I/O of these classes is broken. @EVTO did you modify these classes since you wrote them to simulazione.root?

Hi @eguiraud. We didn’t modify classes, we only have one class version and we always recreate file simulazione.root before using this macro (we have two macros, one for creating the file, one for reading the tree, and we always compile and run both together to avoid inconsistencies)

Alright, can you please share the macro you use to produce simulazione.root too? :slight_smile:

The statement:

    new (&clone1[i]) Intpoint (0,0,0);

is likely meant to be:

    new ((*clone1)[i]) Intpoint (0,0,0);

i.e. the value passed to the placement part of operator new is supposed to be the return value (a TObject*) of TClonesArray::operator[] (while the original code is passing the value of the pointer arithmetic clones1 + i)

#include "TH3D.h"
#include "TVirtualFFT.h"
#include "TF1.h"
#include "TCanvas.h"
#include "TMath.h"
#include <iostream>
#include "TString.h"
#include "TFile.h"
#include "TTree.h"
#include "TSystem.h"
#include "TTreeReader.h"
#include "TTreeReaderValue.h"
#include "TRandom3.h"
#include "TClonesArray.h"
#include "TGraph2D.h"
#include  <vector>
#include <stdio.h>
#include <stdlib.h>

//headers includes

#include "Intpoint.h"
#include "Vertex.h"

using namespace std;


const double Rbp=3.08;//cm
const double R1=4.02;
const double R2=7.02;
const double L=27;

const double sigmax=0.01;
const double sigmay=0.01;
const double sigmaz=5.3;

const int kMaxim=20;
const double etamin=-2.;
const double etamax=+2.;
const TString mul="sì"; 



void simulazione(){
 
  	
  unsigned int seed=18;
  gRandom->SetSeed(seed);

 
  TString filename="kinem.root";
  TString muldis="hmul";
  TString etadis="heta";
  char a;
 
  int accepted;
  int discarded;

  

  Vertex *vertice = NULL;

  TFile  *hfile = TFile::Open("simulazione.root","RECREATE");
  TTree *tree = new TTree("tree", "eventi");
  tree->Branch("Vertext",&vertice);//PV

  tree->Branch("accept",&accepted); 
TClonesArray *bp = new TClonesArray("Intpoint",100);  
 TClonesArray &intbp = *bp;
   tree->Branch("tclonebp",&bp);
  
  tree->SetDirectory(hfile);
 
  //loop sul numero di vertici
  for(int i=0; i<kMaxim;i++){
   	vertice=new Vertex();    
      discarded=0;
      accepted=vertice->Getm()+7; 
     for (int j=0; j<accepted; j++){ new (intbp[j]) Intpoint (0,0,0) ;}
      
    if (accepted>0) tree->Fill(); else i--; 
  
    delete vertice;
  }
  hfile->cd(); 
  tree->Write();
   hfile->Close();
  }

This is a “toy” (cut) version with the branches used by ricprova(). If you need all the complete macros and classes, I’ll ask permission and share all the files (10 files, almost 10^3 lines of code, so maybe GitHub)

This solves the problem,we go hide forever :see_no_evil: :see_no_evil: :see_no_evil:
Thanks a lot