Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
YannickJadoul opened this issue May 27, 2017 · 2 comments
Closed

Comments

@YannickJadoul
Copy link
Collaborator

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.

dean0x7d added a commit to dean0x7d/pybind11 that referenced this issue May 28, 2017
@dean0x7d
Copy link
Member

Thanks for the report and reproducible example. Your hunch was right about tinfo->get_buffer not being inherited. This should be fixed in #881.

@YannickJadoul
Copy link
Collaborator Author

Cool, thanks; still surprised about the speed at which issues get addressed! :-)
And yeah, I could follow and read the code, but don't think I knew how to produce that code looping over the MRO, though.

dean0x7d added a commit that referenced this issue May 29, 2017
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 20, 2021
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 21, 2021
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 22, 2021
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 26, 2021
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 26, 2021
rwgk added a commit to rwgk/pybind11 that referenced this issue Jul 27, 2021
rwgk added a commit that referenced this issue Jul 27, 2021
…ind11.h (#3135)

* Fixing `pragma warning pop` for `__INTEL_COMPILER`.

* Adding push/pop to 3 tests. Removing #878 from top of pybind11.h (it was/is only needed for 1 test).

* Trying again after CI failure, moving the push to the top of 2 tests.

* Trying more after CI failure, adding push/pop to pybind11_tests.h, constructor_stats.h.

* Moving ICC #2196 suppression to CMakeLists.txt

* Fixing condition for `pragma GCC diagnostic push` in pybind11.h

* Moving `pragma warning disable 2196` to common.h

* Revising #ifdef to be more conservative.

* Undoing insertion of notes that will hopefully soon be completely obsolete anyway.
henryiii pushed a commit to henryiii/pybind11 that referenced this issue Jul 29, 2021
…ind11.h (pybind#3135)

* Fixing `pragma warning pop` for `__INTEL_COMPILER`.

* Adding push/pop to 3 tests. Removing pybind#878 from top of pybind11.h (it was/is only needed for 1 test).

* Trying again after CI failure, moving the push to the top of 2 tests.

* Trying more after CI failure, adding push/pop to pybind11_tests.h, constructor_stats.h.

* Moving ICC pybind#2196 suppression to CMakeLists.txt

* Fixing condition for `pragma GCC diagnostic push` in pybind11.h

* Moving `pragma warning disable 2196` to common.h

* Revising #ifdef to be more conservative.

* Undoing insertion of notes that will hopefully soon be completely obsolete anyway.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants