Skip to content

Commit

Permalink
BUG: Fix subarray to object cast ownership details
Browse files Browse the repository at this point in the history
  • Loading branch information
seberg authored and charris committed Jul 24, 2022
1 parent 71f271d commit eeb64e5
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 1 deletion.
11 changes: 10 additions & 1 deletion numpy/core/src/multiarray/arraytypes.c.src
Expand Up @@ -766,14 +766,23 @@ VOID_getitem(void *input, void *vap)
* could have special handling.
*/
PyObject *base = (PyObject *)ap;
while (Py_TYPE(base) == NULL) {
while (base != NULL && Py_TYPE(base) == NULL) {
base = PyArray_BASE((PyArrayObject *)base);
}
ret = (PyArrayObject *)PyArray_NewFromDescrAndBase(
&PyArray_Type, descr->subarray->base,
shape.len, shape.ptr, NULL, ip,
PyArray_FLAGS(ap) & ~NPY_ARRAY_F_CONTIGUOUS,
NULL, base);
if (base == NULL) {
/*
* Need to create a copy, or we may point to wrong data. This path
* is taken when no "valid" array is passed. This happens for
* casts.
*/
PyObject *copy = PyArray_FromArray(ret, NULL, NPY_ARRAY_ENSURECOPY);
Py_SETREF(ret, (PyArrayObject *)copy);
}
npy_free_cache_dim_obj(shape);
return (PyObject *)ret;
}
Expand Down
1 change: 1 addition & 0 deletions numpy/core/src/multiarray/dtype_transfer.c
Expand Up @@ -254,6 +254,7 @@ any_to_object_get_loop(
data->base.free = &_any_to_object_auxdata_free;
data->base.clone = &_any_to_object_auxdata_clone;
data->arr_fields.base = NULL;
Py_SET_TYPE(&data->arr_fields, NULL);
data->arr_fields.descr = context->descriptors[0];
Py_INCREF(data->arr_fields.descr);
data->arr_fields.flags = aligned ? NPY_ARRAY_ALIGNED : 0;
Expand Down
23 changes: 23 additions & 0 deletions numpy/core/tests/test_dtype.py
Expand Up @@ -639,6 +639,29 @@ def test_aligned_empty(self):
dt = np.dtype({"names": [], "formats": [], "itemsize": 0}, align=True)
assert dt == np.dtype([])

def test_subarray_base_item(self):
arr = np.ones(3, dtype=[("f", "i", 3)])
# Extracting the field "absorbs" the subarray into a view:
assert arr["f"].base is arr
# Extract the structured item, and then check the tuple component:
item = arr.item(0)
assert type(item) is tuple and len(item) == 1
assert item[0].base is arr

def test_subarray_cast_copies(self):
# Older versions of NumPy did NOT copy, but they got the ownership
# wrong (not actually knowing the correct base!). Versions since 1.21
# (I think) crashed fairly reliable. This defines the correct behavior
# as a copy. Keeping the ownership would be possible (but harder)
arr = np.ones(3, dtype=[("f", "i", 3)])
cast = arr.astype(object)
for fields in cast:
assert type(fields) == tuple and len(fields) == 1
subarr = fields[0]
assert subarr.base is None
assert subarr.flags.owndata


def iter_struct_object_dtypes():
"""
Iterates over a few complex dtypes and object pattern which
Expand Down

0 comments on commit eeb64e5

Please sign in to comment.