From 6bec180a9b5b89bec290e3c41cc23b01310723fc Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Tue, 14 Jul 2026 20:57:04 +0200 Subject: [PATCH] fix(arrow/scalar): reject negative indices in GetScalar GetScalar only guarded the upper bound (idx >= arr.Len()), and the IsNull(idx) call ran before that check, so a negative index panicked inside the null-bitmap lookup instead of returning an error. Check both bounds first and return arrow.ErrIndex for any out-of-range index. Signed-off-by: Fredrik Fornwall --- arrow/scalar/scalar.go | 10 +++++----- arrow/scalar/scalar_test.go | 13 +++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/arrow/scalar/scalar.go b/arrow/scalar/scalar.go index f3dd8f99..fa47c975 100644 --- a/arrow/scalar/scalar.go +++ b/arrow/scalar/scalar.go @@ -574,13 +574,13 @@ func init() { // GetScalar creates a scalar object from the value at a given index in the // passed in array, returns an error if unable to do so. func GetScalar(arr arrow.Array, idx int) (Scalar, error) { - if arr.DataType().ID() != arrow.DICTIONARY && arr.IsNull(idx) { - return MakeNullScalar(arr.DataType()), nil + if idx < 0 || idx >= arr.Len() { + return nil, fmt.Errorf("%w: called GetScalar with index out of range", + arrow.ErrIndex) } - if idx >= arr.Len() { - return nil, fmt.Errorf("%w: called GetScalar with index larger than array len", - arrow.ErrIndex) + if arr.DataType().ID() != arrow.DICTIONARY && arr.IsNull(idx) { + return MakeNullScalar(arr.DataType()), nil } switch arr := arr.(type) { diff --git a/arrow/scalar/scalar_test.go b/arrow/scalar/scalar_test.go index 453e115b..36fd16bd 100644 --- a/arrow/scalar/scalar_test.go +++ b/arrow/scalar/scalar_test.go @@ -1110,6 +1110,19 @@ func TestDictionaryScalarBasics(t *testing.T) { } } +func TestGetScalarIndexOutOfRange(t *testing.T) { + mem := memory.NewCheckedAllocator(memory.DefaultAllocator) + defer mem.AssertSize(t, 0) + + arr, _, _ := array.FromJSON(mem, arrow.BinaryTypes.String, strings.NewReader(`["alpha", "beta"]`)) + defer arr.Release() + + _, err := scalar.GetScalar(arr, -1) + assert.ErrorIs(t, err, arrow.ErrIndex) + _, err = scalar.GetScalar(arr, 2) + assert.ErrorIs(t, err, arrow.ErrIndex) +} + func TestDictionaryScalarValidateErrors(t *testing.T) { mem := memory.NewCheckedAllocator(memory.DefaultAllocator) defer mem.AssertSize(t, 0)