cosmos72 / gomacro

Interactive Go interpreter and debugger with REPL, Eval, generics and Lisp-like macros

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Problem with accessing uint64 variable inside condition in a loop

Skird opened this issue · comments

Hi! I think I found strange bug when trying to Sprintf uint64 variable

Here is minimal repro

package main

import (
	"fmt"

	"github.com/cosmos72/gomacro/fast"
)

var code = `

import (
	"errors"
	"fmt"
	"math/rand"
)

func GetNewBaz(baz uint64) (uint64, error) {
	if baz > 5 {
		return 3, nil
	}
	return baz, errors.New("fail: baz")
}

func Foo() error {
	var baz uint64 = 10
	q := fmt.Sprintf("starting at baz: %d", baz)
	fmt.Println(q)
	for it := 0; it < 2; it++ {
		newBaz, err := GetNewBaz(baz)
		if err != nil {
			fmt.Println("GetNewBaz errored")
			q := fmt.Sprintf("stopping at baz: %d", baz)
			fmt.Println(q)
			break
		} else {
			baz = newBaz
		}
	}
	return nil
}

`

func main() {
	interp := fast.New()
	interp.Eval(code)
	foo := interp.ValueOf("Foo").Interface().(func() error)
	fmt.Println(foo())
}

It panics like that

$ go run main.go
starting at baz: 10
GetNewBaz errored
panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
github.com/cosmos72/gomacro/fast.(*Symbol).intExpr.func59(0xc000051720?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/identifier.go:964 +0x65
github.com/cosmos72/gomacro/fast.funAsX1.func23(0xc000406198?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/util.go:591 +0x17
github.com/cosmos72/gomacro/fast.call_variadic_ret1.func35(0xc000154460)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/call_variadic.go:423 +0x7d
github.com/cosmos72/gomacro/fast.funAsX1.func35(0xc0000517c8?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/util.go:651 +0x17
github.com/cosmos72/gomacro/fast.(*Comp).DeclVar0.func5(0xc000154460)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/declaration.go:536 +0x35
github.com/cosmos72/gomacro/fast.(*Code).Exec.exec.func2(0xc000154000?)
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/code.go:176 +0x25c
github.com/cosmos72/gomacro/fast.(*Comp).funcGeneric.func2.1({0x236d560, 0x0, 0x0?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/fast/function.go:438 +0xe9
github.com/cosmos72/gomacro/xreflect.MakeFunc.func1({0x236d560, 0x0, 0x0?})
        /home/divashchenko/go/pkg/mod/github.com/cosmos72/gomacro@v0.0.0-20240506194242-2ff796e3da10/xreflect/wrap.go:39 +0xa3
main.main()
        /home/divashchenko/workspace/goplay/main.go:48 +0x5e
exit status 2
  1. It seems to fail on fmt.Sprintf("stopping at baz: %d", baz), but only inside the loop
  2. It does not panic if I change uint64 to uint32 for example
  3. It panics in the same way on REPL too

It seems the line in fast/identifier.go:964 is the culprit
I'm not sure why, but uint64 is treated differently that other types

Hope that helps and thanks again for the cool package! :)

Seems like it has nothing to do with Sprintf, just any reference to baz variable in that branch leads to the same error

package main

import (
	"fmt"

	"github.com/cosmos72/gomacro/fast"
)

var code = `
func Foo() error {
	var baz uint64 = 10
	for it := 0; it < 2; it++ {
		var newBaz uint64
		if baz <= 5 {
			println("Going to access baz")
			bbaz := uint32(baz)
			println(bbaz)
			break
		} else {
			baz = 3
		}
	}
	return nil
}
`

func main() {
	interp := fast.New()
	interp.Eval(code)
	foo := interp.ValueOf("Foo").Interface().(func() error)
	fmt.Println(foo())
}

Prints Going to access baz and then panics
If unused variable newBaz is declared outside loop or not decladred at all everything is ok

UPD: even smaller example