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
- It seems to fail on
fmt.Sprintf("stopping at baz: %d", baz)
, but only inside the loop - It does not panic if I change uint64 to uint32 for example
- 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