Describe the bug
With ROOT 6.32, vector<TFormula*>
seems to trigger a deallocation issue with Python.
Setup
ROOT v6.32.08
Built for linuxx8664gcc on Jan 24 2025, 09:37:12
From tags/v6-32-08@v6-32-08
With c++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
ROOT built from source:
$ root-config --features
cxx17 asimage builtin_clang builtin_cling builtin_fftw3 builtin_gsl builtin_gtest builtin_llvm builtin_nlohmannjson dataframe fftw3 mathmore pyroot roofit runtime_cxxmodules shared soversion sqlite x11 xml
To Reproduce
Please consider the following MWE: Files · raw_ptr · Uranie CEA / Prerequisites / Prerequisites Detection / Mini ROOT Library · GitLab
After loading ROOT, here are the steps to reproduce the error on Linux:
$ git clone -b raw_ptr https://gitlab.com/uranie-cea/prerequisites/prerequisites_detection/mini-root-library.git
$ mkdir build
$ cd build/
$ cmake -DCMAKE_INSTALL_PREFIX=install ../
$ cmake --build . --target install -j $(nproc)
$ ctest -V -R "builder_python"
[...]
4: ROOT: 6.32.08
4: trend: x
4: *** Break *** segmentation violation
[...]
4: #7 0x00007d0d7d991100 in MiniLibrary::TGPBuilder::~TGPBuilder() () from /.../mini-root-library/build/install/lib/libTGPBuilder.so
4: #8 0x00007d0d7d992aca in ROOT::delete_MiniLibrarycLcLTGPBuilder(void*) () from /.../mini-root-library/build/install/lib/libTGPBuilder.so
4: #9 0x00007d0d6ade7835 in CPyCppyy::op_dealloc_nofree(CPyCppyy::CPPInstance*) () from /.../root/lib/libcppyy.so
Here are the definition & implementation of the class:
class TGPBuilder {
private:
std::vector<TFormula*> _trends;
public:
TGPBuilder();
~TGPBuilder();
std::vector<TFormula*> get_trends();
};
MiniLibrary::TGPBuilder::TGPBuilder() {
_trends.push_back(new TFormula("f", "x"));
}
MiniLibrary::TGPBuilder::~TGPBuilder() {
for(auto& trend: _trends)
delete trend;
_trends.clear();
}
std::vector<TFormula*> MiniLibrary::TGPBuilder::get_trends() {
return _trends;
}
And here is the test: test_builder.py · raw_ptr · Uranie CEA / Prerequisites / Prerequisites Detection / Mini ROOT Library · GitLab
import ROOT
print('ROOT:', ROOT.gROOT.GetVersion())
builder = ROOT.MiniLibrary.TGPBuilder()
for trend in builder.get_trends():
print('trend:', trend.GetExpFormula())
Expected behavior
The test seems to pass with ROOT 6.34:
4: ROOT: 6.34.04
4: Print:
4: trend: x
4: Modification
4: Print:
4: trend:
1/1 Test #4: builder_python ................... Passed 0.70 sec
Solutions?
Which solutions do you recommand?
Using smart pointers seems to solve the issue: Files · shared_ptr · Uranie CEA / Prerequisites / Prerequisites Detection / Mini ROOT Library · GitLab
class TGPBuilder {
private:
std::vector<std::shared_ptr<TFormula>> _trends;
public:
TGPBuilder();
const std::vector<std::shared_ptr<TFormula>>& get_trends() const;
};
const std::vector<std::shared_ptr<TFormula>>& MiniLibrary::TGPBuilder::get_trends() const {
return _trends;
}
$ git switch -d shared_ptr
[...]
$ ctest -V -R "builder_python"
[...]
4: ROOT: 6.32.08
4: Print:
4: trend: x
4: Modification
4: Print:
4: trend:
1/1 Test #4: builder_python ................... Passed 0.70 sec