Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Ensure too many advanced indices raises an exception #18257

Merged
merged 2 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 13 additions & 1 deletion numpy/core/src/multiarray/mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -2328,7 +2328,7 @@ PyArray_MapIterNext(PyArrayMapIterObject *mit)
* @param Number of indices
* @param The array that is being iterated
*
* @return 0 on success -1 on failure
* @return 0 on success -1 on failure (broadcasting or too many fancy indices)
*/
static int
mapiter_fill_info(PyArrayMapIterObject *mit, npy_index_info *indices,
Expand Down Expand Up @@ -2369,6 +2369,17 @@ mapiter_fill_info(PyArrayMapIterObject *mit, npy_index_info *indices,
}
}

/* Before contunuing, ensure that there are not too fancy indices */
if (indices[i].type & HAS_FANCY) {
if (NPY_UNLIKELY(j >= NPY_MAXDIMS)) {
PyErr_Format(PyExc_IndexError,
"too many advanced (array) indices. This probably "
"means you are indexing with too many booleans. "
"(more than %d found)", NPY_MAXDIMS);
return -1;
}
}

/* (iterating) fancy index, store the iterator */
if (indices[i].type == HAS_FANCY) {
mit->fancy_strides[j] = PyArray_STRIDE(arr, curr_dim);
Expand Down Expand Up @@ -2655,6 +2666,7 @@ PyArray_MapIterNew(npy_index_info *indices , int index_num, int index_type,
/* For shape reporting on error */
PyArrayObject *original_extra_op = extra_op;

/* NOTE: MAXARGS is the actual limit (2*NPY_MAXDIMS is index number one) */
PyArrayObject *index_arrays[NPY_MAXDIMS];
PyArray_Descr *intp_descr;
PyArray_Descr *dtypes[NPY_MAXDIMS]; /* borrowed references */
Expand Down
17 changes: 17 additions & 0 deletions numpy/core/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import functools
import operator

import pytest

import numpy as np
from numpy.core._multiarray_tests import array_indexing
from itertools import product
Expand Down Expand Up @@ -547,6 +549,21 @@ def test_character_assignment(self):
assert_array_equal(arr[0], np.array("asdfg", dtype="c"))
assert arr[0, 1] == b"s" # make sure not all were set to "a" for both

@pytest.mark.parametrize("index",
[True, False, np.array([0])])
@pytest.mark.parametrize("num", [32, 40])
@pytest.mark.parametrize("original_ndim", [1, 32])
def test_too_many_advanced_indices(self, index, num, original_ndim):
# These are limitations based on the number of arguments we can process.
# For `num=32` (and all boolean cases), the result is actually define;
# but the use of NpyIter (NPY_MAXARGS) limits it for technical reasons.
arr = np.ones((1,) * original_ndim)
with pytest.raises(IndexError):
arr[(index,) * num]
with pytest.raises(IndexError):
arr[(index,) * num] = 1.


class TestFieldIndexing:
def test_scalar_return_type(self):
# Field access on an array should return an array, even if it
Expand Down