[BUG]: static numpy array_t leads to segfault on exit on Python 3.12
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 18k
- Forks
- 2.3k
- Avg merge
- 5d 17h
- Merged PRs (30d)
- 10
Description
Required prerequisites
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker and Discussions to verify that this hasn't already been reported. +1 or comment there if it has.
- 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?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the Python 3.12 failure with the provided test_static module and compare it with Python 3.11, then inspect pybind11/numpy.h and the Static::PYARRAY() static array lifetime. Check both the basic construction command and the construction/deletion sequence. Done means neither scenario segfaults at interpreter exit or while deleting and recreating Static instances.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, numpy, python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100