Repository: d5/tengo
Pull request #394 (2022-09-25 17:22:11)

fix slice low/high index shadowing variables in vm
Variables `low` and `high` are being shadowed. Therefore, when slice index is invalid (not an `integer`), the error message does not gives *correct* invalid type hint, and always return `Runtime Error: invalid slice index type: int`

geseq: @ipsusila did you mean to add the encode/decode to this PR? 
ipsusila: @geseq I'm sorry that the PR is confusing. After I submitting the PR which is the fix for low/high variables, I add commit which includes Encode/Decode to `Compiled` to `forked` repo. I did't realised that the later commit also included in this PR. 

For Encode/Decode feature, I need your suggestions, wether it's acceptable to add such feature. If yes, should I separate the PR, or can we simply change the title and submit both PR?
geseq: No worries at all. 

Ideally please move it to a separate PR. I’ll take a look at it later.


ipsusila: Thank you @geseq I revert Encode/Decode related commit from PR. For Encode/decode, later I will submit the PR.

Patch:
diff --git a/vm.go b/vm.go
index 83e49fd..64bd23b 100644
--- a/vm.go
+++ b/vm.go
@@ -376,8 +376,8 @@ func (v *VM) run() {
 
 			var lowIdx int64
 			if low != UndefinedValue {
-				if low, ok := low.(*Int); ok {
-					lowIdx = low.Value
+				if lowInt, ok := low.(*Int); ok {
+					lowIdx = lowInt.Value
 				} else {
 					v.err = fmt.Errorf("invalid slice index type: %s",
 						low.TypeName())
@@ -391,8 +391,8 @@ func (v *VM) run() {
 				var highIdx int64
 				if high == UndefinedValue {
 					highIdx = numElements
-				} else if high, ok := high.(*Int); ok {
-					highIdx = high.Value
+				} else if highInt, ok := high.(*Int); ok {
+					highIdx = highInt.Value
 				} else {
 					v.err = fmt.Errorf("invalid slice index type: %s",
 						high.TypeName())
@@ -428,8 +428,8 @@ func (v *VM) run() {
 				var highIdx int64
 				if high == UndefinedValue {
 					highIdx = numElements
-				} else if high, ok := high.(*Int); ok {
-					highIdx = high.Value
+				} else if highInt, ok := high.(*Int); ok {
+					highIdx = highInt.Value
 				} else {
 					v.err = fmt.Errorf("invalid slice index type: %s",
 						high.TypeName())
@@ -465,8 +465,8 @@ func (v *VM) run() {
 				var highIdx int64
 				if high == UndefinedValue {
 					highIdx = numElements
-				} else if high, ok := high.(*Int); ok {
-					highIdx = high.Value
+				} else if highInt, ok := high.(*Int); ok {
+					highIdx = highInt.Value
 				} else {
 					v.err = fmt.Errorf("invalid slice index type: %s",
 						high.TypeName())
@@ -502,8 +502,8 @@ func (v *VM) run() {
 				var highIdx int64
 				if high == UndefinedValue {
 					highIdx = numElements
-				} else if high, ok := high.(*Int); ok {
-					highIdx = high.Value
+				} else if highInt, ok := high.(*Int); ok {
+					highIdx = highInt.Value
 				} else {
 					v.err = fmt.Errorf("invalid slice index type: %s",
 						high.TypeName())


Test patch:
diff --git a/vm_test.go b/vm_test.go
index feb91f4..dcde5ec 100644
--- a/vm_test.go
+++ b/vm_test.go
@@ -1090,6 +1090,15 @@ export func() {
 	b := 5
 	return b + "foo"
 }`), "Runtime Error: invalid operation: int + string\n\tat mod2:4:9")
+
+	expectError(t, `a := [1, 2, 3]; b := a[:"invalid"];`, nil,
+		"Runtime Error: invalid slice index type: string")
+	expectError(t, `a := immutable([4, 5, 6]); b := a[:false];`, nil,
+		"Runtime Error: invalid slice index type: bool")
+	expectError(t, `a := "hello"; b := a[:1.23];`, nil,
+		"Runtime Error: invalid slice index type: float")
+	expectError(t, `a := bytes("world"); b := a[:time(1)];`, nil,
+		"Runtime Error: invalid slice index type: time")
 }
 
 func TestVMErrorUnwrap(t *testing.T) {