Skip to content

Commit

Permalink
Merge pull request numpy#12112 from mattip/get_field-offset-check
Browse files Browse the repository at this point in the history
ENH: check getfield arguments to prevent invalid memory access
  • Loading branch information
charris authored Oct 9, 2018
2 parents fb58c06 + 300e9f1 commit 8a560b9
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
5 changes: 5 additions & 0 deletions doc/release/1.16.0-notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,9 @@ Previously `np.core.umath` and `np.core.multiarray` were the c-extension
modules, they are now python wrappers to the single `np.core/_multiarray_math`
c-extension module.

``getfield`` validity checks extended
----------------------------------------
`numpy.ndarray.getfield` now checks the dtype and offset arguments to prevent
accessing invalid memory locations.

.. _`NEP 15` : http://www.numpy.org/neps/nep-0015-merge-multiarray-umath.html
17 changes: 17 additions & 0 deletions numpy/core/src/multiarray/methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset)
PyObject *ret = NULL;
PyObject *safe;
static PyObject *checkfunc = NULL;
int self_elsize, typed_elsize;

/* check that we are not reinterpreting memory containing Objects. */
if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(typed)) {
Expand All @@ -373,6 +374,22 @@ PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset)
}
Py_DECREF(safe);
}
self_elsize = PyArray_ITEMSIZE(self);
typed_elsize = typed->elsize;

/* check that values are valid */
if (typed_elsize > self_elsize) {
PyErr_SetString(PyExc_ValueError, "new type is larger than original type");
return NULL;
}
if (offset < 0) {
PyErr_SetString(PyExc_ValueError, "offset is negative");
return NULL;
}
if (offset > self_elsize - typed_elsize) {
PyErr_SetString(PyExc_ValueError, "new type plus offset is larger than original type");
return NULL;
}

ret = PyArray_NewFromDescr_int(
Py_TYPE(self), typed,
Expand Down
16 changes: 16 additions & 0 deletions numpy/core/tests/test_multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -7662,3 +7662,19 @@ def test_uintalignment_and_alignment():
# check that copy code doesn't complain in debug mode
dst = np.zeros((2,2), dtype='c8')
dst[:,1] = src[:,1] # assert in lowlevel_strided_loops fails?

def test_getfield():
a = np.arange(32, dtype='uint16')
if sys.byteorder == 'little':
i = 0
j = 1
else:
i = 1
j = 0
b = a.getfield('int8', i)
assert_equal(b, a)
b = a.getfield('int8', j)
assert_equal(b, 0)
pytest.raises(ValueError, a.getfield, 'uint8', -1)
pytest.raises(ValueError, a.getfield, 'uint8', 16)
pytest.raises(ValueError, a.getfield, 'uint64', 0)

0 comments on commit 8a560b9

Please sign in to comment.