mirror of
https://github.com/golang/go
synced 2024-11-22 09:04:42 -07:00
runtime: fix heap corruption during GC
The 'n' variable is used during rescan initiation in GC_END case, but it's overwritten with chan capacity in GC_CHAN case. As the result rescan is done with the wrong object size. Fixes #5554. R=golang-dev, khr CC=golang-dev https://golang.org/cl/9831043
This commit is contained in:
parent
d8fd8d89ea
commit
2f5825d427
@ -121,3 +121,31 @@ func TestGcArraySlice(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGcRescan(t *testing.T) {
|
||||
type X struct {
|
||||
c chan error
|
||||
nextx *X
|
||||
}
|
||||
type Y struct {
|
||||
X
|
||||
nexty *Y
|
||||
p *int
|
||||
}
|
||||
var head *Y
|
||||
for i := 0; i < 10; i++ {
|
||||
p := &Y{}
|
||||
p.c = make(chan error)
|
||||
p.nextx = &head.X
|
||||
p.nexty = head
|
||||
p.p = new(int)
|
||||
*p.p = 42
|
||||
head = p
|
||||
runtime.GC()
|
||||
}
|
||||
for p := head; p != nil; p = p.nexty {
|
||||
if *p.p != 42 {
|
||||
t.Fatal("corrupted heap")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +623,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
|
||||
byte *b, *arena_start, *arena_used;
|
||||
uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
|
||||
uintptr *pc, precise_type, nominal_size;
|
||||
uintptr *map_ret, mapkey_size, mapval_size, mapkey_ti, mapval_ti, *chan_ret;
|
||||
uintptr *map_ret, mapkey_size, mapval_size, mapkey_ti, mapval_ti, *chan_ret, chancap;
|
||||
void *obj;
|
||||
Type *t;
|
||||
Slice *sliceptr;
|
||||
@ -1062,13 +1062,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
|
||||
if(!(chantype->elem->kind & KindNoPointers)) {
|
||||
// Channel's buffer follows Hchan immediately in memory.
|
||||
// Size of buffer (cap(c)) is second int in the chan struct.
|
||||
n = ((uintgo*)chan)[1];
|
||||
if(n > 0) {
|
||||
chancap = ((uintgo*)chan)[1];
|
||||
if(chancap > 0) {
|
||||
// TODO(atom): split into two chunks so that only the
|
||||
// in-use part of the circular buffer is scanned.
|
||||
// (Channel routines zero the unused part, so the current
|
||||
// code does not lead to leaks, it's just a little inefficient.)
|
||||
*objbufpos++ = (Obj){(byte*)chan+runtime·Hchansize, n*chantype->elem->size,
|
||||
*objbufpos++ = (Obj){(byte*)chan+runtime·Hchansize, chancap*chantype->elem->size,
|
||||
(uintptr)chantype->elem->gc | PRECISE | LOOP};
|
||||
if(objbufpos == objbuf_end)
|
||||
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
|
||||
|
Loading…
Reference in New Issue
Block a user