diff options
| author | Charles Harris <charlesr.harris@gmail.com> | 2022-07-12 16:17:36 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-12 16:17:36 -0500 |
| commit | b9061328b6c5c49b3f92b4e9793bb8c3ac11b544 (patch) | |
| tree | b70c047f4c27a05ef5e6f588a58b426d0d4b9212 /numpy | |
| parent | a878789ef79abe402340c50a47429367800fe49a (diff) | |
| parent | f1f9834d84a3508aa10cc01157011b5349ec3903 (diff) | |
| download | numpy-b9061328b6c5c49b3f92b4e9793bb8c3ac11b544.tar.gz | |
Merge pull request #21925 from seberg/subarray-object-cast
BUG: Fix subarray to object cast ownership details
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 11 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/dtype_transfer.c | 1 | ||||
| -rw-r--r-- | numpy/core/tests/test_dtype.py | 23 |
3 files changed, 34 insertions, 1 deletions
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index 7cd80ba9a..56ac83cbb 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -804,7 +804,7 @@ 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( @@ -812,6 +812,15 @@ VOID_getitem(void *input, void *vap) 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; } diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c index f8458d2d7..c588494e7 100644 --- a/numpy/core/src/multiarray/dtype_transfer.c +++ b/numpy/core/src/multiarray/dtype_transfer.c @@ -258,6 +258,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; diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py index f95f95893..9b471a5bf 100644 --- a/numpy/core/tests/test_dtype.py +++ b/numpy/core/tests/test_dtype.py @@ -650,6 +650,29 @@ class TestSubarray: 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 |
