aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/walk.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/walk.go')
-rw-r--r--src/cmd/compile/internal/gc/walk.go41
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
}