[issue10181] Problems with Py_buffer management in memoryobject.c (and elsewhere?)
report at bugs.python.org
Mon Jun 27 13:28:13 CEST 2011
Pauli Virtanen <pav at iki.fi> added the comment:
> I think slicing (esp. multidimensional slicing) would be greatly
> simplified if we added a requirement for the *exporting* object
> to provide a sliced view. (The same applies to sub-views, also
> see source comments below ).
> For example, an exporting object could provide a sliced view by adding
> a getslicedbufferproc to PyBufferProcs:
> int PyObject_GetSlicedBuffer(PyObject *obj, Py_buffer *view,
> int flags, PyObject *key);
The same thing can be done via
PyObject_GetBuffer(obj, &view, flags);
PyBuffer_Slice(&view, &sliced_view, flags, key);
given an implementation of PyBuffer_Slice. The logic in PyBuffer_Slice does not depend on where the buffer comes from, and every buffer can be sliced.
As far as I see, the advantage of `getslicedbufferproc` would be to make the implementation of PyMemoryView simpler, but not much else. In my view, having each exporter implement the same logic by itself would only be an unnecessary burden.
> o The invariant that all allocated memory in the buffer belongs
> to the exporting object remains intact.
Numpy arrays do not have this invariant, and they happily re-export memory owned by someone else. This is one root of problems here: the PEP implicitly assumes that re-exporting buffers (e.g. memoryview's implementation of `getbuffer`) is done in the way Numpy does it. Because of this, there is no mechanism for "incrementing the refcount" of an existing buffer export. Maintaining the above invariant then unavoidably leads to strange behavior in corner cases (which probably are very rare, as mentioned above), and as happened here, make the implementation messy and lead to bugs.
The invariant *is* required for guaranteeing that `memoryview.release()` always succeeds. Such a method probably wasn't foreseen in the PEP (and I did not remember that it existed in my first patch), as Numpy arrays don't have any equivalent. The alternatives here are (i) do as Numpy does and give up the invariant and allow `.release()` to fail in some cases, or (ii) document the corner cases in the interface spec and try to detect them and fail if they occur. Which of these is chosen probably does not matter much in practice, but having PyManagedBuffer will make implementing either choice easier.
Python tracker <report at bugs.python.org>
More information about the Python-bugs-list