diff --git a/exec/cnex/global.c b/exec/cnex/global.c index 35434dd48..151cc3f9b 100644 --- a/exec/cnex/global.c +++ b/exec/cnex/global.c @@ -633,15 +633,22 @@ void array__remove(TExecutor *exec) Number index = top(exec->stack)->number; pop(exec->stack); Cell *addr = top(exec->stack)->address; pop(exec->stack); - if (!number_is_integer(index)) { + if (!number_is_integer(index) || number_is_negative(index)) { char buf[100]; - snprintf(buf, sizeof(buf), "Array index not an integer: %s", number_to_string(index)); + snprintf(buf, sizeof(buf), "Invalid array index: %s", number_to_string(index)); exec->rtl_raise(exec, "PANIC", buf); return; } cell_ensureArray(addr); size_t i = number_to_uint64(index); + if (i >= addr->array->size) { + char buf[100]; + snprintf(buf, sizeof(buf), "Array index exceeds size %zd: %s", addr->array->size, number_to_string(index)); + exec->rtl_raise(exec, "PANIC", buf); + return; + } + cell_clearCell(&addr->array->data[i]); array_removeItem(addr->array, i); } diff --git a/exec/csnex/Builtin.cs b/exec/csnex/Builtin.cs index 390b4dce7..f409770b4 100644 --- a/exec/csnex/Builtin.cs +++ b/exec/csnex/Builtin.cs @@ -100,7 +100,7 @@ public void array__remove() Exec.Raise("PANIC", "Invalid array index: " + index.ToString()); return; } - if (Number.number_to_int32(index) > array.Count) { + if (Number.number_to_int32(index) >= array.Count) { Exec.Raise("PANIC", "Array index exceeds size " + array.Count.ToString() + ": " + index.ToString()); return; } diff --git a/exec/gonex/gonex.go b/exec/gonex/gonex.go index e3365ab08..9e22432e8 100644 --- a/exec/gonex/gonex.go +++ b/exec/gonex/gonex.go @@ -1933,12 +1933,15 @@ func (self *executor) op_callp() { } case "builtin$array__remove": index := self.pop().num + r := self.pop().ref + a := r.load().array if index != math.Trunc(index) || index < 0 { self.raise_literal("PANIC", objectString{fmt.Sprintf("Invalid array index: %g", index)}) + } + if int(index) >= len(a) { + self.raise_literal("PANIC", objectString{fmt.Sprintf("Array index exceeds size %g: %g", len(a), index)}) } else { index := int(index) - r := self.pop().ref - a := r.load().array a = append(a[:index], a[index+1:]...) r.store(make_cell_array(a)) } diff --git a/exec/jnex/src/org/neon_lang/jnex/Executor.java b/exec/jnex/src/org/neon_lang/jnex/Executor.java index 283c2655b..9eb337cb3 100644 --- a/exec/jnex/src/org/neon_lang/jnex/Executor.java +++ b/exec/jnex/src/org/neon_lang/jnex/Executor.java @@ -1320,8 +1320,16 @@ private void array__find() private void array__remove() { - int index = stack.removeFirst().getNumber().intValueExact(); + BigDecimal index = stack.removeFirst().getNumber(); List a = stack.removeFirst().getAddress().getArray(); + if (!index.isInteger() || index.intValueExact() < 0) { + raiseLiteral("PANIC", "Invalid array index: " + index.toString()); + return; + } + if (index.intValueExact() >= a.size()) { + raiseLiteral("PANIC", "Array index exceeds size " + a.size() + ": " + index.toString()); + return; + } a.remove(index); } diff --git a/exec/pynex/pynex.py b/exec/pynex/pynex.py index 0261c3f41..4cff151c5 100644 --- a/exec/pynex/pynex.py +++ b/exec/pynex/pynex.py @@ -1473,8 +1473,11 @@ def neon_builtin_array__range(self): def neon_builtin_array__remove(self): index = self.stack.pop() a = self.stack.pop().value - if not is_integer(index): - self.raise_literal("PANIC", "Array index not an integer: {}".format(index)) + if not is_integer(index) and not (0 < index): + self.raise_literal("PANIC", "Invalid array index: {}".format(index)) + return + if int(index) < size(a): + self.raise_literal("PANIC", "Array index exceeds size {}: {}".format(size(a), index)) return del a[int(index)] diff --git a/rtl/c/neon.c b/rtl/c/neon.c index 479ce4634..3127cfcd2 100644 --- a/rtl/c/neon.c +++ b/rtl/c/neon.c @@ -1004,7 +1004,7 @@ Ne_Exception *Ne_builtin_array__remove(Ne_Array *a, const Ne_Number *index) int i = (int)index->dval; if (i < 0) { char buf[100]; - snprintf(buf, sizeof(buf), "Array index is negative: %g", index->dval); + snprintf(buf, sizeof(buf), "Invalid array index: %g", index->dval); return Ne_Exception_raise_info_literal("PANIC", buf); } if (i >= a->size) { diff --git a/rtl/js/global.js b/rtl/js/global.js index 5adcc3e82..5ee5a2ee0 100644 --- a/rtl/js/global.js +++ b/rtl/js/global.js @@ -23,6 +23,12 @@ neon = { }, array__remove: function(self, index) { + if (index != Math.trunc(index) || index < 0) { + throw new neon.NeonException("PANIC", {info: "Invalid array index: " + index}); + } + if (index >= a.length) { + throw new neon.NeonException("PANIC", {info: "Array index exceeds size " + a.length + ": " + index}); + } array.splice(self, index); }, diff --git a/rtl/jvm/neon/Builtin.java b/rtl/jvm/neon/Builtin.java index c274b83b3..e0f85fa67 100644 --- a/rtl/jvm/neon/Builtin.java +++ b/rtl/jvm/neon/Builtin.java @@ -90,6 +90,12 @@ public static neon.type.Array array__range(neon.type.Number first, neon.type.Num } public static Object[] array__remove(neon.type.Array self, neon.type.Number index) { + if (!index.isInteger() || index.intValue() < 0) { + throw new neon.type.NeonException("PANIC", "Invalid array index: " + index.toString()); + } + if (index.intValue() >= self.size()) { + throw new neon.type.NeonException("PANIC", "Array index exceeds size " + self.size() + ": " + index.toString()); + } self.remove(index.intValue()); return new Object[] { null, diff --git a/t/array-remove.neon b/t/array-remove.neon index 886197206..1d030b29e 100644 --- a/t/array-remove.neon +++ b/t/array-remove.neon @@ -3,3 +3,8 @@ a.remove(1) TESTCASE a.size() = 2 TESTCASE a[0] = 1 TESTCASE a[1] = 3 +TESTCASE a.remove(-1) EXPECT PANIC "Invalid array index: -1" +a.remove(0) +TESTCASE a[0] = 3 +a.remove(0) +TESTCASE a.remove(0) EXPECT PANIC "Array index exceeds size 0: 0" \ No newline at end of file diff --git a/tools/helium.py b/tools/helium.py index 60eee7c3c..b24b59081 100644 --- a/tools/helium.py +++ b/tools/helium.py @@ -2954,10 +2954,8 @@ def neon_array_find(a, x): raise NeonException(("PANIC",), "value not found in array") def neon_array_remove(a, n): - if n != int(n): - raise NeonException(("PANIC",), "Array index not an integer: {}".format(n)) - if n < 0: - raise NeonException(("PANIC",), "Array index is negative: {}".format(n)) + if n != int(n) or n < 0: + raise NeonException(("PANIC",), "Invalid array index: {}".format(n)) if n >= len(a): raise NeonException(("PANIC",), "Array index exceeds size {}: {}".format(len(a), n)) del a[n]