Skip to content

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

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions