I've worked for a while to get my code to a minimal reproducible example and I think I have it. See the single main.cpp
function below, compiled (on Linux) one of two ways:
- In serial:
g++ -O3 --std=c++17 -o test_rho.exe main.cpp
- With OpenMP:
g++ -O3 --std=c++17 -fopenmp -o test_rho.exe main.cpp
Without OpenMP the code runs fine. With OpenMP, I get the following error:
About to return 0
free(): double free detected in tcache 2
When using OpenMP, the following changes to main.cpp
will make this error go away:
- Don't define
Wfn()
constructor. More specifically, don't invoke_chi.resize(120)
. - Don't use
private _chi
in the OpenMP loop. - Don't use templating (instead just use
double
on everything).
What is causing a double free here and why do each of the changes above fix the problem?
main.cpp:
#include <iostream>
#include <vector>
// Wfn class
template<typename real>
class Wfn {
public:
Wfn() { _chi.resize(120); }
std::vector<real> rho(int nrhos);
private:
std::vector<real> _chi;
};
// Single Wfn function.
template<typename real>
std::vector<real> Wfn<real>::rho(int nrhos) {
std::vector<real> rhos;
rhos.resize(nrhos);
#pragma omp parallel for private (_chi)
for (size_t irho = 0; irho < nrhos; irho++) {
rhos[irho] = (real)irho;
}
return rhos;
}
// Main
int main(int argc, char** argv) {
Wfn<double> wfn;
std::vector<double> rhovs;
rhovs = wfn.rho(1000);
std::cerr << "About to return 0" << std::endl;
return 0;
}
Update:
In case this helps, the general reason this is happening is because wfn
is going out of scope, but my original question(s) still remain(s). If main is changed to:
int main(int argc, char** argv) {
{
Wfn<double> wfn;
std::vector<double> rhovs;
rhovs = wfn.rho(1000);
std::cerr << "About to exit scope" << std::endl;
}
std::cerr << "About to return 0" << std::endl;
return 0;
}
Then the error is
About to exit scope
free(): double free detected in tcache 2