I need to merge the data from some [.root] files and [.txt] files into one [.root] file.
So I set the parameters of the output file as global variable.
It works well when there are only [.txt] files as follows:
// #include
TString rootfilename;
TFile* file_raw;
TTree* tree_raw;
Int_t ev_num;
TDatime* datime;
Double_t (*waves)[1024];
void read_a_txt(TString filefullpath)
{/*code*/}
void read_a_root(TString filefullpath)
{/* same structure as read_a_txt()*/}
void test()
{
rootfilename = "test.root";
datime = new TDatime;
waves = new Double_t[8][1024]{};
file_raw = new TFile(rootfilename, "recreate");
tree_raw = new TTree("raw", "raw data of the experiment");
tree_raw->SetDirectory(file_raw);
tree_raw->Branch("ev", &ev_num, "ev/I");
tree_raw->Branch("datime", &datime);
tree_raw->Branch("waves", waves, "waves[8][1024]/D");
read_a_txt("1.txt");
read_a_txt("2.txt");
file_raw->Write();
delete datime;
delete[] waves;
delete tree_raw;
delete file_raw;
}
But the program will break down when I call read_a_root()
I have found the problem and the following code works well but I don’t know why
If I define Double_t (*waves)[1024] as global variable, the program will break down when running tree_old->GetEntry(i);
If I define TString rootfilename as global variable, the program will produce the output file correctly but output a message: munmap_chunk(): invalid pointer
// #include
//global variable
TFile* file_raw;
TTree* tree_raw;
Int_t ev_num;
TDatime* datime;
void test()
{
TString rootfilename;
Double_t (*waves)[1024];
rootfilename = "test.root";
datime = new TDatime;
waves = new Double_t[8][1024]{};
file_raw = new TFile(rootfilename, "recreate");
tree_raw = new TTree("raw", "raw data of the experiment");
tree_raw->SetDirectory(file_raw);
tree_raw->Branch("ev", &ev_num, "ev/I");
tree_raw->Branch("datime", &datime);
tree_raw->Branch("waves", waves, "waves[8][1024]/D");
//the code in read_a_root()
...
TTree* tree_old = file_old->Get<TTree>("raw");
...
for (Long64_t i = 0; i < n_event; i++){
tree_old->GetEntry(i);
...
}
//the code in read_a_root()
file_raw->Write();
delete datime;
delete[] waves;
delete tree_raw;
delete file_raw;
}
Besides, the program works well in DEBUG mode of VSCODE. Just like I have encountered last month
So I guess there are memory errors. But as the second program I showed, there is just one function which is the main function. All that determine whether the code breaks is where the pointer is defined.
It also confuses me that even the position of a simple TString will affect the program.
_ROOT Version:6.26.10
_Platform:wsl2 Compiler: Not Provided
Thanks for the post. I do not see anything which seems to point to a ROOT issue, but rather a potential issue to be debugged in your code.
My suggestion would be to trim down the code until the issue becomes easily reproducible and debuggable.
Thanks for your suggestion. I will try to work it out myself.
But I still think the second question is something related ROOT
If I define TString rootfilename as global variable, the program will produce the output file correctly but output a message: munmap_chunk(): invalid pointer
It also confuses me that even the position of a simple TString will affect the program.
This is a cristal clear indication that the problem is either an out-of-bound memory read or write. The presence of the additional local variable changes the location other variable and their content.
As an example, if there is a memory over-write that change the content of the TString then the destructor of the TString might end up trying to delete a ‘random’ memory address instead of what it allocated.
This solved the problem for the test program. But didn’t work for the original program.
And after rebooting my computer, I commented this line as follows in the test program to reproduce it.
But the program still works! I’m quite sure the same code would break in the terminal yesterday. I think it is out of my capacity to figure it out.
Anyway, for nonprofessional users like me: I have found another way to solve the problem: put the whole array in STATIC rather than HEAP, i.e., don’t use new/delete. Just define the array as a global variable, it will be stored in STATIC, which has a capacity of 2GB, much larger than STACK(~MB).
valgrind showed that there are ~900,000 bytes of possibly lost in my program.
So I simplified the program again and again to reduce it.
Finally I got:
#include <iostream>
#include <fstream>
#include <stream>
using namespace std;
#include "TROOT.h"
#include "TSystem.h"
#include "TStyle.h"
#include "TString.h"
#include "TFile.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TDatime.h"
void assemble_data()
{
TString rootfilename = "20240410_20240424_raw2.root";
TFile file_raw_data(rootfilename, "recreate");
TTree tree_raw_data("raw", "raw data of the experiment");
}
int main()
{
assemble_data();
return 0;
}
And it still reports
==12199== HEAP SUMMARY:
==12199== in use at exit: 33,288,806 bytes in 17,545 blocks
==12199== total heap usage: 141,508 allocs, 123,963 frees, 135,447,555 bytes allocated
==12199==
==12199== LEAK SUMMARY:
==12199== definitely lost: 0 bytes in 0 blocks
==12199== indirectly lost: 0 bytes in 0 blocks
==12199== possibly lost: 270,548 bytes in 259 blocks
==12199== still reachable: 820,544 bytes in 7,045 blocks
==12199== of which reachable via heuristic:
==12199== multipleinheritance: 14,584 bytes in 2 blocks
==12199== suppressed: 32,197,714 bytes in 10,241 blocks
==12199== Rerun with --leak-check=full to see details of leaked memory
==12199==
==12199== For lists of detected and suppressed errors, rerun with: -s
==12199== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 208 from 48)
Then I change it back to the original version.
And found the problem disappeared again!!! !!! Even if I put the array on the HEAP which would break yesterday.
Either way, the leak would not be the source of the problem. If valgrind was able to detect the issue it would have reported it before the heap summary.