From c09d0ce0e11c94a83413c1bc6c9b2f5f40008a5a Mon Sep 17 00:00:00 2001 From: Julian Taylor Date: Fri, 18 Jul 2014 21:31:44 +0200 Subject: [PATCH] BUG: initialize object array of array on resize and zeros np.zeros(2, dtype=[('k', object, 2)]) did only initialize the first element to zero while the rest stayed None. In [1]: numpy.zeros(2, dtype=[('k', object, 2)]) Out[1]: array([([0, None],), ([0, None],)], dtype=[('k', 'O', (2,))]) This is a surprising and likely not intended behavior which is fixed here. The changed function PyArray_FillObjectArray is only used with None or zero inputs from numpy, though as its part of the API it could affect third parties but this is not very likely. Additionally the memory after the first element was not initialized when the object was resized. Closes gh-4857 --- numpy/core/src/multiarray/refcount.c | 8 ++++++-- numpy/core/src/multiarray/shape.c | 8 ++++++-- numpy/core/tests/test_multiarray.py | 12 ++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/numpy/core/src/multiarray/refcount.c b/numpy/core/src/multiarray/refcount.c index eab11e933d03..88f660118339 100644 --- a/numpy/core/src/multiarray/refcount.c +++ b/numpy/core/src/multiarray/refcount.c @@ -275,8 +275,12 @@ _fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype) } } else { - Py_XINCREF(obj); - NPY_COPY_PYOBJECT_PTR(optr, &obj); + npy_intp i; + for (i = 0; i < dtype->elsize / sizeof(obj); i++) { + Py_XINCREF(obj); + NPY_COPY_PYOBJECT_PTR(optr, &obj); + optr += sizeof(obj); + } return; } } diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c index d5fde5b9743a..2278b5d5b785 100644 --- a/numpy/core/src/multiarray/shape.c +++ b/numpy/core/src/multiarray/shape.c @@ -326,8 +326,12 @@ _putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) } } else { - Py_INCREF(zero); - NPY_COPY_PYOBJECT_PTR(optr, &zero); + npy_intp i; + for (i = 0; i < dtype->elsize / sizeof(zero); i++) { + Py_INCREF(zero); + NPY_COPY_PYOBJECT_PTR(optr, &zero); + optr += sizeof(zero); + } } return; } diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 2e40a2b7c3a5..9c51895fa73e 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -511,6 +511,10 @@ def test_zeros_obj(self): assert_array_equal(d, [0] * 13) assert_equal(np.count_nonzero(d), 0) + def test_zeros_obj_obj(self): + d = zeros(10, dtype=[('k', object, 2)]) + assert_array_equal(d['k'], 0) + def test_sequence_non_homogenous(self): assert_equal(np.array([4, 2**80]).dtype, np.object) assert_equal(np.array([4, 2**80, 4]).dtype, np.object) @@ -2784,6 +2788,14 @@ def test_zeros_appended(self): assert_array_equal(x[0], np.eye(3)) assert_array_equal(x[1], np.zeros((3, 3))) + def test_obj_obj(self): + # check memory is initialized on resize, gh-4857 + a = ones(10, dtype=[('k', object, 2)]) + a.resize(15,) + assert_equal(a.shape, (15,)) + assert_array_equal(a['k'][-5:], 0) + assert_array_equal(a['k'][:-5], 1) + class TestRecord(TestCase): def test_field_rename(self):