diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/walk.go')
-rw-r--r-- | src/cmd/compile/internal/gc/walk.go | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 7c2e2ab442..d080d21066 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -2071,6 +2071,29 @@ func isstack(n *Node) bool { return false } +// isReflectHeaderDataField reports whether l is an expression p.Data +// where p has type reflect.SliceHeader or reflect.StringHeader. +func isReflectHeaderDataField(l *Node) bool { + if l.Type != Types[TUINTPTR] { + return false + } + + var tsym *Sym + switch l.Op { + case ODOT: + tsym = l.Left.Type.Sym + case ODOTPTR: + tsym = l.Left.Type.Elem().Sym + default: + return false + } + + if tsym == nil || l.Sym.Name != "Data" || tsym.Pkg.Path != "reflect" { + return false + } + return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader" +} + // Do we need a write barrier for the assignment l = r? func needwritebarrier(l *Node, r *Node) bool { if !use_writebarrier { @@ -2081,15 +2104,21 @@ func needwritebarrier(l *Node, r *Node) bool { return false } - // No write barrier for write of non-pointers. - dowidth(l.Type) - - if !haspointers(l.Type) { + // No write barrier for write to stack. + if isstack(l) { return false } - // No write barrier for write to stack. - if isstack(l) { + // Package unsafe's documentation says storing pointers into + // reflect.SliceHeader and reflect.StringHeader's Data fields + // is valid, even though they have type uintptr (#19168). + if isReflectHeaderDataField(l) { + return true + } + + // No write barrier for write of non-pointers. + dowidth(l.Type) + if !haspointers(l.Type) { return false } |