From 0659d80608e9ffeaf52bfbf6a09891e049f4753a Mon Sep 17 00:00:00 2001 From: waterWang Date: Fri, 28 Aug 2026 10:51:47 +0800 Subject: [PATCH] GH-51019: [Python] Raise IndexError for out-of-bounds KeyValueMetadata key/value KeyValueMetadata.key(i)/value(i) forwarded the index straight to the C++ KeyValueMetadata::key/value, whose bounds DCHECKs are compiled out in release builds. An out-of-range or negative index (e.g. on an empty metadata object, as reported) therefore performed an unchecked std::vector::operator[] access and segfaulted the process instead of raising a Python exception. Add an explicit bounds check in the Python bindings so negative and out-of-range indexes raise IndexError, matching the behavior of other indexed pyarrow containers. --- python/pyarrow/tests/test_types.py | 28 ++++++++++++++++++++++++++++ python/pyarrow/types.pxi | 18 ++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/python/pyarrow/tests/test_types.py b/python/pyarrow/tests/test_types.py index 4f251d14334..e321317b8bc 100644 --- a/python/pyarrow/tests/test_types.py +++ b/python/pyarrow/tests/test_types.py @@ -1193,6 +1193,34 @@ def test_key_value_metadata(): ], b='BETA') +def test_key_value_metadata_index_errors(): + meta = pa.KeyValueMetadata({'a': 'A', 'b': 'B'}) + + # in-bounds accesses still work + assert meta.key(0) == b'a' + assert meta.key(1) == b'b' + assert meta.value(0) == b'A' + assert meta.value(1) == b'B' + + # out-of-range indexes raise IndexError instead of segfaulting + with pytest.raises(IndexError): + meta.key(2) + with pytest.raises(IndexError): + meta.key(-1) + with pytest.raises(IndexError): + meta.value(2) + with pytest.raises(IndexError): + meta.value(-1) + + # empty metadata: index 0 is out of bounds too + empty = pa.KeyValueMetadata() + assert len(empty) == 0 + with pytest.raises(IndexError): + empty.key(0) + with pytest.raises(IndexError): + empty.value(0) + + def test_key_value_metadata_duplicates(): meta = pa.KeyValueMetadata({'a': '1', 'b': '2'}) diff --git a/python/pyarrow/types.pxi b/python/pyarrow/types.pxi index f9530a34362..ade18d58897 100644 --- a/python/pyarrow/types.pxi +++ b/python/pyarrow/types.pxi @@ -2386,7 +2386,16 @@ cdef class KeyValueMetadata(_Metadata, Mapping): Returns ------- byte + + Raises + ------ + IndexError + If `i` is negative or out of bounds. """ + if i < 0 or i >= self.metadata.size(): + raise IndexError( + f"key index {i} is out of bounds for metadata of size " + f"{self.metadata.size()}") return self.metadata.key(i) def value(self, i): @@ -2398,7 +2407,16 @@ cdef class KeyValueMetadata(_Metadata, Mapping): Returns ------- byte + + Raises + ------ + IndexError + If `i` is negative or out of bounds. """ + if i < 0 or i >= self.metadata.size(): + raise IndexError( + f"value index {i} is out of bounds for metadata of size " + f"{self.metadata.size()}") return self.metadata.value(i) def keys(self):