Skip to content

spec: range & go: pass a pointer to an element of array leads to a different behavior with/out go #10132

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

Closed
noxiouz opened this issue Mar 11, 2015 · 4 comments

Comments

@noxiouz
Copy link

noxiouz commented Mar 11, 2015

I met a strange behavior while passing elements of array by pointer to a function. It looks like a bug.
You can find example here:
http://play.golang.org/p/e0dDpyCYCG

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

type Item struct {
    name string
}

func (i *Item) Name() string {
    defer wg.Done()
    return i.name
}

func Go(t *Item) {
    fmt.Println(t.Name())
}

func main() {
    f := make([]Item, 0)
    f = append(f, Item{"1"})
    f = append(f, Item{"2"})
    f = append(f, Item{"3"})
    for _, v := range f {
        wg.Add(1)
        go Go(&v)
    }
    wg.Wait()

This example prints

3
3
3

It doesn't look like an expected behavior.
Moreover this example (http://play.golang.org/p/KY4jEgtgGn) (exactly the same, but without go)

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

type Item struct {
    name string
}

func (i *Item) Name() string {
    defer wg.Done()
    return i.name
}

func Go(t *Item) {
    fmt.Println(t.Name())
}

func main() {
    f := make([]Item, 0)
    f = append(f, Item{"1"})
    f = append(f, Item{"2"})
    f = append(f, Item{"3"})
    for _, v := range f {
        wg.Add(1)
        Go(&v)
    }
    wg.Wait()
}

prints

1
2
3

I checked it on 1.3.3, 1.4.1, 1.4.2

@noxiouz noxiouz changed the title range & go: pass a pointer to an element of array casuses to different behavior with/out go range & go: pass a pointer to an element of array casuses to a different behavior with/out go Mar 11, 2015
@noxiouz noxiouz changed the title range & go: pass a pointer to an element of array casuses to a different behavior with/out go range & go: pass a pointer to an element of array leads to a different behavior with/out go Mar 11, 2015
@minux
Copy link
Member

minux commented Mar 11, 2015

@minux minux closed this as completed Mar 11, 2015
@dvyukov
Copy link
Member

dvyukov commented Mar 11, 2015

Run the program with race detector (go build/test/run -race)

@noxiouz
Copy link
Author

noxiouz commented Mar 11, 2015

What a shame =) Sorry for that. Thanks!

@mikioh mikioh changed the title range & go: pass a pointer to an element of array leads to a different behavior with/out go spec: range & go: pass a pointer to an element of array leads to a different behavior with/out go Mar 11, 2015
@FrankReh
Copy link

You are passing an address to a variable to a goroutine but you let the
value at that address change before the goroutines are potentially run.

The idiomatic way of getting the behavior you want is to create a local
variable within the loop, set it equal to your 'v', and then pass the
address of that local. You will get a new local allocated from the heap
in each iteration this way, and you should get the 1,2,3 output.

On Wed, Mar 11, 2015 at 7:23 AM, Anton Tyurin [email protected]
wrote:

I met a strange behavior while passing elements of array by pointer to a
function. It looks like a bug.
You can find example here:
http://play.golang.org/p/e0dDpyCYCG

package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
type Item struct {
name string
}
func (i *Item) Name() string {
defer wg.Done()
return i.name
}
func Go(t *Item) {
fmt.Println(t.Name())
}
func main() {
f := make([]Item, 0)
f = append(f, Item{"1"})
f = append(f, Item{"2"})
f = append(f, Item{"3"})
for _, v := range f {
wg.Add(1)
go Go(&v)
}
wg.Wait()

This example prints

3
3
3

It doesn't look like an expected behavior.
Moreover this example (http://play.golang.org/p/KY4jEgtgGn) (exactly the
same, but without go)

package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
type Item struct {
name string
}
func (i *Item) Name() string {
defer wg.Done()
return i.name
}
func Go(t *Item) {
fmt.Println(t.Name())
}
func main() {
f := make([]Item, 0)
f = append(f, Item{"1"})
f = append(f, Item{"2"})
f = append(f, Item{"3"})
for _, v := range f {
wg.Add(1)
Go(&v)
}
wg.Wait()
}

prints

1
2
3

I checked it on 1.3.3, 1.4.1, 1.4.2


Reply to this email directly or view it on GitHub
#10132.

@golang golang locked and limited conversation to collaborators Jun 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants