-
-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Closed
Labels
Description
The following, albeit slightly contrived, example causes a segfault in _IsWriteable.
foo.pyx:
from libc.stdlib cimport malloc
import numpy as np
cimport numpy as np
np.import_array()
def test(n):
cdef np.npy_intp _n = n
cdef void * data
data = <void *>malloc(_n * sizeof(double))
return np.PyArray_SimpleNewFromData(1, &_n, np.NPY_DOUBLE, data)test.py:
import pyximport
pyximport.install()
import foo
a = foo.test(10)
b = a.reshape((5,2))
b.setflags(write=True)python test.py -> segmentation fault
Here's _IsWriteable (with unnecessary bits removed).
NPY_NO_EXPORT npy_bool
_IsWriteable(PyArrayObject *ap)
{
PyObject *base=PyArray_BASE(ap);
....
/* If we own our own data, then no-problem */
if ((base == NULL) || (PyArray_FLAGS(ap) & NPY_ARRAY_OWNDATA)) {
return NPY_TRUE;
}
....
while(PyArray_Check(base)) {
if (PyArray_CHKFLAGS((PyArrayObject *)base, NPY_ARRAY_OWNDATA)) {
return (npy_bool) (PyArray_ISWRITEABLE((PyArrayObject *)base));
}
base = PyArray_BASE((PyArrayObject *)base);
}
...
}a.setflags(write=True) works because
ap == a
base == NULL
and we hit the first condition (base is NULL or we own the data)
b.setflags(write=True) doesn't work because
ap == b
base == a
b.flags['OWNDATA'] == False
so we go into the loop:
base doesn't own the data either, so we try and find the base of a, which is NULL, and PyArray_Check(NULL) is a segfault.
I think the fix is
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 7b8177c..60a58f6 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -628,6 +628,9 @@ _IsWriteable(PyArrayObject *ap)
return (npy_bool) (PyArray_ISWRITEABLE((PyArrayObject *)base));
}
base = PyArray_BASE((PyArrayObject *)base);
+ if (!base) {
+ return NPY_TRUE;
+ }
}
/*But I'm not sure which of returning True or False is correct.