cmd/compile: remove races introduced in abiutils field update

This fix uses mutex around the problematic store and subsequent access;
if this causes performance problems later a better fix is to do all the
ABI binding in gc/walk where it is single-threaded.

Change-Id: I488f28ab75beb8351c856fd50b0095cab463642e
Reviewed-on: https://go-review.googlesource.com/c/go/+/298109
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
David Chase 2021-03-02 23:39:12 -05:00
parent 3e524ee65a
commit d6f6ef6358
2 changed files with 26 additions and 7 deletions

View file

@ -315,12 +315,31 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo {
return result
}
// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
var parameterUpdateMu sync.Mutex
// FieldOffsetOf returns a concurency-safe version of f.Offset
func FieldOffsetOf(f *types.Field) int64 {
parameterUpdateMu.Lock()
defer parameterUpdateMu.Unlock()
return f.Offset
}
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) {
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
if !isReturn || len(a.Registers) == 0 {
// The type frame offset DOES NOT show effects of minimum frame size.
// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
f.Offset = a.FrameOffset(result)-config.LocalsOffset()
parameterUpdateMu.Lock()
defer parameterUpdateMu.Unlock()
off := a.FrameOffset(result) - config.LocalsOffset()
fOffset := f.Offset
if fOffset == types.BOGUS_FUNARG_OFFSET {
// Set the Offset the first time. After that, we may recompute it, but it should never change.
f.Offset = off
} else if fOffset != off {
panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off))
}
}
}