goformation
goformation copied to clipboard
ParseYAML/ParseYAMLWithOptions is not thread-safe and can cause "concurrent map writes" errors
What
ParseYAMLWithOptions calls intrinsics.ProcessYAML, which calls registerTagMarshallers(), but registerTagMarshallers() is not thread-safe.
registerTagMarshallers() calls yaml.RegisterTagUnmarshaler which writes to a map without ensuring non-parallel writes (e.g. using locking).
fatal error: concurrent map writes
goroutine 11326 [running]:
runtime.throw(0x4141fc4, 0x15)
/usr/local/Cellar/go/1.15.8/libexec/src/runtime/panic.go:1116 +0x72 fp=0xc003ffe300 sp=0xc003ffe2d0 pc=0x437912
runtime.mapassign_faststr(0x3836700, 0xc00044d9b0, 0xc004b96590, 0x4, 0x3)
/usr/local/Cellar/go/1.15.8/libexec/src/runtime/map_faststr.go:211 +0x3f1 fp=0xc003ffe368 sp=0xc003ffe300 pc=0x414891
github.com/sanathkr/go-yaml.registerCustomTagUnmarshaler(...)
/Users/andras/src/github.com/acme/project/vendor/github.com/sanathkr/go-yaml/decode.go:213
github.com/sanathkr/go-yaml.RegisterTagUnmarshaler(...)
/Users/andras/src/github.com/acme/project/vendor/github.com/sanathkr/go-yaml/yaml.go:169
github.com/awslabs/goformation/v4/intrinsics.registerTagMarshallers()
/Users/andras/src/github.com/acme/project/vendor/github.com/awslabs/goformation/v4/intrinsics/tags.go:39 +0xcb fp=0xc003ffe3d0 sp=0xc003ffe368 pc=0x2712c2b
github.com/awslabs/goformation/v4/intrinsics.ProcessYAML(0xc006196400, 0xac7, 0xc00, 0x0, 0xac7, 0xc00, 0xc00, 0xac7, 0xc006196400)
/Users/andras/src/github.com/acme/project/vendor/github.com/awslabs/goformation/v4/intrinsics/intrinsics.go:64 +0x26 fp=0xc003ffe438 sp=0xc003ffe3d0 pc=0x2710566
github.com/awslabs/goformation/v4.ParseYAMLWithOptions(0xc006196400, 0xac7, 0xc00, 0x0, 0xac7, 0xc00, 0x7fa0feefbc60)
/Users/andras/src/github.com/acme/project/vendor/github.com/awslabs/goformation/v4/goformation.go:47 +0x4d fp=0xc003ffe490 sp=0xc003ffe438 pc=0x27ae3ad
github.com/awslabs/goformation/v4.ParseYAML(...)
/Users/andras/src/github.com/acme/project/vendor/github.com/awslabs/goformation/v4/goformation.go:40
[...]
It's using a package scoped (global) map, so if you have multiple parts of your code, e.g. go routines operating on completely different CF templates, you hit this issue :facepalm: