mirror of
https://github.com/golang/go
synced 2024-11-22 14:15:05 -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;
|
byte *b, *arena_start, *arena_used;
|
||||||
uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
|
uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
|
||||||
uintptr *pc, precise_type, nominal_size;
|
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;
|
void *obj;
|
||||||
Type *t;
|
Type *t;
|
||||||
Slice *sliceptr;
|
Slice *sliceptr;
|
||||||
@ -1062,13 +1062,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
|
|||||||
if(!(chantype->elem->kind & KindNoPointers)) {
|
if(!(chantype->elem->kind & KindNoPointers)) {
|
||||||
// Channel's buffer follows Hchan immediately in memory.
|
// Channel's buffer follows Hchan immediately in memory.
|
||||||
// Size of buffer (cap(c)) is second int in the chan struct.
|
// Size of buffer (cap(c)) is second int in the chan struct.
|
||||||
n = ((uintgo*)chan)[1];
|
chancap = ((uintgo*)chan)[1];
|
||||||
if(n > 0) {
|
if(chancap > 0) {
|
||||||
// TODO(atom): split into two chunks so that only the
|
// TODO(atom): split into two chunks so that only the
|
||||||
// in-use part of the circular buffer is scanned.
|
// in-use part of the circular buffer is scanned.
|
||||||
// (Channel routines zero the unused part, so the current
|
// (Channel routines zero the unused part, so the current
|
||||||
// code does not lead to leaks, it's just a little inefficient.)
|
// 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};
|
(uintptr)chantype->elem->gc | PRECISE | LOOP};
|
||||||
if(objbufpos == objbuf_end)
|
if(objbufpos == objbuf_end)
|
||||||
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
|
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
|
||||||
|
Loading…
Reference in New Issue
Block a user