pybind11 icon indicating copy to clipboard operation
pybind11 copied to clipboard

[BUG]: static numpy array_t leads to segfault on exit on Python 3.12

Open taranu opened this issue 7 months ago • 0 comments

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?

taranu avatar Jul 26 '24 17:07 taranu