From d2825ad0fa64f57eda94be4e36d39bcb3d25e569 Mon Sep 17 00:00:00 2001 From: Larry Frieson Date: Mon, 18 Dec 2023 12:20:50 -0800 Subject: [PATCH] Add missing array__remove() tests --- exec/cnex/global.c | 11 +++++++++-- exec/csnex/Builtin.cs | 2 +- exec/gonex/gonex.go | 6 ++++-- exec/jnex/src/org/neon_lang/jnex/Executor.java | 12 ++++++++++-- exec/pynex/pynex.py | 7 +++++-- rtl/c/neon.c | 6 +++--- rtl/js/global.js | 6 ++++++ rtl/jvm/neon/Builtin.java | 10 ++++++++++ t/array-remove.neon | 5 +++++ tools/helium.py | 6 ++---- 10 files changed, 55 insertions(+), 16 deletions(-) diff --git a/exec/cnex/global.c b/exec/cnex/global.c index 35434dd48e..151cc3f9b3 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 390b4dce78..f409770b47 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 e3365ab08d..5304a8592d 100644 --- a/exec/gonex/gonex.go +++ b/exec/gonex/gonex.go @@ -1933,12 +1933,14 @@ 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)}) + } else 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 283c2655be..e73f5ad4d8 100644 --- a/exec/jnex/src/org/neon_lang/jnex/Executor.java +++ b/exec/jnex/src/org/neon_lang/jnex/Executor.java @@ -1320,9 +1320,17 @@ 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(); - a.remove(index); + if (index.stripTrailingZeros().scale() > 0 || 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.intValueExact()); } private void array__reversed() diff --git a/exec/pynex/pynex.py b/exec/pynex/pynex.py index 0261c3f41c..a933e8c39b 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) < len(a): + self.raise_literal("PANIC", "Array index exceeds size {}: {}".format(len(a), index)) return del a[int(index)] diff --git a/rtl/c/neon.c b/rtl/c/neon.c index 479ce46348..8d647b184a 100644 --- a/rtl/c/neon.c +++ b/rtl/c/neon.c @@ -1001,12 +1001,12 @@ Ne_Exception *Ne_builtin_array__find(Ne_Number *result, const Ne_Array *a, void Ne_Exception *Ne_builtin_array__remove(Ne_Array *a, const Ne_Number *index) { - int i = (int)index->dval; - if (i < 0) { + if (index->dval != trunc(index->dval) || index->dval < 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); } + int i = (int)index->dval; if (i >= a->size) { char buf[100]; snprintf(buf, sizeof(buf), "Array index exceeds size %d: %g", a->size, index->dval); diff --git a/rtl/js/global.js b/rtl/js/global.js index 5adcc3e826..5ee5a2ee0d 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 c274b83b31..a8abf18662 100644 --- a/rtl/jvm/neon/Builtin.java +++ b/rtl/jvm/neon/Builtin.java @@ -90,6 +90,16 @@ 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) { + int size = 0; + if (self != null) { + size = self.size(); + } + if (!index.isInteger() || index.intValue() < 0) { + throw new neon.type.NeonException("PANIC", "Invalid array index: " + index.toString()); + } + if (index.intValue() >= size) { + throw new neon.type.NeonException("PANIC", "Array index exceeds size " + self + ": " + index.toString()); + } self.remove(index.intValue()); return new Object[] { null, diff --git a/t/array-remove.neon b/t/array-remove.neon index 8861972063..37e2fb29c6 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" diff --git a/tools/helium.py b/tools/helium.py index 60eee7c3c4..b24b590815 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]