diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2017-02-13 23:23:10 +0000 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2017-03-04 11:48:51 -0700 |
commit | 91374d117e1dea50467a14c0d697690ee9630c1b (patch) | |
tree | 897631645391999a4b5efe3fb387e65a7525c01f | |
parent | 20e89a4e855875d24e96b7877fb22258eaeae5b7 (diff) | |
download | numpy-91374d117e1dea50467a14c0d697690ee9630c1b.tar.gz |
BUG: Fixed undefined behavior when __array_wrap__ returns None
Now `None` is treated like any other return value, rather than a command
to segfault.
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 13 |
2 files changed, 14 insertions, 3 deletions
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 62024d2e3..69fb255fa 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -4395,6 +4395,7 @@ ufunc_generic_call(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) continue; } res = PyObject_CallFunction(wrap, "O(OOi)", mps[j], ufunc, args, i); + /* Handle __array_wrap__ that does not accept a context argument */ if (res == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Clear(); res = PyObject_CallFunctionObjArgs(wrap, mps[j], NULL); @@ -4403,9 +4404,6 @@ ufunc_generic_call(PyUFuncObject *ufunc, PyObject *args, PyObject *kwds) if (res == NULL) { goto fail; } - else if (res == Py_None) { - Py_DECREF(res); - } else { Py_DECREF(mps[j]); retobj[i] = res; diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 4c0243559..6fea832c9 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -1379,6 +1379,19 @@ class TestSpecialMethods(TestCase): a = A() self.assertRaises(RuntimeError, ncu.maximum, a, a) + def test_none_wrap(self): + # Tests that issue #8507 is resolved. Previously, this would segfault + + class A(object): + def __array__(self): + return np.zeros(1) + + def __array_wrap__(self, arr, context=None): + return None + + a = A() + assert_equal(ncu.maximum(a, a), None) + def test_default_prepare(self): class with_wrap(object): |