From: Russ Cox Date: Mon, 25 Aug 2014 18:38:19 +0000 (-0400) Subject: cmd/gc, runtime: treat slices and strings like pointers in garbage collection X-Git-Tag: go1.4beta1~706 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=613383c7651d490aae045eb70cd515b151735766;p=gostls13.git cmd/gc, runtime: treat slices and strings like pointers in garbage collection Before, a slice with cap=0 or a string with len=0 might have its base pointer pointing beyond the actual slice/string data into the next block. The collector had to ignore slices and strings with cap=0 in order to avoid misinterpreting the base pointer. Now, a slice with cap=0 or a string with len=0 still has a base pointer pointing into the actual slice/string data, no matter what. The collector can now always scan the pointer, which means strings and slices are no longer special. Fixes #8404. LGTM=khr, josharian R=josharian, khr, dvyukov CC=golang-codereviews https://golang.org/cl/112570044 --- diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index a9c597cdc8..5fae7a564c 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -254,7 +254,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); goto sbop; diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index 1241a23ea6..5a70fcddaf 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -1599,7 +1599,6 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADD; break; diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index bff2350621..592e81542c 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -247,7 +247,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index 4ac2e92079..a451d7d624 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -1537,14 +1537,12 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADDL; break; case CASE(OADD, TINT64): case CASE(OADD, TUINT64): case CASE(OADD, TPTR64): - case CASE(OADDPTR, TPTR64): a = AADDQ; break; diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index bdf728dbbc..f3093bc26e 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -242,7 +242,6 @@ cgen(Node *n, Node *res) case OOR: case OXOR: case OADD: - case OADDPTR: case OMUL: a = optoas(n->op, nl->type); if(a == AIMULB) { diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 66d5b8d696..9ee418cb78 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -430,7 +430,6 @@ optoas(int op, Type *t) case CASE(OADD, TINT32): case CASE(OADD, TUINT32): case CASE(OADD, TPTR32): - case CASE(OADDPTR, TPTR32): a = AADDL; break; diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index 951170aeff..98556a658f 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -1153,7 +1153,7 @@ exprfmt(Fmt *f, Node *n, int prec) case Csend: return fmtprint(f, "chan<- %N", n->left); default: - if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv) + if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) return fmtprint(f, "chan (%N)", n->left); else return fmtprint(f, "chan %N", n->left); diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 908a5e53d9..86acd88259 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -806,7 +806,8 @@ cgen_eface(Node *n, Node *res) void cgen_slice(Node *n, Node *res) { - Node src, dst, *cap, *len, *offs, *add, *base; + Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con; + Prog *p1, *p2; cap = n->list->n; len = n->list->next->n; @@ -823,6 +824,11 @@ cgen_slice(Node *n, Node *res) // garbage collector can see. base = temp(types[TUINTPTR]); + tmplen = temp(types[TINT]); + if(n->op != OSLICESTR) + tmpcap = temp(types[TINT]); + else + tmpcap = tmplen; if(isnil(n->left)) { tempname(&src, n->left->type); @@ -837,43 +843,62 @@ cgen_slice(Node *n, Node *res) fatal("slicearr is supposed to work on pointer: %+N\n", n); cgen(&src, base); cgen_checknil(base); - if(offs != N) { - add = nod(OADD, base, offs); - typecheck(&add, Erv); - cgen(add, base); - } - } else if(offs == N) { - src.type = types[tptr]; - cgen(&src, base); } else { src.type = types[tptr]; - add = nod(OADDPTR, &src, offs); - typecheck(&add, Erv); - cgen(add, base); + cgen(&src, base); } // committed to the update gvardef(res); + // compute len and cap. + // len = n-i, cap = m-i, and offs = i*width. + // computing offs last lets the multiply overwrite i. + cgen(len, tmplen); + if(n->op != OSLICESTR) + cgen(cap, tmpcap); + + // if new cap != 0 { base += add } + // This avoids advancing base past the end of the underlying array/string, + // so that it cannot point at the next object in memory. + // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. + // In essence we are replacing x[i:j:k] where i == j == k + // or x[i:j] where i == j == cap(x) with x[0:0:0]. + if(offs != N) { + p1 = gjmp(P); + p2 = gjmp(P); + patch(p1, pc); + + nodconst(&con, tmpcap->type, 0); + cmp = nod(OEQ, tmpcap, &con); + typecheck(&cmp, Erv); + bgen(cmp, 1, -1, p2); + + add = nod(OADD, base, offs); + typecheck(&add, Erv); + cgen(add, base); + + patch(p2, pc); + } + // dst.array = src.array [ + lo *width ] dst = *res; dst.xoffset += Array_array; dst.type = types[tptr]; - cgen(base, &dst); // dst.len = hi [ - lo ] dst = *res; dst.xoffset += Array_nel; dst.type = types[simtype[TUINT]]; - cgen(len, &dst); + cgen(tmplen, &dst); if(n->op != OSLICESTR) { // dst.cap = cap [ - lo ] dst = *res; dst.xoffset += Array_cap; dst.type = types[simtype[TUINT]]; - cgen(cap, &dst); + cgen(tmpcap, &dst); } } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 61bb7bd6e4..12c1e98539 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -447,7 +447,6 @@ enum OSUB, // x - y OOR, // x | y OXOR, // x ^ y - OADDPTR, // ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen OADDSTR, // s + "foo" OADDR, // &x OANDAND, // b0 && b1 diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c index e67b0af757..0ad700e82f 100644 --- a/src/cmd/gc/plive.c +++ b/src/cmd/gc/plive.c @@ -1113,8 +1113,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *str; intgo len; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 3:0 = multiword:string + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot *xoffset += t->width; break; @@ -1145,9 +1144,7 @@ twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) // struct { byte *array; uintgo len; uintgo cap; } if((*xoffset & (widthptr-1)) != 0) fatal("twobitwalktype1: invalid TARRAY alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 0); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 2); // 3:1 = multiword/slice + bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot *xoffset += t->width; } else for(i = 0; i < t->bound; i++) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 66efac07d0..05bf2d6521 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -1516,8 +1516,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset) *xoffset += t->width; break; case TSTRING: - proggendata(g, BitsMultiWord); - proggendata(g, BitsString); + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); *xoffset += t->width; break; case TINTER: @@ -1530,8 +1530,8 @@ gengcprog1(ProgGen *g, Type *t, vlong *xoffset) break; case TARRAY: if(isslice(t)) { - proggendata(g, BitsMultiWord); - proggendata(g, BitsSlice); + proggendata(g, BitsPointer); + proggendata(g, BitsScalar); proggendata(g, BitsScalar); } else { t1 = t->type; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 081c373a88..d62d55e773 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -656,11 +656,15 @@ maptype(Type *key, Type *val) { Type *t; Type *bad; - int atype; + int atype, mtype; if(key != nil) { atype = algtype1(key, &bad); - switch(bad == T ? key->etype : bad->etype) { + if(bad == T) + mtype = key->etype; + else + mtype = bad->etype; + switch(mtype) { default: if(atype == ANOEQ) yyerror("invalid map key type %T", key); diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index c295cf6d21..746feb4d1b 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -525,19 +525,6 @@ reswitch: op = n->etype; goto arith; - case OADDPTR: - ok |= Erv; - l = typecheck(&n->left, Erv); - r = typecheck(&n->right, Erv); - if(l->type == T || r->type == T) - goto error; - if(l->type->etype != tptr) - fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left); - if(r->type->etype != TUINTPTR) - fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right); - n->type = types[tptr]; - goto ret; - case OADD: case OAND: case OANDAND: diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index f3886cf73a..c251af660e 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2875,14 +2875,14 @@ sliceany(Node* n, NodeList **init) lb = N; } - // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison - // generate - // if hb > bound || lb > hb { panicslice() } + // Checking src[lb:hb:cb] or src[lb:hb]. + // if chk0 || chk1 || chk2 { panicslice() } chk = N; - chk0 = N; - chk1 = N; - chk2 = N; + chk0 = N; // cap(src) < cb + chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] + chk2 = N; // hb < lb + // All comparisons are unsigned to avoid testing < 0. bt = types[simtype[TUINT]]; if(cb != N && cb->type->width > 4) bt = types[TUINT64]; diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go index d9781699e0..9a2a9f2668 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -2494,6 +2494,15 @@ func TestSlice(t *testing.T) { if vs != s[3:5] { t.Errorf("s.Slice(3, 5) = %q; expected %q", vs, s[3:5]) } + + rv := ValueOf(&xs).Elem() + rv = rv.Slice(3, 4) + ptr2 := rv.Pointer() + rv = rv.Slice(5, 5) + ptr3 := rv.Pointer() + if ptr3 != ptr2 { + t.Errorf("xs.Slice(3,4).Slice3(5,5).Pointer() = %#x, want %#x", ptr3, ptr2) + } } func TestSlice3(t *testing.T) { @@ -2532,6 +2541,15 @@ func TestSlice3(t *testing.T) { s := "hello world" rv = ValueOf(&s).Elem() shouldPanic(func() { rv.Slice3(1, 2, 3) }) + + rv = ValueOf(&xs).Elem() + rv = rv.Slice3(3, 5, 7) + ptr2 := rv.Pointer() + rv = rv.Slice3(4, 4, 4) + ptr3 := rv.Pointer() + if ptr3 != ptr2 { + t.Errorf("xs.Slice3(3,5,7).Slice3(4,4,4).Pointer() = %#x, want %#x", ptr3, ptr2) + } } func TestSetLenCap(t *testing.T) { diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index dda852a3ec..4394ed0739 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -1746,9 +1746,14 @@ func (v Value) Slice(i, j int) Value { // Reinterpret as *sliceHeader to edit. s := (*sliceHeader)(unsafe.Pointer(&x)) - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) s.Len = j - i s.Cap = cap - i + if cap-i > 0 { + s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + } else { + // do not advance pointer, to avoid pointing beyond end of slice + s.Data = base + } fl := v.flag&flagRO | flagIndir | flag(Slice)< 0 { + s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + } else { + // do not advance pointer, to avoid pointing beyond end of slice + s.Data = base + } fl := v.flag&flagRO | flagIndir | flag(Slice)<data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { - case BitsString: - dumpint(FieldKindString); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += BitsPerPointer; - break; - case BitsSlice: - dumpint(FieldKindSlice); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += 2 * BitsPerPointer; - break; + default: + runtime·throw("unexpected garbage collection bits"); case BitsIface: dumpint(FieldKindIface); dumpint(offset + i / BitsPerPointer * PtrSize); @@ -495,13 +487,13 @@ dumproots(void) dumpint(TagData); dumpint((uintptr)data); dumpmemrange(data, edata - data); - dumpfields((BitVector){(edata - data)*8, (uint32*)runtime·gcdatamask}); + dumpfields(runtime·gcdatamask); // bss segment dumpint(TagBss); dumpint((uintptr)bss); dumpmemrange(bss, ebss - bss); - dumpfields((BitVector){(ebss - bss)*8, (uint32*)runtime·gcbssmask}); + dumpfields(runtime·gcdatamask); // MSpan.types allspans = runtime·mheap.allspans; @@ -802,13 +794,11 @@ dumpbvtypes(BitVector *bv, byte *base) if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord) continue; switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { - case BitsString: + default: + runtime·throw("unexpected garbage collection bits"); case BitsIface: i += BitsPerPointer; break; - case BitsSlice: - i += 2 * BitsPerPointer; - break; case BitsEface: dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize)); i += BitsPerPointer; diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index f5a2b2a42d..eafabb364a 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -303,7 +303,6 @@ extern int8 runtime·size_to_class8[1024/8 + 1]; extern int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1]; extern void runtime·InitSizes(void); - typedef struct MCacheList MCacheList; struct MCacheList { @@ -581,6 +580,9 @@ struct StackMap // (the index is encoded in PCDATA_StackMapIndex). BitVector runtime·stackmapdata(StackMap *stackmap, int32 n); +extern BitVector runtime·gcdatamask; +extern BitVector runtime·gcbssmask; + // defined in mgc0.go void runtime·gc_m_ptr(Eface*); void runtime·gc_g_ptr(Eface*); diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index d931e31525..db89f6036f 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -172,8 +172,8 @@ static FinBlock *finc; // cache of free blocks static FinBlock *allfin; // list of all blocks bool runtime·fingwait; bool runtime·fingwake; -byte* runtime·gcdatamask; -byte* runtime·gcbssmask; +BitVector runtime·gcdatamask; +BitVector runtime·gcbssmask; static Lock gclock; @@ -187,7 +187,7 @@ static void gchelperstart(void); static void flushallmcaches(void); static bool scanframe(Stkframe *frame, void *unused); static void scanstack(G *gp); -static byte* unrollglobgcprog(byte *prog, uintptr size); +static BitVector unrollglobgcprog(byte *prog, uintptr size); static FuncVal runfinqv = {runfinq}; static FuncVal bgsweepv = {bgsweep}; @@ -221,8 +221,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask) uintptr i, nobj, size, idx, x, off, scanbufpos; intptr ncached; Workbuf *wbuf; - String *str; - Slice *slice; Iface *iface; Eface *eface; Type *typ; @@ -346,6 +344,10 @@ scanblock(byte *b, uintptr n, byte *ptrmask) obj = *(byte**)(b+i); goto markobj; } + + // With those three out of the way, must be multi-word. + if(bits != BitsMultiWord) + runtime·throw("unexpected garbage collection bits"); // Find the next pair of bits. if(ptrmask == nil) { if(ncached <= 0) { @@ -358,22 +360,8 @@ scanblock(byte *b, uintptr n, byte *ptrmask) bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask; switch(bits) { - case BitsString: - str = (String*)(b+i); - if(str->len > 0) - obj = str->str; - break; - case BitsSlice: - slice = (Slice*)(b+i); - if(Debug && slice->cap < slice->len) { - g->m->traceback = 2; - runtime·printf("bad slice in object %p: %p/%p/%p\n", - b, slice->array, slice->len, slice->cap); - runtime·throw("bad slice in heap object"); - } - if(slice->cap > 0) - obj = slice->array; - break; + default: + runtime·throw("unexpected garbage collection bits"); case BitsIface: iface = (Iface*)(b+i); if(iface->tab != nil) { @@ -392,21 +380,9 @@ scanblock(byte *b, uintptr n, byte *ptrmask) break; } - if(bits == BitsSlice) { - i += 2*PtrSize; - if(ncached == 2) - ncached = 0; - else if(ptrmask == nil) { - // Refill cache and consume one quadruple. - cached = *--ptrbitp; - cached >>= gcBits; - ncached = 1; - } - } else { - i += PtrSize; - cached >>= gcBits; - ncached--; - } + i += PtrSize; + cached >>= gcBits; + ncached--; markobj: // At this point we have extracted the next potential pointer. @@ -513,11 +489,11 @@ markroot(ParFor *desc, uint32 i) // Note: if you add a case here, please also update heapdump.c:dumproots. switch(i) { case RootData: - scanblock(data, edata - data, runtime·gcdatamask); + scanblock(data, edata - data, (byte*)runtime·gcdatamask.data); break; case RootBss: - scanblock(bss, ebss - bss, runtime·gcbssmask); + scanblock(bss, ebss - bss, (byte*)runtime·gcbssmask.data); break; case RootFinalizers: @@ -1852,7 +1828,7 @@ unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse) } // Unrolls GC program prog for data/bss, returns dense GC mask. -static byte* +static BitVector unrollglobgcprog(byte *prog, uintptr size) { byte *mask; @@ -1872,7 +1848,7 @@ unrollglobgcprog(byte *prog, uintptr size) runtime·throw("unrollglobgcprog: program does not end with insEnd"); if(mask[masksize] != 0xa1) runtime·throw("unrollglobgcprog: overflow"); - return mask; + return (BitVector){masksize*8, (uint32*)mask}; } void @@ -2062,7 +2038,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) *mask = runtime·mallocgc(*len, nil, 0); for(i = 0; i < n; i += PtrSize) { off = (p+i-data)/PtrSize; - bits = (runtime·gcdatamask[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; + bits = (((byte*)runtime·gcdatamask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; (*mask)[i/PtrSize] = bits; } return; @@ -2074,7 +2050,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) *mask = runtime·mallocgc(*len, nil, 0); for(i = 0; i < n; i += PtrSize) { off = (p+i-bss)/PtrSize; - bits = (runtime·gcbssmask[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; + bits = (((byte*)runtime·gcbssmask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; (*mask)[i/PtrSize] = bits; } return; diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h index a7292effd3..d04b5cab8f 100644 --- a/src/pkg/runtime/mgc0.h +++ b/src/pkg/runtime/mgc0.h @@ -50,8 +50,8 @@ enum { BitsMultiWord = 3, // BitsMultiWord will be set for the first word of a multi-word item. // When it is set, one of the following will be set for the second word. - BitsString = 0, - BitsSlice = 1, + // NOT USED ANYMORE: BitsString = 0, + // NOT USED ANYMORE: BitsSlice = 1, BitsIface = 2, BitsEface = 3, diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index df2999bbd9..4f63fdf718 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -762,8 +762,6 @@ extern uint32 runtime·cpuid_ecx; extern uint32 runtime·cpuid_edx; extern DebugVars runtime·debug; extern uintptr runtime·maxstacksize; -extern byte* runtime·gcdatamask; -extern byte* runtime·gcbssmask; extern Note runtime·signote; /* diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c index fc11d98c9b..61205bd478 100644 --- a/src/pkg/runtime/stack.c +++ b/src/pkg/runtime/stack.c @@ -592,19 +592,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) break; case BitsMultiWord: switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) { - case BitsString: - // string referents are never on the stack, never need to be adjusted - i++; // skip len - break; - case BitsSlice: - p = scanp[i]; - if(minp <= p && p < maxp) { - if(StackDebug >= 3) - runtime·printf("adjust slice %p\n", p); - scanp[i] = p + delta; - } - i += 2; // skip len, cap - break; + default: + runtime·throw("unexpected garbage collection bits"); case BitsEface: t = (Type*)scanp[i]; if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) { diff --git a/test/slice3.go b/test/slice3.go index 3cf34b57e7..857eaf3a09 100644 --- a/test/slice3.go +++ b/test/slice3.go @@ -19,10 +19,10 @@ var bout *bufio.Writer func main() { bout = bufio.NewWriter(os.Stdout) - + fmt.Fprintf(bout, "%s", programTop) fmt.Fprintf(bout, "func main() {\n") - + index := []string{ "0", "1", @@ -38,7 +38,7 @@ func main() { "v10", "v20", } - + parse := func(s string) (n int, isconst bool) { if s == "vminus1" { return -1, false @@ -69,7 +69,7 @@ func main() { iconst && kconst && iv > kv, iconst && base == "array" && iv > Cap, jconst && base == "array" && jv > Cap, - kconst && base == "array" && kv > Cap: + kconst && base == "array" && kv > Cap: continue } @@ -82,7 +82,7 @@ func main() { xlen = jv - iv xcap = kv - iv } - fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap) + fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap) } } } @@ -147,9 +147,13 @@ func checkSlice(desc string, f func() []byte, xbase, xlen, xcap int) { println(desc, "=", base, len, cap, "want panic") return } - if base != uintptr(xbase) || len != uintptr(xlen) || cap != uintptr(xcap) { + if cap != 0 && base != uintptr(xbase) || base >= 10 || len != uintptr(xlen) || cap != uintptr(xcap) { notOK() - println(desc, "=", base, len, cap, "want", xbase, xlen, xcap) + if cap == 0 { + println(desc, "=", base, len, cap, "want", "0-9", xlen, xcap) + } else { + println(desc, "=", base, len, cap, "want", xbase, xlen, xcap) + } } } diff --git a/test/slicecap.go b/test/slicecap.go new file mode 100644 index 0000000000..dceb7e2cca --- /dev/null +++ b/test/slicecap.go @@ -0,0 +1,90 @@ +// run + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "unsafe" + +var ( + hello = "hello" + bytes = []byte{1, 2, 3, 4, 5} + ints = []int32{1, 2, 3, 4, 5} + + five = 5 + + ok = true +) + +func notOK() { + if ok { + println("BUG:") + ok = false + } +} + +func checkString(desc, s string) { + p1 := *(*uintptr)(unsafe.Pointer(&s)) + p2 := *(*uintptr)(unsafe.Pointer(&hello)) + if p1-p2 >= 5 { + notOK() + println("string", desc, "has invalid base") + } +} + +func checkBytes(desc string, s []byte) { + p1 := *(*uintptr)(unsafe.Pointer(&s)) + p2 := *(*uintptr)(unsafe.Pointer(&bytes)) + if p1-p2 >= 5 { + println("byte slice", desc, "has invalid base") + } +} + +func checkInts(desc string, s []int32) { + p1 := *(*uintptr)(unsafe.Pointer(&s)) + p2 := *(*uintptr)(unsafe.Pointer(&ints)) + if p1-p2 >= 5*4 { + println("int slice", desc, "has invalid base") + } +} + +func main() { + { + x := hello + checkString("x", x) + checkString("x[5:]", x[5:]) + checkString("x[five:]", x[five:]) + checkString("x[5:five]", x[5:five]) + checkString("x[five:5]", x[five:5]) + checkString("x[five:five]", x[five:five]) + checkString("x[1:][2:][2:]", x[1:][2:][2:]) + y := x[4:] + checkString("y[1:]", y[1:]) + } + { + x := bytes + checkBytes("x", x) + checkBytes("x[5:]", x[5:]) + checkBytes("x[five:]", x[five:]) + checkBytes("x[5:five]", x[5:five]) + checkBytes("x[five:5]", x[five:5]) + checkBytes("x[five:five]", x[five:five]) + checkBytes("x[1:][2:][2:]", x[1:][2:][2:]) + y := x[4:] + checkBytes("y[1:]", y[1:]) + } + { + x := ints + checkInts("x", x) + checkInts("x[5:]", x[5:]) + checkInts("x[five:]", x[five:]) + checkInts("x[5:five]", x[5:five]) + checkInts("x[five:5]", x[five:5]) + checkInts("x[five:five]", x[five:five]) + checkInts("x[1:][2:][2:]", x[1:][2:][2:]) + y := x[4:] + checkInts("y[1:]", y[1:]) + } +}