Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

staticcheck: detect access to modified closure #51

Open
judwhite opened this issue Mar 6, 2017 · 4 comments
Open

staticcheck: detect access to modified closure #51

judwhite opened this issue Mar 6, 2017 · 4 comments

Comments

@judwhite
Copy link

judwhite commented Mar 6, 2017

Example bad code:

for _, pr := range prs {
	go func(prNumber int) {
		addPRLabel(gh, prNumber, pr.Base.Ref) // oops
		wg.Done()
	}(pr.Number)
}
@dominikh
Copy link
Owner

dominikh commented Mar 7, 2017

Not a priority because go vet already catches this.

@johanbrandhorst
Copy link

I think this issue should be extended to any use of loop variables inside closures, where the closure isn't executed before the next iteration. That would be quite complicated but apparently possible.

See https://golang.org/doc/faq#closures_and_goroutines and https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables for discussion on this problem from official sources, though specifically referring to the use of goroutines, which is probably the most common.

As anecdotal evidence I can also say that using Ginkgo, which relies on closures, this issue crops up quite a bit, unrelated to goroutines. A linter that could detect any incorrect loop variables in closures would be very valuable.

@bradleyfalzon
Copy link
Contributor

@johanbrandhorst the issue that wiki page points out, as mentioned by @dominikh, is picked up in go vet:

package main

import "fmt"

func main() {
        values := []int{1, 2, 3}
        for val := range values {
                go func() {
                        fmt.Println(val) // main.go:9: range variable val captured by func literal
                }()
        }
}

Or were you referring to something different?

@johanbrandhorst
Copy link

johanbrandhorst commented Apr 12, 2017

This isn't unique to goroutines, and vet doesn't cover the following problematic code:

package main

import "fmt"

func main() {
	values := []int{1, 2, 3}
	var funcs []func()
	for _, val := range values {
		funcs = append(funcs, func() {
			fmt.Println(val)
		})
	}
	for _, f :=  range funcs {
		f()
	}
}

See https://play.golang.org/p/QQgUiKv4xE

Output:

3
3
3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants