From f210c78395630c3d483f356cf88b62d5fdbf0b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 5 Oct 2020 10:48:46 -0700 Subject: [PATCH] panic with a dedicated error when an array access index is out-of-bounds --- runtime/interpreter/errors.go | 16 ++++++++++ runtime/interpreter/value.go | 13 ++++++++- runtime/tests/interpreter/interpreter_test.go | 29 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/runtime/interpreter/errors.go b/runtime/interpreter/errors.go index 871adca3e9..a2da149223 100644 --- a/runtime/interpreter/errors.go +++ b/runtime/interpreter/errors.go @@ -292,3 +292,19 @@ func (e *CyclicLinkError) Error() string { paths, ) } + +// ArrayIndexOutOfBoundsError + +type ArrayIndexOutOfBoundsError struct { + Index int + MaxIndex int + LocationRange +} + +func (e ArrayIndexOutOfBoundsError) Error() string { + return fmt.Sprintf( + "array index out of bounds: got %d, expected max %d", + e.Index, + e.MaxIndex, + ) +} diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 700e02f92e..937968ea21 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -528,8 +528,19 @@ func (v *ArrayValue) Concat(other ConcatenatableValue) Value { return NewArrayValueUnownedNonCopying(concatenated...) } -func (v *ArrayValue) Get(_ *Interpreter, _ LocationRange, key Value) Value { +func (v *ArrayValue) Get(_ *Interpreter, locationRange LocationRange, key Value) Value { integerKey := key.(NumberValue).ToInt() + count := v.Count() + + // Check bounds + if integerKey < 0 || integerKey >= count { + panic(ArrayIndexOutOfBoundsError{ + Index: integerKey, + MaxIndex: count - 1, + LocationRange: locationRange, + }) + } + return v.Values[integerKey] } diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 9660f6e2c4..90dad72d23 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -474,6 +474,35 @@ func TestInterpretArrayIndexing(t *testing.T) { ) } +func TestInterpretInvalidArrayIndexing(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + fun test(): Int { + let z = [0, 3] + return z[2] + } + `) + + _, err := inter.Invoke("test") + + require.Equal(t, + interpreter.ArrayIndexOutOfBoundsError{ + Index: 2, + MaxIndex: 1, + LocationRange: interpreter.LocationRange{ + Location: TestLocation, + Range: ast.Range{ + StartPos: ast.Position{Offset: 71, Line: 4, Column: 19}, + EndPos: ast.Position{Offset: 73, Line: 4, Column: 21}, + }, + }, + }, + err, + ) +} + func TestInterpretArrayIndexingAssignment(t *testing.T) { t.Parallel()