summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGanesh Kathiresan <ganesh3597@gmail.com>2020-10-18 14:33:30 +0530
committerGitHub <noreply@github.com>2020-10-18 10:03:30 +0100
commitbb76bff17f86e468ca9fbc5071d95782dc932c10 (patch)
tree8564243e42afd670a8d7ee6b953b2b9fd3ff776c
parent7b0a764fee6e1614f3249e9082d8c4acf1dc62d5 (diff)
downloadnumpy-bb76bff17f86e468ca9fbc5071d95782dc932c10.tar.gz
BUG: Fixed crash on self-referential dtypes (#17536)
Instead of causing a C stack overflow, these now raise RecursionError. It shouldn't be possible to recurse through the string, type, or byte conversion paths; only the tuple, dict, and list paths are at risk.
-rw-r--r--numpy/core/src/multiarray/descriptor.c27
-rw-r--r--numpy/core/tests/test_dtype.py20
2 files changed, 44 insertions, 3 deletions
diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
index 24a3507bc..a8d575248 100644
--- a/numpy/core/src/multiarray/descriptor.c
+++ b/numpy/core/src/multiarray/descriptor.c
@@ -1497,15 +1497,36 @@ _convert_from_any(PyObject *obj, int align)
}
else if (PyTuple_Check(obj)) {
/* or a tuple */
- return _convert_from_tuple(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a tuple object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_tuple(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyList_Check(obj)) {
/* or a list */
- return _convert_from_array_descr(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a list object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_array_descr(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyDict_Check(obj) || PyDictProxy_Check(obj)) {
/* or a dictionary */
- return _convert_from_dict(obj, align);
+ if (Py_EnterRecursiveCall(
+ " while trying to convert the given data type from"
+ " a dict object" ) != 0) {
+ return NULL;
+ }
+ PyArray_Descr *ret = _convert_from_dict(obj, align);
+ Py_LeaveRecursiveCall();
+ return ret;
}
else if (PyArray_Check(obj)) {
PyErr_SetString(PyExc_TypeError, "Cannot construct a dtype from an array");
diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py
index 45cc0b8b3..ba5069024 100644
--- a/numpy/core/tests/test_dtype.py
+++ b/numpy/core/tests/test_dtype.py
@@ -767,6 +767,26 @@ class TestMonsterType:
('yi', np.dtype((a, (3, 2))))])
assert_dtype_equal(c, d)
+ def test_list_recursion(self):
+ l = list()
+ l.append(('f', l))
+ with pytest.raises(RecursionError):
+ np.dtype(l)
+
+ def test_tuple_recursion(self):
+ d = np.int32
+ for i in range(100000):
+ d = (d, (1,))
+ with pytest.raises(RecursionError):
+ np.dtype(d)
+
+ def test_dict_recursion(self):
+ d = dict(names=['self'], formats=[None], offsets=[0])
+ d['formats'][0] = d
+ with pytest.raises(RecursionError):
+ np.dtype(d)
+
+
class TestMetadata:
def test_no_metadata(self):
d = np.dtype(int)