Skip to content

Buffer protocol for inherited classes results in 'Internal error' #878

Closed
@YannickJadoul

Description

@YannickJadoul

When exposing a derived class that inherits from a base class that implements the buffer protocol, using this protocol fails.

Take for example an extended version of the code in the documentation:

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

class Matrix {
public:
	Matrix(size_t rows, size_t cols) : m_rows(rows), m_cols(cols) {
		m_data = new float[rows*cols];
	}
	float *data() { return m_data; }
	size_t rows() const { return m_rows; }
	size_t cols() const { return m_cols; }
private:
	size_t m_rows, m_cols;
	float *m_data;
};

class SquareMatrix : public Matrix {
public:
	SquareMatrix(size_t n) : Matrix(n, n) {}
};


namespace py = pybind11;

PYBIND11_PLUGIN(test) {
	py::module m("test");

	py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
		.def(py::init<size_t, size_t>())
		.def_buffer([](Matrix &m) -> py::buffer_info {
			return py::buffer_info(m.data(), sizeof(float),	py::format_descriptor<float>::format(), 2, { m.rows(), m.cols() }, { sizeof(float) * m.rows(), sizeof(float) });
		});

	py::class_<SquareMatrix, Matrix>(m, "SquareMatrix")
		.def(py::init<size_t>());
	
	return m.ptr();
}

Using this code results in the following:

>>> import test
>>> import numpy as np
>>> np.asarray(test.Matrix(4,5))
array([[  0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
          0.00000000e+00,   1.51019586e+11],
       [  1.51019586e+11,   4.56150676e-41,   1.32649094e+20,
          4.56150676e-41,   1.11956001e+11],
       [  1.11956001e+11,   4.56150676e-41,   1.32648531e+20,
          4.56150676e-41,   1.52991748e-38],
       [  1.52991748e-38,   0.00000000e+00,   0.00000000e+00,
          0.00000000e+00,   1.27985124e+20]], dtype=float32)
>>> np.asarray(test.SquareMatrix(4))
array(<test.SquareMatrix object at 0x7f2860e198d0>, dtype=object)
>>> memoryview(test.SquareMatrix(4))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BufferError: generic_type::getbuffer(): Internal error

As far as I can see, the problem is that Python knóws that the type implements the buffer protocol (because of the bf_getbuffer and bf_releasebuffer fields), since these are part of the C API inheritance. But the pybind11 specific tinfo->get_buffer does not get inherited from the parent class, resulting in the "generic_type::getbuffer(): Internal error" exception.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions