From 92f4673e20e19e6ce6d84c462f1818fbd41e0b3b Mon Sep 17 00:00:00 2001 From: sayed ahrar Date: Thu, 1 Oct 2026 13:15:07 +0530 Subject: [PATCH] reject negative indices in numpy array bounds checks --- include/pybind11/numpy.h | 6 +++--- tests/test_numpy_array.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index a26ac2b4cd..4b2a2de8c5 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -1158,7 +1158,7 @@ class array : public buffer { /// Dimension along a given axis ssize_t shape(ssize_t dim) const { - if (dim >= ndim()) { + if (dim < 0 || dim >= ndim()) { fail_dim_check(dim, "invalid axis"); } return shape()[dim]; @@ -1176,7 +1176,7 @@ class array : public buffer { /// Stride along a given axis ssize_t strides(ssize_t dim) const { - if (dim >= ndim()) { + if (dim < 0 || dim >= ndim()) { fail_dim_check(dim, "invalid axis"); } return strides()[dim]; @@ -1356,7 +1356,7 @@ class array : public buffer { template void check_dimensions_impl(ssize_t axis, const ssize_t *shape, ssize_t i, Ix... index) const { - if (i >= *shape) { + if (i < 0 || i >= *shape) { throw index_error(std::string("index ") + std::to_string(i) + " is out of bounds for axis " + std::to_string(axis) + " with size " + std::to_string(*shape)); diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index e3f29e92a6..71e79ef242 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -69,6 +69,12 @@ def test_array_attributes(): with pytest.raises(IndexError) as excinfo: m.strides(a, 2) assert str(excinfo.value) == "invalid axis: 2 (ndim = 2)" + with pytest.raises(IndexError) as excinfo: + m.shape(a, -1) + assert str(excinfo.value) == "invalid axis: -1 (ndim = 2)" + with pytest.raises(IndexError) as excinfo: + m.strides(a, -1) + assert str(excinfo.value) == "invalid axis: -1 (ndim = 2)" assert not m.writeable(a) assert m.size(a) == 6 assert m.itemsize(a) == 2 @@ -217,6 +223,14 @@ def test_bounds_check(arr): with pytest.raises(IndexError) as excinfo: func(arr, 0, 4) assert str(excinfo.value) == "index 4 is out of bounds for axis 1 with size 3" + # Negative indices are out of bounds too (they would address memory + # before the start of the buffer). + with pytest.raises(IndexError) as excinfo: + func(arr, -1, 0) + assert str(excinfo.value) == "index -1 is out of bounds for axis 0 with size 2" + with pytest.raises(IndexError) as excinfo: + func(arr, 0, -1) + assert str(excinfo.value) == "index -1 is out of bounds for axis 1 with size 3" def test_make_c_f_array():