Reputation: 768
Currently I am trying to get a struct with a typed memoryview to work. E.g.
ctypedef struct node:
unsigned int[:] inds
If inds is not a memoryview it works flawlessly as far as I can see. However, with a memoryview and using something like
def testFunction():
cdef node testNode
testNode.inds = numpy.ones(3,dtype=numpy.uint32)
I get a Segmentation fault. Is there anything obvious I am overlooking or do typed memoryviews not work in structs?
EDIT:
So I rewrote the example a little bit (due to larsman's questions) to hopefully clarify the problem a little bit:
def testFunction():
cdef node testNode
cdef unsigned int[:] tempInds
tempInds = numpy.ones(3,dtype=numpy.uintc)
testNode.inds = tempInds
Only the last line produces a segfault. I don't know how to check the problem in more detail. For me it currently just looks like the structs can't handle typed memory views... But hopefully I am missing something.
I am using Cython 0.20 (just updated now, previously 0.19 gave the same error). Updated Numpy to 1.8.0 as well.
EDIT 2:
If anyone with similar problems reads this in the future: I searched quite a lot by now and can't get it to work. As everything else is working except for memory views I guess it is not (easily) possible. I intended to use memory views due to the convenient slicing of multidimensional arrays, but apparently they don't work in structs. Now I am saving a C pointer in the struct and cast them to a memory view if I need slicing... One has to be very careful that the arrays are accessed correctly, but in my case it seems to work. If there are no resolving answers in this thread in a couple of weeks from now I am maybe doing a feature request for Cython.
Upvotes: 5
Views: 1557
Reputation: 86
The problem comes from uninitialized memory because of Cython lack of constructors for primitive cdefed structs. When testNode.inds = tempInds assignment is made Cython tries to release testNode.inds which was not even initialized properly and dereferences random pointer.
This is indeed bug in Cython (please file!) and there's currently no solution (to my knowledge), but here's an ugly hack that works.
from libc.string cimport memset
ctypedef struct node:
int dummy_hack
unsigned int[:] inds
def testFunction():
cdef node testNode
cdef unsigned int[:] tempInds
tempInds = numpy.ones(3,dtype=numpy.uintc)
# zero init memory to avoid deref garbage
memset(&testNode.dummy_hack, 0, sizeof(void*)*4)
testNode.inds = tempInds
FYI. Actual memory view object in C++ looks like this (on Cython 21.2):
MemoryView object is
__Pyx_memviewslice struct typedef struct {
struct __pyx_memoryview_obj *memview;
char *data;
Py_ssize_t shape[8];
Py_ssize_t strides[8];
Py_ssize_t suboffsets[8];
};
Upvotes: 2