pybind11
pybind11 copied to clipboard
[BUG]: static numpy array_t leads to segfault on exit on Python 3.12
Required prerequisites
- [X] Make sure you've read the documentation. Your issue may be addressed there.
- [X] Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- [X] Consider asking first in the Gitter chat room or in a Discussion.
What version (or hash if on master) of pybind11 are you using?
2.13.1
Problem description
Observed behaviour: When exiting a Python script after constructing a bound class with an initialized static pybind11::array_t, there is a segfault calling decref on the array on Python 3.12.
Expected behaviour: No segfault, as is the case on Python < 3.12.
I have tested with several combinations of package version but can definitely confirm that on a Fedora 40 conda env with gxx=14.1.0, numpy=2.0.0 and pybind11=2.13.1 the segfault occurs with Python 3.12 but not 3.11, so this does not appear to be a regression in pybind11.
I compiled the module as follows:
g++ -Wall -shared -fPIC -std=c++17 $(python3 -m pybind11 --includes) test_image.cc -o test_static$(python3-config --extension-suffix)
and tested with:
python -c "from test_static import Static; Static()"
It is possible to defer the problem by adding a destructor like so:
~Static() { PYARRAY().release(); }
... however, this only fixes the trivial example and fails as soon as one instance is deleted, and the following example fails upon constructing a second instance:
python -c "from test_static import Static; x = Static(); del x; y = Static()"
Reproducible example code
#include <cassert>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
using namespace pybind11::literals;
struct Static {
public:
Static() { assert(this->PYARRAY().ndim() == 2); }
py::array_t<double>& PYARRAY() const {
static py::array_t<double> array(py::array::ShapeContainer({1, 1}));
return array;
}
};
PYBIND11_MODULE(test_static, m) {
py::class_<Static, std::shared_ptr<Static>>(m, "Static").def(py::init<>());
}
Is this a regression? Put the last known working version here if it is.
Not a regression in pybind11 but perhaps in CPython?