golang竞争条件-在2个goroutine中将其封送为XML

i am getting data race condition when i try to marshal Struct to XML in a GoRoutine of 2 or more.

Sample main program : http://play.golang.org/p/YhkWXWL8C0

i believe xml:"members>member" causing this . if i change it to normal then all works fine. any thoughts why go-1.4.x version doing that.

Family struct {
    XMLName xml.Name `xml:"family"`
    Name    string   `xml:"famil_name"`
    Members []Person `xml:"members>member"`
    //Members []Person `xml:"members"`
}

go run -race data_race.go giving me

2015/02/06 13:53:43  Total GoRoutine Channels Created 2
2015/02/06 13:53:43 <family><famil_name></famil_name><members><person><name>ABCD</name><age>0</age></person><person><name>dummy</name><age>0</age></person></members></family>
==================
WARNING: DATA RACE
Write by goroutine 6:
  runtime.slicecopy()
      /usr/local/go/src/runtime/slice.go:94 +0x0
  encoding/xml.(*parentStack).push()
      /usr/local/go/src/encoding/xml/marshal.go:908 +0x2fb
  encoding/xml.(*printer).marshalStruct()
      /usr/local/go/src/encoding/xml/marshal.go:826 +0x628
  encoding/xml.(*printer).marshalValue()
      /usr/local/go/src/encoding/xml/marshal.go:531 +0x1499
  encoding/xml.(*Encoder).Encode()
      /usr/local/go/src/encoding/xml/marshal.go:153 +0xb8
  encoding/xml.Marshal()
      /usr/local/go/src/encoding/xml/marshal.go:72 +0xfb
  main.ToXml()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:51 +0x227
  main.func·001()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:61 +0x74

Previous read by goroutine 5:
  encoding/xml.(*parentStack).trim()
      /usr/local/go/src/encoding/xml/marshal.go:893 +0x2ae
  encoding/xml.(*printer).marshalStruct()
      /usr/local/go/src/encoding/xml/marshal.go:836 +0x203
  encoding/xml.(*printer).marshalValue()
      /usr/local/go/src/encoding/xml/marshal.go:531 +0x1499
  encoding/xml.(*Encoder).Encode()
      /usr/local/go/src/encoding/xml/marshal.go:153 +0xb8
  encoding/xml.Marshal()
      /usr/local/go/src/encoding/xml/marshal.go:72 +0xfb
  main.ToXml()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:51 +0x227
  main.func·001()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:61 +0x74

Goroutine 6 (running) created at:
  main.AsyncExecute()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:67 +0x15d
  main.main()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:80 +0x2bf

Goroutine 5 (finished) created at:
  main.AsyncExecute()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:67 +0x15d
  main.main()
      /Users/kadalamittai/selfie/go/src/github.com/ivam/goal/command/data_race.go:80 +0x2bf
==================

This looks like a bug in the Go 1.41 library. I've reported it as a bug. Hopefully it should get fixed. I'll leave the analysis below for reference.


What's happening is that there's an implicit shared value due to the use of getTypeInfo() which returns a type description of the struct. For efficiency, it appears to be globally cached state. Other parts of the XML encoder take components of this state and pass it around. It appears that there's an inadvertent mutation happening due to a slice append on a component of the shared value.

The p.stack attribute that's reporting as the source of the data race originates from a part of the typeInfo shared value, where a slice of tinfo.parents gets injected on line 821. That's ultimately where the sharing is happening with the potential for read and writing, because later on there are appends happening on the slice, and that can do mutation on the underlying array.

What should probably happen instead is that the slice should be capacity-restricted so that any potential append won't do a write on the shared array value.

That is, line 897 of the encoder library could probably be be changed from:

897        s.stack = parents[:split]

to:

897        s.stack = parents[:split:split]

to correct the issue.