traefik / yaegi

Yaegi is Another Elegant Go Interpreter
https://pkg.go.dev/github.com/traefik/yaegi
Apache License 2.0
6.78k stars 341 forks source link

crash when iterator is nil in rangeMap #1622

Closed poolpOrg closed 2 months ago

poolpOrg commented 2 months ago

The following program sample.go triggers an unexpected result

package main

import "fmt"

func main() {
        myMap := map[string]chan interface{}{}

        for s, _ := range myMap {
                _ = s
        }
}

Expected result

% go run /tmp/crash.go
%

Got

% yaegi /tmp/crash.go
/tmp/crash.go:6:2: panic: main.main(...)
run: runtime error: invalid memory address or nil pointer dereference
goroutine 1 [running]:
runtime/debug.Stack()
        /usr/local/go/src/runtime/debug/stack.go:24 +0x64
github.com/traefik/yaegi/interp.(*Interpreter).Execute.func1()
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/program.go:146 +0x74
panic({0x1052ae780?, 0x1058d7820?})
        /usr/local/go/src/runtime/panic.go:770 +0x124
github.com/traefik/yaegi/interp.runCfg.func1()
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/run.go:226 +0x198
panic({0x1052ae780?, 0x1058d7820?})
        /usr/local/go/src/runtime/panic.go:770 +0x124
reflect.(*MapIter).Next(0x1052dfdc0?)
        /usr/local/go/src/reflect/value.go:1996 +0x18
github.com/traefik/yaegi/interp.rangeMap.func1(0x14000132630)
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/run.go:2911 +0x8c
github.com/traefik/yaegi/interp.runCfg(0x140005137c0, 0x14000132630, 0x0?, 0x0?)
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/run.go:234 +0x21c
github.com/traefik/yaegi/interp.(*Interpreter).run(0x14000034fc8, 0x14000512c80, 0x14000132420?)
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/run.go:119 +0x370
github.com/traefik/yaegi/interp.(*Interpreter).Execute(0x14000034fc8, 0x14000693530)
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/program.go:172 +0x1c8
github.com/traefik/yaegi/interp.(*Interpreter).eval(0x14000034fc8, {0x14000044630?, 0x8f?}, {0x16b6637f0?, 0x1400050e000?}, 0x10?)
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/interp.go:563 +0x64
github.com/traefik/yaegi/interp.(*Interpreter).EvalPath(0x14000034fc8, {0x16b6637f0, 0xd})
        /Users/gchehade/Wip/github.com/traefik/yaegi/interp/interp.go:512 +0xa4
main.runFile(0x14000034fc8, {0x16b6637f0, 0xd}, 0x0)
        /Users/gchehade/Wip/github.com/traefik/yaegi/cmd/yaegi/run.go:153 +0xe8
main.run({0x14000032050, 0x1, 0x1})
        /Users/gchehade/Wip/github.com/traefik/yaegi/cmd/yaegi/run.go:116 +0xae4
main.main()
        /Users/gchehade/Wip/github.com/traefik/yaegi/cmd/yaegi/yaegi.go:144 +0x308
%

Yaegi Version

<= v0.16.1

Additional Notes

Unsure if this is the proper fix and why iter would be nil in the first place, but the following diff fixes the issue:

diff --git a/interp/run.go b/interp/run.go
index 1ec6760..e1464e8 100644
--- a/interp/run.go
+++ b/interp/run.go
@@ -2908,7 +2908,7 @@ func rangeMap(n *node) {
                value = genValue(n.child[2]) // map
                n.exec = func(f *frame) bltn {
                        iter := f.data[index2].Interface().(*reflect.MapIter)
-                       if !iter.Next() {
+                       if iter == nil || !iter.Next() {
                                return fnext
                        }
                        f.data[index0].Set(iter.Key())
mvertes commented 2 months ago

Thank you for this report. The correct fix is a little bit more complicated than what you have proposed, but you were on the right track.