diff options
author | Ganesh Kathiresan <ganesh3597@gmail.com> | 2020-10-18 14:33:30 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-18 10:03:30 +0100 |
commit | bb76bff17f86e468ca9fbc5071d95782dc932c10 (patch) | |
tree | 8564243e42afd670a8d7ee6b953b2b9fd3ff776c | |
parent | 7b0a764fee6e1614f3249e9082d8c4acf1dc62d5 (diff) | |
download | numpy-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.c | 27 | ||||
-rw-r--r-- | numpy/core/tests/test_dtype.py | 20 |
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) |