Skip to content

Commit

Permalink
BUG: double decref of dtype in failure codepath. Test and fix
Browse files Browse the repository at this point in the history
  • Loading branch information
mattip committed Jan 20, 2019
1 parent f07a38d commit adfaafb
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 18 deletions.
5 changes: 5 additions & 0 deletions numpy/core/src/multiarray/ctors.c
Original file line number Diff line number Diff line change
Expand Up @@ -2495,6 +2495,11 @@ PyArray_FromInterface(PyObject *origin)
&PyArray_Type, dtype,
n, dims, NULL, data,
dataflags, NULL, base);
/*
* Ref to dtype was stolen by PyArray_NewFromDescrAndBase
* Prevent DECREFing dtype in fail codepath by setting to NULL
*/
dtype = NULL;
if (ret == NULL) {
goto fail;
}
Expand Down
52 changes: 34 additions & 18 deletions numpy/core/tests/test_multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -6999,12 +6999,11 @@ def test_multiarray_flags_not_writable_attribute_deletion(self):
assert_raises(AttributeError, delattr, a, s)


def test_array_interface():
# Test scalar coercion within the array interface
class TestArrayInterface():
class Foo(object):
def __init__(self, value):
self.value = value
self.iface = {'typestr': '=f8'}
self.iface = {'typestr': 'f8'}

def __float__(self):
return float(self.value)
Expand All @@ -7013,22 +7012,39 @@ def __float__(self):
def __array_interface__(self):
return self.iface


f = Foo(0.5)
assert_equal(np.array(f), 0.5)
assert_equal(np.array([f]), [0.5])
assert_equal(np.array([f, f]), [0.5, 0.5])
assert_equal(np.array(f).dtype, np.dtype('=f8'))
# Test various shape definitions
f.iface['shape'] = ()
assert_equal(np.array(f), 0.5)
f.iface['shape'] = None
assert_raises(TypeError, np.array, f)
f.iface['shape'] = (1, 1)
assert_equal(np.array(f), [[0.5]])
f.iface['shape'] = (2,)
assert_raises(ValueError, np.array, f)

# test scalar with no shape

@pytest.mark.parametrize('val, iface, expected', [
(f, {}, 0.5),
([f], {}, [0.5]),
([f, f], {}, [0.5, 0.5]),
(f, {'shape': ()}, 0.5),
(f, {'shape': None}, TypeError),
(f, {'shape': (1, 1)}, [[0.5]]),
(f, {'shape': (2,)}, ValueError),
(f, {'strides': ()}, 0.5),
(f, {'strides': (2,)}, ValueError),
(f, {'strides': 16}, TypeError),
])
def test_scalar_interface(self, val, iface, expected):
# Test scalar coercion within the array interface
self.f.iface = {'typestr': 'f8'}
self.f.iface.update(iface)
if HAS_REFCOUNT:
pre_cnt = sys.getrefcount(np.dtype('f8'))
if isinstance(expected, type):
assert_raises(expected, np.array, val)
else:
result = np.array(val)
assert_equal(np.array(val), expected)
assert result.dtype == 'f8'
del result
if HAS_REFCOUNT:
post_cnt = sys.getrefcount(np.dtype('f8'))
assert_equal(pre_cnt, post_cnt)

def test_interface_no_shape():
class ArrayLike(object):
array = np.array(1)
__array_interface__ = array.__array_interface__
Expand Down

0 comments on commit adfaafb

Please sign in to comment.