matplotlib-cpp icon indicating copy to clipboard operation
matplotlib-cpp copied to clipboard

Crash on program exit

Open ed-aka-yaboi opened this issue 4 years ago • 9 comments

The following code segfaults with python 3. It does so on the Py_Finalize call

#include <matplotlibcpp.h>

int main() {
    namespace plt = matplotlibcpp;
    plt::plot({1,3,2,4});
    plt::show();
    plt::close();
    return 0;

The following does not:

#include <matplotlibcpp.h>

int main() {
    namespace plt = matplotlibcpp;
    plt::plot({1,3,2,4});
    plt::show();
    plt::close();
    plt::detail::_interpreter::kill();
    return 0;
}

I'm not plotting in different threads so not sure why this is happening. Perhaps the following will solve this: https://stackoverflow.com/questions/1427002/calling-py-finalize-from-c

ed-aka-yaboi avatar Feb 04 '21 14:02 ed-aka-yaboi

I've encountered the same problem but wasn't able to figure out what goes wrong. But I think you are right that something goes wrong with the call Py_Finalize();.

JonasBreuling avatar Feb 04 '21 17:02 JonasBreuling

I tried a naive implementation of the above fix and it didnt work :(

Apparently Py_InitThreads is deprecated so no ideas here :( not very familiar with embedding python in c/c++

ed-aka-yaboi avatar Feb 04 '21 19:02 ed-aka-yaboi

That is interesting. I made some investigations and here is what I found out.

The following code crashes with a Segfault

#include <matplotlibcpp.h>
int main()
{
    matplotlibcpp::figure();
    matplotlibcpp::show();
}

but this works fine

#include <matplotlibcpp.h>
int main()
{
    matplotlibcpp::figure();
    matplotlibcpp::show();
    Py_Finalize();
}

I've also implemented a minimal working example of the core features of the above two calls. Everything works fine there...

#include <Python.h>

int main()
{
    Py_Initialize();

    PyObject* matplotlibname = PyUnicode_FromString("matplotlib");
    PyObject* matplotlib = PyImport_Import(matplotlibname);
    Py_DECREF(matplotlibname);

    PyObject* pyplotname = PyUnicode_FromString("matplotlib.pyplot");
    PyObject* pymod = PyImport_Import(pyplotname);
    Py_DECREF(pyplotname);

    PyObject* s_python_function_figure = PyObject_GetAttrString(pymod, "figure");
    PyObject* s_python_function_show = PyObject_GetAttrString(pymod, "show");
    PyObject* empty_tuple = PyTuple_New(0);

    PyObject *fig = PyObject_CallObject(s_python_function_figure, empty_tuple);
    PyObject *res = PyObject_CallObject(s_python_function_show, empty_tuple);

    Py_DECREF(matplotlib);
    Py_DECREF(pymod);
    Py_DECREF(s_python_function_figure);
    Py_DECREF(s_python_function_show);
    Py_DECREF(empty_tuple);
    Py_DECREF(fig);
    Py_DECREF(res);

    Py_Finalize();
}

So somewhere between the above core code and the matplotlibcpp code there is a problem I can't figure out.

JonasBreuling avatar Feb 05 '21 06:02 JonasBreuling

Is there any way matplotlibcpp or the python interpreter spin up different threads?

ed-aka-yaboi avatar Feb 05 '21 07:02 ed-aka-yaboi

Sorry for the late reply, I missed your message. And I don't know If something goes wrong with the threads.

JonasBreuling avatar Feb 10 '21 21:02 JonasBreuling

Hi, same problem here, adding Py_Finalize(); at the end of the program fixes it.

filiatra avatar Mar 17 '21 08:03 filiatra

This issue might be related to the backend of matplotlib. See #268

pascal-mueller avatar May 18 '21 12:05 pascal-mueller

@pascal-mueller

It is related, it's explained in the stackoverflow link. Py_Finalize() is called from the _interpreter destructor, which is being called too late, because the interpreter is static. calling kill() or Py_Finalize() before return, in main fixes it. That's with Qt5Agg used by python3. Changing the backend to TkAgg seems to work without issues.

amadeus84 avatar Mar 12 '22 06:03 amadeus84

@amadeus84 Thanks, I remember trying to solve it but couldn't. Can't remember why but also didn't had the time to dig into it too deep. You fix seems easy enough though. I hope it gets merged! It's quit a pain of a bug.

pascal-mueller avatar Mar 14 '22 14:03 pascal-mueller