Commit 0120f837 authored by Russ Cox's avatar Russ Cox

runtime: clear stale values from G.param and SudoG.elem

This change was necessary on the dev.garbage branch
to keep the garbage collector from seeing pointers into
invalid heap areas.

On this default (Go 1.4) branch, the change removes
some possibility for memory leaks.

LGTM=khr
R=golang-codereviews, khr
CC=golang-codereviews, iant, r, rlh
https://golang.org/cl/155760043
parent 3ffd29fb
...@@ -140,10 +140,11 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -140,10 +140,11 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
unlock(&c.lock) unlock(&c.lock)
recvg := sg.g recvg := sg.g
recvg.param = unsafe.Pointer(sg)
if sg.elem != nil { if sg.elem != nil {
memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize)) memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize))
sg.elem = nil
} }
recvg.param = unsafe.Pointer(sg)
if sg.releasetime != 0 { if sg.releasetime != 0 {
sg.releasetime = cputicks() sg.releasetime = cputicks()
} }
...@@ -179,6 +180,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin ...@@ -179,6 +180,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
} }
panic("send on closed channel") panic("send on closed channel")
} }
gp.param = nil
if mysg.releasetime > 0 { if mysg.releasetime > 0 {
blockevent(int64(mysg.releasetime)-t0, 2) blockevent(int64(mysg.releasetime)-t0, 2)
} }
...@@ -278,6 +280,7 @@ func closechan(c *hchan) { ...@@ -278,6 +280,7 @@ func closechan(c *hchan) {
break break
} }
gp := sg.g gp := sg.g
sg.elem = nil
gp.param = nil gp.param = nil
if sg.releasetime != 0 { if sg.releasetime != 0 {
sg.releasetime = cputicks() sg.releasetime = cputicks()
...@@ -292,6 +295,7 @@ func closechan(c *hchan) { ...@@ -292,6 +295,7 @@ func closechan(c *hchan) {
break break
} }
gp := sg.g gp := sg.g
sg.elem = nil
gp.param = nil gp.param = nil
if sg.releasetime != 0 { if sg.releasetime != 0 {
sg.releasetime = cputicks() sg.releasetime = cputicks()
...@@ -372,6 +376,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -372,6 +376,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
if ep != nil { if ep != nil {
memmove(ep, sg.elem, uintptr(c.elemsize)) memmove(ep, sg.elem, uintptr(c.elemsize))
} }
sg.elem = nil
gp := sg.g gp := sg.g
gp.param = unsafe.Pointer(sg) gp.param = unsafe.Pointer(sg)
if sg.releasetime != 0 { if sg.releasetime != 0 {
...@@ -409,9 +414,11 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r ...@@ -409,9 +414,11 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
if mysg.releasetime > 0 { if mysg.releasetime > 0 {
blockevent(mysg.releasetime-t0, 2) blockevent(mysg.releasetime-t0, 2)
} }
haveData := gp.param != nil
gp.param = nil
releaseSudog(mysg) releaseSudog(mysg)
if gp.param != nil { if haveData {
// a sender sent us some data. It already wrote to ep. // a sender sent us some data. It already wrote to ep.
selected = true selected = true
received = true received = true
......
...@@ -148,6 +148,9 @@ func acquireSudog() *sudog { ...@@ -148,6 +148,9 @@ func acquireSudog() *sudog {
c := gomcache() c := gomcache()
s := c.sudogcache s := c.sudogcache
if s != nil { if s != nil {
if s.elem != nil {
gothrow("acquireSudog: found s.elem != nil in cache")
}
c.sudogcache = s.next c.sudogcache = s.next
return s return s
} }
...@@ -168,6 +171,13 @@ func acquireSudog() *sudog { ...@@ -168,6 +171,13 @@ func acquireSudog() *sudog {
//go:nosplit //go:nosplit
func releaseSudog(s *sudog) { func releaseSudog(s *sudog) {
if s.elem != nil {
gothrow("runtime: sudog with non-nil elem")
}
gp := getg()
if gp.param != nil {
gothrow("runtime: releaseSudog with non-nil gp.param")
}
c := gomcache() c := gomcache()
s.next = c.sudogcache s.next = c.sudogcache
c.sudogcache = s c.sudogcache = s
......
...@@ -368,6 +368,7 @@ loop: ...@@ -368,6 +368,7 @@ loop:
// someone woke us up // someone woke us up
sellock(sel) sellock(sel)
sg = (*sudog)(gp.param) sg = (*sudog)(gp.param)
gp.param = nil
// pass 3 - dequeue from unsuccessful chans // pass 3 - dequeue from unsuccessful chans
// otherwise they stack up on quiet channels // otherwise they stack up on quiet channels
...@@ -376,6 +377,10 @@ loop: ...@@ -376,6 +377,10 @@ loop:
// iterating through the linked list they are in reverse order. // iterating through the linked list they are in reverse order.
cas = nil cas = nil
sglist = gp.waiting sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting.
for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
sg1.elem = nil
}
gp.waiting = nil gp.waiting = nil
for i := int(sel.ncase) - 1; i >= 0; i-- { for i := int(sel.ncase) - 1; i >= 0; i-- {
k = &scases[pollorder[i]] k = &scases[pollorder[i]]
...@@ -506,6 +511,7 @@ syncrecv: ...@@ -506,6 +511,7 @@ syncrecv:
if cas.elem != nil { if cas.elem != nil {
memmove(cas.elem, sg.elem, uintptr(c.elemsize)) memmove(cas.elem, sg.elem, uintptr(c.elemsize))
} }
sg.elem = nil
gp = sg.g gp = sg.g
gp.param = unsafe.Pointer(sg) gp.param = unsafe.Pointer(sg)
if sg.releasetime != 0 { if sg.releasetime != 0 {
...@@ -541,6 +547,7 @@ syncsend: ...@@ -541,6 +547,7 @@ syncsend:
if sg.elem != nil { if sg.elem != nil {
memmove(sg.elem, cas.elem, uintptr(c.elemsize)) memmove(sg.elem, cas.elem, uintptr(c.elemsize))
} }
sg.elem = nil
gp = sg.g gp = sg.g
gp.param = unsafe.Pointer(sg) gp.param = unsafe.Pointer(sg)
if sg.releasetime != 0 { if sg.releasetime != 0 {
......
...@@ -173,6 +173,7 @@ func (root *semaRoot) dequeue(s *sudog) { ...@@ -173,6 +173,7 @@ func (root *semaRoot) dequeue(s *sudog) {
} else { } else {
root.head = s.next root.head = s.next
} }
s.elem = nil
s.next = nil s.next = nil
s.prev = nil s.prev = nil
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment