Consider the following simple code:
#include "matplotlibcpp.h"
namespace plt = matplotlibcpp;
int main() {
plt::plot({ 1, 2, 3, 4 });
plt::show();
return 0;
}
It works well in Debug mode (Eclipse CDT, gcc(++17) v. 6.3.0, Win64). But when I run it in Release, the program terminates with exit value -1073741819 (even though it compiles without errors in both cases). Debugging indicates the following problem:
No source available for "_object* matplotlibcpp::detail::get_array<double>
The problem seems to be with PyArray_SimpleNewFromData
appearing in the following function:
template<typename Numeric>
PyObject* get_array(const std::vector<Numeric>& v)
{
npy_intp vsize = v.size();
NPY_TYPES type = select_npy_type<Numeric>::type;
if (type == NPY_NOTYPE) {
size_t memsize = v.size()*sizeof(double);
double* dp = static_cast<double*>(::malloc(memsize));
for (size_t i=0; i<v.size(); ++i)
dp[i] = v[i];
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, NPY_DOUBLE, dp);
PyArray_UpdateFlags(reinterpret_cast<PyArrayObject*>(varray), NPY_ARRAY_OWNDATA);
return varray;
}
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
return varray;
}
in matplotlib.h
.
And now to the weirdest part: I managed to "fix" it by inserting std::cout << std::endl;
just before the line
PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
Alternatively, one can write std::cout << 'a' << std::flush;
(or any other character, as long as you remember to do std::flush
). Curiously, without std::endl
(or std::flush
) the problem will persist, so it is not enough to just print some character. On the other hand, something like std::cout << std::flush;
will NOT work either because it doesn't print anything.
What can be causing this problem? And why the the trick with std::endl
(or std::flush
) fixes it?
Additional info: gdb
analysis indicates a segmentation fault:
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ff67e889efb in matplotlibcpp::detail::get_array<double> (v=Python Exception <class 'gdb.error'>: value has been optimized out
<synthetic pointer>) at ../libs/matplotlibcpp.h:383
383 PyObject* varray = PyArray_SimpleNewFromData(1, &vsize, type, (void*)(v.data()));
which indeed confirms that the problematic line is the line with PyArray_SimpleNewFromData
.
Update: Adding import_array();
just before the problematic line seems to fix the issue (not entirely sure why). The idea was inspired by this SO question.