From 6a2e844f5179e85085723be29c9ba97f1286b698 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Mon, 8 Sep 2014 15:36:21 +1000 Subject: [PATCH 001/430] cmd/gc: fix undefined behaviour warning in subr.c Fixes warning /home/dfc/go/src/cmd/gc/subr.c:3469:8: runtime error: negation of -9223372036854775808 cannot be represented in type 'int64' (aka 'long'); cast to an unsigned type to negate this value to itself LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/141220043 --- src/cmd/gc/subr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 93600c688b..666be96679 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3466,7 +3466,7 @@ smagic(Magic *m) p = m->w-1; ad = m->sd; if(m->sd < 0) - ad = -m->sd; + ad = -(uvlong)m->sd; // bad denominators if(ad == 0 || ad == 1 || ad == two31) { From 4a40fb197931a23c11ff4d677ecee6aefd99d5ca Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Mon, 8 Sep 2014 16:06:41 +1000 Subject: [PATCH 002/430] cmd/cc: fix undefined behaviour warning in bv.c Fixes warning # _/home/dfc/go/misc/cgo/test/backdoor /home/dfc/go/src/cmd/cc/bv.c:43:11: runtime error: left shift of 1 by 31 places cannot be represented in type 'int' LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/136330043 --- src/cmd/cc/bv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/cc/bv.c b/src/cmd/cc/bv.c index 51b7f4076f..db433de6a7 100644 --- a/src/cmd/cc/bv.c +++ b/src/cmd/cc/bv.c @@ -40,6 +40,6 @@ bvset(Bvec *bv, int32 i) if(i < 0 || i >= bv->n) fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1 << (i % WORDBITS); + mask = 1UL << (i % WORDBITS); bv->b[i / WORDBITS] |= mask; } From 4c05d32f795a714106490e5e8b6296b920354674 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 8 Sep 2014 10:07:26 -0400 Subject: [PATCH 003/430] androidtest.bash: adjustment for move from src/pkg to src LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/142740043 --- src/androidtest.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/androidtest.bash b/src/androidtest.bash index 2acfbd815a..504d276c4c 100755 --- a/src/androidtest.bash +++ b/src/androidtest.bash @@ -42,7 +42,7 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \ # into a subdirectory of /data. export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$ FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot -mkdir -p $FAKE_GOROOT/src +mkdir -p $FAKE_GOROOT ln -s $GOROOT/src $FAKE_GOROOT/src ln -s $GOROOT/test $FAKE_GOROOT/test ln -s $GOROOT/lib $FAKE_GOROOT/lib From 526319830bf0d7778226fa9ef558f51ebe67aaa6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 8 Sep 2014 10:14:41 -0700 Subject: [PATCH 004/430] runtime: a few cleanups. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/134630043 --- src/runtime/asm_386.s | 4 ++-- src/runtime/asm_amd64.s | 4 ++-- src/runtime/asm_amd64p32.s | 4 ++-- src/runtime/asm_arm.s | 4 ++-- src/runtime/malloc.go | 2 ++ src/runtime/stubs.go | 9 +-------- src/runtime/thunk.s | 4 ++-- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 25026417bf..7eba8977c6 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -328,7 +328,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0 MOVL $0, DX JMP runtime·morestack(SB) -// reflect·call: call a function with the given argument list +// reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number // of constant-sized-frame functions to encode a few bits of size in the pc. @@ -341,7 +341,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0 JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT reflect·call(SB), NOSPLIT, $0-16 +TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 MOVL argsize+8(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index cc32ad8a18..a47fb09522 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -307,7 +307,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVQ $0, 0x1003 // crash if newstack returns RET -// reflect·call: call a function with the given argument list +// reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number // of constant-sized-frame functions to encode a few bits of size in the pc. @@ -320,7 +320,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT reflect·call(SB), NOSPLIT, $0-24 +TEXT runtime·reflectcall(SB), NOSPLIT, $0-24 MOVLQZX argsize+16(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 6c10bec5c3..95d04cae4f 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -280,7 +280,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVL $0, 0x1003 // crash if newstack returns RET -// reflect·call: call a function with the given argument list +// reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number // of constant-sized-frame functions to encode a few bits of size in the pc. @@ -293,7 +293,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT reflect·call(SB), NOSPLIT, $0-16 +TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 MOVLQZX argsize+8(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 3db907945c..af536f079c 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -319,7 +319,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0 MOVW $0, R7 B runtime·morestack(SB) -// reflect·call: call a function with the given argument list +// reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number // of constant-sized-frame functions to encode a few bits of size in the pc. @@ -331,7 +331,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0 MOVW $NAME(SB), R1; \ B (R1) -TEXT reflect·call(SB),NOSPLIT,$-4-16 +TEXT runtime·reflectcall(SB),NOSPLIT,$-4-16 MOVW argsize+8(FP), R0 DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 883ca0cef7..b3c9c1fd78 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -35,6 +35,8 @@ const ( bitMask = bitBoundary | bitMarked mSpanInUse = 0 + + concurrentSweep = true ) // Page number (address>>pageShift) diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 03f618e155..bf6c33a41e 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -7,9 +7,6 @@ package runtime import "unsafe" // Declarations for runtime services implemented in C or assembly. -// C implementations of these functions are in stubs.goc. -// Assembly implementations are in various files, see comments with -// each function. const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const @@ -26,7 +23,7 @@ func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(p) + delta) } -// in stubs.goc +// in runtime.c func getg() *g func acquirem() *m func releasem(mp *m) @@ -114,10 +111,6 @@ func memclr(ptr unsafe.Pointer, n uintptr) //go:noescape func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) -const ( - concurrentSweep = true -) - func gosched() func starttheworld() func stoptheworld() diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index babc927680..7bdf7b950d 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -56,8 +56,8 @@ TEXT runtime∕pprof·runtime_cyclesPerSecond(SB),NOSPLIT,$0-0 TEXT bytes·Compare(SB),NOSPLIT,$0-0 JMP runtime·cmpbytes(SB) -TEXT runtime·reflectcall(SB), NOSPLIT, $0-0 - JMP reflect·call(SB) +TEXT reflect·call(SB), NOSPLIT, $0-0 + JMP runtime·reflectcall(SB) TEXT reflect·chanclose(SB), NOSPLIT, $0-0 JMP runtime·closechan(SB) From c81a0ed3c50606d1ada0fd9b571611b3687c90e1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 14:05:23 -0400 Subject: [PATCH 005/430] liblink, runtime: diagnose and fix C code running on Go stack This CL contains compiler+runtime changes that detect C code running on Go (not g0, not gsignal) stacks, and it contains corrections for what it detected. The detection works by changing the C prologue to use a different stack guard word in the G than Go prologue does. On the g0 and gsignal stacks, that stack guard word is set to the usual stack guard value. But on ordinary Go stacks, that stack guard word is set to ^0, which will make any stack split check fail. The C prologue then calls morestackc instead of morestack, and morestackc aborts the program with a message about running C code on a Go stack. This check catches all C code running on the Go stack except NOSPLIT code. The NOSPLIT code is allowed, so the check is complete. Since it is a dynamic check, the code must execute to be caught. But unlike the static checks we've been using in cmd/ld, the dynamic check works with function pointers and other indirect calls. For example it caught sigpanic being pushed onto Go stacks in the signal handlers. Fixes #8667. LGTM=khr, iant R=golang-codereviews, khr, iant CC=golang-codereviews, r https://golang.org/cl/133700043 --- src/liblink/obj5.c | 7 +- src/liblink/obj6.c | 11 +++ src/liblink/obj8.c | 11 ++- src/runtime/cgo/callbacks.c | 30 ++------ src/runtime/cgo/cgo.go | 7 -- src/runtime/cgocallback.go | 37 ++++++++++ src/runtime/heapdump.c | 34 +++++++--- src/runtime/mgc0.c | 128 +++++++++++++++++++++++------------ src/runtime/mgc0.go | 35 ++++++++++ src/runtime/os_darwin.c | 42 ++---------- src/runtime/os_dragonfly.c | 42 ++---------- src/runtime/os_freebsd.c | 42 ++---------- src/runtime/os_linux.c | 42 ++---------- src/runtime/os_nacl.c | 13 ---- src/runtime/os_nacl.go | 11 +++ src/runtime/os_netbsd.c | 42 ++---------- src/runtime/os_openbsd.c | 42 ++---------- src/runtime/os_plan9.c | 78 --------------------- src/runtime/os_plan9.go | 72 ++++++++++++++++++++ src/runtime/os_solaris.c | 42 ++---------- src/runtime/os_windows.c | 29 -------- src/runtime/os_windows.go | 27 ++++++++ src/runtime/panic.c | 1 + src/runtime/panic.go | 20 ++++++ src/runtime/print1.go | 3 - src/runtime/proc.c | 83 +++-------------------- src/runtime/proc.go | 73 ++++++++++++++++++++ src/runtime/race.go | 2 + src/runtime/runtime.h | 2 + src/runtime/sigpanic_unix.go | 40 +++++++++++ src/runtime/stack.c | 28 +++++--- src/runtime/string.c | 73 +------------------- src/runtime/string.go | 57 ++++++++++++++++ src/runtime/stubs.go | 1 - src/runtime/thunk.s | 13 +++- src/runtime/traceback.go | 16 ----- 36 files changed, 605 insertions(+), 631 deletions(-) create mode 100644 src/runtime/cgocallback.go create mode 100644 src/runtime/sigpanic_unix.go diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c index 6630a59231..d9f980aca8 100644 --- a/src/liblink/obj5.c +++ b/src/liblink/obj5.c @@ -769,6 +769,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) p->as = AMOVW; p->from.type = D_OREG; p->from.reg = REGG; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_REG; p->to.reg = 1; @@ -884,7 +886,10 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) p->as = ABL; p->scond = C_SCOND_LS; p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[noctxt]; + if(ctxt->cursym->cfunc) + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + else + p->to.sym = ctxt->symmorestack[noctxt]; // BLS start p = appendp(ctxt, p); diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c index 6a7ff48b0a..572219b5b7 100644 --- a/src/liblink/obj6.c +++ b/src/liblink/obj6.c @@ -783,6 +783,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_SP; indir_cx(ctxt, &p->to); + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAQ -xxx(SP), AX @@ -797,6 +799,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_AX; indir_cx(ctxt, &p->to); + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else { // Such a large stack we need to protect against wraparound. // If SP is close to zero: @@ -817,6 +821,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = mov; indir_cx(ctxt, &p->from); p->from.offset = 0; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_SI; p = appendp(ctxt, p); @@ -873,6 +879,11 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(ctxt, p); + if(ctxt->cursym->cfunc) { + p->as = ACALL; + p->to.type = D_BRANCH; + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + } else if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c index 03f12462e8..d8a93fb576 100644 --- a/src/liblink/obj8.c +++ b/src/liblink/obj8.c @@ -539,6 +539,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAL -(framesize-StackSmall)(SP), AX @@ -553,6 +555,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; + if(ctxt->cursym->cfunc) + p->to.offset = 3*ctxt->arch->ptrsize; } else { // Such a large stack we need to protect against wraparound // if SP is close to zero. @@ -572,6 +576,8 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = AMOVL; p->from.type = D_INDIR+D_CX; p->from.offset = 0; + if(ctxt->cursym->cfunc) + p->from.offset = 3*ctxt->arch->ptrsize; p->to.type = D_SI; p = appendp(ctxt, p); @@ -641,7 +647,10 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p = appendp(ctxt, p); p->as = ACALL; p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[noctxt]; + if(ctxt->cursym->cfunc) + p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); + else + p->to.sym = ctxt->symmorestack[noctxt]; p = appendp(ctxt, p); p->as = AJMP; diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c index f074237d5f..16614d03db 100644 --- a/src/runtime/cgo/callbacks.c +++ b/src/runtime/cgo/callbacks.c @@ -33,18 +33,7 @@ // crosscall2(_cgo_allocate, &a, sizeof a); // /* Here a.ret is a pointer to the allocated memory. */ -static void -_cgo_allocate_internal(uintptr len, byte *ret) -{ - CgoMal *c; - - ret = runtime·mallocgc(len, nil, 0); - c = runtime·mallocgc(sizeof(*c), nil, 0); - c->next = g->m->cgomal; - c->alloc = ret; - g->m->cgomal = c; - FLUSH(&ret); -} +void runtime·_cgo_allocate_internal(void); #pragma cgo_export_static _cgo_allocate #pragma cgo_export_dynamic _cgo_allocate @@ -52,7 +41,7 @@ _cgo_allocate_internal(uintptr len, byte *ret) void _cgo_allocate(void *a, int32 n) { - runtime·cgocallback((void(*)(void))_cgo_allocate_internal, a, n); + runtime·cgocallback((void(*)(void))runtime·_cgo_allocate_internal, a, n); } // Panic. The argument is converted into a Go string. @@ -63,18 +52,7 @@ _cgo_allocate(void *a, int32 n) // crosscall2(_cgo_panic, &a, sizeof a); // /* The function call will not return. */ -extern void ·cgoStringToEface(String, Eface*); - -static void -_cgo_panic_internal(byte *p) -{ - String s; - Eface err; - - s = runtime·gostring(p); - ·cgoStringToEface(s, &err); - runtime·gopanic(err); -} +void runtime·_cgo_panic_internal(void); #pragma cgo_export_static _cgo_panic #pragma cgo_export_dynamic _cgo_panic @@ -82,7 +60,7 @@ _cgo_panic_internal(byte *p) void _cgo_panic(void *a, int32 n) { - runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n); + runtime·cgocallback((void(*)(void))runtime·_cgo_panic_internal, a, n); } #pragma cgo_import_static x_cgo_init diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go index 786ae515c8..8528692f7b 100644 --- a/src/runtime/cgo/cgo.go +++ b/src/runtime/cgo/cgo.go @@ -24,10 +24,3 @@ package cgo */ import "C" - -// Supports _cgo_panic by converting a string constant to an empty -// interface. - -func cgoStringToEface(s string, ret *interface{}) { - *ret = s -} diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go new file mode 100644 index 0000000000..844a095c22 --- /dev/null +++ b/src/runtime/cgocallback.go @@ -0,0 +1,37 @@ +// Copyright 2011 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 runtime + +import "unsafe" + +// These functions are called from C code via cgo/callbacks.c. + +// Allocate memory. This allocates the requested number of bytes in +// memory controlled by the Go runtime. The allocated memory will be +// zeroed. You are responsible for ensuring that the Go garbage +// collector can see a pointer to the allocated memory for as long as +// it is valid, e.g., by storing a pointer in a local variable in your +// C function, or in memory allocated by the Go runtime. If the only +// pointers are in a C global variable or in memory allocated via +// malloc, then the Go garbage collector may collect the memory. +// +// TODO(rsc,iant): This memory is untyped. +// Either we need to add types or we need to stop using it. + +func _cgo_allocate_internal(len uintptr) unsafe.Pointer { + ret := gomallocgc(len, nil, 0) + c := new(cgomal) + c.alloc = ret + gp := getg() + c.next = gp.m.cgomal + gp.m.cgomal = c + return ret +} + +// Panic. + +func _cgo_panic_internal(p *byte) { + panic(gostringnocopy(p)) +} diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index d07fdb29bc..435e0b2dae 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -711,7 +711,7 @@ dumpmemprof(void) } static void -mdump(G *gp) +mdump(void) { byte *hdr; uintptr i; @@ -737,18 +737,32 @@ mdump(G *gp) dumpmemprof(); dumpint(TagEOF); flush(); - - gp->param = nil; - runtime·casgstatus(gp, Gwaiting, Grunning); - runtime·gogo(&gp->sched); } +static void writeheapdump_m(void); + +#pragma textflag NOSPLIT void runtime∕debug·WriteHeapDump(uintptr fd) { - void (*fn)(G*); + void (*fn)(void); + + g->m->scalararg[0] = fd; + fn = writeheapdump_m; + runtime·onM(&fn); +} + +static void +writeheapdump_m(void) +{ + uintptr fd; + + fd = g->m->scalararg[0]; + g->m->scalararg[0] = 0; // Stop the world. + runtime·casgstatus(g->m->curg, Grunning, Gwaiting); + g->waitreason = runtime·gostringnocopy((byte*)"dumping heap"); runtime·semacquire(&runtime·worldsema, false); g->m->gcing = 1; runtime·stoptheworld(); @@ -761,11 +775,8 @@ runtime∕debug·WriteHeapDump(uintptr fd) // Set dump file. dumpfd = fd; - // Call dump routine on M stack. - runtime·casgstatus(g, Grunning, Gwaiting); - g->waitreason = runtime·gostringnocopy((byte*)"dumping heap"); - fn = mdump; - runtime·mcall(&fn); + // Call dump routine. + mdump(); // Reset dump file. dumpfd = 0; @@ -780,6 +791,7 @@ runtime∕debug·WriteHeapDump(uintptr fd) g->m->locks++; runtime·semrelease(&runtime·worldsema); runtime·starttheworld(); + runtime·casgstatus(g->m->curg, Gwaiting, Grunning); g->m->locks--; } diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index d4c414736b..1505cedcc0 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -124,9 +124,8 @@ static FinBlock *allfin; // list of all blocks BitVector runtime·gcdatamask; BitVector runtime·gcbssmask; -static Mutex gclock; +extern Mutex runtime·gclock; -static void bgsweep(void); static Workbuf* getempty(Workbuf*); static Workbuf* getfull(Workbuf*); static void putempty(Workbuf*); @@ -137,7 +136,8 @@ static bool scanframe(Stkframe *frame, void *unused); static void scanstack(G *gp); static BitVector unrollglobgcprog(byte *prog, uintptr size); -static FuncVal bgsweepv = {bgsweep}; +void runtime·bgsweep(void); +static FuncVal bgsweepv = {runtime·bgsweep}; static struct { uint64 full; // lock-free list of full blocks @@ -1041,9 +1041,10 @@ runtime·MSpan_Sweep(MSpan *s, bool preserve) return res; } -// State of background sweep. -// Pretected by gclock. -static struct +// State of background runtime·sweep. +// Pretected by runtime·gclock. +// Must match mgc0.go. +struct { G* g; bool parked; @@ -1052,29 +1053,7 @@ static struct uint32 nbgsweep; uint32 npausesweep; -} sweep; - -// background sweeping goroutine -static void -bgsweep(void) -{ - g->issystem = true; - for(;;) { - while(runtime·sweepone() != -1) { - sweep.nbgsweep++; - runtime·gosched(); - } - runtime·lock(&gclock); - if(!runtime·mheap.sweepdone) { - // It's possible if GC has happened between sweepone has - // returned -1 and gclock lock. - runtime·unlock(&gclock); - continue; - } - sweep.parked = true; - runtime·parkunlock(&gclock, runtime·gostringnocopy((byte*)"GC sweep wait")); - } -} +} runtime·sweep; // sweeps one span // returns number of pages returned to heap, or -1 if there is nothing to sweep @@ -1090,7 +1069,7 @@ runtime·sweepone(void) g->m->locks++; sg = runtime·mheap.sweepgen; for(;;) { - idx = runtime·xadd(&sweep.spanidx, 1) - 1; + idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1; if(idx >= work.nspan) { runtime·mheap.sweepdone = true; g->m->locks--; @@ -1111,6 +1090,30 @@ runtime·sweepone(void) } } +static void +sweepone_m(void) +{ + g->m->scalararg[0] = runtime·sweepone(); +} + +#pragma textflag NOSPLIT +uintptr +runtime·gosweepone(void) +{ + void (*fn)(void); + + fn = sweepone_m; + runtime·onM(&fn); + return g->m->scalararg[0]; +} + +#pragma textflag NOSPLIT +bool +runtime·gosweepdone(void) +{ + return runtime·mheap.sweepdone; +} + void runtime·gchelper(void) { @@ -1328,7 +1331,7 @@ gc(struct gc_args *args) // Sweep what is not sweeped by bgsweep. while(runtime·sweepone() != -1) - sweep.npausesweep++; + runtime·sweep.npausesweep++; // Cache runtime.mheap.allspans in work.spans to avoid conflicts with // resizing/freeing allspans. @@ -1407,11 +1410,11 @@ gc(struct gc_args *args) mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000, heap0>>20, heap1>>20, obj, mstats.nmalloc, mstats.nfree, - work.nspan, sweep.nbgsweep, sweep.npausesweep, + work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep, stats.nhandoff, stats.nhandoffcnt, work.markfor->nsteal, work.markfor->nstealcnt, stats.nprocyield, stats.nosyield, stats.nsleep); - sweep.nbgsweep = sweep.npausesweep = 0; + runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0; } // See the comment in the beginning of this function as to why we need the following. @@ -1426,23 +1429,23 @@ gc(struct gc_args *args) runtime·mheap.sweepdone = false; work.spans = runtime·mheap.allspans; work.nspan = runtime·mheap.nspan; - sweep.spanidx = 0; + runtime·sweep.spanidx = 0; runtime·unlock(&runtime·mheap.lock); // Temporary disable concurrent sweep, because we see failures on builders. if(ConcurrentSweep && !args->eagersweep) { - runtime·lock(&gclock); - if(sweep.g == nil) - sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc); - else if(sweep.parked) { - sweep.parked = false; - runtime·ready(sweep.g); + runtime·lock(&runtime·gclock); + if(runtime·sweep.g == nil) + runtime·sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc); + else if(runtime·sweep.parked) { + runtime·sweep.parked = false; + runtime·ready(runtime·sweep.g); } - runtime·unlock(&gclock); + runtime·unlock(&runtime·gclock); } else { // Sweep all spans eagerly. while(runtime·sweepone() != -1) - sweep.npausesweep++; + runtime·sweep.npausesweep++; } runtime·mProf_GC(); @@ -1451,9 +1454,27 @@ gc(struct gc_args *args) extern uintptr runtime·sizeof_C_MStats; +static void readmemstats_m(void); + +#pragma textflag NOSPLIT void runtime·ReadMemStats(MStats *stats) { + void (*fn)(void); + + g->m->ptrarg[0] = stats; + fn = readmemstats_m; + runtime·onM(&fn); +} + +static void +readmemstats_m(void) +{ + MStats *stats; + + stats = g->m->ptrarg[0]; + g->m->ptrarg[0] = nil; + // Have to acquire worldsema to stop the world, // because stoptheworld can only be used by // one goroutine at a time, and there might be @@ -1478,11 +1499,28 @@ runtime·ReadMemStats(MStats *stats) g->m->locks--; } +static void readgcstats_m(void); + +#pragma textflag NOSPLIT void runtime∕debug·readGCStats(Slice *pauses) { + void (*fn)(void); + + g->m->ptrarg[0] = pauses; + fn = readgcstats_m; + runtime·onM(&fn); +} + +static void +readgcstats_m(void) +{ + Slice *pauses; uint64 *p; uint32 i, n; + + pauses = g->m->ptrarg[0]; + g->m->ptrarg[0] = nil; // Calling code in runtime/debug should make the slice large enough. if(pauses->cap < nelem(mstats.pause_ns)+3) @@ -1510,7 +1548,8 @@ runtime∕debug·readGCStats(Slice *pauses) } void -runtime·setgcpercent_m(void) { +runtime·setgcpercent_m(void) +{ int32 in; int32 out; @@ -1901,7 +1940,8 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) void runtime·gc_unixnanotime(int64 *now); -int64 runtime·unixnanotime(void) +int64 +runtime·unixnanotime(void) { int64 now; diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 2d9d76a474..0984fc58d6 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -68,3 +68,38 @@ func clearpools() { } } } + +// State of background sweep. +// Protected by gclock. +// Must match mgc0.c. +var sweep struct { + g *g + parked bool + spanidx uint32 // background sweeper position + nbgsweep uint32 + npausesweep uint32 +} + +var gclock mutex // also in mgc0.c +func gosweepone() uintptr +func gosweepdone() bool + +func bgsweep() { + getg().issystem = true + for { + for gosweepone() != ^uintptr(0) { + sweep.nbgsweep++ + gosched() + } + lock(&gclock) + if !gosweepdone() { + // This can happen if a GC runs between + // gosweepone returning ^0 above + // and the lock being acquired. + unlock(&gclock) + continue + } + sweep.parked = true + goparkunlock(&gclock, "GC sweep wait") + } +} diff --git a/src/runtime/os_darwin.c b/src/runtime/os_darwin.c index 536f688cf1..2de0cd949e 100644 --- a/src/runtime/os_darwin.c +++ b/src/runtime/os_darwin.c @@ -498,41 +498,6 @@ runtime·mach_semrelease(uint32 sem) } } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - #pragma textflag NOSPLIT void runtime·osyield(void) @@ -593,3 +558,10 @@ runtime·unblocksignals(void) { runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_dragonfly.c b/src/runtime/os_dragonfly.c index d470f7c78c..208252d9f3 100644 --- a/src/runtime/os_dragonfly.c +++ b/src/runtime/os_dragonfly.c @@ -215,41 +215,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -338,3 +303,10 @@ runtime·unblocksignals(void) { runtime·sigprocmask(&sigset_none, nil); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c index aae944ea11..476def557f 100644 --- a/src/runtime/os_freebsd.c +++ b/src/runtime/os_freebsd.c @@ -223,41 +223,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -346,3 +311,10 @@ runtime·unblocksignals(void) { runtime·sigprocmask(&sigset_none, nil); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_linux.c b/src/runtime/os_linux.c index 66e7bcec05..3a8c1a7579 100644 --- a/src/runtime/os_linux.c +++ b/src/runtime/os_linux.c @@ -237,41 +237,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -368,3 +333,10 @@ runtime·unblocksignals(void) { runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c index 37a1fcca0d..aecd61740c 100644 --- a/src/runtime/os_nacl.c +++ b/src/runtime/os_nacl.c @@ -291,19 +291,6 @@ runtime·closeonexec(int32) { } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - // Native Client only invokes the exception handler for memory faults. - g->sig = SIGSEGV; - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); -} - uint32 runtime·writelock; // test-and-set spin lock for runtime.write /* diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index 12a15aea0d..a6c409c091 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -28,3 +28,14 @@ const stackSystem = 0 func os_sigpipe() { gothrow("too many writes on closed pipe") } + +func sigpanic() { + g := getg() + if !canpanic(g) { + gothrow("unexpected signal during runtime execution") + } + + // Native Client only invokes the exception handler for memory faults. + g.sig = _SIGSEGV + panicmem() +} diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c index d6c3bc8261..db64b01c8d 100644 --- a/src/runtime/os_netbsd.c +++ b/src/runtime/os_netbsd.c @@ -293,41 +293,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -394,3 +359,10 @@ runtime·unblocksignals(void) { runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c index 59abc97b7c..045c3a9462 100644 --- a/src/runtime/os_openbsd.c +++ b/src/runtime/os_openbsd.c @@ -248,41 +248,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -346,3 +311,10 @@ runtime·unblocksignals(void) { runtime·sigprocmask(SIG_SETMASK, sigset_none); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c index 853f3ef7a1..ab4a51e884 100644 --- a/src/runtime/os_plan9.c +++ b/src/runtime/os_plan9.c @@ -326,84 +326,6 @@ runtime·semawakeup(M *mp) runtime·plan9_semrelease(&mp->waitsemacount, 1); } -static int64 -atolwhex(byte *p) -{ - int64 n; - int32 f; - - n = 0; - f = 0; - while(*p == ' ' || *p == '\t') - p++; - if(*p == '-' || *p == '+') { - if(*p++ == '-') - f = 1; - while(*p == ' ' || *p == '\t') - p++; - } - if(p[0] == '0' && p[1]) { - if(p[1] == 'x' || p[1] == 'X') { - p += 2; - for(;;) { - if('0' <= *p && *p <= '9') - n = n*16 + *p++ - '0'; - else if('a' <= *p && *p <= 'f') - n = n*16 + *p++ - 'a' + 10; - else if('A' <= *p && *p <= 'F') - n = n*16 + *p++ - 'A' + 10; - else - break; - } - } else - while('0' <= *p && *p <= '7') - n = n*8 + *p++ - '0'; - } else - while('0' <= *p && *p <= '9') - n = n*10 + *p++ - '0'; - if(f) - n = -n; - return n; -} - -void -runtime·sigpanic(void) -{ - byte *p; - - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGRFAULT: - case SIGWFAULT: - p = runtime·strstr((byte*)g->m->notesig, (byte*)"addr=")+5; - g->sigcode1 = atolwhex(p); - if(g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - break; - case SIGTRAP: - if(g->paniconfault) - runtime·panicstring("invalid memory address or nil pointer dereference"); - runtime·throw(g->m->notesig); - break; - case SIGINTDIV: - runtime·panicstring("integer divide by zero"); - break; - case SIGFLOAT: - runtime·panicstring("floating point error"); - break; - default: - runtime·panicstring(g->m->notesig); - break; - } -} - #pragma textflag NOSPLIT int32 runtime·read(int32 fd, void *buf, int32 nbytes) diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index c45d22551f..09cb3d93ff 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -32,3 +32,75 @@ type _Plink uintptr func os_sigpipe() { gothrow("too many writes on closed pipe") } + +func sigpanic() { + g := getg() + if !canpanic(g) { + gothrow("unexpected signal during runtime execution") + } + + note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig))) + switch g.sig { + case _SIGRFAULT, _SIGWFAULT: + addr := note[index(note, "addr=")+5:] + g.sigcode1 = uintptr(atolwhex(addr)) + if g.sigcode1 < 0x1000 || g.paniconfault { + panicmem() + } + print("unexpected fault address ", hex(g.sigcode1), "\n") + gothrow("fault") + case _SIGTRAP: + if g.paniconfault { + panicmem() + } + gothrow(note) + case _SIGINTDIV: + panicdivide() + case _SIGFLOAT: + panicfloat() + default: + panic(errorString(note)) + } +} + +func atolwhex(p string) int64 { + for hasprefix(p, " ") || hasprefix(p, "\t") { + p = p[1:] + } + neg := false + if hasprefix(p, "-") || hasprefix(p, "+") { + neg = p[0] == '-' + p = p[1:] + for hasprefix(p, " ") || hasprefix(p, "\t") { + p = p[1:] + } + } + var n int64 + switch { + case hasprefix(p, "0x"), hasprefix(p, "0X"): + p = p[2:] + for ; len(p) > 0; p = p[1:] { + if '0' <= p[0] && p[0] <= '9' { + n = n*16 + int64(p[0]-'0') + } else if 'a' <= p[0] && p[0] <= 'f' { + n = n*16 + int64(p[0]-'a'+10) + } else if 'A' <= p[0] && p[0] <= 'F' { + n = n*16 + int64(p[0]-'A'+10) + } else { + break + } + } + case hasprefix(p, "0"): + for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { + n = n*8 + int64(p[0]-'0') + } + default: + for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { + n = n*10 + int64(p[0]-'0') + } + } + if neg { + n = -n + } + return n +} diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c index e35d2b9971..97afdf40c1 100644 --- a/src/runtime/os_solaris.c +++ b/src/runtime/os_solaris.c @@ -194,41 +194,6 @@ runtime·unminit(void) runtime·signalstack(nil, 0); } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case SIGBUS: - if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGSEGV: - if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case SIGFPE: - switch(g->sigcode0) { - case FPE_INTDIV: - runtime·panicstring("integer divide by zero"); - case FPE_INTOVF: - runtime·panicstring("integer overflow"); - } - runtime·panicstring("floating point error"); - } - runtime·panicstring(runtime·sigtab[g->sig].name); -} - uintptr runtime·memlimit(void) { @@ -580,3 +545,10 @@ runtime·osyield(void) } runtime·osyield1(); } + +#pragma textflag NOSPLIT +int8* +runtime·signame(int32 sig) +{ + return runtime·sigtab[sig].name; +} diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index a4d77f6b75..4e7c50b7fd 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -453,35 +453,6 @@ runtime·issigpanic(uint32 code) return 0; } -void -runtime·sigpanic(void) -{ - if(!runtime·canpanic(g)) - runtime·throw("unexpected signal during runtime execution"); - - switch(g->sig) { - case EXCEPTION_ACCESS_VIOLATION: - if(g->sigcode1 < 0x1000 || g->paniconfault) { - if(g->sigpc == 0) - runtime·panicstring("call of nil func value"); - runtime·panicstring("invalid memory address or nil pointer dereference"); - } - runtime·printf("unexpected fault address %p\n", g->sigcode1); - runtime·throw("fault"); - case EXCEPTION_INT_DIVIDE_BY_ZERO: - runtime·panicstring("integer divide by zero"); - case EXCEPTION_INT_OVERFLOW: - runtime·panicstring("integer overflow"); - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_UNDERFLOW: - runtime·panicstring("floating point error"); - } - runtime·throw("fault"); -} - void runtime·initsig(void) { diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 6a3bfca41f..da4c736add 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -31,3 +31,30 @@ const stackSystem = 512 * ptrSize func os_sigpipe() { gothrow("too many writes on closed pipe") } + +func sigpanic() { + g := getg() + if !canpanic(g) { + gothrow("unexpected signal during runtime execution") + } + + switch uint32(g.sig) { + case _EXCEPTION_ACCESS_VIOLATION: + if g.sigcode1 < 0x1000 || g.paniconfault { + panicmem() + } + print("unexpected fault address ", hex(g.sigcode1), "\n") + gothrow("fault") + case _EXCEPTION_INT_DIVIDE_BY_ZERO: + panicdivide() + case _EXCEPTION_INT_OVERFLOW: + panicoverflow() + case _EXCEPTION_FLT_DENORMAL_OPERAND, + _EXCEPTION_FLT_DIVIDE_BY_ZERO, + _EXCEPTION_FLT_INEXACT_RESULT, + _EXCEPTION_FLT_OVERFLOW, + _EXCEPTION_FLT_UNDERFLOW: + panicfloat() + } + gothrow("fault") +} diff --git a/src/runtime/panic.c b/src/runtime/panic.c index e38ce740bc..4b21975b16 100644 --- a/src/runtime/panic.c +++ b/src/runtime/panic.c @@ -190,6 +190,7 @@ runtime·dopanic_m(void) runtime·exit(2); } +#pragma textflag NOSPLIT bool runtime·canpanic(G *gp) { diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 1e35561d15..a425e83b51 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -24,6 +24,24 @@ func panicdivide() { panic(divideError) } +var overflowError = error(errorString("integer overflow")) + +func panicoverflow() { + panic(overflowError) +} + +var floatError = error(errorString("floating point error")) + +func panicfloat() { + panic(floatError) +} + +var memoryError = error(errorString("invalid memory address or nil pointer dereference")) + +func panicmem() { + panic(memoryError) +} + func throwreturn() { gothrow("no return at end of a typed function - compiler is broken") } @@ -214,3 +232,5 @@ func Goexit() { } goexit() } + +func canpanic(*g) bool diff --git a/src/runtime/print1.go b/src/runtime/print1.go index 93f83ed26f..0fa1fb63c4 100644 --- a/src/runtime/print1.go +++ b/src/runtime/print1.go @@ -10,9 +10,6 @@ import "unsafe" // should use printhex instead of printuint (decimal). type hex uint64 -//go:noescape -func gostring(*byte) string - func bytes(s string) (ret []byte) { rp := (*slice)(unsafe.Pointer(&ret)) sp := (*_string)(noescape(unsafe.Pointer(&s))) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 698be9ffae..c462ae2b5e 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -212,84 +212,10 @@ runtime·schedinit(void) runtime·cgoFree = _cgo_free; } -extern void main·init(void); -extern void runtime·init(void); -extern void main·main(void); - -static FuncVal initDone = { runtime·unlockOSThread }; - -// The main goroutine. -// Note: C frames in general are not copyable during stack growth, for two reasons: -// 1) We don't know where in a frame to find pointers to other stack locations. -// 2) There's no guarantee that globals or heap values do not point into the frame. -// -// The C frame for runtime.main is copyable, because: -// 1) There are no pointers to other stack locations in the frame -// (d.fn points at a global, d.link is nil, d.argp is -1). -// 2) The only pointer into this frame is from the defer chain, -// which is explicitly handled during stack copying. void -runtime·main(void) +runtime·newsysmon(void) { - Defer d; - - // Racectx of m0->g0 is used only as the parent of the main goroutine. - // It must not be used for anything else. - g->m->g0->racectx = 0; - - // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. - // Using decimal instead of binary GB and MB because - // they look nicer in the stack overflow failure message. - if(sizeof(void*) == 8) - runtime·maxstacksize = 1000000000; - else - runtime·maxstacksize = 250000000; - newm(sysmon, nil); - - // Lock the main goroutine onto this, the main OS thread, - // during initialization. Most programs won't care, but a few - // do require certain calls to be made by the main thread. - // Those can arrange for main.main to run in the main thread - // by calling runtime.LockOSThread during initialization - // to preserve the lock. - runtime·lockOSThread(); - - // Defer unlock so that runtime.Goexit during init does the unlock too. - d.fn = &initDone; - d.siz = 0; - d.link = g->defer; - d.argp = NoArgs; - d.special = true; - g->defer = &d; - - if(g->m != &runtime·m0) - runtime·throw("runtime·main not on m0"); - - runtime·init(); - mstats.enablegc = 1; // now that runtime is initialized, GC is okay - - main·init(); - - if(g->defer != &d || d.fn != &initDone) - runtime·throw("runtime: bad defer entry after init"); - g->defer = d.link; - runtime·unlockOSThread(); - - main·main(); - if(raceenabled) - runtime·racefini(); - - // Make racy client program work: if panicking on - // another goroutine at the same time as main returns, - // let the other goroutine finish printing the panic trace. - // Once it does, it will exit. See issue 3934. - if(runtime·panicking) - runtime·park(nil, nil, runtime·gostringnocopy((byte*)"panicwait")); - - runtime·exit(0); - for(;;) - *(int32*)runtime·main = 0; } static void @@ -322,6 +248,8 @@ mcommoninit(M *mp) mp->id = runtime·sched.mcount++; checkmcount(); runtime·mpreinit(mp); + if(mp->gsignal) + mp->gsignal->stackguard1 = mp->gsignal->stackguard; // Add to runtime·allm so garbage collector doesn't free g->m // when it is just in a register or thread-local storage. @@ -977,6 +905,7 @@ runtime·allocm(P *p) else mp->g0 = runtime·malg(8192); mp->g0->m = mp; + mp->g0->stackguard1 = mp->g0->stackguard; if(p == g->m->p) releasep(); @@ -1733,6 +1662,7 @@ runtime·park_m(G *gp) } // Scheduler yield. +#pragma textflag NOSPLIT void runtime·gosched(void) { @@ -2210,6 +2140,7 @@ runtime·malg(int32 stacksize) newg->stack0 = (uintptr)stk; newg->stackguard = (uintptr)stk + StackGuard; newg->stackguard0 = newg->stackguard; + newg->stackguard1 = ~(uintptr)0; newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop); } return newg; @@ -2261,6 +2192,8 @@ runtime·newproc(int32 siz, FuncVal* fn, ...) g->m->locks--; } +void runtime·main(void); + // Create a new g running fn with narg bytes of arguments starting // at argp and returning nret bytes of results. callerpc is the // address of the go statement that created this. The new g is put diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 48b8cbe394..27e84230a1 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -6,6 +6,79 @@ package runtime import "unsafe" +func newsysmon() + +func runtime_init() +func main_init() +func main_main() + +// The main goroutine. +func main() { + g := getg() + + // Racectx of m0->g0 is used only as the parent of the main goroutine. + // It must not be used for anything else. + g.m.g0.racectx = 0 + + // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. + // Using decimal instead of binary GB and MB because + // they look nicer in the stack overflow failure message. + if ptrSize == 8 { + maxstacksize = 1000000000 + } else { + maxstacksize = 250000000 + } + + onM(newsysmon) + + // Lock the main goroutine onto this, the main OS thread, + // during initialization. Most programs won't care, but a few + // do require certain calls to be made by the main thread. + // Those can arrange for main.main to run in the main thread + // by calling runtime.LockOSThread during initialization + // to preserve the lock. + lockOSThread() + + // Defer unlock so that runtime.Goexit during init does the unlock too. + needUnlock := true + defer func() { + if needUnlock { + unlockOSThread() + } + }() + + if g.m != &m0 { + gothrow("runtime.main not on m0") + } + + runtime_init() + memstats.enablegc = true // now that runtime is initialized, GC is okay + + main_init() + + needUnlock = false + unlockOSThread() + + main_main() + if raceenabled { + racefini() + } + + // Make racy client program work: if panicking on + // another goroutine at the same time as main returns, + // let the other goroutine finish printing the panic trace. + // Once it does, it will exit. See issue 3934. + if panicking != 0 { + gopark(nil, nil, "panicwait") + } + + exit(0) + for { + var x *int32 + *x = 0 + } +} + var parkunlock_c byte // start forcegc helper goroutine diff --git a/src/runtime/race.go b/src/runtime/race.go index c7573517dc..bb0ee6df65 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -12,6 +12,8 @@ import ( "unsafe" ) +func racefini() + // RaceDisable disables handling of race events in the current goroutine. func RaceDisable() diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 02563fd36c..e6db8cb836 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -271,6 +271,8 @@ struct G uintptr stackguard0; // cannot move - also known to liblink, libmach, runtime/cgo uintptr stackbase; // cannot move - also known to libmach, runtime/cgo Panic* panic; // cannot move - also known to liblink + // stackguard1 is checked by C code; it is set to ~0 in ordinary (non-g0, non-gsignal) goroutines + uintptr stackguard1; // cannot move - also known to liblink Defer* defer; Gobuf sched; uintptr syscallstack; // if status==Gsyscall, syscallstack = stackbase to use during gc diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go new file mode 100644 index 0000000000..68079859b0 --- /dev/null +++ b/src/runtime/sigpanic_unix.go @@ -0,0 +1,40 @@ +// 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. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package runtime + +func signame(int32) *byte + +func sigpanic() { + g := getg() + if !canpanic(g) { + gothrow("unexpected signal during runtime execution") + } + + switch g.sig { + case _SIGBUS: + if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 || g.paniconfault { + panicmem() + } + print("unexpected fault address ", hex(g.sigcode1), "\n") + gothrow("fault") + case _SIGSEGV: + if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault { + panicmem() + } + print("unexpected fault address ", hex(g.sigcode1), "\n") + gothrow("fault") + case _SIGFPE: + switch g.sigcode0 { + case _FPE_INTDIV: + panicdivide() + case _FPE_INTOVF: + panicoverflow() + } + panicfloat() + } + panic(errorString(gostringnocopy(signame(g.sig)))) +} diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 18b3f40648..bb8c7ac11b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -428,13 +428,6 @@ checkframecopy(Stkframe *frame, void *arg) runtime·printf(" \n"); return false; // stop traceback } - if(f->entry == (uintptr)runtime·main) { - // A special routine at the TOS of the main routine. - // We will allow it to be copied even though we don't - // have full GC info for it (because it is written in C). - cinfo->frames++; - return false; // stop traceback - } if(f->entry == (uintptr)runtime·switchtoM) { // A special routine at the bottom of stack of a goroutine that does onM call. // We will allow it to be copied even though we don't @@ -657,8 +650,7 @@ adjustframe(Stkframe *frame, void *arg) f = frame->fn; if(StackDebug >= 2) runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); - if(f->entry == (uintptr)runtime·main || - f->entry == (uintptr)runtime·switchtoM) + if(f->entry == (uintptr)runtime·switchtoM) return true; targetpc = frame->continpc; if(targetpc == 0) { @@ -1126,3 +1118,21 @@ runtime·shrinkstack(G *gp) return; copystack(gp, nframes, newsize); } + +static void badc(void); + +#pragma textflag NOSPLIT +void +runtime·morestackc(void) +{ + void (*fn)(void); + + fn = badc; + runtime·onM(&fn); +} + +static void +badc(void) +{ + runtime·throw("attempt to execute C code on Go stack"); +} diff --git a/src/runtime/string.c b/src/runtime/string.c index 4f25adf8e3..811a289060 100644 --- a/src/runtime/string.c +++ b/src/runtime/string.c @@ -37,59 +37,6 @@ runtime·findnullw(uint16 *s) uintptr runtime·maxstring = 256; // a hint for print -static String -gostringsize(intgo l) -{ - String s; - uintptr ms; - - if(l == 0) - return runtime·emptystring; - s.str = runtime·mallocgc(l, 0, FlagNoScan|FlagNoZero); - s.len = l; - for(;;) { - ms = runtime·maxstring; - if((uintptr)l <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)l)) - break; - } - return s; -} - -String -runtime·gostring(byte *str) -{ - intgo l; - String s; - - l = runtime·findnull(str); - s = gostringsize(l); - runtime·memmove(s.str, str, l); - return s; -} - -String -runtime·gostringn(byte *str, intgo l) -{ - String s; - - s = gostringsize(l); - runtime·memmove(s.str, str, l); - return s; -} - -// used by cmd/cgo -Slice -runtime·gobytes(byte *p, intgo n) -{ - Slice sl; - - sl.array = runtime·mallocgc(n, 0, FlagNoScan|FlagNoZero); - sl.len = n; - sl.cap = n; - runtime·memmove(sl.array, p, n); - return sl; -} - #pragma textflag NOSPLIT String runtime·gostringnocopy(byte *str) @@ -189,6 +136,8 @@ runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */ return 4; } +String runtime·gostringsize(intgo); + String runtime·gostringw(uint16 *str) { @@ -199,7 +148,7 @@ runtime·gostringw(uint16 *str) n1 = 0; for(i=0; str[i]; i++) n1 += runetochar(buf, str[i]); - s = gostringsize(n1+4); + s = runtime·gostringsize(n1+4); n2 = 0; for(i=0; str[i]; i++) { // check for race @@ -212,22 +161,6 @@ runtime·gostringw(uint16 *str) return s; } -String -runtime·catstring(String s1, String s2) -{ - String s3; - - if(s1.len == 0) - return s2; - if(s2.len == 0) - return s1; - - s3 = gostringsize(s1.len + s2.len); - runtime·memmove(s3.str, s1.str, s1.len); - runtime·memmove(s3.str+s1.len, s2.str, s2.len); - return s3; -} - int32 runtime·strcmp(byte *s1, byte *s2) { diff --git a/src/runtime/string.go b/src/runtime/string.go index da3160449f..99cce1326a 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -239,3 +239,60 @@ func rawruneslice(size int) (b []rune) { (*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4) return } + +// used by cmd/cgo +func gobytes(p *byte, n int) []byte { + if n == 0 { + return make([]byte, 0) + } + x := make([]byte, n) + memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n)) + return x +} + +func gostringsize(n int) string { + s, _ := rawstring(n) + return s +} + +//go:noescape +func findnull(*byte) int + +func gostring(p *byte) string { + l := findnull(p) + if l == 0 { + return "" + } + s, b := rawstring(l) + memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l)) + return s +} + +func gostringn(p *byte, l int) string { + if l == 0 { + return "" + } + s, b := rawstring(l) + memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l)) + return s +} + +func index(s, t string) int { + if len(t) == 0 { + return 0 + } + for i := 0; i < len(s); i++ { + if s[i] == t[0] && hasprefix(s[i:], t) { + return i + } + } + return -1 +} + +func contains(s, t string) bool { + return index(s, t) >= 0 +} + +func hasprefix(s, t string) bool { + return len(s) >= len(t) && s[:len(t)] == t +} diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index bf6c33a41e..f8ea1092e9 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -223,7 +223,6 @@ func lessstack() func morestack() func mstart() func rt0_go() -func sigpanic() // return0 is a stub used to return 0 from deferproc. // It is called at the very end of deferproc to signal diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index 7bdf7b950d..35b250f8c5 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -143,8 +143,17 @@ TEXT reflect·unsafe_NewArray(SB),NOSPLIT,$0-0 TEXT reflect·makechan(SB),NOSPLIT,$0-0 JMP runtime·makechan(SB) -TEXT reflect·rselect(SB), NOSPLIT, $0-0 +TEXT reflect·rselect(SB),NOSPLIT,$0-0 JMP runtime·reflect_rselect(SB) -TEXT os·sigpipe(SB), NOSPLIT, $0-0 +TEXT os·sigpipe(SB),NOSPLIT,$0-0 JMP runtime·os_sigpipe(SB) + +TEXT runtime·runtime_init(SB),NOSPLIT,$0-0 + JMP runtime·init(SB) + +TEXT runtime·main_init(SB),NOSPLIT,$0-0 + JMP main·init(SB) + +TEXT runtime·main_main(SB),NOSPLIT,$0-0 + JMP main·main(SB) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index ec7be28dc0..c1a019296f 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -526,22 +526,6 @@ func showframe(f *_func, gp *g) bool { return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.") } -func contains(s, t string) bool { - if len(t) == 0 { - return true - } - for i := 0; i < len(s); i++ { - if s[i] == t[0] && hasprefix(s[i:], t) { - return true - } - } - return false -} - -func hasprefix(s, t string) bool { - return len(s) >= len(t) && s[:len(t)] == t -} - var gStatusStrings = [...]string{ _Gidle: "idle", _Grunnable: "runnable", From 3a3d47db370805205181da8f96ebf79c3507e953 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 8 Sep 2014 12:33:08 -0700 Subject: [PATCH 006/430] runtime: merge panic1.go back into panic.go LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/139370043 --- src/runtime/panic.go | 202 ++++++++++++++++++++++++++++++++++++++++ src/runtime/panic1.go | 209 ------------------------------------------ 2 files changed, 202 insertions(+), 209 deletions(-) delete mode 100644 src/runtime/panic1.go diff --git a/src/runtime/panic.go b/src/runtime/panic.go index a425e83b51..740fa026e2 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -234,3 +234,205 @@ func Goexit() { } func canpanic(*g) bool + +// Print all currently active panics. Used when crashing. +func printpanics(p *_panic) { + if p.link != nil { + printpanics(p.link) + print("\t") + } + print("panic: ") + printany(p.arg) + if p.recovered { + print(" [recovered]") + } + print("\n") +} + +// The implementation of the predeclared function panic. +func gopanic(e interface{}) { + gp := getg() + if gp.m.curg != gp { + gothrow("panic on m stack") + } + var p _panic + var dabort _defer + p.arg = e + p.link = gp._panic + gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) + + fn := abortpanic + dabort.fn = *(**funcval)(unsafe.Pointer(&fn)) + dabort.siz = ptrSize + dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here? + dabort.argp = _NoArgs + dabort.special = true + + for { + d := gp._defer + if d == nil { + break + } + // take defer off list in case of recursive panic + gp._defer = d.link + argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy + pc := d.pc + + // The deferred function may cause another panic, + // so reflectcall may not return. Set up a defer + // to mark this panic aborted if that happens. + dabort.link = gp._defer + gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort))) + p._defer = d + + p.argp = getargp(0) + reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) + p.argp = 0 + + // reflectcall did not panic. Remove dabort. + if gp._defer != &dabort { + gothrow("bad defer entry in panic") + } + gp._defer = dabort.link + + // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic + //GC() + + freedefer(d) + if p.recovered { + gp._panic = p.link + // Aborted panics are marked but remain on the g.panic list. + // Remove them from the list and free the associated defers. + for gp._panic != nil && gp._panic.aborted { + freedefer(gp._panic._defer) + gp._panic = gp._panic.link + } + if gp._panic == nil { // must be done with signal + gp.sig = 0 + } + // Pass information about recovering frame to recovery. + gp.sigcode0 = uintptr(argp) + gp.sigcode1 = pc + mcall(recovery_m) + gothrow("recovery failed") // mcall should not return + } + } + + // ran out of deferred calls - old-school panic now + startpanic() + printpanics(gp._panic) + dopanic(0) // should not return + *(*int)(nil) = 0 // not reached +} + +// getargp returns the location where the caller +// writes outgoing function call arguments. +//go:nosplit +func getargp(x int) uintptr { + // x is an argument mainly so that we can return its address. + // However, we need to make the function complex enough + // that it won't be inlined. We always pass x = 0, so this code + // does nothing other than keep the compiler from thinking + // the function is simple enough to inline. + if x > 0 { + return getcallersp(unsafe.Pointer(&x)) * 0 + } + return uintptr(noescape(unsafe.Pointer(&x))) +} + +func abortpanic(p *_panic) { + p.aborted = true +} + +// The implementation of the predeclared function recover. +// Cannot split the stack because it needs to reliably +// find the stack segment of its caller. +// +// TODO(rsc): Once we commit to CopyStackAlways, +// this doesn't need to be nosplit. +//go:nosplit +func gorecover(argp uintptr) interface{} { + // Must be in a function running as part of a deferred call during the panic. + // Must be called from the topmost function of the call + // (the function used in the defer statement). + // p.argp is the argument pointer of that topmost deferred function call. + // Compare against argp reported by caller. + // If they match, the caller is the one who can recover. + gp := getg() + p := gp._panic + if p != nil && !p.recovered && argp == p.argp { + p.recovered = true + return p.arg + } + return nil +} + +//go:nosplit +func startpanic() { + onM(startpanic_m) +} + +//go:nosplit +func dopanic(unused int) { + gp := getg() + mp := acquirem() + mp.ptrarg[0] = unsafe.Pointer(gp) + mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused)) + mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused)) + onM(dopanic_m) // should never return + *(*int)(nil) = 0 +} + +//go:nosplit +func throw(s *byte) { + gp := getg() + if gp.m.throwing == 0 { + gp.m.throwing = 1 + } + startpanic() + print("fatal error: ", gostringnocopy(s), "\n") + dopanic(0) + *(*int)(nil) = 0 // not reached +} + +//go:nosplit +func gothrow(s string) { + gp := getg() + if gp.m.throwing == 0 { + gp.m.throwing = 1 + } + startpanic() + print("fatal error: ", s, "\n") + dopanic(0) + *(*int)(nil) = 0 // not reached +} + +func panicstring(s *int8) { + // m.softfloat is set during software floating point, + // which might cause a fault during a memory load. + // It increments m.locks to avoid preemption. + // If we're panicking, the software floating point frames + // will be unwound, so decrement m.locks as they would. + gp := getg() + if gp.m.softfloat != 0 { + gp.m.locks-- + gp.m.softfloat = 0 + } + + if gp.m.mallocing != 0 { + print("panic: ", s, "\n") + gothrow("panic during malloc") + } + if gp.m.gcing != 0 { + print("panic: ", s, "\n") + gothrow("panic during gc") + } + if gp.m.locks != 0 { + print("panic: ", s, "\n") + gothrow("panic holding locks") + } + + var err interface{} + newErrorCString(unsafe.Pointer(s), &err) + gopanic(err) +} diff --git a/src/runtime/panic1.go b/src/runtime/panic1.go deleted file mode 100644 index e877434320..0000000000 --- a/src/runtime/panic1.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2012 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 runtime - -import "unsafe" - -// Print all currently active panics. Used when crashing. -func printpanics(p *_panic) { - if p.link != nil { - printpanics(p.link) - print("\t") - } - print("panic: ") - printany(p.arg) - if p.recovered { - print(" [recovered]") - } - print("\n") -} - -// The implementation of the predeclared function panic. -func gopanic(e interface{}) { - gp := getg() - if gp.m.curg != gp { - gothrow("panic on m stack") - } - var p _panic - var dabort _defer - p.arg = e - p.link = gp._panic - gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) - - fn := abortpanic - dabort.fn = *(**funcval)(unsafe.Pointer(&fn)) - dabort.siz = ptrSize - dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here? - dabort.argp = _NoArgs - dabort.special = true - - for { - d := gp._defer - if d == nil { - break - } - // take defer off list in case of recursive panic - gp._defer = d.link - argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy - pc := d.pc - - // The deferred function may cause another panic, - // so reflectcall may not return. Set up a defer - // to mark this panic aborted if that happens. - dabort.link = gp._defer - gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort))) - p._defer = d - - p.argp = getargp(0) - reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) - p.argp = 0 - - // reflectcall did not panic. Remove dabort. - if gp._defer != &dabort { - gothrow("bad defer entry in panic") - } - gp._defer = dabort.link - - // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic - //GC() - - freedefer(d) - if p.recovered { - gp._panic = p.link - // Aborted panics are marked but remain on the g.panic list. - // Remove them from the list and free the associated defers. - for gp._panic != nil && gp._panic.aborted { - freedefer(gp._panic._defer) - gp._panic = gp._panic.link - } - if gp._panic == nil { // must be done with signal - gp.sig = 0 - } - // Pass information about recovering frame to recovery. - gp.sigcode0 = uintptr(argp) - gp.sigcode1 = pc - mcall(recovery_m) - gothrow("recovery failed") // mcall should not return - } - } - - // ran out of deferred calls - old-school panic now - startpanic() - printpanics(gp._panic) - dopanic(0) // should not return - *(*int)(nil) = 0 // not reached -} - -// getargp returns the location where the caller -// writes outgoing function call arguments. -//go:nosplit -func getargp(x int) uintptr { - // x is an argument mainly so that we can return its address. - // However, we need to make the function complex enough - // that it won't be inlined. We always pass x = 0, so this code - // does nothing other than keep the compiler from thinking - // the function is simple enough to inline. - if x > 0 { - return getcallersp(unsafe.Pointer(&x)) * 0 - } - return uintptr(noescape(unsafe.Pointer(&x))) -} - -func abortpanic(p *_panic) { - p.aborted = true -} - -// The implementation of the predeclared function recover. -// Cannot split the stack because it needs to reliably -// find the stack segment of its caller. -// -// TODO(rsc): Once we commit to CopyStackAlways, -// this doesn't need to be nosplit. -//go:nosplit -func gorecover(argp uintptr) interface{} { - // Must be in a function running as part of a deferred call during the panic. - // Must be called from the topmost function of the call - // (the function used in the defer statement). - // p.argp is the argument pointer of that topmost deferred function call. - // Compare against argp reported by caller. - // If they match, the caller is the one who can recover. - gp := getg() - p := gp._panic - if p != nil && !p.recovered && argp == p.argp { - p.recovered = true - return p.arg - } - return nil -} - -//go:nosplit -func startpanic() { - onM(startpanic_m) -} - -//go:nosplit -func dopanic(unused int) { - gp := getg() - mp := acquirem() - mp.ptrarg[0] = unsafe.Pointer(gp) - mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused)) - mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused)) - onM(dopanic_m) // should never return - *(*int)(nil) = 0 -} - -//go:nosplit -func throw(s *byte) { - gp := getg() - if gp.m.throwing == 0 { - gp.m.throwing = 1 - } - startpanic() - print("fatal error: ", gostringnocopy(s), "\n") - dopanic(0) - *(*int)(nil) = 0 // not reached -} - -//go:nosplit -func gothrow(s string) { - gp := getg() - if gp.m.throwing == 0 { - gp.m.throwing = 1 - } - startpanic() - print("fatal error: ", s, "\n") - dopanic(0) - *(*int)(nil) = 0 // not reached -} - -func panicstring(s *int8) { - // m.softfloat is set during software floating point, - // which might cause a fault during a memory load. - // It increments m.locks to avoid preemption. - // If we're panicking, the software floating point frames - // will be unwound, so decrement m.locks as they would. - gp := getg() - if gp.m.softfloat != 0 { - gp.m.locks-- - gp.m.softfloat = 0 - } - - if gp.m.mallocing != 0 { - print("panic: ", s, "\n") - gothrow("panic during malloc") - } - if gp.m.gcing != 0 { - print("panic: ", s, "\n") - gothrow("panic during gc") - } - if gp.m.locks != 0 { - print("panic: ", s, "\n") - gothrow("panic holding locks") - } - - var err interface{} - newErrorCString(unsafe.Pointer(s), &err) - gopanic(err) -} From 201cfe4afb657fec7bc9535ff0e2312be762c2ca Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 16:56:46 -0400 Subject: [PATCH 007/430] runtime: run sighandler on g0 stack on windows The sighander has been run at the bottom of the currently executing goroutine stack, but it's in C, and we don't want C on our ordinary goroutine stacks. Worse, it does a lot of stuff, and it might need more stack space. There is scary code in traceback_windows.go that talks about stack splits during sighandler. Moving sighandler to g0 will eliminate the possibility of stack splits and such, and then we can delete traceback_windows.go entirely. Win win. On the builder, all.bat passes with GOARCH=amd64 and all.bat gets most of the way with GOARCH=386 except for a DLL-loading test that I think is unrelated. Fixes windows build. TBR=brainman, iant CC=golang-codereviews https://golang.org/cl/140380043 --- src/runtime/sys_windows_386.s | 47 ++++++++++++++++++++++++++++----- src/runtime/sys_windows_amd64.s | 47 ++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index a9e096f018..7d4dc6a69c 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -76,7 +76,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL ptrs+0(FP), CX - SUBL $32, SP + SUBL $40, SP // save callee-saved registers MOVL BX, 28(SP) @@ -84,10 +84,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL SI, 20(SP) MOVL DI, 24(SP) - MOVL 0(CX), BX // ExceptionRecord* - MOVL 4(CX), CX // Context* - - // fetch g + // find g get_tls(DX) CMPL DX, $0 JNE 3(PC) @@ -97,6 +94,35 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 CMPL DX, $0 JNE 2(PC) CALL runtime·badsignal2(SB) + + // save g and SP in case of stack switch + MOVL DX, 32(SP) // g + MOVL SP, 36(SP) + + // do we need to switch to the g0 stack? + MOVL g_m(DX), BX + MOVL m_g0(BX), BX + CMPL DX, BX + JEQ sigtramp_g0 + + // switch to the g0 stack + get_tls(BP) + MOVL BX, g(BP) + MOVL (g_sched+gobuf_sp)(BX), DI + // make it look like mstart called us on g0, to stop traceback + SUBL $4, DI + MOVL $runtime·mstart(SB), 0(DI) + // traceback will think that we've done SUBL + // on this stack, so subtract them here to match. + // (we need room for sighandler arguments anyway). + // and re-save old SP for restoring later. + SUBL $40, DI + MOVL SP, 36(DI) + MOVL DI, SP + +sigtramp_g0: + MOVL 0(CX), BX // ExceptionRecord* + MOVL 4(CX), CX // Context* // call sighandler(ExceptionRecord*, Context*, G*) MOVL BX, 0(SP) MOVL CX, 4(SP) @@ -105,6 +131,13 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // AX is set to report result back to Windows MOVL 12(SP), AX + // switch back to original stack and g + // no-op if we never left. + MOVL 36(SP), SP + MOVL 32(SP), DX + get_tls(BP) + MOVL DX, g(BP) + done: // restore callee-saved registers MOVL 24(SP), DI @@ -112,7 +145,7 @@ done: MOVL 16(SP), BP MOVL 28(SP), BX - ADDL $32, SP + ADDL $40, SP // RET 4 (return and pop 4 bytes parameters) BYTE $0xC2; WORD $4 RET // unreached; make assembler happy @@ -128,7 +161,7 @@ TEXT runtime·profileloop(SB),NOSPLIT,$0 PUSHL $runtime·profileloop1(SB) CALL runtime·externalthreadhandler(SB) MOVL 4(SP), CX - ADDL $12, SP + ADDL $40, SP JMP CX TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 21f73daf09..3d63a04de9 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -106,7 +106,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved // as required by windows callback convention. PUSHFQ - SUBQ $96, SP + SUBQ $112, SP MOVQ DI, 80(SP) MOVQ SI, 72(SP) MOVQ BP, 64(SP) @@ -116,10 +116,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVQ R14, 32(SP) MOVQ R15, 88(SP) - MOVQ 0(CX), BX // ExceptionRecord* - MOVQ 8(CX), CX // Context* - - // fetch g + // find g get_tls(DX) CMPQ DX, $0 JNE 3(PC) @@ -129,6 +126,37 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 CMPQ DX, $0 JNE 2(PC) CALL runtime·badsignal2(SB) + + // save g and SP in case of stack switch + MOVQ DX, 96(SP) // g + MOVQ SP, 104(SP) + + // do we need to switch to the g0 stack? + MOVQ g_m(DX), BX + MOVQ m_g0(BX), BX + CMPQ DX, BX + JEQ sigtramp_g0 + + // switch to g0 stack + get_tls(BP) + MOVQ BX, g(BP) + MOVQ (g_sched+gobuf_sp)(BX), DI + // make it look like mstart called us on g0, to stop traceback + SUBQ $8, DI + MOVQ $runtime·mstart(SB), SI + MOVQ SI, 0(DI) + // traceback will think that we've done PUSHFQ and SUBQ + // on this stack, so subtract them here to match. + // (we need room for sighandler arguments anyway). + // and re-save old SP for restoring later. + SUBQ $(112+8), DI + // save g, save old stack pointer. + MOVQ SP, 104(DI) + MOVQ DI, SP + +sigtramp_g0: + MOVQ 0(CX), BX // ExceptionRecord* + MOVQ 8(CX), CX // Context* // call sighandler(ExceptionRecord*, Context*, G*) MOVQ BX, 0(SP) MOVQ CX, 8(SP) @@ -137,6 +165,13 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // AX is set to report result back to Windows MOVL 24(SP), AX + // switch back to original stack and g + // no-op if we never left. + MOVQ 104(SP), SP + MOVQ 96(SP), DX + get_tls(BP) + MOVQ DX, g(BP) + done: // restore registers as required for windows callback MOVQ 88(SP), R15 @@ -147,7 +182,7 @@ done: MOVQ 64(SP), BP MOVQ 72(SP), SI MOVQ 80(SP), DI - ADDQ $96, SP + ADDQ $112, SP POPFQ RET From cf622d758cd51cfa09f5b503d323c81ed3a5541e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 16:59:59 -0400 Subject: [PATCH 008/430] syscall: keep allocated C string live across call to Syscall Given: p := alloc() fn_taking_ptr(p) p is NOT recorded as live at the call to fn_taking_ptr: it's not needed by the code following the call. p was passed to fn_taking_ptr, and fn_taking_ptr must keep it alive as long as it needs it. In practice, fn_taking_ptr will keep its own arguments live for as long as the function is executing. But if instead you have: p := alloc() i := uintptr(unsafe.Pointer(p)) fn_taking_int(i) p is STILL NOT recorded as live at the call to fn_taking_int: it's not needed by the code following the call. fn_taking_int is responsible for keeping its own arguments live, but fn_taking_int is written to take an integer, so even though fn_taking_int does keep its argument live, that argument does not keep the allocated memory live, because the garbage collector does not dereference integers. The shorter form: p := alloc() fn_taking_int(uintptr(unsafe.Pointer(p))) and the even shorter form: fn_taking_int(uintptr(unsafe.Pointer(alloc()))) are both the same as the 3-line form above. syscall.Syscall is like fn_taking_int: it is written to take a list of integers, and yet those integers are sometimes pointers. If there is no other copy of those pointers being kept live, the memory they point at may be garbage collected during the call to syscall.Syscall. This is happening on Solaris: for whatever reason, the timing is such that the garbage collector manages to free the string argument to the open(2) system call before the system call has been invoked. Change the system call wrappers to insert explicit references that will keep the allocations alive in the original frame (and therefore preserve the memory) until after syscall.Syscall has returned. Should fix Solaris flakiness. This is not a problem for cgo, because cgo wrappers have correctly typed arguments. LGTM=iant, khr, aram, rlh R=iant, khr, bradfitz, aram, rlh CC=dvyukov, golang-codereviews, r https://golang.org/cl/139360044 --- src/syscall/asm.s | 8 ++++ src/syscall/dll_windows.go | 1 + src/syscall/mksyscall.pl | 6 +++ src/syscall/mksyscall_solaris.pl | 8 +++- src/syscall/so_solaris.go | 2 + src/syscall/syscall.go | 7 ++++ src/syscall/syscall_darwin.go | 1 + src/syscall/syscall_linux.go | 8 +++- src/syscall/syscall_linux_386.go | 1 + src/syscall/syscall_linux_arm.go | 1 + src/syscall/syscall_plan9.go | 2 + src/syscall/zsyscall_darwin_386.go | 32 ++++++++++++++++ src/syscall/zsyscall_darwin_amd64.go | 32 ++++++++++++++++ src/syscall/zsyscall_dragonfly_386.go | 30 +++++++++++++++ src/syscall/zsyscall_dragonfly_amd64.go | 30 +++++++++++++++ src/syscall/zsyscall_freebsd_386.go | 30 +++++++++++++++ src/syscall/zsyscall_freebsd_amd64.go | 30 +++++++++++++++ src/syscall/zsyscall_freebsd_arm.go | 30 +++++++++++++++ src/syscall/zsyscall_linux_386.go | 50 ++++++++++++++++++++++++ src/syscall/zsyscall_linux_amd64.go | 51 +++++++++++++++++++++++++ src/syscall/zsyscall_linux_arm.go | 50 ++++++++++++++++++++++++ src/syscall/zsyscall_netbsd_386.go | 27 +++++++++++++ src/syscall/zsyscall_netbsd_amd64.go | 27 +++++++++++++ src/syscall/zsyscall_netbsd_arm.go | 27 +++++++++++++ src/syscall/zsyscall_openbsd_386.go | 29 ++++++++++++++ src/syscall/zsyscall_openbsd_amd64.go | 29 ++++++++++++++ src/syscall/zsyscall_plan9_386.go | 46 +++++++++++++--------- src/syscall/zsyscall_plan9_amd64.go | 12 +++++- src/syscall/zsyscall_solaris_amd64.go | 23 +++++++++++ 29 files changed, 607 insertions(+), 23 deletions(-) create mode 100644 src/syscall/asm.s diff --git a/src/syscall/asm.s b/src/syscall/asm.s new file mode 100644 index 0000000000..d4ca868f17 --- /dev/null +++ b/src/syscall/asm.s @@ -0,0 +1,8 @@ +// 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. + +#include "textflag.h" + +TEXT ·use(SB),NOSPLIT,$0 + RET diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go index d29e9921cf..c2394682d9 100644 --- a/src/syscall/dll_windows.go +++ b/src/syscall/dll_windows.go @@ -72,6 +72,7 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) { return nil, err } a, e := getprocaddress(uintptr(d.Handle), namep) + use(unsafe.Pointer(namep)) if e != 0 { return nil, &DLLError{ Err: e, diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl index 6d35fa6892..dff9138385 100755 --- a/src/syscall/mksyscall.pl +++ b/src/syscall/mksyscall.pl @@ -132,6 +132,7 @@ while(<>) { # Prepare arguments to Syscall. my @args = (); + my @uses = (); my $n = 0; foreach my $p (@in) { my ($name, $type) = parseparam($p); @@ -142,12 +143,14 @@ while(<>) { $text .= "\t_p$n, $errvar = BytePtrFromString($name)\n"; $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; push @args, "uintptr(unsafe.Pointer(_p$n))"; + push @uses, "use(unsafe.Pointer(_p$n))"; $n++; } elsif($type eq "string") { print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; $text .= "\tvar _p$n *byte\n"; $text .= "\t_p$n, _ = BytePtrFromString($name)\n"; push @args, "uintptr(unsafe.Pointer(_p$n))"; + push @uses, "use(unsafe.Pointer(_p$n))"; $n++; } elsif($type =~ /^\[\](.*)/) { # Convert slice into pointer, length. @@ -278,6 +281,9 @@ while(<>) { } else { $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; } + foreach my $use (@uses) { + $text .= "\t$use\n"; + } $text .= $body; if ($plan9 && $ret[2] eq "e1") { diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl index 130d043d96..e72a4d11ae 100755 --- a/src/syscall/mksyscall_solaris.pl +++ b/src/syscall/mksyscall_solaris.pl @@ -136,8 +136,8 @@ while(<>) { # Prepare arguments to Syscall. my @args = (); + my @uses = (); my $n = 0; - my @pin= (); foreach my $p (@in) { my ($name, $type) = parseparam($p); if($type =~ /^\*/) { @@ -147,12 +147,14 @@ while(<>) { $text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; push @args, "uintptr(unsafe.Pointer(_p$n))"; + push @uses, "use(unsafe.Pointer(_p$n))"; $n++; } elsif($type eq "string") { print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; $text .= "\tvar _p$n $strconvtype\n"; $text .= "\t_p$n, _ = $strconvfunc($name)\n"; push @args, "uintptr(unsafe.Pointer(_p$n))"; + push @uses, "use(unsafe.Pointer(_p$n))"; $n++; } elsif($type =~ /^\[\](.*)/) { # Convert slice into pointer, length. @@ -176,7 +178,6 @@ while(<>) { } else { push @args, "uintptr($name)"; } - push @pin, sprintf "\"%s=\", %s, ", $name, $name; } my $nargs = @args; @@ -240,6 +241,9 @@ while(<>) { } else { $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; } + foreach my $use (@uses) { + $text .= "\t$use\n"; + } $text .= $body; if ($do_errno) { diff --git a/src/syscall/so_solaris.go b/src/syscall/so_solaris.go index bf1b756049..8b1980fb40 100644 --- a/src/syscall/so_solaris.go +++ b/src/syscall/so_solaris.go @@ -39,6 +39,7 @@ func loadSO(name string) (*so, error) { return nil, err } h, e := dlopen(namep, 1) // RTLD_LAZY + use(unsafe.Pointer(namep)) if e != 0 { return nil, &soError{ Err: e, @@ -70,6 +71,7 @@ func (d *so) FindProc(name string) (*proc, error) { return nil, err } a, _ := dlsym(uintptr(d.Handle), namep) + use(unsafe.Pointer(namep)) if a == 0 { return nil, &soError{ Err: ENOSYS, diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go index 3fd95798f3..1f209ecd58 100644 --- a/src/syscall/syscall.go +++ b/src/syscall/syscall.go @@ -26,6 +26,8 @@ // package syscall +import "unsafe" + // StringByteSlice is deprecated. Use ByteSliceFromString instead. // If s contains a NUL byte this function panics instead of // returning an error. @@ -86,3 +88,8 @@ func (ts *Timespec) Nano() int64 { func (tv *Timeval) Nano() int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 } + +// use is a no-op, but the compiler cannot see that it is. +// Calling use(p) ensures that p is kept live until that point. +//go:noescape +func use(p unsafe.Pointer) diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go index 97414dcda6..f026a56d8b 100644 --- a/src/syscall/syscall_darwin.go +++ b/src/syscall/syscall_darwin.go @@ -143,6 +143,7 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( uintptr(options), 0, ) + use(unsafe.Pointer(_p0)) if e1 != 0 { return nil, e1 } diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 36ba0518d3..c40c718904 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -94,7 +94,9 @@ func Futimesat(dirfd int, path string, tv []Timeval) (err error) { if err != nil { return err } - return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) + err = futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) + use(unsafe.Pointer(pathp)) + return err } func Futimes(fd int, tv []Timeval) (err error) { @@ -769,7 +771,9 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri if err != nil { return err } - return mount(source, target, fstype, flags, datap) + err = mount(source, target, fstype, flags, datap) + use(unsafe.Pointer(datap)) + return err } // Sendto diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go index 3cb201998c..827875053d 100644 --- a/src/syscall/syscall_linux_386.go +++ b/src/syscall/syscall_linux_386.go @@ -332,6 +332,7 @@ func Statfs(path string, buf *Statfs_t) (err error) { return err } _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + use(unsafe.Pointer(pathp)) if e != 0 { err = e } diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go index 3631b59db2..b127345d3f 100644 --- a/src/syscall/syscall_linux_arm.go +++ b/src/syscall/syscall_linux_arm.go @@ -101,6 +101,7 @@ func Statfs(path string, buf *Statfs_t) (err error) { return err } _, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf))) + use(unsafe.Pointer(pathp)) if e != 0 { err = e } diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go index ddd93ad5db..618e02cecf 100644 --- a/src/syscall/syscall_plan9.go +++ b/src/syscall/syscall_plan9.go @@ -260,7 +260,9 @@ func Unmount(name, old string) (err error) { return err } r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0) + use(unsafe.Pointer(namep)) } + use(unsafe.Pointer(oldp)) if int32(r0) == -1 { err = e diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go index a6a176b601..934565fc31 100644 --- a/src/syscall/zsyscall_darwin_386.go +++ b/src/syscall/zsyscall_darwin_386.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -298,6 +299,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -323,6 +325,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -338,6 +341,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -353,6 +357,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -368,6 +373,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -383,6 +389,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -434,6 +441,8 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { return } _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -710,6 +719,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -730,6 +740,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -755,6 +767,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +783,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -785,6 +799,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -800,6 +815,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -883,6 +899,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -899,6 +916,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -972,6 +990,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -993,6 +1012,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1008,6 +1029,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1023,6 +1045,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1089,6 +1112,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1195,6 +1219,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1210,6 +1235,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1230,6 +1256,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1255,6 +1283,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1278,6 +1307,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1293,6 +1323,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1308,6 +1339,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go index f5867c45da..75cf2513b5 100644 --- a/src/syscall/zsyscall_darwin_amd64.go +++ b/src/syscall/zsyscall_darwin_amd64.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -298,6 +299,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -323,6 +325,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -338,6 +341,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -353,6 +357,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -368,6 +373,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -383,6 +389,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -434,6 +441,8 @@ func Exchangedata(path1 string, path2 string, options int) (err error) { return } _, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options)) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -710,6 +719,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -730,6 +740,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -755,6 +767,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +783,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -785,6 +799,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -800,6 +815,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -883,6 +899,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -899,6 +916,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -972,6 +990,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -993,6 +1012,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1008,6 +1029,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1023,6 +1045,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1089,6 +1112,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1195,6 +1219,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1210,6 +1235,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1230,6 +1256,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1255,6 +1283,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1278,6 +1307,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1293,6 +1323,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1308,6 +1339,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_dragonfly_386.go b/src/syscall/zsyscall_dragonfly_386.go index 0ec8132326..01b0819772 100644 --- a/src/syscall/zsyscall_dragonfly_386.go +++ b/src/syscall/zsyscall_dragonfly_386.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -312,6 +313,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -337,6 +339,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -352,6 +355,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -367,6 +371,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -382,6 +387,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -397,6 +403,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -724,6 +731,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -744,6 +752,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -769,6 +779,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -784,6 +795,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -799,6 +811,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -814,6 +827,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -839,6 +853,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -855,6 +870,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -894,6 +910,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -915,6 +932,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -930,6 +949,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -945,6 +965,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1011,6 +1032,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1107,6 +1129,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1122,6 +1145,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1166,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1167,6 +1193,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1190,6 +1217,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1205,6 +1233,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1220,6 +1249,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go index 8c7cce54e7..0121374692 100644 --- a/src/syscall/zsyscall_dragonfly_amd64.go +++ b/src/syscall/zsyscall_dragonfly_amd64.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -312,6 +313,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -337,6 +339,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -352,6 +355,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -367,6 +371,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -382,6 +387,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -397,6 +403,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -724,6 +731,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -744,6 +752,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -769,6 +779,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -784,6 +795,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -799,6 +811,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -814,6 +827,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -839,6 +853,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -855,6 +870,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -894,6 +910,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -915,6 +932,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -930,6 +949,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -945,6 +965,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1011,6 +1032,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1107,6 +1129,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1122,6 +1145,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1166,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1167,6 +1193,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1190,6 +1217,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1205,6 +1233,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1220,6 +1249,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go index 5befe83c6b..c8c636fa11 100644 --- a/src/syscall/zsyscall_freebsd_386.go +++ b/src/syscall/zsyscall_freebsd_386.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -278,6 +279,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -303,6 +305,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -318,6 +321,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -333,6 +337,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -348,6 +353,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -363,6 +369,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -690,6 +697,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -710,6 +718,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -735,6 +745,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -750,6 +761,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -765,6 +777,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -780,6 +793,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -805,6 +819,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -821,6 +836,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -894,6 +910,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -915,6 +932,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -930,6 +949,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -945,6 +965,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1011,6 +1032,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1107,6 +1129,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1122,6 +1145,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1166,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1167,6 +1193,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1190,6 +1217,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1205,6 +1233,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1220,6 +1249,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go index ab2eb80c62..026b560ca0 100644 --- a/src/syscall/zsyscall_freebsd_amd64.go +++ b/src/syscall/zsyscall_freebsd_amd64.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -278,6 +279,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -303,6 +305,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -318,6 +321,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -333,6 +337,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -348,6 +353,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -363,6 +369,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -690,6 +697,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -710,6 +718,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -735,6 +745,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -750,6 +761,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -765,6 +777,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -780,6 +793,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -805,6 +819,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -821,6 +836,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -894,6 +910,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -915,6 +932,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -930,6 +949,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -945,6 +965,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1011,6 +1032,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1107,6 +1129,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1122,6 +1145,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1166,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1167,6 +1193,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1190,6 +1217,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1205,6 +1233,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1220,6 +1249,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go index c1f0f907cd..0c349cb61d 100644 --- a/src/syscall/zsyscall_freebsd_arm.go +++ b/src/syscall/zsyscall_freebsd_arm.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -278,6 +279,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -303,6 +305,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -318,6 +321,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -333,6 +337,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -348,6 +353,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -363,6 +369,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -690,6 +697,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -710,6 +718,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -735,6 +745,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -750,6 +761,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -765,6 +777,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -780,6 +793,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -805,6 +819,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -821,6 +836,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -894,6 +910,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -915,6 +932,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -930,6 +949,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -945,6 +965,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1011,6 +1032,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1107,6 +1129,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1122,6 +1145,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1166,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1167,6 +1193,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1190,6 +1217,7 @@ func Undelete(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1205,6 +1233,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1220,6 +1249,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index bfac41655a..dee8343134 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -14,6 +14,7 @@ func open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -30,6 +31,7 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) return } r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -66,6 +68,7 @@ func utimes(path string, times *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -81,6 +84,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) { return } _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -144,6 +148,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { return } _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -169,6 +174,9 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt return } _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + use(unsafe.Pointer(_p2)) if e1 != 0 { err = e1 } @@ -184,6 +192,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -199,6 +208,7 @@ func Acct(path string) (err error) { return } _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -225,6 +235,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -240,6 +251,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -255,6 +267,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -280,6 +293,7 @@ func Creat(path string, mode uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -383,6 +397,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -428,6 +443,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -443,6 +459,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -591,6 +608,8 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { _p2 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) sz = int(r0) if e1 != 0 { err = e1 @@ -607,6 +626,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e return } r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + use(unsafe.Pointer(_p0)) watchdesc = int(r0) if e1 != 0 { err = e1 @@ -688,6 +708,8 @@ func Link(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -709,6 +731,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + use(unsafe.Pointer(_p0)) sz = int(r0) if e1 != 0 { err = e1 @@ -725,6 +748,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -740,6 +764,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -755,6 +780,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +796,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -810,6 +837,8 @@ func PivotRoot(newroot string, putold string) (err error) { return } _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -858,6 +887,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -879,6 +909,8 @@ func Removexattr(path string, attr string) (err error) { return } _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -899,6 +931,8 @@ func Rename(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -919,6 +953,8 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e return } _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -934,6 +970,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1033,6 +1070,8 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { _p2 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1053,6 +1092,8 @@ func Symlink(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1135,6 +1176,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1150,6 +1192,7 @@ func Unlinkat(dirfd int, path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1165,6 +1208,7 @@ func Unmount(target string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1200,6 +1244,7 @@ func Utime(path string, buf *Utimbuf) (err error) { return } _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1358,6 +1403,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1455,6 +1501,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1470,6 +1517,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1601,6 +1649,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1626,6 +1675,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 537b080888..ed3afd4e0c 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -14,6 +14,7 @@ func open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -30,6 +31,7 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) return } r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -66,6 +68,7 @@ func utimes(path string, times *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -81,6 +84,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) { return } _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -144,6 +148,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { return } _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -169,6 +174,9 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt return } _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + use(unsafe.Pointer(_p2)) if e1 != 0 { err = e1 } @@ -184,6 +192,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -199,6 +208,7 @@ func Acct(path string) (err error) { return } _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -225,6 +235,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -240,6 +251,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -255,6 +267,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -280,6 +293,7 @@ func Creat(path string, mode uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -383,6 +397,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -428,6 +443,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -443,6 +459,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -591,6 +608,8 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { _p2 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) sz = int(r0) if e1 != 0 { err = e1 @@ -607,6 +626,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e return } r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + use(unsafe.Pointer(_p0)) watchdesc = int(r0) if e1 != 0 { err = e1 @@ -688,6 +708,8 @@ func Link(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -709,6 +731,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + use(unsafe.Pointer(_p0)) sz = int(r0) if e1 != 0 { err = e1 @@ -725,6 +748,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -740,6 +764,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -755,6 +780,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +796,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -810,6 +837,8 @@ func PivotRoot(newroot string, putold string) (err error) { return } _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -858,6 +887,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -879,6 +909,8 @@ func Removexattr(path string, attr string) (err error) { return } _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -899,6 +931,8 @@ func Rename(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -919,6 +953,8 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e return } _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -934,6 +970,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1033,6 +1070,8 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { _p2 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1053,6 +1092,8 @@ func Symlink(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1135,6 +1176,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1150,6 +1192,7 @@ func Unlinkat(dirfd int, path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1165,6 +1208,7 @@ func Unmount(target string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1200,6 +1244,7 @@ func Utime(path string, buf *Utimbuf) (err error) { return } _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1358,6 +1403,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1475,6 +1521,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1500,6 +1547,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1673,6 +1721,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1688,6 +1737,7 @@ func Statfs(path string, buf *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1713,6 +1763,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index 3665a32038..fbf69350df 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -14,6 +14,7 @@ func open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -30,6 +31,7 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) return } r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -66,6 +68,7 @@ func utimes(path string, times *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -81,6 +84,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) { return } _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -144,6 +148,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) { return } _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -169,6 +174,9 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt return } _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + use(unsafe.Pointer(_p2)) if e1 != 0 { err = e1 } @@ -184,6 +192,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -199,6 +208,7 @@ func Acct(path string) (err error) { return } _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -225,6 +235,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -240,6 +251,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -255,6 +267,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -280,6 +293,7 @@ func Creat(path string, mode uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -383,6 +397,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -428,6 +443,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -443,6 +459,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { return } _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -591,6 +608,8 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) { _p2 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) sz = int(r0) if e1 != 0 { err = e1 @@ -607,6 +626,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e return } r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask)) + use(unsafe.Pointer(_p0)) watchdesc = int(r0) if e1 != 0 { err = e1 @@ -688,6 +708,8 @@ func Link(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -709,6 +731,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + use(unsafe.Pointer(_p0)) sz = int(r0) if e1 != 0 { err = e1 @@ -725,6 +748,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -740,6 +764,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -755,6 +780,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +796,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -810,6 +837,8 @@ func PivotRoot(newroot string, putold string) (err error) { return } _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -858,6 +887,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -879,6 +909,8 @@ func Removexattr(path string, attr string) (err error) { return } _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -899,6 +931,8 @@ func Rename(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -919,6 +953,8 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e return } _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -934,6 +970,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1033,6 +1070,8 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { _p2 = unsafe.Pointer(&_zero) } _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1053,6 +1092,8 @@ func Symlink(oldpath string, newpath string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1135,6 +1176,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1150,6 +1192,7 @@ func Unlinkat(dirfd int, path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1165,6 +1208,7 @@ func Unmount(target string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1200,6 +1244,7 @@ func Utime(path string, buf *Utimbuf) (err error) { return } _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1537,6 +1582,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1604,6 +1650,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1629,6 +1676,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1747,6 +1795,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1817,6 +1866,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go index 281208f411..e9bd3d0f67 100644 --- a/src/syscall/zsyscall_netbsd_386.go +++ b/src/syscall/zsyscall_netbsd_386.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -295,6 +296,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -320,6 +322,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -335,6 +338,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -350,6 +354,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -365,6 +370,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -380,6 +386,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -672,6 +679,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -692,6 +700,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -717,6 +727,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -732,6 +743,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -747,6 +759,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -762,6 +775,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -787,6 +801,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -803,6 +818,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -876,6 +892,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -897,6 +914,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -912,6 +931,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -927,6 +947,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1074,6 +1095,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1094,6 +1116,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1119,6 +1143,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1167,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1157,6 +1183,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go index ed9a87df6c..1acd7c2736 100644 --- a/src/syscall/zsyscall_netbsd_amd64.go +++ b/src/syscall/zsyscall_netbsd_amd64.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -295,6 +296,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -320,6 +322,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -335,6 +338,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -350,6 +354,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -365,6 +370,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -380,6 +386,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -672,6 +679,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -692,6 +700,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -717,6 +727,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -732,6 +743,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -747,6 +759,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -762,6 +775,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -787,6 +801,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -803,6 +818,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -876,6 +892,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -897,6 +914,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -912,6 +931,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -927,6 +947,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1074,6 +1095,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1094,6 +1116,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1119,6 +1143,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1167,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1157,6 +1183,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go index c5c9a9f2c6..898e0ce809 100644 --- a/src/syscall/zsyscall_netbsd_arm.go +++ b/src/syscall/zsyscall_netbsd_arm.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -295,6 +296,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -320,6 +322,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -335,6 +338,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -350,6 +354,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -365,6 +370,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -380,6 +386,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -672,6 +679,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -692,6 +700,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -717,6 +727,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -732,6 +743,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -747,6 +759,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -762,6 +775,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -787,6 +801,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -803,6 +818,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -876,6 +892,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -897,6 +914,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -912,6 +931,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -927,6 +947,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1074,6 +1095,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1094,6 +1116,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1119,6 +1143,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1142,6 +1167,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1157,6 +1183,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go index 785e7c3b8e..5b005d2dc3 100644 --- a/src/syscall/zsyscall_openbsd_386.go +++ b/src/syscall/zsyscall_openbsd_386.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -293,6 +294,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -318,6 +320,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -333,6 +336,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -348,6 +352,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -363,6 +368,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -378,6 +384,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -680,6 +687,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -700,6 +708,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -725,6 +735,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -740,6 +751,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -755,6 +767,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +783,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -795,6 +809,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -811,6 +826,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -884,6 +900,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -905,6 +922,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -920,6 +939,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -935,6 +955,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1001,6 +1022,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1097,6 +1119,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1112,6 +1135,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1132,6 +1156,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1157,6 +1183,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1180,6 +1207,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1195,6 +1223,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go index 7a8d9b6f1d..ce9397bcae 100644 --- a/src/syscall/zsyscall_openbsd_amd64.go +++ b/src/syscall/zsyscall_openbsd_amd64.go @@ -230,6 +230,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) { return } _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -293,6 +294,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -318,6 +320,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -333,6 +336,7 @@ func Chflags(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -348,6 +352,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -363,6 +368,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -378,6 +384,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -680,6 +687,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -700,6 +708,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -725,6 +735,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -740,6 +751,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -755,6 +767,7 @@ func Mkfifo(path string, mode uint32) (err error) { return } _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -770,6 +783,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -795,6 +809,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -811,6 +826,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -884,6 +900,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -905,6 +922,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -920,6 +939,7 @@ func Revoke(path string) (err error) { return } _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -935,6 +955,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1001,6 +1022,7 @@ func Setlogin(name string) (err error) { return } _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1097,6 +1119,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1112,6 +1135,7 @@ func Statfs(path string, stat *Statfs_t) (err error) { return } _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1132,6 +1156,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -1157,6 +1183,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length)) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1180,6 +1207,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -1195,6 +1223,7 @@ func Unmount(path string, flags int) (err error) { return } _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go index 5ffa0e439d..44b74d71c1 100644 --- a/src/syscall/zsyscall_plan9_386.go +++ b/src/syscall/zsyscall_plan9_386.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_386.go +// mksyscall.pl -l32 -plan9 syscall_plan9.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package syscall @@ -15,7 +15,7 @@ func fd2path(fd int, buf []byte) (err error) { _p0 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -25,7 +25,7 @@ func fd2path(fd int, buf []byte) (err error) { func pipe(p *[2]_C_int) (err error) { r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -42,7 +42,7 @@ func await(s []byte) (n int, err error) { } r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) n = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -53,7 +53,7 @@ func await(s []byte) (n int, err error) { func Dup(oldfd int, newfd int) (fd int, err error) { r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) fd = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -68,8 +68,9 @@ func Open(path string, mode int) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) fd = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -84,8 +85,9 @@ func Create(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -100,7 +102,8 @@ func Remove(path string) (err error) { return } r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int(r0) == -1 { + use(unsafe.Pointer(_p0)) + if int32(r0) == -1 { err = e1 } return @@ -117,7 +120,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { } r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -134,7 +137,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { } r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) n = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -144,7 +147,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { func Close(fd int) (err error) { r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -159,7 +162,8 @@ func Chdir(path string) (err error) { return } r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) - if int(r0) == -1 { + use(unsafe.Pointer(_p0)) + if int32(r0) == -1 { err = e1 } return @@ -179,7 +183,9 @@ func Bind(name string, old string, flag int) (err error) { return } r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) - if int(r0) == -1 { + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if int32(r0) == -1 { err = e1 } return @@ -199,7 +205,9 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) { return } r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) - if int(r0) == -1 { + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) + if int32(r0) == -1 { err = e1 } return @@ -220,8 +228,9 @@ func Stat(path string, edir []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) + use(unsafe.Pointer(_p0)) n = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -238,7 +247,7 @@ func Fstat(fd int, edir []byte) (n int, err error) { } r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) n = int(r0) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return @@ -259,7 +268,8 @@ func Wstat(path string, edir []byte) (err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) - if int(r0) == -1 { + use(unsafe.Pointer(_p0)) + if int32(r0) == -1 { err = e1 } return @@ -275,7 +285,7 @@ func Fwstat(fd int, edir []byte) (err error) { _p0 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) - if int(r0) == -1 { + if int32(r0) == -1 { err = e1 } return diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go index c64533f492..44b74d71c1 100644 --- a/src/syscall/zsyscall_plan9_amd64.go +++ b/src/syscall/zsyscall_plan9_amd64.go @@ -1,4 +1,4 @@ -// mksyscall.pl -l32 -plan9 syscall_plan9.go syscall_plan9_amd64.go +// mksyscall.pl -l32 -plan9 syscall_plan9.go // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package syscall @@ -68,6 +68,7 @@ func Open(path string, mode int) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if int32(r0) == -1 { err = e1 @@ -84,6 +85,7 @@ func Create(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) + use(unsafe.Pointer(_p0)) fd = int(r0) if int32(r0) == -1 { err = e1 @@ -100,6 +102,7 @@ func Remove(path string) (err error) { return } r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if int32(r0) == -1 { err = e1 } @@ -159,6 +162,7 @@ func Chdir(path string) (err error) { return } r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) if int32(r0) == -1 { err = e1 } @@ -179,6 +183,8 @@ func Bind(name string, old string, flag int) (err error) { return } r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if int32(r0) == -1 { err = e1 } @@ -199,6 +205,8 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) { return } r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if int32(r0) == -1 { err = e1 } @@ -220,6 +228,7 @@ func Stat(path string, edir []byte) (n int, err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) + use(unsafe.Pointer(_p0)) n = int(r0) if int32(r0) == -1 { err = e1 @@ -259,6 +268,7 @@ func Wstat(path string, edir []byte) (err error) { _p1 = unsafe.Pointer(&_zero) } r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) + use(unsafe.Pointer(_p0)) if int32(r0) == -1 { err = e1 } diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go index 8847cad012..43b224a7ba 100644 --- a/src/syscall/zsyscall_solaris_amd64.go +++ b/src/syscall/zsyscall_solaris_amd64.go @@ -142,6 +142,7 @@ func Access(path string, mode uint32) (err error) { return } _, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -163,6 +164,7 @@ func Chdir(path string) (err error) { return } _, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -176,6 +178,7 @@ func Chmod(path string, mode uint32) (err error) { return } _, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -189,6 +192,7 @@ func Chown(path string, uid int, gid int) (err error) { return } _, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -202,6 +206,7 @@ func Chroot(path string) (err error) { return } _, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -360,6 +365,7 @@ func Lchown(path string, uid int, gid int) (err error) { return } _, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -378,6 +384,8 @@ func Link(path string, link string) (err error) { return } _, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -399,6 +407,7 @@ func Lstat(path string, stat *Stat_t) (err error) { return } _, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -412,6 +421,7 @@ func Mkdir(path string, mode uint32) (err error) { return } _, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -425,6 +435,7 @@ func Mknod(path string, mode uint32, dev int) (err error) { return } _, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -446,6 +457,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) { return } r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0) + use(unsafe.Pointer(_p0)) fd = int(r0) if e1 != 0 { err = e1 @@ -460,6 +472,7 @@ func Pathconf(path string, name int) (val int, err error) { return } r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) val = int(r0) if e1 != 0 { err = e1 @@ -517,6 +530,7 @@ func Readlink(path string, buf []byte) (n int, err error) { _p1 = &buf[0] } r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0) + use(unsafe.Pointer(_p0)) n = int(r0) if e1 != 0 { err = e1 @@ -536,6 +550,8 @@ func Rename(from string, to string) (err error) { return } _, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -549,6 +565,7 @@ func Rmdir(path string) (err error) { return } _, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -660,6 +677,7 @@ func Stat(path string, stat *Stat_t) (err error) { return } _, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -678,6 +696,8 @@ func Symlink(path string, link string) (err error) { return } _, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) if e1 != 0 { err = e1 } @@ -699,6 +719,7 @@ func Truncate(path string, length int64) (err error) { return } _, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -734,6 +755,7 @@ func Unlink(path string) (err error) { return } _, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } @@ -747,6 +769,7 @@ func Utimes(path string, times *[2]Timeval) (err error) { return } _, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0) + use(unsafe.Pointer(_p0)) if e1 != 0 { err = e1 } From 9e7c22938cb3c7af9dc02447eebf4ab31bc40cc1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 17:01:40 -0400 Subject: [PATCH 009/430] runtime: undo stray edit from CL 140380043 Was having serious editor problems on Windows. TBR=brainman, iant CC=golang-codereviews https://golang.org/cl/137370043 --- src/runtime/sys_windows_386.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 7d4dc6a69c..fc19f5650a 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -161,7 +161,7 @@ TEXT runtime·profileloop(SB),NOSPLIT,$0 PUSHL $runtime·profileloop1(SB) CALL runtime·externalthreadhandler(SB) MOVL 4(SP), CX - ADDL $40, SP + ADDL $12, SP JMP CX TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 From 318294286a2d92b24dc98553ac3913cf80c98a7f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 17:23:40 -0400 Subject: [PATCH 010/430] runtime: enable StackCopyAlways Let's see how close we are to this being ready. Will roll back if it breaks any builds in non-trivial ways. LGTM=r, khr R=iant, khr, r CC=golang-codereviews https://golang.org/cl/138200043 --- src/runtime/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index bb8c7ac11b..ca0eed06f9 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -26,7 +26,7 @@ enum StackCache = 1, - StackCopyAlways = 0, // expect to be able to copy stacks 100% of the time + StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time }; // Global pool of spans that have free stacks. From dc089574c49f3e426da4387a9448ca1a631c0b42 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 9 Sep 2014 07:35:44 +1000 Subject: [PATCH 011/430] doc: amend installation instructions Fixes #8674. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/139320044 --- doc/install.html | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/doc/install.html b/doc/install.html index 2de04471c5..ae7a212655 100644 --- a/doc/install.html +++ b/doc/install.html @@ -224,19 +224,12 @@ If you see the "hello, world" message then your Go installation is working.

You're almost done. -You just need to do a little more setup. +You just need to set up your environment.

- -How to Write Go Code -Learn how to set up and use the Go tools - -

- -

-The How to Write Go Code document -provides essential setup instructions for using the Go tools. +Read the How to Write Go Code document, +which provides essential setup instructions for using the Go tools.

From 857d55a3f9cfc8ccc8aef24571417ae4ecabbcc9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 17:37:49 -0400 Subject: [PATCH 012/430] runtime: mark freedefer and deferclass go:nosplit This should make deferreturn nosplit all the way down, which should fix the current windows/amd64 failure. If not, I will change StackCopyAlways back to 0. TBR=khr CC=golang-codereviews https://golang.org/cl/135600043 --- src/runtime/panic.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 740fa026e2..a5a8fbd6dd 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -95,6 +95,7 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn // This maps exactly to malloc size classes. // defer size class for arg size sz +//go:nosplit func deferclass(siz uintptr) uintptr { return (siz + 7) >> 4 } @@ -159,6 +160,7 @@ func newdefer(siz int32) *_defer { // Free the given defer. // The defer cannot be used after this call. +//go:nosplit func freedefer(d *_defer) { if d.special { return From ec96795ba20209263a0bbb17a073a9c028e74437 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 8 Sep 2014 14:54:00 -0700 Subject: [PATCH 013/430] go/parser: fix (pathological) corner case Inside a control clause (if ... {}), composite literals starting with a type name must be parenthesized. A composite literal used in the array length expression of an array composite literal is already parenthesized. Not a valid program, but syntactically is should be accepted. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/142760043 --- src/go/parser/parser.go | 2 ++ src/go/parser/short_test.go | 1 + 2 files changed, 3 insertions(+) diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go index 9c62076f25..4a005d8ffa 100644 --- a/src/go/parser/parser.go +++ b/src/go/parser/parser.go @@ -641,6 +641,7 @@ func (p *parser) parseArrayType() ast.Expr { } lbrack := p.expect(token.LBRACK) + p.exprLev++ var len ast.Expr // always permit ellipsis for more fault-tolerant parsing if p.tok == token.ELLIPSIS { @@ -649,6 +650,7 @@ func (p *parser) parseArrayType() ast.Expr { } else if p.tok != token.RBRACK { len = p.parseRhs() } + p.exprLev-- p.expect(token.RBRACK) elt := p.parseType() diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go index f861086ddb..05e44de28a 100644 --- a/src/go/parser/short_test.go +++ b/src/go/parser/short_test.go @@ -39,6 +39,7 @@ var valids = []string{ `package p; func ((*T),) m() {}`, `package p; func (*(T),) m() {}`, `package p; func _(x []int) { for range x {} }`, + `package p; func _() { if [T{}.n]int{} {} }`, } func TestValid(t *testing.T) { From 5103500d130b3b74c0c3a75ac8dab5285111ffbe Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 18:07:33 -0400 Subject: [PATCH 014/430] runtime: mark endcgo go:nosplit Should help windows/amd64. TBR=khr CC=golang-codereviews https://golang.org/cl/134660043 --- src/runtime/cgocall.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index 76a533e933..a21474b01f 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -134,6 +134,7 @@ func cgocall_errno(fn, arg unsafe.Pointer) int32 { return errno } +//go:nosplit func endcgo(mp *m) { mp.ncgo-- if mp.ncgo == 0 { From 176020e1b1aa92a92423e7f1920d2a904c634394 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 18:07:50 -0400 Subject: [PATCH 015/430] runtime: turn off StackCopyAlways windows/amd64 failure: http://build.golang.org/log/1ded5e3ef4bd1226f976e3180772f87e6c918255 # ..\misc\cgo\testso runtime: copystack: locals size info only for syscall.Syscall fatal error: split stack not allowed runtime stack: runtime.throw(0xa64cc7) c:/go/src/runtime/panic.go:395 +0xad fp=0x6fde0 sp=0x6fdb0 runtime.newstack() c:/go/src/runtime/stack.c:1001 +0x750 fp=0x6ff20 sp=0x6fde0 runtime.morestack() c:/go/src/runtime/asm_amd64.s:306 +0x73 fp=0x6ff28 sp=0x6ff20 goroutine 1 [stack growth, locked to thread]: runtime.freedefer(0xc0820ce120) c:/go/src/runtime/panic.go:162 fp=0xc08201b1a0 sp=0xc08201b198 runtime.deferreturn(0xa69420) c:/go/src/runtime/panic.go:211 +0xa8 fp=0xc08201b1e8 sp=0xc08201b1a0 runtime.cgocall_errno(0x498c00, 0xc08201b228, 0x0) c:/go/src/runtime/cgocall.go:134 +0x10e fp=0xc08201b210 sp=0xc08201b1e8 syscall.Syscall(0x7786b1d0, 0x2, 0xc0820c85b0, 0xc08201b2d8, 0x0, 0x0, 0x0, 0x0) c:/go/src/runtime/syscall_windows.c:74 +0x3c fp=0xc08201b260 sp=0xc08201b210 syscall.findFirstFile1(0xc0820c85b0, 0xc08201b2d8, 0x500000000000000, 0x0, 0x0) c:/go/src/syscall/zsyscall_windows.go:340 +0x76 fp=0xc08201b2b0 sp=0xc08201b260 syscall.FindFirstFile(0xc0820c85b0, 0xc08210c500, 0xc0820c85b0, 0x0, 0x0) c:/go/src/syscall/syscall_windows.go:907 +0x6a fp=0xc08201b530 sp=0xc08201b2b0 os.openDir(0xc0820b2e40, 0x33, 0x0, 0x0, 0x0) c:/go/src/os/file_windows.go:96 +0x110 fp=0xc08201b5e0 sp=0xc08201b530 os.OpenFile(0xc0820b2e40, 0x33, 0x0, 0x0, 0x41, 0x0, 0x0) c:/go/src/os/file_windows.go:143 +0x1e9 fp=0xc08201b650 sp=0xc08201b5e0 TBR=khr CC=golang-codereviews https://golang.org/cl/138230043 --- src/runtime/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index ca0eed06f9..bb8c7ac11b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -26,7 +26,7 @@ enum StackCache = 1, - StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time + StackCopyAlways = 0, // expect to be able to copy stacks 100% of the time }; // Global pool of spans that have free stacks. From 1fadd9e1aed80d27799cecace3f3764048d8ddd3 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 9 Sep 2014 07:22:11 +0900 Subject: [PATCH 016/430] net: don't set wrong option for controlling tcp keepalive on openbsd Fixes #8679. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/141730043 --- src/net/tcpsockopt_openbsd.go | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/net/tcpsockopt_openbsd.go b/src/net/tcpsockopt_openbsd.go index 3480f932c8..1644343114 100644 --- a/src/net/tcpsockopt_openbsd.go +++ b/src/net/tcpsockopt_openbsd.go @@ -2,26 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TCP socket options for openbsd - package net import ( - "os" "syscall" "time" ) -// Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - - // The kernel expects seconds so round to next highest second. - d += (time.Second - time.Nanosecond) - secs := int(d.Seconds()) - - return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs)) + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.EPROTONOSUPPORT } From 1d88f9dd4ddc99c557593007ac4118492d559d05 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 8 Sep 2014 15:42:48 -0700 Subject: [PATCH 017/430] runtime: note the double-releasem isn't an error. LGTM=bradfitz R=dave, bradfitz CC=golang-codereviews https://golang.org/cl/136390043 --- src/runtime/malloc.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index b3c9c1fd78..8181312f17 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -134,6 +134,8 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { if mp.curg != nil { mp.curg.stackguard0 = mp.curg.stackguard } + // Note: one releasem for the acquirem just above. + // The other for the acquirem at start of malloc. releasem(mp) releasem(mp) } @@ -309,6 +311,8 @@ marked: if mp.curg != nil { mp.curg.stackguard0 = mp.curg.stackguard } + // Note: one releasem for the acquirem just above. + // The other for the acquirem at start of malloc. releasem(mp) releasem(mp) } From 0133e0a208661c5eb4af9d30600f8632ed744b84 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Tue, 9 Sep 2014 09:12:21 +1000 Subject: [PATCH 018/430] A+C: John Olds (individual CLA) Generated by a+c. LGTM=jtolds, jbd R=gobot, jbd, jtolds CC=golang-codereviews https://golang.org/cl/137300043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 29aca3dbc4..2c3d945b1a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -189,6 +189,7 @@ Hong Ruiqi Icarus Sparry Ingo Oeser Isaac Wagner +JT Olds Jakob Borg Jakub Ryszard Czarnowicz James David Chalfant diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4d2aacafa9..b20cf055af 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -267,6 +267,7 @@ Icarus Sparry Ingo Oeser Isaac Wagner Ivan Krasin +JT Olds Jacob Baskin Jakob Borg Jakub Ryszard Czarnowicz From 815a843b6aff1a1db558514811bed4c78adce522 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 20:37:28 -0400 Subject: [PATCH 019/430] runtime: enable StackCopyAlways It worked at CL 134660043 on the builders, so I believe it will stick this time. LGTM=bradfitz R=khr, bradfitz CC=golang-codereviews https://golang.org/cl/141280043 --- src/runtime/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index bb8c7ac11b..ca0eed06f9 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -26,7 +26,7 @@ enum StackCache = 1, - StackCopyAlways = 0, // expect to be able to copy stacks 100% of the time + StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time }; // Global pool of spans that have free stacks. From d2788dc50308104ae642bd3fc043f2faf9bb413f Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 8 Sep 2014 17:40:32 -0700 Subject: [PATCH 020/430] syscall: fix comment in mkall_windows.bat src/pkg -> src LGTM=alex.brainman R=alex.brainman CC=golang-codereviews https://golang.org/cl/139400043 --- src/syscall/mkall_windows.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/mkall_windows.bat b/src/syscall/mkall_windows.bat index 9c91a1064d..0f3a98b727 100644 --- a/src/syscall/mkall_windows.bat +++ b/src/syscall/mkall_windows.bat @@ -4,7 +4,7 @@ @echo off if exist mkall.sh goto dirok -echo mkall_windows.bat must be run from src\pkg\syscall directory +echo mkall_windows.bat must be run from src\syscall directory goto :end :dirok From 55c458e05f35d0d5d539107da07b744ad96f268e Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 8 Sep 2014 17:42:21 -0700 Subject: [PATCH 021/430] runtime: on bigger maps, start iterator at a random bucket. This change brings the iter/delete pattern down to O(n lgn) from O(n^2). Fixes #8412. before: BenchmarkMapPop100 50000 32498 ns/op BenchmarkMapPop1000 500 3244851 ns/op BenchmarkMapPop10000 5 270276855 ns/op after: BenchmarkMapPop100 100000 16169 ns/op BenchmarkMapPop1000 5000 300416 ns/op BenchmarkMapPop10000 300 5990814 ns/op LGTM=iant R=golang-codereviews, iant, khr CC=golang-codereviews https://golang.org/cl/141270043 --- src/runtime/hashmap.go | 33 +++++++++++++++++++++++---------- src/runtime/map_test.go | 21 +++++++++++++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 55287f6ff9..cbcc6c4041 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -134,11 +134,12 @@ type hiter struct { h *hmap buckets unsafe.Pointer // bucket ptr at hash_iter initialization time bptr *bmap // current bucket + startBucket uintptr // bucket iteration started at offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) - done bool + wrapped bool // already wrapped around from end of bucket array to beginning B uint8 + i uint8 bucket uintptr - i uintptr checkBucket uintptr } @@ -560,10 +561,22 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { it.B = h.B it.buckets = h.buckets + // decide where to start + switch { + case h.B == 0: + it.startBucket = 0 + it.offset = uint8(fastrand1()) & (bucketCnt - 1) + case h.B <= 31: + it.startBucket = uintptr(fastrand1()) & (uintptr(1)< Date: Mon, 8 Sep 2014 17:47:12 -0700 Subject: [PATCH 022/430] syscall: keep Windows syscall pointers live too Like https://golang.org/cl/139360044 LGTM=rsc, alex.brainman R=alex.brainman, rsc CC=golang-codereviews https://golang.org/cl/138250043 --- src/syscall/mksyscall_windows.go | 24 ++++++++++++++++++++++-- src/syscall/zsyscall_windows.go | 15 +++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index 1cdd6b4d22..ea9ee45511 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -158,6 +158,7 @@ func (p *Param) SyscallArgList() []string { case p.Type[0] == '*': s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name) case p.Type == "string": + p.fn.use(p.tmpVar()) s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar()) case p.Type == "bool": s = p.tmpVar() @@ -303,6 +304,7 @@ type Fn struct { Params []*Param Rets *Rets PrintTrace bool + Used []string dllname string dllfuncname string src string @@ -310,6 +312,15 @@ type Fn struct { curTmpVarIdx int // insure tmp variables have uniq names } +func (f *Fn) use(v string) { + for _, e := range f.Used { + if e == v { + return + } + } + f.Used = append(f.Used, v) +} + // extractParams parses s to extract function parameters. func extractParams(s string, f *Fn) ([]*Param, error) { s = trim(s) @@ -328,7 +339,7 @@ func extractParams(s string, f *Fn) ([]*Param, error) { } } ps[i] = &Param{ - Name: trim(b[0]), + Name: sanitizeName(trim(b[0])), Type: trim(b[1]), fn: f, tmpVarIdx: -1, @@ -337,6 +348,13 @@ func extractParams(s string, f *Fn) ([]*Param, error) { return ps, nil } +func sanitizeName(n string) string { + if n == "use" { + return "use_" + } + return n +} + // extractSection extracts text out of string s starting after start // and ending just before end. found return value will indicate success, // and prefix, body and suffix will contain correspondent parts of string s. @@ -680,7 +698,7 @@ var ( {{define "funcbody"}} func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{ {{template "tmpvars" .}} {{template "syscall" .}} -{{template "seterror" .}}{{template "printtrace" .}} return +{{template "used" .}}{{template "seterror" .}}{{template "printtrace" .}} return } {{end}} @@ -689,6 +707,8 @@ func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{ {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} +{{define "used"}}{{range .Used}}use(unsafe.Pointer({{.}}));{{end}}{{end}} + {{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}} {{end}}{{end}} diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 1f44750b7f..9f2c84fb1f 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -177,6 +177,7 @@ func LoadLibrary(libname string) (handle Handle, err error) { return } r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) handle = Handle(r0) if handle == 0 { if e1 != 0 { @@ -207,6 +208,7 @@ func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { return } r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(_p0)), 0) + use(unsafe.Pointer(_p0)) proc = uintptr(r0) if proc == 0 { if e1 != 0 { @@ -1559,6 +1561,7 @@ func GetHostByName(name string) (h *Hostent, err error) { return } r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) h = (*Hostent)(unsafe.Pointer(r0)) if h == nil { if e1 != 0 { @@ -1582,6 +1585,8 @@ func GetServByName(name string, proto string) (s *Servent, err error) { return } r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + use(unsafe.Pointer(_p0)) + use(unsafe.Pointer(_p1)) s = (*Servent)(unsafe.Pointer(r0)) if s == nil { if e1 != 0 { @@ -1606,6 +1611,7 @@ func GetProtoByName(name string) (p *Protoent, err error) { return } r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + use(unsafe.Pointer(_p0)) p = (*Protoent)(unsafe.Pointer(r0)) if p == nil { if e1 != 0 { @@ -1624,6 +1630,7 @@ func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSR return } r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(_p0)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + use(unsafe.Pointer(_p0)) if r0 != 0 { status = Errno(r0) } @@ -1743,8 +1750,8 @@ func NetApiBufferFree(buf *byte) (neterr error) { return } -func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) +func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use_ *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use_)), 0, 0) if r1 == 0 { if e1 != 0 { err = error(e1) @@ -1755,8 +1762,8 @@ func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint3 return } -func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) +func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use_ *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use_)), 0, 0) if r1 == 0 { if e1 != 0 { err = error(e1) From 0f99a91bb56dd01dfd4e5ce4344e6006e3463ade Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 8 Sep 2014 21:02:36 -0400 Subject: [PATCH 023/430] runtime: let stack copier update Panic structs for us It already is updating parts of them; we're just getting lucky retraversing them and not finding much to do. Change argp to a pointer so that it will be updated too. Existing tests break if you apply the change to adjustpanics without also updating the type of argp. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/139380043 --- src/runtime/panic.go | 6 +++--- src/runtime/runtime.h | 2 +- src/runtime/stack.c | 20 +++++++++----------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index a5a8fbd6dd..52ab654646 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -287,9 +287,9 @@ func gopanic(e interface{}) { gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort))) p._defer = d - p.argp = getargp(0) + p.argp = unsafe.Pointer(getargp(0)) reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) - p.argp = 0 + p.argp = nil // reflectcall did not panic. Remove dabort. if gp._defer != &dabort { @@ -362,7 +362,7 @@ func gorecover(argp uintptr) interface{} { // If they match, the caller is the one who can recover. gp := getg() p := gp._panic - if p != nil && !p.recovered && argp == p.argp { + if p != nil && !p.recovered && argp == uintptr(p.argp) { p.recovered = true return p.arg } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index e6db8cb836..9584c5dfcc 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -653,7 +653,7 @@ struct Defer */ struct Panic { - uintptr argp; // pointer to arguments of deferred call run during panic; cannot move - known to liblink + void* argp; // pointer to arguments of deferred call run during panic; cannot move - known to liblink Eface arg; // argument to panic Panic* link; // link to earlier panic Defer* defer; // current executing defer diff --git a/src/runtime/stack.c b/src/runtime/stack.c index ca0eed06f9..8461c01f37 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -712,6 +712,10 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) // get adjusted appropriately. // This only happens for runtime.main and runtime.gopanic now, // but a compiler optimization could do more of this. + // If such an optimization were introduced, Defer.argp should + // change to have pointer type so that it will be updated by + // the stack copying. Today both of those on-stack defers + // set argp = NoArgs, so no adjustment is necessary. *dp = (Defer*)((byte*)d + adjinfo->delta); continue; } @@ -751,17 +755,11 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) static void adjustpanics(G *gp, AdjustInfo *adjinfo) { - Panic *p, **l; - - // only the topmost panic is on the current stack - for(l = &gp->panic; (p = *l) != nil; ) { - if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase) - *l = (Panic*)((byte*)p + adjinfo->delta); - l = &p->link; - - if(adjinfo->oldstk <= (byte*)p->argp && (byte*)p->argp < adjinfo->oldbase) - p->argp += adjinfo->delta; - } + // Panic structs are all on the stack + // and are adjusted by stack copying. + // The only pointer we need to update is gp->panic, the head of the list. + if(adjinfo->oldstk <= (byte*)gp->panic && (byte*)gp->panic < adjinfo->oldbase) + gp->panic = (Panic*)((byte*)gp->panic + adjinfo->delta); } static void From bffb0590c1e1125830377165eb98bf1b73bb016e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 01:08:34 -0400 Subject: [PATCH 024/430] runtime: merge mallocgc, gomallocgc I assumed they were the same when I wrote cgocallback.go earlier today. Merge them to eliminate confusion. I can't tell what gomallocgc did before with a nil type but without FlagNoScan. I created a call like that in cgocallback.go this morning, translating from a C file. It was supposed to do what the C version did, namely treat the block conservatively. Now it will. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/141810043 --- src/runtime/cgocallback.go | 2 +- src/runtime/chan.go | 2 +- src/runtime/malloc.c | 15 --------------- src/runtime/malloc.go | 19 +++++++++---------- src/runtime/mgc0.c | 8 ++++---- src/runtime/os_plan9.c | 5 +++-- src/runtime/os_windows.c | 4 +++- src/runtime/panic.go | 2 +- src/runtime/parfor.c | 3 ++- src/runtime/proc.c | 4 ++-- src/runtime/runtime.c | 5 +++-- src/runtime/select.go | 2 +- src/runtime/string.go | 6 +++--- 13 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go index 844a095c22..b3edfb672a 100644 --- a/src/runtime/cgocallback.go +++ b/src/runtime/cgocallback.go @@ -21,7 +21,7 @@ import "unsafe" // Either we need to add types or we need to stop using it. func _cgo_allocate_internal(len uintptr) unsafe.Pointer { - ret := gomallocgc(len, nil, 0) + ret := mallocgc(len, conservative, 0) c := new(cgomal) c.alloc = ret gp := getg() diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 91ade4d37e..226b824065 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -37,7 +37,7 @@ func makechan(t *chantype, size int64) *hchan { // buf points into the same allocation, elemtype is persistent. // SudoG's are referenced from their owning thread so they can't be collected. // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. - c = (*hchan)(gomallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan)) + c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan)) if size > 0 && elem.size != 0 { c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize)) } else { diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index 752ff60f37..b56f42531e 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -23,23 +23,8 @@ MStats runtime·memstats; Type* runtime·conservative; -void runtime·cmallocgc(uintptr size, Type *typ, uint32 flag, void **ret); void runtime·gc_notype_ptr(Eface*); -void* -runtime·mallocgc(uintptr size, Type *typ, uint32 flag) -{ - void *ret; - - // Call into the Go version of mallocgc. - // TODO: maybe someday we can get rid of this. It is - // probably the only location where we run Go code on the M stack. - if((flag&FlagNoScan) == 0 && typ == nil) - typ = runtime·conservative; - runtime·cmallocgc(size, typ, flag, &ret); - return ret; -} - int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) { diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 8181312f17..ca7cb6d36a 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -51,12 +51,16 @@ var maxMem uintptr // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. -func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { +func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { if size == 0 { return unsafe.Pointer(&zeroObject) } size0 := size + if flags&flagNoScan == 0 && typ == nil { + gothrow("malloc missing type") + } + // This function must be atomic wrt GC, but for performance reasons // we don't acquirem/releasem on fast path. The code below does not have // split stack checks, so it can't be preempted by GC. @@ -338,18 +342,13 @@ marked: return x } -// cmallocgc is a trampoline used to call the Go malloc from C. -func cmallocgc(size uintptr, typ *_type, flags int, ret *unsafe.Pointer) { - *ret = gomallocgc(size, typ, flags) -} - // implementation of new builtin func newobject(typ *_type) unsafe.Pointer { flags := 0 if typ.kind&kindNoPointers != 0 { flags |= flagNoScan } - return gomallocgc(uintptr(typ.size), typ, flags) + return mallocgc(uintptr(typ.size), typ, flags) } // implementation of make builtin for slices @@ -361,13 +360,13 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer { if int(n) < 0 || (typ.size > 0 && n > maxMem/uintptr(typ.size)) { panic("runtime: allocation size out of range") } - return gomallocgc(uintptr(typ.size)*n, typ, flags) + return mallocgc(uintptr(typ.size)*n, typ, flags) } // rawmem returns a chunk of pointerless memory. It is // not zeroed. func rawmem(size uintptr) unsafe.Pointer { - return gomallocgc(size, nil, flagNoScan|flagNoZero) + return mallocgc(size, nil, flagNoScan|flagNoZero) } // round size up to next size class @@ -725,7 +724,7 @@ func runfinq() { // all not yet finalized objects are stored in finq. // If we do not mark it as FlagNoScan, // the last finalized object is not collected. - frame = gomallocgc(framesz, nil, flagNoScan) + frame = mallocgc(framesz, nil, flagNoScan) framecap = framesz } diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 1505cedcc0..cdda6e7e6f 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1867,7 +1867,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) if(p >= runtime·data && p < runtime·edata) { n = ((PtrType*)t)->elem->size; *len = n/PtrSize; - *mask = runtime·mallocgc(*len, nil, 0); + *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-runtime·data)/PtrSize; bits = (((byte*)runtime·gcdatamask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; @@ -1879,7 +1879,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) if(p >= runtime·bss && p < runtime·ebss) { n = ((PtrType*)t)->elem->size; *len = n/PtrSize; - *mask = runtime·mallocgc(*len, nil, 0); + *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-runtime·bss)/PtrSize; bits = (((byte*)runtime·gcbssmask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; @@ -1890,7 +1890,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) // heap if(runtime·mlookup(p, &base, &n, nil)) { *len = n/PtrSize; - *mask = runtime·mallocgc(*len, nil, 0); + *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (uintptr*)(base+i) - (uintptr*)runtime·mheap.arena_start; b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1; @@ -1929,7 +1929,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) size = bv.n/BitsPerPointer*PtrSize; n = ((PtrType*)t)->elem->size; *len = n/PtrSize; - *mask = runtime·mallocgc(*len, nil, 0); + *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-(byte*)frame.varp+size)/PtrSize; bits = (bv.data[off*BitsPerPointer/32] >> ((off*BitsPerPointer)%32))&BitsMask; diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c index ab4a51e884..fe92e5b269 100644 --- a/src/runtime/os_plan9.c +++ b/src/runtime/os_plan9.c @@ -6,6 +6,7 @@ #include "os_GOOS.h" #include "arch_GOARCH.h" #include "textflag.h" +#include "malloc.h" int8 *goos = "plan9"; extern SigTab runtime·sigtab[]; @@ -20,11 +21,11 @@ runtime·mpreinit(M *mp) // Initialize stack and goroutine for note handling. mp->gsignal = runtime·malg(32*1024); mp->gsignal->m = mp; - mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, 0); + mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan); // Initialize stack for handling strings from the // errstr system call, as used in package syscall. - mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, 0); + mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan); } // Called to initialize a new m (including the bootstrap m). diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 4e7c50b7fd..8d069d3ee3 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -7,6 +7,8 @@ #include "defs_GOOS_GOARCH.h" #include "os_GOOS.h" #include "textflag.h" +#include "arch_GOARCH.h" +#include "malloc.h" #pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll" #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" @@ -144,7 +146,7 @@ runtime·goenvs(void) for(p=env; *p; n++) p += runtime·findnullw(p)+1; - s = runtime·mallocgc(n*sizeof s[0], nil, 0); + s = runtime·mallocgc(n*sizeof s[0], runtime·conservative, 0); p = env; for(i=0; ithr = (ParForThread*)((byte*)(desc+1) + CacheLineSize); desc->nthrmax = nthrmax; return desc; diff --git a/src/runtime/proc.c b/src/runtime/proc.c index c462ae2b5e..6132fee579 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2286,7 +2286,7 @@ allgadd(G *gp) cap = 4096/sizeof(new[0]); if(cap < 2*allgcap) cap = 2*allgcap; - new = runtime·mallocgc(cap*sizeof(new[0]), nil, 0); + new = runtime·mallocgc(cap*sizeof(new[0]), runtime·conservative, 0); if(new == nil) runtime·throw("runtime: cannot allocate memory"); if(runtime·allg != nil) @@ -2757,7 +2757,7 @@ procresize(int32 new) for(i = 0; i < new; i++) { p = runtime·allp[i]; if(p == nil) { - p = (P*)runtime·mallocgc(sizeof(*p), 0, 0); + p = (P*)runtime·mallocgc(sizeof(*p), runtime·conservative, 0); p->id = i; p->status = Pgcstop; runtime·atomicstorep(&runtime·allp[i], p); diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 42ce1dadfb..97d040664b 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -6,6 +6,7 @@ #include "stack.h" #include "arch_GOARCH.h" #include "textflag.h" +#include "malloc.h" // Keep a cached value to make gotraceback fast, // since we call it on every call to gentraceback. @@ -96,7 +97,7 @@ runtime·goargs(void) if(Windows) return; - s = runtime·mallocgc(argc*sizeof s[0], nil, 0); + s = runtime·mallocgc(argc*sizeof s[0], runtime·conservative, 0); for(i=0; i Date: Tue, 9 Sep 2014 16:05:00 +1000 Subject: [PATCH 025/430] undo CL 140110043 / 17b5fc2aa130 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I have found better approach, then longer wait. See CL 134360043 for details. ««« original CL description runtime/pprof: adjust cpuHogger so that tests pass on windows builders LGTM=rsc R=dvyukov, rsc CC=golang-codereviews https://golang.org/cl/140110043 »»» LGTM=dave R=golang-codereviews, dave, dvyukov CC=golang-codereviews https://golang.org/cl/133500043 --- src/runtime/pprof/pprof_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index 54f93f8610..edd471a0c9 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -23,12 +23,12 @@ import ( func cpuHogger(f func()) { // We only need to get one 100 Hz clock tick, so we've got - // a 100x safety buffer. - // But do at least 2000 iterations (which should take about 400ms), + // a 25x safety buffer. + // But do at least 500 iterations (which should take about 100ms), // otherwise TestCPUProfileMultithreaded can fail if only one - // thread is scheduled during the 1 second period. + // thread is scheduled during the 250ms period. t0 := time.Now() - for i := 0; i < 2000 || time.Since(t0) < time.Second; i++ { + for i := 0; i < 500 || time.Since(t0) < 250*time.Millisecond; i++ { f() } } From 15b76ad94b1054ec7fd6853530bff782790b5727 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 13:39:57 -0400 Subject: [PATCH 026/430] runtime: assume precisestack, copystack, StackCopyAlways, ScanStackByFrames Commit to stack copying for stack growth. We're carrying around a surprising amount of cruft from older schemes. I am confident that precise stack scans and stack copying are here to stay. Delete fallback code for when precise stack info is disabled. Delete fallback code for when copying stacks is disabled. Delete fallback code for when StackCopyAlways is disabled. Delete Stktop chain - there is only one stack segment now. Delete M.moreargp, M.moreargsize, M.moreframesize, M.cret. Delete G.writenbuf (unrelated, just dead). Delete runtime.lessstack, runtime.oldstack. Delete many amd64 morestack variants. Delete initialization of morestack frame/arg sizes (shortens split prologue!). Replace G's stackguard/stackbase/stack0/stacksize/ syscallstack/syscallguard/forkstackguard with simple stack bounds (lo, hi). Update liblink, runtime/cgo for adjustments to G. LGTM=khr R=khr, bradfitz CC=golang-codereviews, iant, r https://golang.org/cl/137410043 --- include/link.h | 2 +- src/cmd/dist/buildruntime.c | 2 + src/liblink/obj5.c | 30 +- src/liblink/obj6.c | 186 +--- src/liblink/obj8.c | 39 +- src/runtime/asm_386.s | 52 +- src/runtime/asm_amd64.s | 174 +-- src/runtime/asm_amd64p32.s | 167 +-- src/runtime/asm_arm.s | 39 +- src/runtime/cgo/gcc_darwin_386.c | 13 +- src/runtime/cgo/gcc_darwin_amd64.c | 13 +- src/runtime/cgo/gcc_dragonfly_386.c | 13 +- src/runtime/cgo/gcc_dragonfly_amd64.c | 13 +- src/runtime/cgo/gcc_freebsd_386.c | 13 +- src/runtime/cgo/gcc_freebsd_amd64.c | 13 +- src/runtime/cgo/gcc_freebsd_arm.c | 13 +- src/runtime/cgo/gcc_linux_386.c | 13 +- src/runtime/cgo/gcc_linux_amd64.c | 13 +- src/runtime/cgo/gcc_linux_arm.c | 13 +- src/runtime/cgo/gcc_netbsd_386.c | 13 +- src/runtime/cgo/gcc_netbsd_amd64.c | 13 +- src/runtime/cgo/gcc_netbsd_arm.c | 13 +- src/runtime/cgo/gcc_openbsd_386.c | 13 +- src/runtime/cgo/gcc_openbsd_amd64.c | 13 +- src/runtime/cgo/gcc_windows_386.c | 6 +- src/runtime/cgo/gcc_windows_amd64.c | 6 +- src/runtime/cgo/libcgo.h | 4 +- src/runtime/export_test.go | 1 - src/runtime/heapdump.c | 4 +- src/runtime/malloc.go | 4 +- src/runtime/mgc0.c | 43 +- src/runtime/mgc0.h | 2 - src/runtime/os_darwin.c | 2 +- src/runtime/os_dragonfly.c | 2 +- src/runtime/os_freebsd.c | 2 +- src/runtime/os_linux.c | 2 +- src/runtime/os_nacl.c | 2 +- src/runtime/os_netbsd.c | 2 +- src/runtime/os_openbsd.c | 2 +- src/runtime/os_solaris.c | 2 +- src/runtime/panic.c | 35 +- src/runtime/proc.c | 156 ++- src/runtime/runtime.h | 72 +- src/runtime/stack.c | 383 ++----- src/runtime/stack.h | 6 +- src/runtime/stack_gen_test.go | 1473 ------------------------- src/runtime/stack_test.go | 54 - src/runtime/stubs.go | 1 - src/runtime/traceback.go | 38 +- src/runtime/traceback_windows.go | 63 -- 50 files changed, 359 insertions(+), 2894 deletions(-) delete mode 100644 src/runtime/stack_gen_test.go delete mode 100644 src/runtime/traceback_windows.go diff --git a/include/link.h b/include/link.h index 73f148c14c..8c73eab51e 100644 --- a/include/link.h +++ b/include/link.h @@ -392,7 +392,7 @@ struct Link LSym* sym_divu; LSym* sym_mod; LSym* sym_modu; - LSym* symmorestack[20]; + LSym* symmorestack[2]; LSym* tlsg; LSym* plan9privates; Prog* curp; diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c index 6e87029e7c..36efb5711c 100644 --- a/src/cmd/dist/buildruntime.c +++ b/src/cmd/dist/buildruntime.c @@ -246,6 +246,8 @@ ok: aggr = "alg"; else if(streq(fields.p[1], "Panic")) aggr = "panic"; + else if(streq(fields.p[1], "Stack")) + aggr = "stack"; } if(hasprefix(lines.p[i], "}")) aggr = nil; diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c index d9f980aca8..a571d8f166 100644 --- a/src/liblink/obj5.c +++ b/src/liblink/obj5.c @@ -458,7 +458,7 @@ addstacksplit(Link *ctxt, LSym *cursym) p->as = AMOVW; p->from.type = D_OREG; p->from.reg = REGG; - p->from.offset = 2*ctxt->arch->ptrsize; // G.panic + p->from.offset = 4*ctxt->arch->ptrsize; // G.panic p->to.type = D_REG; p->to.reg = 1; @@ -762,15 +762,14 @@ softfloat(Link *ctxt, LSym *cursym) static Prog* stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) { - int32 arg; - // MOVW g_stackguard(g), R1 p = appendp(ctxt, p); p->as = AMOVW; p->from.type = D_OREG; p->from.reg = REGG; + p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->from.offset = 3*ctxt->arch->ptrsize; + p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 p->to.type = D_REG; p->to.reg = 1; @@ -849,29 +848,6 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt) p->scond = C_SCOND_NE; } - // MOVW.LS $framesize, R1 - p = appendp(ctxt, p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - p->from.offset = framesize; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW.LS $args, R2 - p = appendp(ctxt, p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - arg = ctxt->cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - ctxt->diag("misaligned argument size in stack split"); - p->from.offset = arg; - p->to.type = D_REG; - p->to.reg = 2; - // MOVW.LS R14, R3 p = appendp(ctxt, p); p->as = AMOVW; diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c index 572219b5b7..2acfd2f70d 100644 --- a/src/liblink/obj6.c +++ b/src/liblink/obj6.c @@ -342,32 +342,6 @@ nacladdr(Link *ctxt, Prog *p, Addr *a) } } -static char* -morename[] = -{ - "runtime.morestack00", - "runtime.morestack00_noctxt", - "runtime.morestack10", - "runtime.morestack10_noctxt", - "runtime.morestack01", - "runtime.morestack01_noctxt", - "runtime.morestack11", - "runtime.morestack11_noctxt", - - "runtime.morestack8", - "runtime.morestack8_noctxt", - "runtime.morestack16", - "runtime.morestack16_noctxt", - "runtime.morestack24", - "runtime.morestack24_noctxt", - "runtime.morestack32", - "runtime.morestack32_noctxt", - "runtime.morestack40", - "runtime.morestack40_noctxt", - "runtime.morestack48", - "runtime.morestack48_noctxt", -}; - static Prog* load_g_cx(Link*, Prog*); static Prog* stacksplit(Link*, Prog*, int32, int32, int, Prog**); static void indir_cx(Link*, Addr*); @@ -388,19 +362,16 @@ parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg) static void addstacksplit(Link *ctxt, LSym *cursym) { - Prog *p, *q, *q1, *p1, *p2; + Prog *p, *q, *p1, *p2; int32 autoffset, deltasp; int a, pcsize; - uint32 i; vlong textstksiz, textarg; if(ctxt->tlsg == nil) ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0); if(ctxt->symmorestack[0] == nil) { - if(nelem(morename) > nelem(ctxt->symmorestack)) - sysfatal("Link.symmorestack needs at least %d elements", nelem(morename)); - for(i=0; isymmorestack[i] = linklookup(ctxt, morename[i], 0); + ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0); + ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0); } if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil) @@ -481,7 +452,7 @@ addstacksplit(Link *ctxt, LSym *cursym) p = appendp(ctxt, p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; - p->from.offset = 2*ctxt->arch->ptrsize; // G.panic + p->from.offset = 4*ctxt->arch->ptrsize; // G.panic p->to.type = D_BX; if(ctxt->headtype == Hnacl) { p->as = AMOVL; @@ -545,42 +516,6 @@ addstacksplit(Link *ctxt, LSym *cursym) p2->pcond = p; } - if(ctxt->debugstack > 1 && autoffset) { - // 6l -K -K means double-check for stack overflow - // even after calling morestack and even if the - // function is marked as nosplit. - p = appendp(ctxt, p); - p->as = AMOVQ; - indir_cx(ctxt, &p->from); - p->from.offset = 0; - p->to.type = D_BX; - - p = appendp(ctxt, p); - p->as = ASUBQ; - p->from.type = D_CONST; - p->from.offset = StackSmall+32; - p->to.type = D_BX; - - p = appendp(ctxt, p); - p->as = ACMPQ; - p->from.type = D_SP; - p->to.type = D_BX; - - p = appendp(ctxt, p); - p->as = AJHI; - p->to.type = D_BRANCH; - q1 = p; - - p = appendp(ctxt, p); - p->as = AINT; - p->from.type = D_CONST; - p->from.offset = 3; - - p = appendp(ctxt, p); - p->as = ANOP; - q1->pcond = p; - } - if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) { // 6l -Z means zero the stack frame on entry. // This slows down function calls but can help avoid @@ -731,9 +666,9 @@ static Prog* stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog **jmpok) { Prog *q, *q1; - uint32 moreconst1, moreconst2, i; int cmp, lea, mov, sub; + USED(textarg); cmp = ACMPQ; lea = ALEAQ; mov = AMOVQ; @@ -746,35 +681,6 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog sub = ASUBL; } - if(ctxt->debugstack) { - // 6l -K means check not only for stack - // overflow but stack underflow. - // On underflow, INT 3 (breakpoint). - // Underflow itself is rare but this also - // catches out-of-sync stack guard info - - p = appendp(ctxt, p); - p->as = cmp; - indir_cx(ctxt, &p->from); - p->from.offset = 8; - p->to.type = D_SP; - - p = appendp(ctxt, p); - p->as = AJHI; - p->to.type = D_BRANCH; - p->to.offset = 4; - q1 = p; - - p = appendp(ctxt, p); - p->as = AINT; - p->from.type = D_CONST; - p->from.offset = 3; - - p = appendp(ctxt, p); - p->as = ANOP; - q1->pcond = p; - } - q1 = nil; if(framesize <= StackSmall) { // small stack: SP <= stackguard @@ -783,8 +689,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_SP; indir_cx(ctxt, &p->to); + p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->to.offset = 3*ctxt->arch->ptrsize; + p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAQ -xxx(SP), AX @@ -799,8 +706,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->as = cmp; p->from.type = D_AX; indir_cx(ctxt, &p->to); + p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->to.offset = 3*ctxt->arch->ptrsize; + p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 } else { // Such a large stack we need to protect against wraparound. // If SP is close to zero: @@ -820,9 +728,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p = appendp(ctxt, p); p->as = mov; indir_cx(ctxt, &p->from); - p->from.offset = 0; + p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->from.offset = 3*ctxt->arch->ptrsize; + p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 p->to.type = D_SI; p = appendp(ctxt, p); @@ -860,75 +768,13 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog p->to.type = D_BRANCH; q = p; - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - moreconst1 = 0; - if(StackTop + textarg + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin) - moreconst1 = framesize; - moreconst2 = textarg; - if(moreconst2 == 1) // special marker - moreconst2 = 0; - if((moreconst2&7) != 0) - ctxt->diag("misaligned argument size in stack split"); - // 4 varieties varieties (const1==0 cross const2==0) - // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(ctxt, p); - if(ctxt->cursym->cfunc) { - p->as = ACALL; - p->to.type = D_BRANCH; + p->as = ACALL; + p->to.type = D_BRANCH; + if(ctxt->cursym->cfunc) p->to.sym = linklookup(ctxt, "runtime.morestackc", 0); - } else - if(moreconst1 == 0 && moreconst2 == 0) { - p->as = ACALL; - p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[0*2+noctxt]; - } else - if(moreconst1 != 0 && moreconst2 == 0) { - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = moreconst1; - p->to.type = D_AX; - - p = appendp(ctxt, p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[1*2+noctxt]; - } else - if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { - i = moreconst2/8 + 3; - p->as = ACALL; - p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[i*2+noctxt]; - } else - if(moreconst1 == 0 && moreconst2 != 0) { - p->as = AMOVL; - p->from.type = D_CONST; - p->from.offset = moreconst2; - p->to.type = D_AX; - - p = appendp(ctxt, p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[2*2+noctxt]; - } else { - // Pass framesize and argsize. - p->as = AMOVQ; - p->from.type = D_CONST; - p->from.offset = (uint64)moreconst2 << 32; - p->from.offset |= moreconst1; - p->to.type = D_AX; - - p = appendp(ctxt, p); - p->as = ACALL; - p->to.type = D_BRANCH; - p->to.sym = ctxt->symmorestack[3*2+noctxt]; - } + else + p->to.sym = ctxt->symmorestack[noctxt]; p = appendp(ctxt, p); p->as = AJMP; diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c index d8a93fb576..f54153ae9b 100644 --- a/src/liblink/obj8.c +++ b/src/liblink/obj8.c @@ -335,7 +335,7 @@ addstacksplit(Link *ctxt, LSym *cursym) p = appendp(ctxt, p); p->as = AMOVL; p->from.type = D_INDIR+D_CX; - p->from.offset = 2*ctxt->arch->ptrsize; // G.panic + p->from.offset = 4*ctxt->arch->ptrsize; // G.panic p->to.type = D_BX; p = appendp(ctxt, p); @@ -501,7 +501,6 @@ static Prog* stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) { Prog *q, *q1; - int arg; if(ctxt->debugstack) { // 8l -K means check not only for stack @@ -539,8 +538,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->to.offset = 3*ctxt->arch->ptrsize; + p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 } else if(framesize <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAL -(framesize-StackSmall)(SP), AX @@ -555,8 +555,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = ACMPL; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; + p->to.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->to.offset = 3*ctxt->arch->ptrsize; + p->to.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 } else { // Such a large stack we need to protect against wraparound // if SP is close to zero. @@ -576,8 +577,9 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->as = AMOVL; p->from.type = D_INDIR+D_CX; p->from.offset = 0; + p->from.offset = 2*ctxt->arch->ptrsize; // G.stackguard0 if(ctxt->cursym->cfunc) - p->from.offset = 3*ctxt->arch->ptrsize; + p->from.offset = 3*ctxt->arch->ptrsize; // G.stackguard1 p->to.type = D_SI; p = appendp(ctxt, p); @@ -617,33 +619,6 @@ stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok) p->to.offset = 4; q = p; - p = appendp(ctxt, p); // save frame size in DI - p->as = AMOVL; - p->to.type = D_DI; - p->from.type = D_CONST; - - // If we ask for more stack, we'll get a minimum of StackMin bytes. - // We need a stack frame large enough to hold the top-of-stack data, - // the function arguments+results, our caller's PC, our frame, - // a word for the return PC of the next call, and then the StackLimit bytes - // that must be available on entry to any function called from a function - // that did a stack check. If StackMin is enough, don't ask for a specific - // amount: then we can use the custom functions and save a few - // instructions. - if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin) - p->from.offset = (framesize+7) & ~7LL; - - arg = ctxt->cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - ctxt->diag("misaligned argument size in stack split"); - p = appendp(ctxt, p); // save arg size in AX - p->as = AMOVL; - p->to.type = D_AX; - p->from.type = D_CONST; - p->from.offset = arg; - p = appendp(ctxt, p); p->as = ACALL; p->to.type = D_BRANCH; diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 7eba8977c6..fc01b995b1 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -19,9 +19,10 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 // _cgo_init may update stackguard. MOVL $runtime·g0(SB), BP LEAL (-64*1024+104)(SP), BX - MOVL BX, g_stackguard(BP) MOVL BX, g_stackguard0(BP) - MOVL SP, g_stackbase(BP) + MOVL BX, g_stackguard1(BP) + MOVL BX, (g_stack+stack_lo)(BP) + MOVL SP, (g_stack+stack_hi)(BP) // find out information about the processor we're on MOVL $0, AX @@ -44,10 +45,14 @@ nocpuinfo: MOVL BX, 4(SP) MOVL BP, 0(SP) CALL AX + // update stackguard after _cgo_init MOVL $runtime·g0(SB), CX - MOVL g_stackguard0(CX), AX - MOVL AX, g_stackguard(CX) + MOVL (g_stack+stack_lo)(CX), AX + ADDL $const_StackGuard, AX + MOVL AX, g_stackguard0(CX) + MOVL AX, g_stackguard1(CX) + // skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows CMPL runtime·iswindows(SB), $0 JEQ ok @@ -289,19 +294,12 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 JNE 2(PC) INT $3 - // frame size in DI - // arg size in AX - // Save in m. - MOVL DI, m_moreframesize(BX) - MOVL AX, m_moreargsize(BX) - // Called from f. // Set m->morebuf to f's caller. MOVL 4(SP), DI // f's caller's PC MOVL DI, (m_morebuf+gobuf_pc)(BX) LEAL 8(SP), CX // f's caller's SP MOVL CX, (m_morebuf+gobuf_sp)(BX) - MOVL CX, m_moreargp(BX) get_tls(CX) MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) @@ -437,25 +435,6 @@ CALLFN(runtime·call268435456, 268435456) CALLFN(runtime·call536870912, 536870912) CALLFN(runtime·call1073741824, 1073741824) -// Return point when leaving stack. -// -// Lessstack can appear in stack traces for the same reason -// as morestack; in that context, it has 0 arguments. -TEXT runtime·lessstack(SB), NOSPLIT, $0-0 - // Save return value in m->cret - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - MOVL AX, m_cret(BX) - - // Call oldstack on m->g0's stack. - MOVL m_g0(BX), BP - MOVL BP, g(CX) - MOVL (g_sched+gobuf_sp)(BP), SP - CALL runtime·oldstack(SB) - MOVL $0, 0x1004 // crash if oldstack returns - RET - // bool cas(int32 *val, int32 old, int32 new) // Atomically: // if(*val == old){ @@ -836,10 +815,10 @@ TEXT setg_gcc<>(SB), NOSPLIT, $0 TEXT runtime·stackcheck(SB), NOSPLIT, $0-0 get_tls(CX) MOVL g(CX), AX - CMPL g_stackbase(AX), SP + CMPL (g_stack+stack_hi)(AX), SP JHI 2(PC) INT $3 - CMPL SP, g_stackguard(AX) + CMPL SP, (g_stack+stack_lo)(AX) JHI 2(PC) INT $3 RET @@ -904,15 +883,6 @@ TEXT runtime·emptyfunc(SB),0,$0-0 TEXT runtime·abort(SB),NOSPLIT,$0-0 INT $0x3 -TEXT runtime·stackguard(SB),NOSPLIT,$0-8 - MOVL SP, DX - MOVL DX, sp+0(FP) - get_tls(CX) - MOVL g(CX), BX - MOVL g_stackguard(BX), DX - MOVL DX, limit+4(FP) - RET - GLOBL runtime·tls0(SB), $32 // hash function using AES hardware instructions diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index a47fb09522..a32e03e4ee 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -19,9 +19,10 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 // _cgo_init may update stackguard. MOVQ $runtime·g0(SB), DI LEAQ (-64*1024+104)(SP), BX - MOVQ BX, g_stackguard(DI) MOVQ BX, g_stackguard0(DI) - MOVQ SP, g_stackbase(DI) + MOVQ BX, g_stackguard1(DI) + MOVQ BX, (g_stack+stack_lo)(DI) + MOVQ SP, (g_stack+stack_hi)(DI) // find out information about the processor we're on MOVQ $0, AX @@ -42,13 +43,16 @@ nocpuinfo: MOVQ DI, CX // Win64 uses CX for first parameter MOVQ $setg_gcc<>(SB), SI CALL AX + // update stackguard after _cgo_init MOVQ $runtime·g0(SB), CX - MOVQ g_stackguard0(CX), AX - MOVQ AX, g_stackguard(CX) + MOVQ (g_stack+stack_lo)(CX), AX + ADDQ $const_StackGuard, AX + MOVQ AX, g_stackguard0(CX) + MOVQ AX, g_stackguard1(CX) + CMPL runtime·iswindows(SB), $0 JEQ ok - needtls: // skip TLS setup on Plan 9 CMPL runtime·isplan9(SB), $1 @@ -261,7 +265,6 @@ onm: */ // Called during function prolog when more stack is needed. -// Caller has already done get_tls(CX); MOVQ m(CX), BX. // // The traceback routines see morestack on a g0 as being // the top of a stack (for example, morestack calling newstack @@ -269,6 +272,8 @@ onm: // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT,$0-0 // Cannot grow scheduler stack (m->g0). + MOVQ g(CX), BX + MOVQ g_m(BX), BX MOVQ m_g0(BX), SI CMPQ g(CX), SI JNE 2(PC) @@ -286,7 +291,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVQ AX, (m_morebuf+gobuf_pc)(BX) LEAQ 16(SP), AX // f's caller's SP MOVQ AX, (m_morebuf+gobuf_sp)(BX) - MOVQ AX, m_moreargp(BX) get_tls(CX) MOVQ g(CX), SI MOVQ SI, (m_morebuf+gobuf_g)(BX) @@ -307,6 +311,11 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVQ $0, 0x1003 // crash if newstack returns RET +// morestack but not preserving ctxt. +TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 + MOVL $0, DX + JMP runtime·morestack(SB) + // reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number @@ -415,142 +424,6 @@ CALLFN(runtime·call268435456, 268435456) CALLFN(runtime·call536870912, 536870912) CALLFN(runtime·call1073741824, 1073741824) -// Return point when leaving stack. -// -// Lessstack can appear in stack traces for the same reason -// as morestack; in that context, it has 0 arguments. -TEXT runtime·lessstack(SB), NOSPLIT, $0-0 - // Save return value in m->cret - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVQ AX, m_cret(BX) - - // Call oldstack on m->g0's stack. - MOVQ m_g0(BX), BP - MOVQ BP, g(CX) - MOVQ (g_sched+gobuf_sp)(BP), SP - CALL runtime·oldstack(SB) - MOVQ $0, 0x1004 // crash if oldstack returns - RET - -// morestack trampolines -TEXT runtime·morestack00(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVQ $0, AX - MOVQ AX, m_moreframesize(BX) - MOVQ $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack01(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - SHLQ $32, AX - MOVQ AX, m_moreframesize(BX) - MOVQ $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack10(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVLQZX AX, AX - MOVQ AX, m_moreframesize(BX) - MOVQ $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack11(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - MOVQ AX, m_moreframesize(BX) - MOVQ $runtime·morestack(SB), AX - JMP AX - -// subcases of morestack01 -// with const of 8,16,...48 -TEXT runtime·morestack8(SB),NOSPLIT,$0 - MOVQ $1, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack16(SB),NOSPLIT,$0 - MOVQ $2, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack24(SB),NOSPLIT,$0 - MOVQ $3, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack32(SB),NOSPLIT,$0 - MOVQ $4, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack40(SB),NOSPLIT,$0 - MOVQ $5, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack48(SB),NOSPLIT,$0 - MOVQ $6, R8 - MOVQ $morestack<>(SB), AX - JMP AX - -TEXT morestack<>(SB),NOSPLIT,$0 - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_m(BX), BX - SHLQ $35, R8 - MOVQ R8, m_moreframesize(BX) - MOVQ $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack00(SB) - -TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack01(SB) - -TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack10(SB) - -TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack11(SB) - -TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack8(SB) - -TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack16(SB) - -TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack24(SB) - -TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack32(SB) - -TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack40(SB) - -TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack48(SB) - // bool cas(int32 *val, int32 old, int32 new) // Atomically: // if(*val == old){ @@ -922,14 +795,14 @@ TEXT setg_gcc<>(SB),NOSPLIT,$0 MOVQ DI, g(AX) RET -// check that SP is in range [g->stackbase, g->stackguard) +// check that SP is in range [g->stack.lo, g->stack.hi) TEXT runtime·stackcheck(SB), NOSPLIT, $0-0 get_tls(CX) MOVQ g(CX), AX - CMPQ g_stackbase(AX), SP + CMPQ (g_stack+stack_hi)(AX), SP JHI 2(PC) INT $3 - CMPQ SP, g_stackguard(AX) + CMPQ SP, (g_stack+stack_lo)(AX) JHI 2(PC) INT $3 RET @@ -978,15 +851,6 @@ TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 MOVQ AX, ret+0(FP) RET -TEXT runtime·stackguard(SB),NOSPLIT,$0-16 - MOVQ SP, DX - MOVQ DX, sp+0(FP) - get_tls(CX) - MOVQ g(CX), BX - MOVQ g_stackguard(BX), DX - MOVQ DX, limit+8(FP) - RET - GLOBL runtime·tls0(SB), $64 // hash function using AES hardware instructions diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 95d04cae4f..046eb1cd6f 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -20,10 +20,11 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 // create istack out of the given (operating system) stack. MOVL $runtime·g0(SB), DI - LEAL (-64*1024+104)(SP), DI - MOVL BX, g_stackguard(DI) + LEAL (-64*1024+104)(SP), BX MOVL BX, g_stackguard0(DI) - MOVL SP, g_stackbase(DI) + MOVL BX, g_stackguard1(DI) + MOVL BX, (g_stack+stack_lo)(DI) + MOVL SP, (g_stack+stack_hi)(DI) // find out information about the processor we're on MOVQ $0, AX @@ -234,13 +235,16 @@ onm: */ // Called during function prolog when more stack is needed. -// Caller has already done get_tls(CX); MOVQ m(CX), BX. // // The traceback routines see morestack on a g0 as being // the top of a stack (for example, morestack calling newstack // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT,$0-0 + get_tls(CX) + MOVL g(CX), BX + MOVL g_m(BX), BX + // Cannot grow scheduler stack (m->g0). MOVL m_g0(BX), SI CMPL g(CX), SI @@ -259,7 +263,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVL AX, (m_morebuf+gobuf_pc)(BX) LEAL 16(SP), AX // f's caller's SP MOVL AX, (m_morebuf+gobuf_sp)(BX) - MOVL AX, m_moreargp(BX) get_tls(CX) MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) @@ -280,6 +283,11 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVL $0, 0x1003 // crash if newstack returns RET +// morestack trampolines +TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 + MOVL $0, DX + JMP runtime·morestack(SB) + // reflectcall: call a function with the given argument list // func call(f *FuncVal, arg *byte, argsize, retoffset uint32). // we don't have variable-sized frames, so we use a small number @@ -389,142 +397,6 @@ CALLFN(runtime·call268435456, 268435456) CALLFN(runtime·call536870912, 536870912) CALLFN(runtime·call1073741824, 1073741824) -// Return point when leaving stack. -// -// Lessstack can appear in stack traces for the same reason -// as morestack; in that context, it has 0 arguments. -TEXT runtime·lessstack(SB), NOSPLIT, $0-0 - // Save return value in m->cret - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - MOVQ AX, m_cret(BX) // MOVQ, to save all 64 bits - - // Call oldstack on m->g0's stack. - MOVL m_g0(BX), BX - MOVL BX, g(CX) - MOVL (g_sched+gobuf_sp)(BX), SP - CALL runtime·oldstack(SB) - MOVL $0, 0x1004 // crash if oldstack returns - RET - -// morestack trampolines -TEXT runtime·morestack00(SB),NOSPLIT,$0 - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - MOVQ $0, AX - MOVQ AX, m_moreframesize(BX) - MOVL $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack01(SB),NOSPLIT,$0 - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - SHLQ $32, AX - MOVQ AX, m_moreframesize(BX) - MOVL $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack10(SB),NOSPLIT,$0 - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - MOVLQZX AX, AX - MOVQ AX, m_moreframesize(BX) - MOVL $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack11(SB),NOSPLIT,$0 - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - MOVQ AX, m_moreframesize(BX) - MOVL $runtime·morestack(SB), AX - JMP AX - -// subcases of morestack01 -// with const of 8,16,...48 -TEXT runtime·morestack8(SB),NOSPLIT,$0 - MOVQ $1, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack16(SB),NOSPLIT,$0 - MOVQ $2, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack24(SB),NOSPLIT,$0 - MOVQ $3, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack32(SB),NOSPLIT,$0 - MOVQ $4, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack40(SB),NOSPLIT,$0 - MOVQ $5, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT runtime·morestack48(SB),NOSPLIT,$0 - MOVQ $6, R8 - MOVL $morestack<>(SB), AX - JMP AX - -TEXT morestack<>(SB),NOSPLIT,$0 - get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX - SHLQ $35, R8 - MOVQ R8, m_moreframesize(BX) - MOVL $runtime·morestack(SB), AX - JMP AX - -TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack00(SB) - -TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack01(SB) - -TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack10(SB) - -TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack11(SB) - -TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack8(SB) - -TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack16(SB) - -TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack24(SB) - -TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack32(SB) - -TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack40(SB) - -TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0 - MOVL $0, DX - JMP runtime·morestack48(SB) - // bool cas(int32 *val, int32 old, int32 new) // Atomically: // if(*val == old){ @@ -722,10 +594,10 @@ TEXT runtime·setg(SB), NOSPLIT, $0-4 TEXT runtime·stackcheck(SB), NOSPLIT, $0-0 get_tls(CX) MOVL g(CX), AX - CMPL g_stackbase(AX), SP + CMPL (g_stack+stack_hi)(AX), SP JHI 2(PC) MOVL 0, AX - CMPL SP, g_stackguard(AX) + CMPL SP, (g_stack+stack_lo)(AX) JHI 2(PC) MOVL 0, AX RET @@ -789,15 +661,6 @@ TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 MOVQ AX, ret+0(FP) RET -TEXT runtime·stackguard(SB),NOSPLIT,$0-8 - MOVL SP, DX - MOVL DX, sp+0(FP) - get_tls(CX) - MOVL g(CX), BX - MOVL g_stackguard(BX), DX - MOVL DX, limit+4(FP) - RET - GLOBL runtime·tls0(SB), $64 // hash function using AES hardware instructions diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index af536f079c..ac78bd9dc5 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -31,9 +31,11 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4 // create istack out of the OS stack MOVW $(-8192+104)(R13), R0 - MOVW R0, g_stackguard(g) // (w 104b guard) MOVW R0, g_stackguard0(g) - MOVW R13, g_stackbase(g) + MOVW R0, g_stackguard1(g) + MOVW R0, (g_stack+stack_lo)(g) + MOVW R13, (g_stack+stack_hi)(g) + BL runtime·emptyfunc(SB) // fault if stack check is wrong #ifndef GOOS_nacl @@ -51,8 +53,10 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4 nocgo: // update stackguard after _cgo_init - MOVW g_stackguard0(g), R0 - MOVW R0, g_stackguard(g) + MOVW (g_stack+stack_lo)(g), R0 + ADD $const_StackGuard, R0 + MOVW R0, g_stackguard0(g) + MOVW R0, g_stackguard1(g) BL runtime·checkgoarm(SB) BL runtime·check(SB) @@ -287,9 +291,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0 CMP g, R4 BL.EQ runtime·abort(SB) - MOVW R1, m_moreframesize(R8) - MOVW R2, m_moreargsize(R8) - // Called from f. // Set g->sched to context in f. MOVW R7, (g_sched+gobuf_ctxt)(g) @@ -302,7 +303,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0 MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC MOVW SP, (m_morebuf+gobuf_sp)(R8) // f's caller's SP MOVW $4(SP), R3 // f's argument pointer - MOVW R3, m_moreargp(R8) MOVW g, (m_morebuf+gobuf_g)(R8) // Call newstack on m->g0's stack. @@ -436,22 +436,6 @@ CALLFN(runtime·call268435456, 268435456) CALLFN(runtime·call536870912, 536870912) CALLFN(runtime·call1073741824, 1073741824) -// Return point when leaving stack. -// using frame size $-4 means do not save LR on stack. -// -// Lessstack can appear in stack traces for the same reason -// as morestack; in that context, it has 0 arguments. -TEXT runtime·lessstack(SB),NOSPLIT,$-4-0 - // Save return value in m->cret - MOVW g_m(g), R8 - MOVW R0, m_cret(R8) - - // Call oldstack on m->g0's stack. - MOVW m_g0(R8), R0 - BL setg<>(SB) - MOVW (g_sched+gobuf_sp)(g), SP - BL runtime·oldstack(SB) - // void jmpdefer(fn, sp); // called from deferreturn. // 1. grab stored LR for caller @@ -721,13 +705,6 @@ TEXT runtime·atomicloaduintptr(SB),NOSPLIT,$0-8 TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8 B runtime·atomicload(SB) -TEXT runtime·stackguard(SB),NOSPLIT,$0-8 - MOVW R13, R1 - MOVW g_stackguard(g), R2 - MOVW R1, sp+0(FP) - MOVW R2, limit+4(FP) - RET - // AES hashing not implemented for ARM TEXT runtime·aeshash(SB),NOSPLIT,$-4-0 MOVW $0, R0 diff --git a/src/runtime/cgo/gcc_darwin_386.c b/src/runtime/cgo/gcc_darwin_386.c index d1ef31ed4e..6668ba4a21 100644 --- a/src/runtime/cgo/gcc_darwin_386.c +++ b/src/runtime/cgo/gcc_darwin_386.c @@ -100,7 +100,7 @@ x_cgo_init(G *g) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); inittls(); @@ -121,7 +121,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -140,14 +141,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - pthread_setspecific(k1, (void*)ts.g); crosscall_386(ts.fn); diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c index 358a2816a3..dc679acab9 100644 --- a/src/runtime/cgo/gcc_darwin_amd64.c +++ b/src/runtime/cgo/gcc_darwin_amd64.c @@ -71,7 +71,7 @@ x_cgo_init(G *g) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); inittls(); @@ -92,7 +92,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -111,14 +112,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - pthread_setspecific(k1, (void*)ts.g); crosscall_amd64(ts.fn); diff --git a/src/runtime/cgo/gcc_dragonfly_386.c b/src/runtime/cgo/gcc_dragonfly_386.c index 6af61ac495..074418f77d 100644 --- a/src/runtime/cgo/gcc_dragonfly_386.c +++ b/src/runtime/cgo/gcc_dragonfly_386.c @@ -21,7 +21,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -59,14 +60,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c index a29d522946..f79f652e46 100644 --- a/src/runtime/cgo/gcc_dragonfly_amd64.c +++ b/src/runtime/cgo/gcc_dragonfly_amd64.c @@ -21,7 +21,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -59,14 +60,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_freebsd_386.c b/src/runtime/cgo/gcc_freebsd_386.c index 6af61ac495..074418f77d 100644 --- a/src/runtime/cgo/gcc_freebsd_386.c +++ b/src/runtime/cgo/gcc_freebsd_386.c @@ -21,7 +21,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -59,14 +60,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c index a29d522946..f79f652e46 100644 --- a/src/runtime/cgo/gcc_freebsd_amd64.c +++ b/src/runtime/cgo/gcc_freebsd_amd64.c @@ -21,7 +21,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -59,14 +60,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_freebsd_arm.c b/src/runtime/cgo/gcc_freebsd_arm.c index 16530f0200..2a86a91174 100644 --- a/src/runtime/cgo/gcc_freebsd_arm.c +++ b/src/runtime/cgo/gcc_freebsd_arm.c @@ -32,7 +32,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -56,7 +56,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); size = 0; pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -76,14 +77,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; - crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g); return nil; } diff --git a/src/runtime/cgo/gcc_linux_386.c b/src/runtime/cgo/gcc_linux_386.c index 82b156cbb0..9801c87bdb 100644 --- a/src/runtime/cgo/gcc_linux_386.c +++ b/src/runtime/cgo/gcc_linux_386.c @@ -19,7 +19,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -43,7 +43,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); size = 0; pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -61,14 +62,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c index fdbf51c254..275d5ddaca 100644 --- a/src/runtime/cgo/gcc_linux_amd64.c +++ b/src/runtime/cgo/gcc_linux_amd64.c @@ -19,7 +19,7 @@ x_cgo_init(G* g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -38,7 +38,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -56,14 +57,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_linux_arm.c b/src/runtime/cgo/gcc_linux_arm.c index ef16d2341a..7d4b4d6d4f 100644 --- a/src/runtime/cgo/gcc_linux_arm.c +++ b/src/runtime/cgo/gcc_linux_arm.c @@ -31,7 +31,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); size = 0; pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -50,14 +51,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; - crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g); return nil; } @@ -71,7 +64,7 @@ x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); if (x_cgo_inittls) { diff --git a/src/runtime/cgo/gcc_netbsd_386.c b/src/runtime/cgo/gcc_netbsd_386.c index a2b7ef3fc5..2505e6dc7c 100644 --- a/src/runtime/cgo/gcc_netbsd_386.c +++ b/src/runtime/cgo/gcc_netbsd_386.c @@ -20,7 +20,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -39,7 +39,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -58,14 +59,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_netbsd_amd64.c b/src/runtime/cgo/gcc_netbsd_amd64.c index ccd08b73ce..8f646502d7 100644 --- a/src/runtime/cgo/gcc_netbsd_amd64.c +++ b/src/runtime/cgo/gcc_netbsd_amd64.c @@ -20,7 +20,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -59,14 +60,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_netbsd_arm.c b/src/runtime/cgo/gcc_netbsd_arm.c index 5c0603dc6e..7a98c0de24 100644 --- a/src/runtime/cgo/gcc_netbsd_arm.c +++ b/src/runtime/cgo/gcc_netbsd_arm.c @@ -21,7 +21,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); } @@ -40,7 +40,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -60,14 +61,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096 * 2; - crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g); return nil; } diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c index 48b4bc7393..582e943f34 100644 --- a/src/runtime/cgo/gcc_openbsd_386.c +++ b/src/runtime/cgo/gcc_openbsd_386.c @@ -92,7 +92,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); // Locate symbol for the system pthread_create function. @@ -126,7 +126,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = sys_pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -147,14 +148,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c index 5f0d3bb453..35b359bbaf 100644 --- a/src/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/runtime/cgo/gcc_openbsd_amd64.c @@ -92,7 +92,7 @@ x_cgo_init(G *g, void (*setg)(void*)) setg_gcc = setg; pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - g->stackguard = (uintptr)&attr - size + 4096; + g->stacklo = (uintptr)&attr - size + 4096; pthread_attr_destroy(&attr); // Locate symbol for the system pthread_create function. @@ -127,7 +127,8 @@ _cgo_sys_thread_start(ThreadStart *ts) pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); - ts->g->stackguard = size; + // Leave stacklo=0 and set stackhi=size; mstack will do the rest. + ts->g->stackhi = size; err = sys_pthread_create(&p, &attr, threadentry, ts); pthread_sigmask(SIG_SETMASK, &oset, nil); @@ -148,14 +149,6 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - - /* - * _cgo_sys_thread_start set stackguard to stack size; - * change to actual guard pointer. - */ - ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096; - /* * Set specific keys. */ diff --git a/src/runtime/cgo/gcc_windows_386.c b/src/runtime/cgo/gcc_windows_386.c index 0935b74f22..acd038ccd6 100644 --- a/src/runtime/cgo/gcc_windows_386.c +++ b/src/runtime/cgo/gcc_windows_386.c @@ -20,7 +20,7 @@ void x_cgo_init(G *g) { int tmp; - g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024; + g->stacklo = (uintptr)&tmp - STACKSIZE + 8*1024; } @@ -44,8 +44,8 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024; + ts.g->stackhi = (uintptr)&ts; + ts.g->stacklo = (uintptr)&ts - STACKSIZE + 8*1024; /* * Set specific keys in thread local storage. diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c index 4a2540a352..ce7e06b3df 100644 --- a/src/runtime/cgo/gcc_windows_amd64.c +++ b/src/runtime/cgo/gcc_windows_amd64.c @@ -20,7 +20,7 @@ void x_cgo_init(G *g) { int tmp; - g->stackguard = (uintptr)&tmp - STACKSIZE + 8*1024; + g->stacklo = (uintptr)&tmp - STACKSIZE + 8*1024; } @@ -44,8 +44,8 @@ threadentry(void *v) ts = *(ThreadStart*)v; free(v); - ts.g->stackbase = (uintptr)&ts; - ts.g->stackguard = (uintptr)&ts - STACKSIZE + 8*1024; + ts.g->stackhi = (uintptr)&ts; + ts.g->stacklo = (uintptr)&ts - STACKSIZE + 8*1024; /* * Set specific keys in thread local storage. diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h index 799af05ead..9d918fd7ab 100644 --- a/src/runtime/cgo/libcgo.h +++ b/src/runtime/cgo/libcgo.h @@ -21,8 +21,8 @@ typedef uintptr_t uintptr; typedef struct G G; struct G { - uintptr stackguard; - uintptr stackbase; + uintptr stacklo; + uintptr stackhi; }; /* diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 07ef26f25a..1f1b5fc794 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -24,7 +24,6 @@ func stackguard() (sp, limit uintptr) var Entersyscall = entersyscall var Exitsyscall = exitsyscall var LockedOSThread = lockedOSThread -var Stackguard = stackguard type LFNode struct { Next *LFNode diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index 435e0b2dae..db2c552b72 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -382,7 +382,7 @@ dumpgoroutine(G *gp) Panic *p; bool (*fn)(Stkframe*, void*); - if(gp->syscallstack != (uintptr)nil) { + if(gp->syscallsp != (uintptr)nil) { sp = gp->syscallsp; pc = gp->syscallpc; lr = 0; @@ -412,8 +412,6 @@ dumpgoroutine(G *gp) child.arglen = 0; child.sp = nil; child.depth = 0; - if(!ScanStackByFrames) - runtime·throw("need frame info to dump stacks"); fn = dumpframe; runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, false); diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index ca7cb6d36a..890ddea6d5 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -136,7 +136,7 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { } mp.mallocing = 0 if mp.curg != nil { - mp.curg.stackguard0 = mp.curg.stackguard + mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard } // Note: one releasem for the acquirem just above. // The other for the acquirem at start of malloc. @@ -313,7 +313,7 @@ marked: } mp.mallocing = 0 if mp.curg != nil { - mp.curg.stackguard0 = mp.curg.stackguard + mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard } // Note: one releasem for the acquirem just above. // The other for the acquirem at start of malloc. diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index cdda6e7e6f..da0455d923 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -689,9 +689,6 @@ static void scanstack(G *gp) { M *mp; - int32 n; - Stktop *stk; - uintptr sp, guard; bool (*fn)(Stkframe*, void*); if(runtime·readgstatus(gp)&Gscan == 0) { @@ -719,44 +716,8 @@ scanstack(G *gp) if((mp = gp->m) != nil && mp->helpgc) runtime·throw("can't scan gchelper stack"); - if(gp->syscallstack != (uintptr)nil) { - // Scanning another goroutine that is about to enter or might - // have just exited a system call. It may be executing code such - // as schedlock and may have needed to start a new stack segment. - // Use the stack segment and stack pointer at the time of - // the system call instead, since that won't change underfoot. - sp = gp->syscallsp; - stk = (Stktop*)gp->syscallstack; - guard = gp->syscallguard; - } else { - // Scanning another goroutine's stack. - // The goroutine is usually asleep (the world is stopped). - sp = gp->sched.sp; - stk = (Stktop*)gp->stackbase; - guard = gp->stackguard; - } - if(ScanStackByFrames) { - USED(sp); - USED(stk); - USED(guard); - fn = scanframe; - runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false); - } else { - n = 0; - while(stk) { - if(sp < guard-StackGuard || (uintptr)stk < sp) { - runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk); - runtime·throw("scanstack"); - } - if(Debug > 2) - runtime·printf("conservative stack %p+%p\n", (byte*)sp, (uintptr)stk-sp); - scanblock((byte*)sp, (uintptr)stk - sp, ScanConservatively); - sp = stk->gobuf.sp; - guard = stk->stackguard; - stk = (Stktop*)stk->stackbase; - n++; - } - } + fn = scanframe; + runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false); } // The gp has been moved to a gc safepoint. If there is gcphase specific diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h index d04b5cab8f..0daf7511b6 100644 --- a/src/runtime/mgc0.h +++ b/src/runtime/mgc0.h @@ -5,8 +5,6 @@ // Garbage collector (GC) enum { - ScanStackByFrames = 1, - // Four bits per word (see #defines below). gcBits = 4, wordsPerBitmapByte = 8/gcBits, diff --git a/src/runtime/os_darwin.c b/src/runtime/os_darwin.c index 2de0cd949e..bbd29282b0 100644 --- a/src/runtime/os_darwin.c +++ b/src/runtime/os_darwin.c @@ -144,7 +144,7 @@ void runtime·minit(void) { // Initialize signal handling. - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); } diff --git a/src/runtime/os_dragonfly.c b/src/runtime/os_dragonfly.c index 208252d9f3..e372205ec8 100644 --- a/src/runtime/os_dragonfly.c +++ b/src/runtime/os_dragonfly.c @@ -204,7 +204,7 @@ void runtime·minit(void) { // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(&sigset_none, nil); } diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c index 476def557f..cde6936de5 100644 --- a/src/runtime/os_freebsd.c +++ b/src/runtime/os_freebsd.c @@ -212,7 +212,7 @@ void runtime·minit(void) { // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(&sigset_none, nil); } diff --git a/src/runtime/os_linux.c b/src/runtime/os_linux.c index 3a8c1a7579..0d8ffc995f 100644 --- a/src/runtime/os_linux.c +++ b/src/runtime/os_linux.c @@ -226,7 +226,7 @@ void runtime·minit(void) { // Initialize signal handling. - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset)); } diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c index aecd61740c..14b5583033 100644 --- a/src/runtime/os_nacl.c +++ b/src/runtime/os_nacl.c @@ -31,7 +31,7 @@ runtime·minit(void) int32 ret; // Initialize signal handling - ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024); if(ret < 0) runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret); diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c index db64b01c8d..58e5bedf2f 100644 --- a/src/runtime/os_netbsd.c +++ b/src/runtime/os_netbsd.c @@ -282,7 +282,7 @@ runtime·minit(void) g->m->procid = runtime·lwp_self(); // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); } diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c index 045c3a9462..91bd9449a1 100644 --- a/src/runtime/os_openbsd.c +++ b/src/runtime/os_openbsd.c @@ -237,7 +237,7 @@ void runtime·minit(void) { // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(SIG_SETMASK, sigset_none); } diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c index 97afdf40c1..4b382b731b 100644 --- a/src/runtime/os_solaris.c +++ b/src/runtime/os_solaris.c @@ -183,7 +183,7 @@ runtime·minit(void) { runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno); // Initialize signal handling - runtime·signalstack((byte*)g->m->gsignal->stackguard - StackGuard, 32*1024); + runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); } diff --git a/src/runtime/panic.c b/src/runtime/panic.c index 4b21975b16..e015e41cca 100644 --- a/src/runtime/panic.c +++ b/src/runtime/panic.c @@ -51,8 +51,11 @@ runtime·recovery_m(G *gp) argp = (void*)gp->sigcode0; pc = (uintptr)gp->sigcode1; - // Unwind to the stack frame with d's arguments in it. - runtime·unwindstack(gp, argp); + // d's arguments need to be in the stack. + if(argp != nil && ((uintptr)argp < gp->stack.lo || gp->stack.hi < (uintptr)argp)) { + runtime·printf("recover: %p not in [%p, %p]\n", argp, gp->stack.lo, gp->stack.hi); + runtime·throw("bad recovery"); + } // Make the deferproc for this d return again, // this time returning 1. The calling function will @@ -73,34 +76,6 @@ runtime·recovery_m(G *gp) runtime·gogo(&gp->sched); } -// Free stack frames until we hit the last one -// or until we find the one that contains the sp. -void -runtime·unwindstack(G *gp, byte *sp) -{ - Stktop *top; - byte *stk; - - // Must be called from a different goroutine, usually m->g0. - if(g == gp) - runtime·throw("unwindstack on self"); - - while((top = (Stktop*)gp->stackbase) != 0 && top->stackbase != 0) { - stk = (byte*)gp->stackguard - StackGuard; - if(stk <= sp && sp < (byte*)gp->stackbase) - break; - gp->stackbase = top->stackbase; - gp->stackguard = top->stackguard; - gp->stackguard0 = gp->stackguard; - runtime·stackfree(gp, stk, top); - } - - if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) { - runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase); - runtime·throw("bad unwindstack"); - } -} - void runtime·startpanic_m(void) { diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 6132fee579..a7f9db410f 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -168,7 +168,6 @@ runtime·schedinit(void) g->racectx = runtime·raceinit(); runtime·sched.maxmcount = 10000; - runtime·precisestack = true; // haveexperiment("precisestack"); runtime·symtabinit(); runtime·stackinit(); @@ -196,11 +195,6 @@ runtime·schedinit(void) } procresize(procs); - runtime·copystack = runtime·precisestack; - p = runtime·getenv("GOCOPYSTACK"); - if(p != nil && !runtime·strcmp(p, (byte*)"0")) - runtime·copystack = false; - if(runtime·buildVersion.str == nil) { // Condition should never trigger. This code just serves // to ensure runtime·buildVersion is kept in the resulting binary. @@ -249,7 +243,7 @@ mcommoninit(M *mp) checkmcount(); runtime·mpreinit(mp); if(mp->gsignal) - mp->gsignal->stackguard1 = mp->gsignal->stackguard; + mp->gsignal->stackguard1 = mp->gsignal->stack.lo + StackGuard; // Add to runtime·allm so garbage collector doesn't free g->m // when it is just in a register or thread-local storage. @@ -827,9 +821,34 @@ runtime·starttheworld(void) g->stackguard0 = StackPreempt; } +static void mstart(void); + // Called to start an M. +#pragma textflag NOSPLIT void runtime·mstart(void) +{ + uintptr x, size; + + if(g->stack.lo == 0) { + // Initialize stack bounds from system stack. + // Cgo may have left stack size in stack.hi. + size = g->stack.hi; + if(size == 0) + size = 8192; + g->stack.hi = (uintptr)&x; + g->stack.lo = g->stack.hi - size + 1024; + } + + // Initialize stack guards so that we can start calling + // both Go and C functions with stack growth prologues. + g->stackguard0 = g->stack.lo + StackGuard; + g->stackguard1 = g->stackguard0; + mstart(); +} + +static void +mstart(void) { if(g != g->m->g0) runtime·throw("bad runtime·mstart"); @@ -839,7 +858,6 @@ runtime·mstart(void) // so other calls can reuse this stack space. runtime·gosave(&g->m->g0->sched); g->m->g0->sched.pc = (uintptr)-1; // make sure it is never used - g->m->g0->stackguard = g->m->g0->stackguard0; // cgo sets only stackguard0, copy it to stackguard runtime·asminit(); runtime·minit(); @@ -905,7 +923,6 @@ runtime·allocm(P *p) else mp->g0 = runtime·malg(8192); mp->g0->m = mp; - mp->g0->stackguard1 = mp->g0->stackguard; if(p == g->m->p) releasep(); @@ -1003,9 +1020,9 @@ runtime·needm(byte x) // scheduling stack is, but we assume there's at least 32 kB, // which is more than enough for us. runtime·setg(mp->g0); - g->stackbase = (uintptr)(&x + 1024); - g->stackguard = (uintptr)(&x - 32*1024); - g->stackguard0 = g->stackguard; + g->stack.hi = (uintptr)(&x + 1024); + g->stack.lo = (uintptr)(&x - 32*1024); + g->stackguard0 = g->stack.lo + StackGuard; // Initialize this thread to use the m. runtime·asminit(); @@ -1029,13 +1046,11 @@ runtime·newextram(void) mp = runtime·allocm(nil); gp = runtime·malg(4096); gp->sched.pc = (uintptr)runtime·goexit; - gp->sched.sp = gp->stackbase; + gp->sched.sp = gp->stack.hi; gp->sched.lr = 0; gp->sched.g = gp; gp->syscallpc = gp->sched.pc; gp->syscallsp = gp->sched.sp; - gp->syscallstack = gp->stackbase; - gp->syscallguard = gp->stackguard; // malg returns status as Gidle, change to Gsyscall before adding to allg // where GC will see it. runtime·casgstatus(gp, Gidle, Gsyscall); @@ -1161,7 +1176,7 @@ newm(void(*fn)(void), P *p) runtime·asmcgocall(_cgo_thread_start, &ts); return; } - runtime·newosproc(mp, (byte*)mp->g0->stackbase); + runtime·newosproc(mp, (byte*)mp->g0->stack.hi); } // Stops execution of the current m until new work is available. @@ -1368,7 +1383,7 @@ execute(G *gp) runtime·casgstatus(gp, Grunnable, Grunning); gp->waitsince = 0; gp->preempt = false; - gp->stackguard0 = gp->stackguard; + gp->stackguard0 = gp->stack.lo + StackGuard; g->m->p->schedtick++; g->m->curg = gp; gp->m = g->m; @@ -1693,7 +1708,7 @@ runtime·gosched_m(G *gp) } // Finishes execution of the current goroutine. -// Need to mark it as nosplit, because it runs with sp > stackbase (as runtime·lessstack). +// Need to mark it as nosplit, because it runs with sp > stackbase. // Since it does not return it does not matter. But if it is preempted // at the split stack check, GC will complain about inconsistent sp. #pragma textflag NOSPLIT @@ -1733,7 +1748,6 @@ goexit0(G *gp) runtime·throw("internal lockOSThread error"); } g->m->locked = 0; - runtime·unwindstack(gp, nil); gfput(g->m->p, gp); schedule(); } @@ -1791,10 +1805,8 @@ void save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); g->syscallsp = g->sched.sp; g->syscallpc = g->sched.pc; - g->syscallstack = g->stackbase; - g->syscallguard = g->stackguard; runtime·casgstatus(g, Grunning, Gsyscall); - if(g->syscallsp < g->syscallguard-StackGuard || g->syscallstack < g->syscallsp) { + if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) { fn = entersyscall_bad; runtime·onM(&fn); } @@ -1828,7 +1840,7 @@ entersyscall_bad(void) gp = g->m->curg; runtime·printf("entersyscall inconsistent %p [%p,%p]\n", - gp->syscallsp, gp->syscallguard-StackGuard, gp->syscallstack); + gp->syscallsp, gp->stack.lo, gp->stack.hi); runtime·throw("entersyscall"); } @@ -1871,10 +1883,8 @@ void save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); g->syscallsp = g->sched.sp; g->syscallpc = g->sched.pc; - g->syscallstack = g->stackbase; - g->syscallguard = g->stackguard; runtime·casgstatus(g, Grunning, Gsyscall); - if(g->syscallsp < g->syscallguard-StackGuard || g->syscallstack < g->syscallsp) { + if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) { fn = entersyscall_bad; runtime·onM(&fn); } @@ -1914,8 +1924,7 @@ runtime·exitsyscall(void) runtime·casgstatus(g, Gsyscall, Grunning); // Garbage collector isn't running (since we are), - // so okay to clear gcstack and gcsp. - g->syscallstack = (uintptr)nil; + // so okay to clear syscallsp. g->syscallsp = (uintptr)nil; g->m->locks--; if(g->preempt) { @@ -1923,7 +1932,7 @@ runtime·exitsyscall(void) g->stackguard0 = StackPreempt; } else { // otherwise restore the real stackguard, we've spoiled it in entersyscall/entersyscallblock - g->stackguard0 = g->stackguard; + g->stackguard0 = g->stack.lo + StackGuard; } g->throwsplit = 0; return; @@ -1936,12 +1945,11 @@ runtime·exitsyscall(void) runtime·mcall(&fn); // Scheduler returned, so we're allowed to run now. - // Delete the gcstack information that we left for + // Delete the syscallsp information that we left for // the garbage collector during the system call. // Must wait until now because until gosched returns // we don't know for sure that the garbage collector // is not running. - g->syscallstack = (uintptr)nil; g->syscallsp = (uintptr)nil; g->m->p->syscalltick++; g->throwsplit = 0; @@ -2047,9 +2055,7 @@ beforefork(void) // Code between fork and exec must not allocate memory nor even try to grow stack. // Here we spoil g->stackguard to reliably detect any attempts to grow stack. // runtime_AfterFork will undo this in parent process, but not in child. - gp->m->forkstackguard = gp->stackguard; - gp->stackguard0 = StackPreempt-1; - gp->stackguard = StackPreempt-1; + gp->stackguard0 = StackFork; } // Called from syscall package before fork. @@ -2071,9 +2077,7 @@ afterfork(void) gp = g->m->curg; // See the comment in runtime_BeforeFork. - gp->stackguard0 = gp->m->forkstackguard; - gp->stackguard = gp->m->forkstackguard; - gp->m->forkstackguard = 0; + gp->stackguard0 = gp->stack.lo + StackGuard; hz = runtime·sched.profilehz; if(hz != 0) @@ -2102,10 +2106,11 @@ mstackalloc(G *gp) G *newg; uintptr size; - newg = (G*)gp->param; - size = newg->stacksize; - newg->stacksize = 0; - gp->param = runtime·stackalloc(newg, size); + newg = g->m->ptrarg[0]; + size = g->m->scalararg[0]; + + newg->stack = runtime·stackalloc(size); + runtime·gogo(&gp->sched); } @@ -2114,34 +2119,24 @@ G* runtime·malg(int32 stacksize) { G *newg; - byte *stk; void (*fn)(G*); - if(StackTop < sizeof(Stktop)) { - runtime·printf("runtime: SizeofStktop=%d, should be >=%d\n", (int32)StackTop, (int32)sizeof(Stktop)); - runtime·throw("runtime: bad stack.h"); - } - newg = allocg(); if(stacksize >= 0) { stacksize = runtime·round2(StackSystem + stacksize); if(g == g->m->g0) { // running on scheduler stack already. - stk = runtime·stackalloc(newg, stacksize); + newg->stack = runtime·stackalloc(stacksize); } else { // have to call stackalloc on scheduler stack. - newg->stacksize = stacksize; - g->param = newg; + g->m->scalararg[0] = stacksize; + g->m->ptrarg[0] = newg; fn = mstackalloc; runtime·mcall(&fn); - stk = g->param; - g->param = nil; + g->m->ptrarg[0] = nil; } - newg->stack0 = (uintptr)stk; - newg->stackguard = (uintptr)stk + StackGuard; - newg->stackguard0 = newg->stackguard; + newg->stackguard0 = newg->stack.lo + StackGuard; newg->stackguard1 = ~(uintptr)0; - newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop); } return newg; } @@ -2222,19 +2217,18 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp runtime·throw("runtime.newproc: function arguments too large for new goroutine"); p = g->m->p; - if((newg = gfget(p)) != nil) { - if(newg->stackguard - StackGuard != newg->stack0) - runtime·throw("invalid stack in newg"); - } else { + if((newg = gfget(p)) == nil) { newg = runtime·malg(StackMin); runtime·casgstatus(newg, Gidle, Gdead); allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. } + if(newg->stack.hi == 0) + runtime·throw("newproc1: newg missing stack"); if(runtime·readgstatus(newg) != Gdead) runtime·throw("newproc1: new g is not Gdead"); - sp = (byte*)newg->stackbase; + sp = (byte*)newg->stack.hi; sp -= siz; runtime·memmove(sp, argp, narg); if(thechar == '5') { @@ -2307,27 +2301,18 @@ static void gfput(P *p, G *gp) { uintptr stksize; - Stktop *top; if(runtime·readgstatus(gp) != Gdead) runtime·throw("gfput: bad status (not Gdead)"); - if(gp->stackguard - StackGuard != gp->stack0) - runtime·throw("invalid stack in gfput"); - stksize = gp->stackbase + sizeof(Stktop) - gp->stack0; - if(stksize != gp->stacksize) { - runtime·printf("runtime: bad stacksize, goroutine %D, remain=%d, last=%d\n", - gp->goid, (int32)gp->stacksize, (int32)stksize); - runtime·throw("gfput: bad stacksize"); - } - top = (Stktop*)gp->stackbase; + stksize = gp->stack.hi - gp->stack.lo; + if(stksize != FixedStack) { // non-standard stack size - free it. - runtime·stackfree(gp, (void*)gp->stack0, top); - gp->stack0 = 0; - gp->stackguard = 0; + runtime·stackfree(gp->stack); + gp->stack.lo = 0; + gp->stack.hi = 0; gp->stackguard0 = 0; - gp->stackbase = 0; } gp->schedlink = p->gfree; p->gfree = gp; @@ -2352,7 +2337,6 @@ static G* gfget(P *p) { G *gp; - byte *stk; void (*fn)(G*); retry: @@ -2374,25 +2358,21 @@ retry: p->gfree = gp->schedlink; p->gfreecnt--; - if(gp->stack0 == 0) { + if(gp->stack.lo == 0) { // Stack was deallocated in gfput. Allocate a new one. if(g == g->m->g0) { - stk = runtime·stackalloc(gp, FixedStack); + gp->stack = runtime·stackalloc(FixedStack); } else { - gp->stacksize = FixedStack; - g->param = gp; + g->m->scalararg[0] = FixedStack; + g->m->ptrarg[0] = gp; fn = mstackalloc; runtime·mcall(&fn); - stk = g->param; - g->param = nil; + g->m->ptrarg[0] = nil; } - gp->stack0 = (uintptr)stk; - gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stktop); - gp->stackguard = (uintptr)stk + StackGuard; - gp->stackguard0 = gp->stackguard; + gp->stackguard0 = gp->stack.lo + StackGuard; } else { if(raceenabled) - runtime·racemalloc((void*)gp->stack0, gp->stackbase + sizeof(Stktop) - gp->stack0); + runtime·racemalloc((void*)gp->stack.lo, gp->stack.hi - gp->stack.lo); } } return gp; @@ -2654,7 +2634,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) // in runtime.gogo. traceback = true; if(gp == nil || gp != mp->curg || - (uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr)sp || + (uintptr)sp < gp->stack.lo || gp->stack.hi < (uintptr)sp || ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes)) traceback = false; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 9584c5dfcc..4622a2c3d7 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -62,7 +62,6 @@ typedef struct M M; typedef struct P P; typedef struct Note Note; typedef struct Slice Slice; -typedef struct Stktop Stktop; typedef struct String String; typedef struct FuncVal FuncVal; typedef struct SigTab SigTab; @@ -74,12 +73,12 @@ typedef struct InterfaceType InterfaceType; typedef struct Eface Eface; typedef struct Type Type; typedef struct PtrType PtrType; -typedef struct ChanType ChanType; +typedef struct ChanType ChanType; typedef struct MapType MapType; typedef struct Defer Defer; typedef struct Panic Panic; typedef struct Hmap Hmap; -typedef struct Hiter Hiter; +typedef struct Hiter Hiter; typedef struct Hchan Hchan; typedef struct Complex64 Complex64; typedef struct Complex128 Complex128; @@ -92,7 +91,8 @@ typedef struct ParForThread ParForThread; typedef struct CgoMal CgoMal; typedef struct PollDesc PollDesc; typedef struct DebugVars DebugVars; -typedef struct ForceGCState ForceGCState; +typedef struct ForceGCState ForceGCState; +typedef struct Stack Stack; /* * Per-CPU declaration. @@ -265,23 +265,33 @@ struct WinCallbackContext bool cleanstack; }; +// Stack describes a Go execution stack. +// The bounds of the stack are exactly [lo, hi), +// with no implicit data structures on either side. +struct Stack +{ + uintptr lo; + uintptr hi; +}; + struct G { - // stackguard0 can be set to StackPreempt as opposed to stackguard - uintptr stackguard0; // cannot move - also known to liblink, libmach, runtime/cgo - uintptr stackbase; // cannot move - also known to libmach, runtime/cgo - Panic* panic; // cannot move - also known to liblink - // stackguard1 is checked by C code; it is set to ~0 in ordinary (non-g0, non-gsignal) goroutines - uintptr stackguard1; // cannot move - also known to liblink - Defer* defer; + // Stack parameters. + // stack describes the actual stack memory: [stack.lo, stack.hi). + // stackguard0 is the stack pointer compared in the Go stack growth prologue. + // It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption. + // stackguard1 is the stack pointer compared in the C stack growth prologue. + // It is stack.lo+StackGuard on g0 and gsignal stacks. + // It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash). + Stack stack; // offset known to runtime/cgo + uintptr stackguard0; // offset known to liblink + uintptr stackguard1; // offset known to liblink + + Panic* panic; // innermost panic - offset known to liblink + Defer* defer; // innermost defer Gobuf sched; - uintptr syscallstack; // if status==Gsyscall, syscallstack = stackbase to use during gc uintptr syscallsp; // if status==Gsyscall, syscallsp = sched.sp to use during gc uintptr syscallpc; // if status==Gsyscall, syscallpc = sched.pc to use during gc - uintptr syscallguard; // if status==Gsyscall, syscallguard = stackguard to use during gc - uintptr stackguard; // same as stackguard0, but not set to StackPreempt - uintptr stack0; - uintptr stacksize; void* param; // passed parameter on wakeup uint32 atomicstatus; int64 goid; @@ -291,34 +301,29 @@ struct G bool issystem; // do not output in stack dump, ignore in deadlock detector bool preempt; // preemption signal, duplicates stackguard0 = StackPreempt bool paniconfault; // panic (instead of crash) on unexpected fault address - bool preemptscan; // preempted g does scan for GC - bool gcworkdone; // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle + bool preemptscan; // preempted g does scan for GC + bool gcworkdone; // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle bool throwsplit; // must not split stack int8 raceignore; // ignore race detection events M* m; // for debuggers, but offset not hard-coded M* lockedm; int32 sig; - int32 writenbuf; Slice writebuf; uintptr sigcode0; uintptr sigcode1; uintptr sigpc; uintptr gopc; // pc of go statement that created this goroutine uintptr racectx; - SudoG *waiting; // sudog structures this G is waiting on (that have a valid elem ptr) + SudoG* waiting; // sudog structures this G is waiting on (that have a valid elem ptr) uintptr end[]; }; struct M { G* g0; // goroutine with scheduling stack - void* moreargp; // argument pointer for more stack Gobuf morebuf; // gobuf arg to morestack // Fields not known to debuggers. - uint32 moreframesize; // size arguments to morestack - uint32 moreargsize; // known by amd64 asm to follow moreframesize - uintreg cret; // return value from C uint64 procid; // for debuggers, but offset not hard-coded G* gsignal; // signal-handling G uintptr tls[4]; // thread-local storage (for x86 extern register) @@ -362,7 +367,6 @@ struct M uint8 traceback; bool (*waitunlockf)(G*, void*); void* waitlock; - uintptr forkstackguard; uintptr scalararg[4]; // scalar argument/return for mcall void* ptrarg[4]; // pointer argument/return for mcall #ifdef GOOS_windows @@ -442,16 +446,6 @@ enum LockInternal = 2, }; -struct Stktop -{ - // The offsets of these fields are known to (hard-coded in) libmach. - uintptr stackguard; - uintptr stackbase; - Gobuf gobuf; - uint32 argsize; - - uint8* argp; // pointer to arguments in old frame -}; struct SigTab { int32 flags; @@ -596,8 +590,6 @@ struct ForceGCState }; extern uint32 runtime·gcphase; -extern bool runtime·precisestack; -extern bool runtime·copystack; /* * defined macros @@ -758,7 +750,6 @@ void runtime·gogo(Gobuf*); void runtime·gostartcall(Gobuf*, void(*)(void), void*); void runtime·gostartcallfn(Gobuf*, FuncVal*); void runtime·gosave(Gobuf*); -void runtime·lessstack(void); void runtime·goargs(void); void runtime·goenvs(void); void runtime·goenvs_unix(void); @@ -809,8 +800,8 @@ int32 runtime·funcspdelta(Func*, uintptr); int8* runtime·funcname(Func*); int32 runtime·pcdatavalue(Func*, int32, uintptr); void runtime·stackinit(void); -void* runtime·stackalloc(G*, uint32); -void runtime·stackfree(G*, void*, Stktop*); +Stack runtime·stackalloc(uint32); +void runtime·stackfree(Stack); void runtime·shrinkstack(G*); MCache* runtime·allocmcache(void); void runtime·freemcache(MCache*); @@ -873,7 +864,6 @@ int64 runtime·unixnanotime(void); // real time, can skip void runtime·dopanic(int32); void runtime·startpanic(void); void runtime·freezetheworld(void); -void runtime·unwindstack(G*, byte*); void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp); void runtime·resetcpuprofiler(int32); void runtime·setcpuprofilerate(int32); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 8461c01f37..2e0c91de08 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -25,8 +25,6 @@ enum StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free StackCache = 1, - - StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time }; // Global pool of spans that have free stacks. @@ -185,13 +183,12 @@ runtime·stackcache_clear(MCache *c) runtime·unlock(&stackpoolmu); } -void* -runtime·stackalloc(G *gp, uint32 n) +Stack +runtime·stackalloc(uint32 n) { uint8 order; uint32 n2; void *v; - Stktop *top; MLink *x; MSpan *s; MCache *c; @@ -206,12 +203,11 @@ runtime·stackalloc(G *gp, uint32 n) if(StackDebug >= 1) runtime·printf("stackalloc %d\n", n); - gp->stacksize += n; if(runtime·debug.efence || StackFromSystem) { v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys); if(v == nil) runtime·throw("out of memory (stackalloc)"); - return v; + return (Stack){(uintptr)v, (uintptr)v+n}; } // Small stacks are allocated with a fixed-size free-list allocator. @@ -249,32 +245,32 @@ runtime·stackalloc(G *gp, uint32 n) runtime·throw("out of memory"); v = (byte*)(s->start<= 1) runtime·printf(" allocated %p\n", v); - return v; + return (Stack){(uintptr)v, (uintptr)v+n}; } void -runtime·stackfree(G *gp, void *v, Stktop *top) +runtime·stackfree(Stack stk) { uint8 order; uintptr n, n2; MSpan *s; MLink *x; MCache *c; + void *v; - n = (uintptr)(top+1) - (uintptr)v; + n = stk.hi - stk.lo; + v = (void*)stk.lo; if(n & (n-1)) runtime·throw("stack not a power of 2"); if(StackDebug >= 1) { runtime·printf("stackfree %p %d\n", v, (int32)n); runtime·memclr(v, n); // for testing, clobber stack data } - gp->stacksize -= n; if(runtime·debug.efence || StackFromSystem) { if(runtime·debug.efence || StackFaultOnFree) runtime·SysFault(v, n); @@ -312,70 +308,6 @@ runtime·stackfree(G *gp, void *v, Stktop *top) } } -// Called from runtime·lessstack when returning from a function which -// allocated a new stack segment. The function's return value is in -// m->cret. -void -runtime·oldstack(void) -{ - Stktop *top; - uint32 argsize; - byte *sp, *old; - uintptr *src, *dst, *dstend; - G *gp; - int64 goid; - int32 oldstatus; - - if(StackCopyAlways) - runtime·throw("unexpected call to oldstack"); - - gp = g->m->curg; - top = (Stktop*)gp->stackbase; - if(top == nil) - runtime·throw("nil stackbase"); - old = (byte*)gp->stackguard - StackGuard; - sp = (byte*)top; - argsize = top->argsize; - - if(StackDebug >= 1) { - runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n", - top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)g->m->cret, (uintptr)argsize); - } - - gp->sched = top->gobuf; - gp->sched.ret = g->m->cret; - g->m->cret = 0; // drop reference - // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow - // happens during a function call inside entersyscall. - - oldstatus = runtime·readgstatus(gp); - oldstatus &= ~Gscan; - if(oldstatus != Grunning && oldstatus != Gsyscall) { - runtime·printf("runtime: oldstack status=%d\n", oldstatus); - runtime·throw("oldstack"); - } - runtime·casgstatus(gp, oldstatus, Gcopystack); - gp->waitreason = runtime·gostringnocopy((byte*)"stack unsplit"); - - if(argsize > 0) { - sp -= argsize; - dst = (uintptr*)top->argp; - dstend = dst + argsize/sizeof(*dst); - src = (uintptr*)sp; - while(dst < dstend) - *dst++ = *src++; - } - goid = top->gobuf.g->goid; // fault if g is bad, before gogo - USED(goid); - - gp->stackbase = top->stackbase; - gp->stackguard = top->stackguard; - gp->stackguard0 = gp->stackguard; - runtime·stackfree(gp, old, top); - runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Grunning or Gsyscall - runtime·gogo(&gp->sched); -} - uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real static uint8* @@ -403,8 +335,7 @@ mapnames[] = { typedef struct CopyableInfo CopyableInfo; struct CopyableInfo { - byte *stk; // bottom address of segment - byte *base; // top address of segment (including Stktop) + Stack stk; int32 frames; // count of copyable frames (-1 = not copyable) }; @@ -421,9 +352,9 @@ checkframecopy(Stkframe *frame, void *arg) cinfo = arg; f = frame->fn; if(StackDebug >= 2) - runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base); + runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk.lo, cinfo->stk.hi); // if we're not in the segment any more, return immediately. - if((byte*)frame->varp < cinfo->stk || (byte*)frame->varp >= cinfo->base) { + if(frame->varp < cinfo->stk.lo || frame->varp >= cinfo->stk.hi) { if(StackDebug >= 2) runtime·printf(" \n"); return false; // stop traceback @@ -439,14 +370,12 @@ checkframecopy(Stkframe *frame, void *arg) stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); if(stackmap == nil) { cinfo->frames = -1; - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f)); + runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f)); return false; } if(stackmap->n <= 0) { cinfo->frames = -1; - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f)); + runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f)); return false; } } @@ -454,8 +383,7 @@ checkframecopy(Stkframe *frame, void *arg) stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); if(stackmap == nil) { cinfo->frames = -1; - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f)); + runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f)); return false; } } @@ -476,10 +404,9 @@ copyabletopsegment(G *gp) StackMap *stackmap; bool (*cb)(Stkframe*, void*); - if(gp->stackbase == 0) - runtime·throw("stackbase == 0"); - cinfo.stk = (byte*)gp->stackguard - StackGuard; - cinfo.base = (byte*)gp->stackbase + sizeof(Stktop); + if(gp->stack.lo == 0) + runtime·throw("missing stack in copyabletopsegment"); + cinfo.stk = gp->stack; cinfo.frames = 0; // Check that each frame is copyable. As a side effect, @@ -494,21 +421,20 @@ copyabletopsegment(G *gp) // Check to make sure all Defers are copyable for(d = gp->defer; d != nil; d = d->link) { - if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) { + if(cinfo.stk.lo <= (uintptr)d && (uintptr)d < cinfo.stk.hi) { // Defer is on the stack. Its copyableness has // been established during stack walking. // For now, this only happens with the Defer in runtime.main. continue; } - if((byte*)d->argp < cinfo.stk || cinfo.base <= (byte*)d->argp) + if(d->argp < cinfo.stk.lo || cinfo.stk.hi <= d->argp) break; // a defer for the next segment fn = d->fn; if(fn == nil) // See issue 8047 continue; f = runtime·findfunc((uintptr)fn->fn); if(f == nil) { - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn); + runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn); return -1; } @@ -519,18 +445,16 @@ copyabletopsegment(G *gp) // C (particularly, cgo) lies to us. See issue 7695. stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); if(stackmap == nil || stackmap->n <= 0) { - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: no arg info for deferred %s\n", runtime·funcname(f)); + runtime·printf("runtime: copystack: no arg info for deferred %s\n", runtime·funcname(f)); return -1; } stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); if(stackmap == nil || stackmap->n <= 0) { - if(StackDebug >= 1 || StackCopyAlways) - runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f)); + runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f)); return -1; } - if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) { + if(cinfo.stk.lo <= (uintptr)fn && (uintptr)fn < cinfo.stk.hi) { // FuncVal is on the stack. Again, its copyableness // was established during stack walking. continue; @@ -548,8 +472,7 @@ copyabletopsegment(G *gp) typedef struct AdjustInfo AdjustInfo; struct AdjustInfo { - byte *oldstk; // bottom address of segment - byte *oldbase; // top address of segment (after Stktop) + Stack old; uintptr delta; // ptr distance from old to new stack (newbase - oldbase) }; @@ -564,8 +487,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) Type *t; Itab *tab; - minp = adjinfo->oldstk; - maxp = adjinfo->oldbase; + minp = (byte*)adjinfo->old.lo; + maxp = (byte*)adjinfo->old.hi; delta = adjinfo->delta; num = bv->n / BitsPerPointer; for(i = 0; i < num; i++) { @@ -693,7 +616,7 @@ adjustframe(Stkframe *frame, void *arg) static void adjustctxt(G *gp, AdjustInfo *adjinfo) { - if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < adjinfo->oldbase) + if(adjinfo->old.lo <= (uintptr)gp->sched.ctxt && (uintptr)gp->sched.ctxt < adjinfo->old.hi) gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta; } @@ -707,7 +630,7 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) BitVector bv; for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { - if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) { + if(adjinfo->old.lo <= (uintptr)d && (uintptr)d < adjinfo->old.hi) { // The Defer record is on the stack. Its fields will // get adjusted appropriately. // This only happens for runtime.main and runtime.gopanic now, @@ -719,8 +642,12 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) *dp = (Defer*)((byte*)d + adjinfo->delta); continue; } - if((byte*)d->argp < adjinfo->oldstk || adjinfo->oldbase <= (byte*)d->argp) - break; // a defer for the next segment + if(d->argp == NoArgs) + continue; + if(d->argp < adjinfo->old.lo || adjinfo->old.hi <= d->argp) { + runtime·printf("runtime: adjustdefers argp=%p stk=%p %p\n", d->argp, adjinfo->old.lo, adjinfo->old.hi); + runtime·throw("adjustdefers: unexpected argp"); + } fn = d->fn; if(fn == nil) { // Defer of nil function. It will panic when run, and there @@ -734,7 +661,7 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) if(StackDebug >= 4) runtime·printf(" checking defer %s\n", runtime·funcname(f)); // Defer's FuncVal might be on the stack - if(adjinfo->oldstk <= (byte*)fn && (byte*)fn < adjinfo->oldbase) { + if(adjinfo->old.lo <= (uintptr)fn && (uintptr)fn < adjinfo->old.hi) { if(StackDebug >= 3) runtime·printf(" adjust defer fn %s\n", runtime·funcname(f)); d->fn = (FuncVal*)((byte*)fn + adjinfo->delta); @@ -758,7 +685,7 @@ adjustpanics(G *gp, AdjustInfo *adjinfo) // Panic structs are all on the stack // and are adjusted by stack copying. // The only pointer we need to update is gp->panic, the head of the list. - if(adjinfo->oldstk <= (byte*)gp->panic && (byte*)gp->panic < adjinfo->oldbase) + if(adjinfo->old.lo <= (uintptr)gp->panic && (uintptr)gp->panic < adjinfo->old.hi) gp->panic = (Panic*)((byte*)gp->panic + adjinfo->delta); } @@ -772,10 +699,10 @@ adjustsudogs(G *gp, AdjustInfo *adjinfo) // might be in the stack. for(s = gp->waiting; s != nil; s = s->waitlink) { e = s->elem; - if(adjinfo->oldstk <= e && e < adjinfo->oldbase) + if(adjinfo->old.lo <= (uintptr)e && (uintptr)e < adjinfo->old.hi) s->elem = e + adjinfo->delta; e = (byte*)s->selectdone; - if(adjinfo->oldstk <= e && e < adjinfo->oldbase) + if(adjinfo->old.lo <= (uintptr)e && (uintptr)e < adjinfo->old.hi) s->selectdone = (uint32*)(e + adjinfo->delta); } } @@ -785,36 +712,28 @@ adjustsudogs(G *gp, AdjustInfo *adjinfo) static void copystack(G *gp, uintptr nframes, uintptr newsize) { - byte *oldstk, *oldbase, *newstk, *newbase; - uintptr oldsize, used; + Stack old, new; + uintptr used; AdjustInfo adjinfo; - Stktop *oldtop, *newtop; uint32 oldstatus; bool (*cb)(Stkframe*, void*); - if(gp->syscallstack != 0) - runtime·throw("can't handle stack copy in syscall yet"); - oldstk = (byte*)gp->stackguard - StackGuard; - if(gp->stackbase == 0) + if(gp->syscallsp != 0) + runtime·throw("stack growth not allowed in system call"); + old = gp->stack; + if(old.lo == 0) runtime·throw("nil stackbase"); - oldbase = (byte*)gp->stackbase + sizeof(Stktop); - oldsize = oldbase - oldstk; - used = oldbase - (byte*)gp->sched.sp; - oldtop = (Stktop*)gp->stackbase; + used = old.hi - gp->sched.sp; // allocate new stack - newstk = runtime·stackalloc(gp, newsize); - newbase = newstk + newsize; - newtop = (Stktop*)(newbase - sizeof(Stktop)); + new = runtime·stackalloc(newsize); if(StackDebug >= 1) - runtime·printf("copystack gp=%p [%p %p]/%d -> [%p %p]/%d\n", gp, oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize); - USED(oldsize); + runtime·printf("copystack gp=%p [%p %p %p]/%d -> [%p %p %p]/%d\n", gp, old.lo, old.hi-used, old.hi, (int32)(old.hi-old.lo), new.lo, new.hi-used, new.hi, (int32)newsize); // adjust pointers in the to-be-copied frames - adjinfo.oldstk = oldstk; - adjinfo.oldbase = oldbase; - adjinfo.delta = newbase - oldbase; + adjinfo.old = old; + adjinfo.delta = new.hi - old.hi; cb = adjustframe; runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, &cb, &adjinfo, false); @@ -824,26 +743,25 @@ copystack(G *gp, uintptr nframes, uintptr newsize) adjustpanics(gp, &adjinfo); adjustsudogs(gp, &adjinfo); - // copy the stack (including Stktop) to the new location - runtime·memmove(newbase - used, oldbase - used, used); + // copy the stack to the new location + runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used); + oldstatus = runtime·readgstatus(gp); oldstatus &= ~Gscan; - if (oldstatus == Gwaiting || oldstatus == Grunnable) + if(oldstatus == Gwaiting || oldstatus == Grunnable) runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is Gwaiting or Grunnable else runtime·throw("copystack: bad status, not Gwaiting or Grunnable"); + // Swap out old stack for new one - gp->stackbase = (uintptr)newtop; - gp->stackguard = (uintptr)newstk + StackGuard; - gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a preempt request - if(gp->stack0 == (uintptr)oldstk) - gp->stack0 = (uintptr)newstk; - gp->sched.sp = (uintptr)(newbase - used); + gp->stack = new; + gp->stackguard0 = new.lo + StackGuard; // NOTE: might clobber a preempt request + gp->sched.sp = new.hi - used; runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable // free old stack - runtime·stackfree(gp, oldstk, oldtop); + runtime·stackfree(old); } // round x up to a power of 2. @@ -858,27 +776,22 @@ runtime·round2(int32 x) return 1 << s; } -// Called from runtime·morestack when a new stack segment is needed. -// Allocate a new stack big enough for m->moreframesize bytes, -// copy m->moreargsize bytes to the new frame, -// and then act as though runtime·lessstack called the function at m->morepc. +// Called from runtime·morestack when more stack is needed. +// Allocate larger stack and relocate to new stack. +// Stack growth is multiplicative, for constant amortized cost. // -// g->atomicstatus will be Grunning, Gsyscall or Gscanrunning, Gscansyscall upon entry. +// g->atomicstatus will be Grunning or Gscanrunning upon entry. // If the GC is trying to stop this g then it will set preemptscan to true. void runtime·newstack(void) { - int32 framesize, argsize, oldstatus, oldsize, newsize, nframes; - Stktop *top; - byte *stk, *oldstk, *oldbase; + int32 oldsize, newsize, nframes; uintptr sp; - uintptr *src, *dst, *dstend; G *gp; - Gobuf label, morebuf; - void *moreargp; + Gobuf morebuf; - if(g->m->forkstackguard) - runtime·throw("split stack after fork"); + if(g->m->morebuf.g->stackguard0 == (uintptr)StackFork) + runtime·throw("stack growth after fork"); if(g->m->morebuf.g != g->m->curg) { runtime·printf("runtime: newstack called from g=%p\n" "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n", @@ -890,64 +803,50 @@ runtime·newstack(void) if(g->throwsplit) runtime·throw("runtime: stack split at bad time"); - // The goroutine must be executing in order to call newstack, so the possible states are - // Grunning and Gsyscall (and, due to GC, also Gscanrunning and Gscansyscall). + // The goroutine must be executing in order to call newstack, + // so it must be Grunning or Gscanrunning. - // gp->status is usually Grunning, but it could be Gsyscall if a stack overflow - // happens during a function call inside entersyscall. gp = g->m->curg; - oldstatus = runtime·readgstatus(gp) & ~Gscan; - framesize = g->m->moreframesize; - argsize = g->m->moreargsize; - moreargp = g->m->moreargp; - g->m->moreargp = nil; morebuf = g->m->morebuf; g->m->morebuf.pc = (uintptr)nil; g->m->morebuf.lr = (uintptr)nil; g->m->morebuf.sp = (uintptr)nil; - runtime·casgstatus(gp, oldstatus, Gwaiting); // oldstatus is not in a Gscan status + runtime·casgstatus(gp, Grunning, Gwaiting); gp->waitreason = runtime·gostringnocopy((byte*)"stack growth"); runtime·rewindmorestack(&gp->sched); - if(gp->stackbase == 0) - runtime·throw("nil stackbase"); + if(gp->stack.lo == 0) + runtime·throw("missing stack in newstack"); sp = gp->sched.sp; if(thechar == '6' || thechar == '8') { // The call to morestack cost a word. sp -= sizeof(uintreg); } - if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) { - runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n" + if(StackDebug >= 1 || sp < gp->stack.lo) { + runtime·printf("runtime: newstack sp=%p stack=[%p, %p]\n" "\tmorebuf={pc:%p sp:%p lr:%p}\n" "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n", - (uintptr)framesize, (uintptr)argsize, sp, gp->stackguard - StackGuard, gp->stackbase, + sp, gp->stack.lo, gp->stack.hi, g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr, gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt); } - if(sp < gp->stackguard - StackGuard) { - runtime·printf("runtime: gp=%p, gp->status=%d, oldstatus=%d\n ", (void*)gp, runtime·readgstatus(gp), oldstatus); - runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stackguard - StackGuard); + if(sp < gp->stack.lo) { + runtime·printf("runtime: gp=%p, gp->status=%d\n ", (void*)gp, runtime·readgstatus(gp)); + runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stack.lo); runtime·throw("runtime: split stack overflow"); } - if(argsize % sizeof(uintptr) != 0) { - runtime·printf("runtime: stack growth with misaligned argsize %d\n", argsize); - runtime·throw("runtime: stack growth argsize"); - } - if(gp->stackguard0 == (uintptr)StackPreempt) { if(gp == g->m->g0) runtime·throw("runtime: preempt g0"); - if(oldstatus == Grunning && g->m->p == nil && g->m->locks == 0) + if(g->m->p == nil && g->m->locks == 0) runtime·throw("runtime: g is running but p is not"); - if(oldstatus == Gsyscall && g->m->locks == 0) - runtime·throw("runtime: stack growth during syscall"); - if(oldstatus == Grunning && gp->preemptscan) { + if(gp->preemptscan) { runtime·gcphasework(gp); runtime·casgstatus(gp, Gwaiting, Grunning); - gp->stackguard0 = gp->stackguard; + gp->stackguard0 = gp->stack.lo + StackGuard; gp->preempt = false; gp->preemptscan = false; // Tells the GC premption was successful. runtime·gogo(&gp->sched); // never return @@ -955,105 +854,37 @@ runtime·newstack(void) // Be conservative about where we preempt. // We are interested in preempting user Go code, not runtime code. - if(oldstatus != Grunning || g->m->locks || g->m->mallocing || g->m->gcing || g->m->p->status != Prunning) { + if(g->m->locks || g->m->mallocing || g->m->gcing || g->m->p->status != Prunning) { // Let the goroutine keep running for now. // gp->preempt is set, so it will be preempted next time. - gp->stackguard0 = gp->stackguard; - runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Gsyscall or Grunning + gp->stackguard0 = gp->stack.lo + StackGuard; + runtime·casgstatus(gp, Gwaiting, Grunning); runtime·gogo(&gp->sched); // never return } // Act like goroutine called runtime.Gosched. - runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Gsyscall or Grunning + runtime·casgstatus(gp, Gwaiting, Grunning); runtime·gosched_m(gp); // never return } - // If every frame on the top segment is copyable, allocate a bigger segment - // and move the segment instead of allocating a new segment. - if(runtime·copystack) { - if(!runtime·precisestack) - runtime·throw("can't copy stacks without precise stacks"); - nframes = copyabletopsegment(gp); - if(nframes != -1) { - oldstk = (byte*)gp->stackguard - StackGuard; - oldbase = (byte*)gp->stackbase + sizeof(Stktop); - oldsize = oldbase - oldstk; - newsize = oldsize * 2; - // Note that the concurrent GC might be scanning the stack as we try to replace it. - // copystack takes care of the appropriate coordination with the stack scanner. - copystack(gp, nframes, newsize); - if(StackDebug >= 1) - runtime·printf("stack grow done\n"); - if(gp->stacksize > runtime·maxstacksize) { - runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize); - runtime·throw("stack overflow"); - } - runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Gsyscall or Grunning - runtime·gogo(&gp->sched); - } - // TODO: if stack is uncopyable because we're in C code, patch return value at - // end of C code to trigger a copy as soon as C code exits. That way, we'll - // have stack available if we get this deep again. - } + // Allocate a bigger segment and move the stack. + nframes = copyabletopsegment(gp); + if(nframes == -1) + runtime·throw("unable to grow stack"); - if(StackCopyAlways) - runtime·throw("split stack not allowed"); - - // allocate new segment. - framesize += argsize; - framesize += StackExtra; // room for more functions, Stktop. - if(framesize < StackMin) - framesize = StackMin; - framesize += StackSystem; - framesize = runtime·round2(framesize); - stk = runtime·stackalloc(gp, framesize); - if(gp->stacksize > runtime·maxstacksize) { + oldsize = gp->stack.hi - gp->stack.lo; + newsize = oldsize * 2; + if(newsize > runtime·maxstacksize) { runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize); runtime·throw("stack overflow"); } - top = (Stktop*)(stk+framesize-sizeof(*top)); - if(StackDebug >= 1) { - runtime·printf("\t-> new stack gp=%p [%p, %p]\n", gp, stk, top); - } - - top->stackbase = gp->stackbase; - top->stackguard = gp->stackguard; - top->gobuf = morebuf; - top->argp = moreargp; - top->argsize = argsize; - - gp->stackbase = (uintptr)top; - gp->stackguard = (uintptr)stk + StackGuard; - gp->stackguard0 = gp->stackguard; - - sp = (uintptr)top; - if(argsize > 0) { - sp -= argsize; - dst = (uintptr*)sp; - dstend = dst + argsize/sizeof(*dst); - src = (uintptr*)top->argp; - while(dst < dstend) - *dst++ = *src++; - } - - if(thechar == '5') { - // caller would have saved its LR below args. - sp -= sizeof(void*); - *(void**)sp = nil; - } - - // Continue as if lessstack had just called m->morepc - // (the PC that decided to grow the stack). - runtime·memclr((byte*)&label, sizeof label); - label.sp = sp; - label.pc = (uintptr)runtime·lessstack; - label.g = g->m->curg; - runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt); - gp->sched.ctxt = nil; - runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Grunning or Gsyscall - runtime·gogo(&label); - - *(int32*)345 = 123; // never return + // Note that the concurrent GC might be scanning the stack as we try to replace it. + // copystack takes care of the appropriate coordination with the stack scanner. + copystack(gp, nframes, newsize); + if(StackDebug >= 1) + runtime·printf("stack grow done\n"); + runtime·casgstatus(gp, Gwaiting, Grunning); + runtime·gogo(&gp->sched); } #pragma textflag NOSPLIT @@ -1083,28 +914,24 @@ void runtime·shrinkstack(G *gp) { int32 nframes; - byte *oldstk, *oldbase; uintptr used, oldsize, newsize; - if(!runtime·copystack) - return; if(runtime·readgstatus(gp) == Gdead) return; - if(gp->stackbase == 0) - runtime·throw("stackbase == 0"); + if(gp->stack.lo == 0) + runtime·throw("missing stack in shrinkstack"); //return; // TODO: why does this happen? - oldstk = (byte*)gp->stackguard - StackGuard; - oldbase = (byte*)gp->stackbase + sizeof(Stktop); - oldsize = oldbase - oldstk; + oldsize = gp->stack.hi - gp->stack.lo; newsize = oldsize / 2; if(newsize < FixedStack) return; // don't shrink below the minimum-sized stack - used = oldbase - (byte*)gp->sched.sp; + used = gp->stack.hi - gp->sched.sp; if(used >= oldsize / 4) return; // still using at least 1/4 of the segment. - if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case? + if(gp->syscallsp != 0) // TODO: can we handle this case? return; + #ifdef GOOS_windows if(gp->m != nil && gp->m->libcallsp != 0) return; diff --git a/src/runtime/stack.h b/src/runtime/stack.h index 7f8c43ee54..b30e322166 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -99,11 +99,6 @@ enum { // The maximum number of bytes that a chain of NOSPLIT // functions can use. StackLimit = StackGuard - StackSystem - StackSmall, - - // The assumed size of the top-of-stack data block. - // The actual size can be smaller than this but cannot be larger. - // Checked in proc.c's runtime.malg. - StackTop = 88, }; // Goroutine preemption request. @@ -117,3 +112,4 @@ enum StackPreempt = -1314, }; */ +#define StackFork ((uint64)-1234) diff --git a/src/runtime/stack_gen_test.go b/src/runtime/stack_gen_test.go deleted file mode 100644 index 28101062cc..0000000000 --- a/src/runtime/stack_gen_test.go +++ /dev/null @@ -1,1473 +0,0 @@ -// 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 runtime_test - -import ( - . "runtime" -) - -var splitTests = []func() (uintptr, uintptr){ - // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt - stack4, stack8, stack12, stack16, stack20, stack24, stack28, - stack32, stack36, stack40, stack44, stack48, stack52, stack56, - stack60, stack64, stack68, stack72, stack76, stack80, stack84, - stack88, stack92, stack96, stack100, stack104, stack108, stack112, - stack116, stack120, stack124, stack128, stack132, stack136, - stack140, stack144, stack148, stack152, stack156, stack160, - stack164, stack168, stack172, stack176, stack180, stack184, - stack188, stack192, stack196, stack200, stack204, stack208, - stack212, stack216, stack220, stack224, stack228, stack232, - stack236, stack240, stack244, stack248, stack252, stack256, - stack260, stack264, stack268, stack272, stack276, stack280, - stack284, stack288, stack292, stack296, stack300, stack304, - stack308, stack312, stack316, stack320, stack324, stack328, - stack332, stack336, stack340, stack344, stack348, stack352, - stack356, stack360, stack364, stack368, stack372, stack376, - stack380, stack384, stack388, stack392, stack396, stack400, - stack404, stack408, stack412, stack416, stack420, stack424, - stack428, stack432, stack436, stack440, stack444, stack448, - stack452, stack456, stack460, stack464, stack468, stack472, - stack476, stack480, stack484, stack488, stack492, stack496, - stack500, stack504, stack508, stack512, stack516, stack520, - stack524, stack528, stack532, stack536, stack540, stack544, - stack548, stack552, stack556, stack560, stack564, stack568, - stack572, stack576, stack580, stack584, stack588, stack592, - stack596, stack600, stack604, stack608, stack612, stack616, - stack620, stack624, stack628, stack632, stack636, stack640, - stack644, stack648, stack652, stack656, stack660, stack664, - stack668, stack672, stack676, stack680, stack684, stack688, - stack692, stack696, stack700, stack704, stack708, stack712, - stack716, stack720, stack724, stack728, stack732, stack736, - stack740, stack744, stack748, stack752, stack756, stack760, - stack764, stack768, stack772, stack776, stack780, stack784, - stack788, stack792, stack796, stack800, stack804, stack808, - stack812, stack816, stack820, stack824, stack828, stack832, - stack836, stack840, stack844, stack848, stack852, stack856, - stack860, stack864, stack868, stack872, stack876, stack880, - stack884, stack888, stack892, stack896, stack900, stack904, - stack908, stack912, stack916, stack920, stack924, stack928, - stack932, stack936, stack940, stack944, stack948, stack952, - stack956, stack960, stack964, stack968, stack972, stack976, - stack980, stack984, stack988, stack992, stack996, stack1000, - stack1004, stack1008, stack1012, stack1016, stack1020, stack1024, - stack1028, stack1032, stack1036, stack1040, stack1044, stack1048, - stack1052, stack1056, stack1060, stack1064, stack1068, stack1072, - stack1076, stack1080, stack1084, stack1088, stack1092, stack1096, - stack1100, stack1104, stack1108, stack1112, stack1116, stack1120, - stack1124, stack1128, stack1132, stack1136, stack1140, stack1144, - stack1148, stack1152, stack1156, stack1160, stack1164, stack1168, - stack1172, stack1176, stack1180, stack1184, stack1188, stack1192, - stack1196, stack1200, stack1204, stack1208, stack1212, stack1216, - stack1220, stack1224, stack1228, stack1232, stack1236, stack1240, - stack1244, stack1248, stack1252, stack1256, stack1260, stack1264, - stack1268, stack1272, stack1276, stack1280, stack1284, stack1288, - stack1292, stack1296, stack1300, stack1304, stack1308, stack1312, - stack1316, stack1320, stack1324, stack1328, stack1332, stack1336, - stack1340, stack1344, stack1348, stack1352, stack1356, stack1360, - stack1364, stack1368, stack1372, stack1376, stack1380, stack1384, - stack1388, stack1392, stack1396, stack1400, stack1404, stack1408, - stack1412, stack1416, stack1420, stack1424, stack1428, stack1432, - stack1436, stack1440, stack1444, stack1448, stack1452, stack1456, - stack1460, stack1464, stack1468, stack1472, stack1476, stack1480, - stack1484, stack1488, stack1492, stack1496, stack1500, stack1504, - stack1508, stack1512, stack1516, stack1520, stack1524, stack1528, - stack1532, stack1536, stack1540, stack1544, stack1548, stack1552, - stack1556, stack1560, stack1564, stack1568, stack1572, stack1576, - stack1580, stack1584, stack1588, stack1592, stack1596, stack1600, - stack1604, stack1608, stack1612, stack1616, stack1620, stack1624, - stack1628, stack1632, stack1636, stack1640, stack1644, stack1648, - stack1652, stack1656, stack1660, stack1664, stack1668, stack1672, - stack1676, stack1680, stack1684, stack1688, stack1692, stack1696, - stack1700, stack1704, stack1708, stack1712, stack1716, stack1720, - stack1724, stack1728, stack1732, stack1736, stack1740, stack1744, - stack1748, stack1752, stack1756, stack1760, stack1764, stack1768, - stack1772, stack1776, stack1780, stack1784, stack1788, stack1792, - stack1796, stack1800, stack1804, stack1808, stack1812, stack1816, - stack1820, stack1824, stack1828, stack1832, stack1836, stack1840, - stack1844, stack1848, stack1852, stack1856, stack1860, stack1864, - stack1868, stack1872, stack1876, stack1880, stack1884, stack1888, - stack1892, stack1896, stack1900, stack1904, stack1908, stack1912, - stack1916, stack1920, stack1924, stack1928, stack1932, stack1936, - stack1940, stack1944, stack1948, stack1952, stack1956, stack1960, - stack1964, stack1968, stack1972, stack1976, stack1980, stack1984, - stack1988, stack1992, stack1996, stack2000, stack2004, stack2008, - stack2012, stack2016, stack2020, stack2024, stack2028, stack2032, - stack2036, stack2040, stack2044, stack2048, stack2052, stack2056, - stack2060, stack2064, stack2068, stack2072, stack2076, stack2080, - stack2084, stack2088, stack2092, stack2096, stack2100, stack2104, - stack2108, stack2112, stack2116, stack2120, stack2124, stack2128, - stack2132, stack2136, stack2140, stack2144, stack2148, stack2152, - stack2156, stack2160, stack2164, stack2168, stack2172, stack2176, - stack2180, stack2184, stack2188, stack2192, stack2196, stack2200, - stack2204, stack2208, stack2212, stack2216, stack2220, stack2224, - stack2228, stack2232, stack2236, stack2240, stack2244, stack2248, - stack2252, stack2256, stack2260, stack2264, stack2268, stack2272, - stack2276, stack2280, stack2284, stack2288, stack2292, stack2296, - stack2300, stack2304, stack2308, stack2312, stack2316, stack2320, - stack2324, stack2328, stack2332, stack2336, stack2340, stack2344, - stack2348, stack2352, stack2356, stack2360, stack2364, stack2368, - stack2372, stack2376, stack2380, stack2384, stack2388, stack2392, - stack2396, stack2400, stack2404, stack2408, stack2412, stack2416, - stack2420, stack2424, stack2428, stack2432, stack2436, stack2440, - stack2444, stack2448, stack2452, stack2456, stack2460, stack2464, - stack2468, stack2472, stack2476, stack2480, stack2484, stack2488, - stack2492, stack2496, stack2500, stack2504, stack2508, stack2512, - stack2516, stack2520, stack2524, stack2528, stack2532, stack2536, - stack2540, stack2544, stack2548, stack2552, stack2556, stack2560, - stack2564, stack2568, stack2572, stack2576, stack2580, stack2584, - stack2588, stack2592, stack2596, stack2600, stack2604, stack2608, - stack2612, stack2616, stack2620, stack2624, stack2628, stack2632, - stack2636, stack2640, stack2644, stack2648, stack2652, stack2656, - stack2660, stack2664, stack2668, stack2672, stack2676, stack2680, - stack2684, stack2688, stack2692, stack2696, stack2700, stack2704, - stack2708, stack2712, stack2716, stack2720, stack2724, stack2728, - stack2732, stack2736, stack2740, stack2744, stack2748, stack2752, - stack2756, stack2760, stack2764, stack2768, stack2772, stack2776, - stack2780, stack2784, stack2788, stack2792, stack2796, stack2800, - stack2804, stack2808, stack2812, stack2816, stack2820, stack2824, - stack2828, stack2832, stack2836, stack2840, stack2844, stack2848, - stack2852, stack2856, stack2860, stack2864, stack2868, stack2872, - stack2876, stack2880, stack2884, stack2888, stack2892, stack2896, - stack2900, stack2904, stack2908, stack2912, stack2916, stack2920, - stack2924, stack2928, stack2932, stack2936, stack2940, stack2944, - stack2948, stack2952, stack2956, stack2960, stack2964, stack2968, - stack2972, stack2976, stack2980, stack2984, stack2988, stack2992, - stack2996, stack3000, stack3004, stack3008, stack3012, stack3016, - stack3020, stack3024, stack3028, stack3032, stack3036, stack3040, - stack3044, stack3048, stack3052, stack3056, stack3060, stack3064, - stack3068, stack3072, stack3076, stack3080, stack3084, stack3088, - stack3092, stack3096, stack3100, stack3104, stack3108, stack3112, - stack3116, stack3120, stack3124, stack3128, stack3132, stack3136, - stack3140, stack3144, stack3148, stack3152, stack3156, stack3160, - stack3164, stack3168, stack3172, stack3176, stack3180, stack3184, - stack3188, stack3192, stack3196, stack3200, stack3204, stack3208, - stack3212, stack3216, stack3220, stack3224, stack3228, stack3232, - stack3236, stack3240, stack3244, stack3248, stack3252, stack3256, - stack3260, stack3264, stack3268, stack3272, stack3276, stack3280, - stack3284, stack3288, stack3292, stack3296, stack3300, stack3304, - stack3308, stack3312, stack3316, stack3320, stack3324, stack3328, - stack3332, stack3336, stack3340, stack3344, stack3348, stack3352, - stack3356, stack3360, stack3364, stack3368, stack3372, stack3376, - stack3380, stack3384, stack3388, stack3392, stack3396, stack3400, - stack3404, stack3408, stack3412, stack3416, stack3420, stack3424, - stack3428, stack3432, stack3436, stack3440, stack3444, stack3448, - stack3452, stack3456, stack3460, stack3464, stack3468, stack3472, - stack3476, stack3480, stack3484, stack3488, stack3492, stack3496, - stack3500, stack3504, stack3508, stack3512, stack3516, stack3520, - stack3524, stack3528, stack3532, stack3536, stack3540, stack3544, - stack3548, stack3552, stack3556, stack3560, stack3564, stack3568, - stack3572, stack3576, stack3580, stack3584, stack3588, stack3592, - stack3596, stack3600, stack3604, stack3608, stack3612, stack3616, - stack3620, stack3624, stack3628, stack3632, stack3636, stack3640, - stack3644, stack3648, stack3652, stack3656, stack3660, stack3664, - stack3668, stack3672, stack3676, stack3680, stack3684, stack3688, - stack3692, stack3696, stack3700, stack3704, stack3708, stack3712, - stack3716, stack3720, stack3724, stack3728, stack3732, stack3736, - stack3740, stack3744, stack3748, stack3752, stack3756, stack3760, - stack3764, stack3768, stack3772, stack3776, stack3780, stack3784, - stack3788, stack3792, stack3796, stack3800, stack3804, stack3808, - stack3812, stack3816, stack3820, stack3824, stack3828, stack3832, - stack3836, stack3840, stack3844, stack3848, stack3852, stack3856, - stack3860, stack3864, stack3868, stack3872, stack3876, stack3880, - stack3884, stack3888, stack3892, stack3896, stack3900, stack3904, - stack3908, stack3912, stack3916, stack3920, stack3924, stack3928, - stack3932, stack3936, stack3940, stack3944, stack3948, stack3952, - stack3956, stack3960, stack3964, stack3968, stack3972, stack3976, - stack3980, stack3984, stack3988, stack3992, stack3996, stack4000, - stack4004, stack4008, stack4012, stack4016, stack4020, stack4024, - stack4028, stack4032, stack4036, stack4040, stack4044, stack4048, - stack4052, stack4056, stack4060, stack4064, stack4068, stack4072, - stack4076, stack4080, stack4084, stack4088, stack4092, stack4096, - stack4100, stack4104, stack4108, stack4112, stack4116, stack4120, - stack4124, stack4128, stack4132, stack4136, stack4140, stack4144, - stack4148, stack4152, stack4156, stack4160, stack4164, stack4168, - stack4172, stack4176, stack4180, stack4184, stack4188, stack4192, - stack4196, stack4200, stack4204, stack4208, stack4212, stack4216, - stack4220, stack4224, stack4228, stack4232, stack4236, stack4240, - stack4244, stack4248, stack4252, stack4256, stack4260, stack4264, - stack4268, stack4272, stack4276, stack4280, stack4284, stack4288, - stack4292, stack4296, stack4300, stack4304, stack4308, stack4312, - stack4316, stack4320, stack4324, stack4328, stack4332, stack4336, - stack4340, stack4344, stack4348, stack4352, stack4356, stack4360, - stack4364, stack4368, stack4372, stack4376, stack4380, stack4384, - stack4388, stack4392, stack4396, stack4400, stack4404, stack4408, - stack4412, stack4416, stack4420, stack4424, stack4428, stack4432, - stack4436, stack4440, stack4444, stack4448, stack4452, stack4456, - stack4460, stack4464, stack4468, stack4472, stack4476, stack4480, - stack4484, stack4488, stack4492, stack4496, stack4500, stack4504, - stack4508, stack4512, stack4516, stack4520, stack4524, stack4528, - stack4532, stack4536, stack4540, stack4544, stack4548, stack4552, - stack4556, stack4560, stack4564, stack4568, stack4572, stack4576, - stack4580, stack4584, stack4588, stack4592, stack4596, stack4600, - stack4604, stack4608, stack4612, stack4616, stack4620, stack4624, - stack4628, stack4632, stack4636, stack4640, stack4644, stack4648, - stack4652, stack4656, stack4660, stack4664, stack4668, stack4672, - stack4676, stack4680, stack4684, stack4688, stack4692, stack4696, - stack4700, stack4704, stack4708, stack4712, stack4716, stack4720, - stack4724, stack4728, stack4732, stack4736, stack4740, stack4744, - stack4748, stack4752, stack4756, stack4760, stack4764, stack4768, - stack4772, stack4776, stack4780, stack4784, stack4788, stack4792, - stack4796, stack4800, stack4804, stack4808, stack4812, stack4816, - stack4820, stack4824, stack4828, stack4832, stack4836, stack4840, - stack4844, stack4848, stack4852, stack4856, stack4860, stack4864, - stack4868, stack4872, stack4876, stack4880, stack4884, stack4888, - stack4892, stack4896, stack4900, stack4904, stack4908, stack4912, - stack4916, stack4920, stack4924, stack4928, stack4932, stack4936, - stack4940, stack4944, stack4948, stack4952, stack4956, stack4960, - stack4964, stack4968, stack4972, stack4976, stack4980, stack4984, - stack4988, stack4992, stack4996, stack5000, -} - -// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/' -func stack4() (uintptr, uintptr) { var buf [4]byte; use(buf[:]); return Stackguard() } -func stack8() (uintptr, uintptr) { var buf [8]byte; use(buf[:]); return Stackguard() } -func stack12() (uintptr, uintptr) { var buf [12]byte; use(buf[:]); return Stackguard() } -func stack16() (uintptr, uintptr) { var buf [16]byte; use(buf[:]); return Stackguard() } -func stack20() (uintptr, uintptr) { var buf [20]byte; use(buf[:]); return Stackguard() } -func stack24() (uintptr, uintptr) { var buf [24]byte; use(buf[:]); return Stackguard() } -func stack28() (uintptr, uintptr) { var buf [28]byte; use(buf[:]); return Stackguard() } -func stack32() (uintptr, uintptr) { var buf [32]byte; use(buf[:]); return Stackguard() } -func stack36() (uintptr, uintptr) { var buf [36]byte; use(buf[:]); return Stackguard() } -func stack40() (uintptr, uintptr) { var buf [40]byte; use(buf[:]); return Stackguard() } -func stack44() (uintptr, uintptr) { var buf [44]byte; use(buf[:]); return Stackguard() } -func stack48() (uintptr, uintptr) { var buf [48]byte; use(buf[:]); return Stackguard() } -func stack52() (uintptr, uintptr) { var buf [52]byte; use(buf[:]); return Stackguard() } -func stack56() (uintptr, uintptr) { var buf [56]byte; use(buf[:]); return Stackguard() } -func stack60() (uintptr, uintptr) { var buf [60]byte; use(buf[:]); return Stackguard() } -func stack64() (uintptr, uintptr) { var buf [64]byte; use(buf[:]); return Stackguard() } -func stack68() (uintptr, uintptr) { var buf [68]byte; use(buf[:]); return Stackguard() } -func stack72() (uintptr, uintptr) { var buf [72]byte; use(buf[:]); return Stackguard() } -func stack76() (uintptr, uintptr) { var buf [76]byte; use(buf[:]); return Stackguard() } -func stack80() (uintptr, uintptr) { var buf [80]byte; use(buf[:]); return Stackguard() } -func stack84() (uintptr, uintptr) { var buf [84]byte; use(buf[:]); return Stackguard() } -func stack88() (uintptr, uintptr) { var buf [88]byte; use(buf[:]); return Stackguard() } -func stack92() (uintptr, uintptr) { var buf [92]byte; use(buf[:]); return Stackguard() } -func stack96() (uintptr, uintptr) { var buf [96]byte; use(buf[:]); return Stackguard() } -func stack100() (uintptr, uintptr) { var buf [100]byte; use(buf[:]); return Stackguard() } -func stack104() (uintptr, uintptr) { var buf [104]byte; use(buf[:]); return Stackguard() } -func stack108() (uintptr, uintptr) { var buf [108]byte; use(buf[:]); return Stackguard() } -func stack112() (uintptr, uintptr) { var buf [112]byte; use(buf[:]); return Stackguard() } -func stack116() (uintptr, uintptr) { var buf [116]byte; use(buf[:]); return Stackguard() } -func stack120() (uintptr, uintptr) { var buf [120]byte; use(buf[:]); return Stackguard() } -func stack124() (uintptr, uintptr) { var buf [124]byte; use(buf[:]); return Stackguard() } -func stack128() (uintptr, uintptr) { var buf [128]byte; use(buf[:]); return Stackguard() } -func stack132() (uintptr, uintptr) { var buf [132]byte; use(buf[:]); return Stackguard() } -func stack136() (uintptr, uintptr) { var buf [136]byte; use(buf[:]); return Stackguard() } -func stack140() (uintptr, uintptr) { var buf [140]byte; use(buf[:]); return Stackguard() } -func stack144() (uintptr, uintptr) { var buf [144]byte; use(buf[:]); return Stackguard() } -func stack148() (uintptr, uintptr) { var buf [148]byte; use(buf[:]); return Stackguard() } -func stack152() (uintptr, uintptr) { var buf [152]byte; use(buf[:]); return Stackguard() } -func stack156() (uintptr, uintptr) { var buf [156]byte; use(buf[:]); return Stackguard() } -func stack160() (uintptr, uintptr) { var buf [160]byte; use(buf[:]); return Stackguard() } -func stack164() (uintptr, uintptr) { var buf [164]byte; use(buf[:]); return Stackguard() } -func stack168() (uintptr, uintptr) { var buf [168]byte; use(buf[:]); return Stackguard() } -func stack172() (uintptr, uintptr) { var buf [172]byte; use(buf[:]); return Stackguard() } -func stack176() (uintptr, uintptr) { var buf [176]byte; use(buf[:]); return Stackguard() } -func stack180() (uintptr, uintptr) { var buf [180]byte; use(buf[:]); return Stackguard() } -func stack184() (uintptr, uintptr) { var buf [184]byte; use(buf[:]); return Stackguard() } -func stack188() (uintptr, uintptr) { var buf [188]byte; use(buf[:]); return Stackguard() } -func stack192() (uintptr, uintptr) { var buf [192]byte; use(buf[:]); return Stackguard() } -func stack196() (uintptr, uintptr) { var buf [196]byte; use(buf[:]); return Stackguard() } -func stack200() (uintptr, uintptr) { var buf [200]byte; use(buf[:]); return Stackguard() } -func stack204() (uintptr, uintptr) { var buf [204]byte; use(buf[:]); return Stackguard() } -func stack208() (uintptr, uintptr) { var buf [208]byte; use(buf[:]); return Stackguard() } -func stack212() (uintptr, uintptr) { var buf [212]byte; use(buf[:]); return Stackguard() } -func stack216() (uintptr, uintptr) { var buf [216]byte; use(buf[:]); return Stackguard() } -func stack220() (uintptr, uintptr) { var buf [220]byte; use(buf[:]); return Stackguard() } -func stack224() (uintptr, uintptr) { var buf [224]byte; use(buf[:]); return Stackguard() } -func stack228() (uintptr, uintptr) { var buf [228]byte; use(buf[:]); return Stackguard() } -func stack232() (uintptr, uintptr) { var buf [232]byte; use(buf[:]); return Stackguard() } -func stack236() (uintptr, uintptr) { var buf [236]byte; use(buf[:]); return Stackguard() } -func stack240() (uintptr, uintptr) { var buf [240]byte; use(buf[:]); return Stackguard() } -func stack244() (uintptr, uintptr) { var buf [244]byte; use(buf[:]); return Stackguard() } -func stack248() (uintptr, uintptr) { var buf [248]byte; use(buf[:]); return Stackguard() } -func stack252() (uintptr, uintptr) { var buf [252]byte; use(buf[:]); return Stackguard() } -func stack256() (uintptr, uintptr) { var buf [256]byte; use(buf[:]); return Stackguard() } -func stack260() (uintptr, uintptr) { var buf [260]byte; use(buf[:]); return Stackguard() } -func stack264() (uintptr, uintptr) { var buf [264]byte; use(buf[:]); return Stackguard() } -func stack268() (uintptr, uintptr) { var buf [268]byte; use(buf[:]); return Stackguard() } -func stack272() (uintptr, uintptr) { var buf [272]byte; use(buf[:]); return Stackguard() } -func stack276() (uintptr, uintptr) { var buf [276]byte; use(buf[:]); return Stackguard() } -func stack280() (uintptr, uintptr) { var buf [280]byte; use(buf[:]); return Stackguard() } -func stack284() (uintptr, uintptr) { var buf [284]byte; use(buf[:]); return Stackguard() } -func stack288() (uintptr, uintptr) { var buf [288]byte; use(buf[:]); return Stackguard() } -func stack292() (uintptr, uintptr) { var buf [292]byte; use(buf[:]); return Stackguard() } -func stack296() (uintptr, uintptr) { var buf [296]byte; use(buf[:]); return Stackguard() } -func stack300() (uintptr, uintptr) { var buf [300]byte; use(buf[:]); return Stackguard() } -func stack304() (uintptr, uintptr) { var buf [304]byte; use(buf[:]); return Stackguard() } -func stack308() (uintptr, uintptr) { var buf [308]byte; use(buf[:]); return Stackguard() } -func stack312() (uintptr, uintptr) { var buf [312]byte; use(buf[:]); return Stackguard() } -func stack316() (uintptr, uintptr) { var buf [316]byte; use(buf[:]); return Stackguard() } -func stack320() (uintptr, uintptr) { var buf [320]byte; use(buf[:]); return Stackguard() } -func stack324() (uintptr, uintptr) { var buf [324]byte; use(buf[:]); return Stackguard() } -func stack328() (uintptr, uintptr) { var buf [328]byte; use(buf[:]); return Stackguard() } -func stack332() (uintptr, uintptr) { var buf [332]byte; use(buf[:]); return Stackguard() } -func stack336() (uintptr, uintptr) { var buf [336]byte; use(buf[:]); return Stackguard() } -func stack340() (uintptr, uintptr) { var buf [340]byte; use(buf[:]); return Stackguard() } -func stack344() (uintptr, uintptr) { var buf [344]byte; use(buf[:]); return Stackguard() } -func stack348() (uintptr, uintptr) { var buf [348]byte; use(buf[:]); return Stackguard() } -func stack352() (uintptr, uintptr) { var buf [352]byte; use(buf[:]); return Stackguard() } -func stack356() (uintptr, uintptr) { var buf [356]byte; use(buf[:]); return Stackguard() } -func stack360() (uintptr, uintptr) { var buf [360]byte; use(buf[:]); return Stackguard() } -func stack364() (uintptr, uintptr) { var buf [364]byte; use(buf[:]); return Stackguard() } -func stack368() (uintptr, uintptr) { var buf [368]byte; use(buf[:]); return Stackguard() } -func stack372() (uintptr, uintptr) { var buf [372]byte; use(buf[:]); return Stackguard() } -func stack376() (uintptr, uintptr) { var buf [376]byte; use(buf[:]); return Stackguard() } -func stack380() (uintptr, uintptr) { var buf [380]byte; use(buf[:]); return Stackguard() } -func stack384() (uintptr, uintptr) { var buf [384]byte; use(buf[:]); return Stackguard() } -func stack388() (uintptr, uintptr) { var buf [388]byte; use(buf[:]); return Stackguard() } -func stack392() (uintptr, uintptr) { var buf [392]byte; use(buf[:]); return Stackguard() } -func stack396() (uintptr, uintptr) { var buf [396]byte; use(buf[:]); return Stackguard() } -func stack400() (uintptr, uintptr) { var buf [400]byte; use(buf[:]); return Stackguard() } -func stack404() (uintptr, uintptr) { var buf [404]byte; use(buf[:]); return Stackguard() } -func stack408() (uintptr, uintptr) { var buf [408]byte; use(buf[:]); return Stackguard() } -func stack412() (uintptr, uintptr) { var buf [412]byte; use(buf[:]); return Stackguard() } -func stack416() (uintptr, uintptr) { var buf [416]byte; use(buf[:]); return Stackguard() } -func stack420() (uintptr, uintptr) { var buf [420]byte; use(buf[:]); return Stackguard() } -func stack424() (uintptr, uintptr) { var buf [424]byte; use(buf[:]); return Stackguard() } -func stack428() (uintptr, uintptr) { var buf [428]byte; use(buf[:]); return Stackguard() } -func stack432() (uintptr, uintptr) { var buf [432]byte; use(buf[:]); return Stackguard() } -func stack436() (uintptr, uintptr) { var buf [436]byte; use(buf[:]); return Stackguard() } -func stack440() (uintptr, uintptr) { var buf [440]byte; use(buf[:]); return Stackguard() } -func stack444() (uintptr, uintptr) { var buf [444]byte; use(buf[:]); return Stackguard() } -func stack448() (uintptr, uintptr) { var buf [448]byte; use(buf[:]); return Stackguard() } -func stack452() (uintptr, uintptr) { var buf [452]byte; use(buf[:]); return Stackguard() } -func stack456() (uintptr, uintptr) { var buf [456]byte; use(buf[:]); return Stackguard() } -func stack460() (uintptr, uintptr) { var buf [460]byte; use(buf[:]); return Stackguard() } -func stack464() (uintptr, uintptr) { var buf [464]byte; use(buf[:]); return Stackguard() } -func stack468() (uintptr, uintptr) { var buf [468]byte; use(buf[:]); return Stackguard() } -func stack472() (uintptr, uintptr) { var buf [472]byte; use(buf[:]); return Stackguard() } -func stack476() (uintptr, uintptr) { var buf [476]byte; use(buf[:]); return Stackguard() } -func stack480() (uintptr, uintptr) { var buf [480]byte; use(buf[:]); return Stackguard() } -func stack484() (uintptr, uintptr) { var buf [484]byte; use(buf[:]); return Stackguard() } -func stack488() (uintptr, uintptr) { var buf [488]byte; use(buf[:]); return Stackguard() } -func stack492() (uintptr, uintptr) { var buf [492]byte; use(buf[:]); return Stackguard() } -func stack496() (uintptr, uintptr) { var buf [496]byte; use(buf[:]); return Stackguard() } -func stack500() (uintptr, uintptr) { var buf [500]byte; use(buf[:]); return Stackguard() } -func stack504() (uintptr, uintptr) { var buf [504]byte; use(buf[:]); return Stackguard() } -func stack508() (uintptr, uintptr) { var buf [508]byte; use(buf[:]); return Stackguard() } -func stack512() (uintptr, uintptr) { var buf [512]byte; use(buf[:]); return Stackguard() } -func stack516() (uintptr, uintptr) { var buf [516]byte; use(buf[:]); return Stackguard() } -func stack520() (uintptr, uintptr) { var buf [520]byte; use(buf[:]); return Stackguard() } -func stack524() (uintptr, uintptr) { var buf [524]byte; use(buf[:]); return Stackguard() } -func stack528() (uintptr, uintptr) { var buf [528]byte; use(buf[:]); return Stackguard() } -func stack532() (uintptr, uintptr) { var buf [532]byte; use(buf[:]); return Stackguard() } -func stack536() (uintptr, uintptr) { var buf [536]byte; use(buf[:]); return Stackguard() } -func stack540() (uintptr, uintptr) { var buf [540]byte; use(buf[:]); return Stackguard() } -func stack544() (uintptr, uintptr) { var buf [544]byte; use(buf[:]); return Stackguard() } -func stack548() (uintptr, uintptr) { var buf [548]byte; use(buf[:]); return Stackguard() } -func stack552() (uintptr, uintptr) { var buf [552]byte; use(buf[:]); return Stackguard() } -func stack556() (uintptr, uintptr) { var buf [556]byte; use(buf[:]); return Stackguard() } -func stack560() (uintptr, uintptr) { var buf [560]byte; use(buf[:]); return Stackguard() } -func stack564() (uintptr, uintptr) { var buf [564]byte; use(buf[:]); return Stackguard() } -func stack568() (uintptr, uintptr) { var buf [568]byte; use(buf[:]); return Stackguard() } -func stack572() (uintptr, uintptr) { var buf [572]byte; use(buf[:]); return Stackguard() } -func stack576() (uintptr, uintptr) { var buf [576]byte; use(buf[:]); return Stackguard() } -func stack580() (uintptr, uintptr) { var buf [580]byte; use(buf[:]); return Stackguard() } -func stack584() (uintptr, uintptr) { var buf [584]byte; use(buf[:]); return Stackguard() } -func stack588() (uintptr, uintptr) { var buf [588]byte; use(buf[:]); return Stackguard() } -func stack592() (uintptr, uintptr) { var buf [592]byte; use(buf[:]); return Stackguard() } -func stack596() (uintptr, uintptr) { var buf [596]byte; use(buf[:]); return Stackguard() } -func stack600() (uintptr, uintptr) { var buf [600]byte; use(buf[:]); return Stackguard() } -func stack604() (uintptr, uintptr) { var buf [604]byte; use(buf[:]); return Stackguard() } -func stack608() (uintptr, uintptr) { var buf [608]byte; use(buf[:]); return Stackguard() } -func stack612() (uintptr, uintptr) { var buf [612]byte; use(buf[:]); return Stackguard() } -func stack616() (uintptr, uintptr) { var buf [616]byte; use(buf[:]); return Stackguard() } -func stack620() (uintptr, uintptr) { var buf [620]byte; use(buf[:]); return Stackguard() } -func stack624() (uintptr, uintptr) { var buf [624]byte; use(buf[:]); return Stackguard() } -func stack628() (uintptr, uintptr) { var buf [628]byte; use(buf[:]); return Stackguard() } -func stack632() (uintptr, uintptr) { var buf [632]byte; use(buf[:]); return Stackguard() } -func stack636() (uintptr, uintptr) { var buf [636]byte; use(buf[:]); return Stackguard() } -func stack640() (uintptr, uintptr) { var buf [640]byte; use(buf[:]); return Stackguard() } -func stack644() (uintptr, uintptr) { var buf [644]byte; use(buf[:]); return Stackguard() } -func stack648() (uintptr, uintptr) { var buf [648]byte; use(buf[:]); return Stackguard() } -func stack652() (uintptr, uintptr) { var buf [652]byte; use(buf[:]); return Stackguard() } -func stack656() (uintptr, uintptr) { var buf [656]byte; use(buf[:]); return Stackguard() } -func stack660() (uintptr, uintptr) { var buf [660]byte; use(buf[:]); return Stackguard() } -func stack664() (uintptr, uintptr) { var buf [664]byte; use(buf[:]); return Stackguard() } -func stack668() (uintptr, uintptr) { var buf [668]byte; use(buf[:]); return Stackguard() } -func stack672() (uintptr, uintptr) { var buf [672]byte; use(buf[:]); return Stackguard() } -func stack676() (uintptr, uintptr) { var buf [676]byte; use(buf[:]); return Stackguard() } -func stack680() (uintptr, uintptr) { var buf [680]byte; use(buf[:]); return Stackguard() } -func stack684() (uintptr, uintptr) { var buf [684]byte; use(buf[:]); return Stackguard() } -func stack688() (uintptr, uintptr) { var buf [688]byte; use(buf[:]); return Stackguard() } -func stack692() (uintptr, uintptr) { var buf [692]byte; use(buf[:]); return Stackguard() } -func stack696() (uintptr, uintptr) { var buf [696]byte; use(buf[:]); return Stackguard() } -func stack700() (uintptr, uintptr) { var buf [700]byte; use(buf[:]); return Stackguard() } -func stack704() (uintptr, uintptr) { var buf [704]byte; use(buf[:]); return Stackguard() } -func stack708() (uintptr, uintptr) { var buf [708]byte; use(buf[:]); return Stackguard() } -func stack712() (uintptr, uintptr) { var buf [712]byte; use(buf[:]); return Stackguard() } -func stack716() (uintptr, uintptr) { var buf [716]byte; use(buf[:]); return Stackguard() } -func stack720() (uintptr, uintptr) { var buf [720]byte; use(buf[:]); return Stackguard() } -func stack724() (uintptr, uintptr) { var buf [724]byte; use(buf[:]); return Stackguard() } -func stack728() (uintptr, uintptr) { var buf [728]byte; use(buf[:]); return Stackguard() } -func stack732() (uintptr, uintptr) { var buf [732]byte; use(buf[:]); return Stackguard() } -func stack736() (uintptr, uintptr) { var buf [736]byte; use(buf[:]); return Stackguard() } -func stack740() (uintptr, uintptr) { var buf [740]byte; use(buf[:]); return Stackguard() } -func stack744() (uintptr, uintptr) { var buf [744]byte; use(buf[:]); return Stackguard() } -func stack748() (uintptr, uintptr) { var buf [748]byte; use(buf[:]); return Stackguard() } -func stack752() (uintptr, uintptr) { var buf [752]byte; use(buf[:]); return Stackguard() } -func stack756() (uintptr, uintptr) { var buf [756]byte; use(buf[:]); return Stackguard() } -func stack760() (uintptr, uintptr) { var buf [760]byte; use(buf[:]); return Stackguard() } -func stack764() (uintptr, uintptr) { var buf [764]byte; use(buf[:]); return Stackguard() } -func stack768() (uintptr, uintptr) { var buf [768]byte; use(buf[:]); return Stackguard() } -func stack772() (uintptr, uintptr) { var buf [772]byte; use(buf[:]); return Stackguard() } -func stack776() (uintptr, uintptr) { var buf [776]byte; use(buf[:]); return Stackguard() } -func stack780() (uintptr, uintptr) { var buf [780]byte; use(buf[:]); return Stackguard() } -func stack784() (uintptr, uintptr) { var buf [784]byte; use(buf[:]); return Stackguard() } -func stack788() (uintptr, uintptr) { var buf [788]byte; use(buf[:]); return Stackguard() } -func stack792() (uintptr, uintptr) { var buf [792]byte; use(buf[:]); return Stackguard() } -func stack796() (uintptr, uintptr) { var buf [796]byte; use(buf[:]); return Stackguard() } -func stack800() (uintptr, uintptr) { var buf [800]byte; use(buf[:]); return Stackguard() } -func stack804() (uintptr, uintptr) { var buf [804]byte; use(buf[:]); return Stackguard() } -func stack808() (uintptr, uintptr) { var buf [808]byte; use(buf[:]); return Stackguard() } -func stack812() (uintptr, uintptr) { var buf [812]byte; use(buf[:]); return Stackguard() } -func stack816() (uintptr, uintptr) { var buf [816]byte; use(buf[:]); return Stackguard() } -func stack820() (uintptr, uintptr) { var buf [820]byte; use(buf[:]); return Stackguard() } -func stack824() (uintptr, uintptr) { var buf [824]byte; use(buf[:]); return Stackguard() } -func stack828() (uintptr, uintptr) { var buf [828]byte; use(buf[:]); return Stackguard() } -func stack832() (uintptr, uintptr) { var buf [832]byte; use(buf[:]); return Stackguard() } -func stack836() (uintptr, uintptr) { var buf [836]byte; use(buf[:]); return Stackguard() } -func stack840() (uintptr, uintptr) { var buf [840]byte; use(buf[:]); return Stackguard() } -func stack844() (uintptr, uintptr) { var buf [844]byte; use(buf[:]); return Stackguard() } -func stack848() (uintptr, uintptr) { var buf [848]byte; use(buf[:]); return Stackguard() } -func stack852() (uintptr, uintptr) { var buf [852]byte; use(buf[:]); return Stackguard() } -func stack856() (uintptr, uintptr) { var buf [856]byte; use(buf[:]); return Stackguard() } -func stack860() (uintptr, uintptr) { var buf [860]byte; use(buf[:]); return Stackguard() } -func stack864() (uintptr, uintptr) { var buf [864]byte; use(buf[:]); return Stackguard() } -func stack868() (uintptr, uintptr) { var buf [868]byte; use(buf[:]); return Stackguard() } -func stack872() (uintptr, uintptr) { var buf [872]byte; use(buf[:]); return Stackguard() } -func stack876() (uintptr, uintptr) { var buf [876]byte; use(buf[:]); return Stackguard() } -func stack880() (uintptr, uintptr) { var buf [880]byte; use(buf[:]); return Stackguard() } -func stack884() (uintptr, uintptr) { var buf [884]byte; use(buf[:]); return Stackguard() } -func stack888() (uintptr, uintptr) { var buf [888]byte; use(buf[:]); return Stackguard() } -func stack892() (uintptr, uintptr) { var buf [892]byte; use(buf[:]); return Stackguard() } -func stack896() (uintptr, uintptr) { var buf [896]byte; use(buf[:]); return Stackguard() } -func stack900() (uintptr, uintptr) { var buf [900]byte; use(buf[:]); return Stackguard() } -func stack904() (uintptr, uintptr) { var buf [904]byte; use(buf[:]); return Stackguard() } -func stack908() (uintptr, uintptr) { var buf [908]byte; use(buf[:]); return Stackguard() } -func stack912() (uintptr, uintptr) { var buf [912]byte; use(buf[:]); return Stackguard() } -func stack916() (uintptr, uintptr) { var buf [916]byte; use(buf[:]); return Stackguard() } -func stack920() (uintptr, uintptr) { var buf [920]byte; use(buf[:]); return Stackguard() } -func stack924() (uintptr, uintptr) { var buf [924]byte; use(buf[:]); return Stackguard() } -func stack928() (uintptr, uintptr) { var buf [928]byte; use(buf[:]); return Stackguard() } -func stack932() (uintptr, uintptr) { var buf [932]byte; use(buf[:]); return Stackguard() } -func stack936() (uintptr, uintptr) { var buf [936]byte; use(buf[:]); return Stackguard() } -func stack940() (uintptr, uintptr) { var buf [940]byte; use(buf[:]); return Stackguard() } -func stack944() (uintptr, uintptr) { var buf [944]byte; use(buf[:]); return Stackguard() } -func stack948() (uintptr, uintptr) { var buf [948]byte; use(buf[:]); return Stackguard() } -func stack952() (uintptr, uintptr) { var buf [952]byte; use(buf[:]); return Stackguard() } -func stack956() (uintptr, uintptr) { var buf [956]byte; use(buf[:]); return Stackguard() } -func stack960() (uintptr, uintptr) { var buf [960]byte; use(buf[:]); return Stackguard() } -func stack964() (uintptr, uintptr) { var buf [964]byte; use(buf[:]); return Stackguard() } -func stack968() (uintptr, uintptr) { var buf [968]byte; use(buf[:]); return Stackguard() } -func stack972() (uintptr, uintptr) { var buf [972]byte; use(buf[:]); return Stackguard() } -func stack976() (uintptr, uintptr) { var buf [976]byte; use(buf[:]); return Stackguard() } -func stack980() (uintptr, uintptr) { var buf [980]byte; use(buf[:]); return Stackguard() } -func stack984() (uintptr, uintptr) { var buf [984]byte; use(buf[:]); return Stackguard() } -func stack988() (uintptr, uintptr) { var buf [988]byte; use(buf[:]); return Stackguard() } -func stack992() (uintptr, uintptr) { var buf [992]byte; use(buf[:]); return Stackguard() } -func stack996() (uintptr, uintptr) { var buf [996]byte; use(buf[:]); return Stackguard() } -func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() } -func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() } -func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() } -func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() } -func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() } -func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() } -func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() } -func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() } -func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() } -func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() } -func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() } -func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() } -func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() } -func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() } -func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() } -func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() } -func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() } -func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() } -func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() } -func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() } -func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() } -func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() } -func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() } -func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() } -func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() } -func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() } -func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() } -func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() } -func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() } -func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() } -func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() } -func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() } -func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() } -func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() } -func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() } -func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() } -func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() } -func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() } -func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() } -func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() } -func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() } -func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() } -func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() } -func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() } -func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() } -func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() } -func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() } -func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() } -func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() } -func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() } -func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() } -func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() } -func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() } -func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() } -func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() } -func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() } -func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() } -func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() } -func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() } -func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() } -func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() } -func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() } -func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() } -func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() } -func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() } -func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() } -func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() } -func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() } -func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() } -func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() } -func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() } -func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() } -func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() } -func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() } -func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() } -func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() } -func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() } -func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() } -func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() } -func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() } -func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() } -func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() } -func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() } -func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() } -func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() } -func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() } -func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() } -func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() } -func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() } -func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() } -func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() } -func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() } -func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() } -func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() } -func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() } -func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() } -func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() } -func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() } -func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() } -func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() } -func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() } -func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() } -func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() } -func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() } -func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() } -func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() } -func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() } -func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() } -func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() } -func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() } -func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() } -func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() } -func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() } -func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() } -func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() } -func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() } -func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() } -func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() } -func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() } -func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() } -func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() } -func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() } -func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() } -func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() } -func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() } -func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() } -func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() } -func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() } -func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() } -func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() } -func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() } -func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() } -func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() } -func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() } -func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() } -func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() } -func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() } -func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() } -func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() } -func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() } -func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() } -func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() } -func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() } -func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() } -func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() } -func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() } -func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() } -func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() } -func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() } -func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() } -func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() } -func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() } -func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() } -func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() } -func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() } -func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() } -func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() } -func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() } -func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() } -func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() } -func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() } -func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() } -func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() } -func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() } -func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() } -func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() } -func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() } -func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() } -func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() } -func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() } -func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() } -func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() } -func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() } -func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() } -func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() } -func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() } -func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() } -func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() } -func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() } -func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() } -func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() } -func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() } -func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() } -func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() } -func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() } -func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() } -func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() } -func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() } -func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() } -func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() } -func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() } -func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() } -func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() } -func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() } -func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() } -func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() } -func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() } -func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() } -func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() } -func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() } -func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() } -func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() } -func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() } -func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() } -func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() } -func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() } -func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() } -func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() } -func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() } -func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() } -func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() } -func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() } -func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() } -func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() } -func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() } -func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() } -func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() } -func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() } -func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() } -func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() } -func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() } -func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() } -func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() } -func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() } -func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() } -func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() } -func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() } -func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() } -func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() } -func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() } -func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() } -func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() } -func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() } -func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() } -func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() } -func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() } -func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() } -func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() } -func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() } -func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() } -func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() } -func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() } -func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() } -func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() } -func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() } -func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() } -func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() } -func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() } -func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() } -func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() } -func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() } -func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() } -func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() } -func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() } -func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() } -func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() } -func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() } -func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() } -func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() } -func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() } -func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() } -func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() } -func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() } -func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() } -func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() } -func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() } -func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() } -func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() } -func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() } -func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() } -func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() } -func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() } -func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() } -func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() } -func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() } -func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() } -func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() } -func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() } -func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() } -func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() } -func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() } -func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() } -func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() } -func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() } -func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() } -func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() } -func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() } -func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() } -func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() } -func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() } -func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() } -func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() } -func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() } -func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() } -func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() } -func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() } -func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() } -func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() } -func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() } -func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() } -func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() } -func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() } -func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() } -func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() } -func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() } -func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() } -func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() } -func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() } -func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() } -func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() } -func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() } -func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() } -func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() } -func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() } -func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() } -func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() } -func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() } -func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() } -func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() } -func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() } -func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() } -func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() } -func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() } -func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() } -func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() } -func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() } -func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() } -func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() } -func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() } -func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() } -func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() } -func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() } -func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() } -func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() } -func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() } -func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() } -func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() } -func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() } -func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() } -func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() } -func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() } -func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() } -func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() } -func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() } -func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() } -func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() } -func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() } -func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() } -func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() } -func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() } -func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() } -func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() } -func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() } -func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() } -func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() } -func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() } -func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() } -func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() } -func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() } -func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() } -func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() } -func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() } -func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() } -func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() } -func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() } -func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() } -func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() } -func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() } -func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() } -func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() } -func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() } -func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() } -func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() } -func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() } -func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() } -func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() } -func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() } -func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() } -func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() } -func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() } -func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() } -func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() } -func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() } -func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() } -func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() } -func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() } -func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() } -func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() } -func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() } -func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() } -func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() } -func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() } -func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() } -func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() } -func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() } -func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() } -func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() } -func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() } -func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() } -func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() } -func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() } -func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() } -func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() } -func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() } -func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() } -func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() } -func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() } -func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() } -func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() } -func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() } -func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() } -func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() } -func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() } -func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() } -func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() } -func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() } -func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() } -func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() } -func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() } -func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() } -func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() } -func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() } -func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() } -func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() } -func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() } -func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() } -func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() } -func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() } -func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() } -func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() } -func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() } -func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() } -func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() } -func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() } -func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() } -func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() } -func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() } -func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() } -func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() } -func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() } -func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() } -func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() } -func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() } -func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() } -func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() } -func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() } -func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() } -func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() } -func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() } -func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() } -func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() } -func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() } -func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() } -func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() } -func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() } -func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() } -func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() } -func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() } -func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() } -func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() } -func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() } -func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() } -func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() } -func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() } -func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() } -func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() } -func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() } -func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() } -func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() } -func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() } -func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() } -func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() } -func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() } -func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() } -func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() } -func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() } -func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() } -func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() } -func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() } -func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() } -func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() } -func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() } -func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() } -func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() } -func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() } -func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() } -func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() } -func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() } -func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() } -func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() } -func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() } -func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() } -func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() } -func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() } -func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() } -func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() } -func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() } -func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() } -func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() } -func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() } -func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() } -func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() } -func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() } -func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() } -func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() } -func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() } -func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() } -func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() } -func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() } -func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() } -func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() } -func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() } -func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() } -func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() } -func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() } -func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() } -func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() } -func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() } -func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() } -func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() } -func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() } -func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() } -func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() } -func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() } -func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() } -func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() } -func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() } -func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() } -func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() } -func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() } -func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() } -func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() } -func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() } -func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() } -func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() } -func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() } -func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() } -func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() } -func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() } -func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() } -func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() } -func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() } -func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() } -func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() } -func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() } -func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() } -func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() } -func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() } -func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() } -func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() } -func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() } -func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() } -func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() } -func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() } -func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() } -func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() } -func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() } -func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() } -func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() } -func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() } -func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() } -func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() } -func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() } -func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() } -func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() } -func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() } -func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() } -func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() } -func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() } -func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() } -func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() } -func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() } -func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() } -func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() } -func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() } -func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() } -func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() } -func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() } -func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() } -func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() } -func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() } -func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() } -func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() } -func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() } -func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() } -func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() } -func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() } -func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() } -func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() } -func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() } -func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() } -func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() } -func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() } -func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() } -func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() } -func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() } -func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() } -func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() } -func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() } -func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() } -func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() } -func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() } -func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() } -func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() } -func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() } -func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() } -func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() } -func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() } -func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() } -func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() } -func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() } -func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() } -func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() } -func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() } -func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() } -func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() } -func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() } -func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() } -func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() } -func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() } -func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() } -func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() } -func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() } -func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() } -func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() } -func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() } -func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() } -func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() } -func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() } -func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() } -func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() } -func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() } -func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() } -func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() } -func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() } -func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() } -func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() } -func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() } -func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() } -func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() } -func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() } -func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() } -func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() } -func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() } -func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() } -func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() } -func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() } -func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() } -func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() } -func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() } -func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() } -func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() } -func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() } -func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() } -func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() } -func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() } -func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() } -func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() } -func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() } -func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() } -func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() } -func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() } -func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() } -func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() } -func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() } -func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() } -func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() } -func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() } -func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() } -func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() } -func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() } -func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() } -func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() } -func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() } -func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() } -func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() } -func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() } -func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() } -func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() } -func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() } -func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() } -func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() } -func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() } -func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() } -func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() } -func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() } -func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() } -func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() } -func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() } -func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() } -func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() } -func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() } -func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() } -func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() } -func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() } -func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() } -func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() } -func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() } -func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() } -func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() } -func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() } -func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() } -func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() } -func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() } -func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() } -func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() } -func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() } -func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() } -func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() } -func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() } -func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() } -func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() } -func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() } -func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() } -func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() } -func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() } -func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() } -func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() } -func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() } -func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() } -func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() } -func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() } -func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() } -func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() } -func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() } -func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() } -func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() } -func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() } -func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() } -func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() } -func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() } -func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() } -func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() } -func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() } -func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() } -func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() } -func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() } -func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() } -func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() } -func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() } -func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() } -func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() } -func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() } -func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() } -func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() } -func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() } -func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() } -func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() } -func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() } -func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() } -func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() } -func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() } -func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() } -func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() } -func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() } -func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() } -func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() } -func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() } -func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() } -func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() } -func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() } -func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() } -func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() } -func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() } -func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() } -func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() } -func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() } -func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() } -func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() } -func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() } -func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() } -func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() } -func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() } -func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() } -func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() } -func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() } -func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() } -func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() } -func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() } -func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() } -func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() } -func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() } -func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() } -func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() } -func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() } -func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() } -func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() } -func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() } -func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() } -func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() } -func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() } -func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() } -func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() } -func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() } -func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() } -func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() } -func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() } -func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() } -func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() } -func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() } -func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() } -func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() } -func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() } -func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() } -func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() } -func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() } -func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() } -func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() } -func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() } -func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() } -func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() } -func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() } -func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() } -func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() } -func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() } -func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() } -func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() } -func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() } -func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() } -func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() } -func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() } -func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() } -func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() } -func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() } -func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() } -func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() } -func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() } -func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() } -func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() } -func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() } -func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() } -func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() } -func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() } -func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() } -func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() } -func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() } -func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() } -func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() } -func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() } -func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() } -func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() } -func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() } -func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() } -func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() } -func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() } -func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() } -func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() } -func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() } -func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() } -func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() } -func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() } -func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() } -func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() } -func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() } -func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() } -func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() } -func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() } -func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() } -func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() } -func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() } -func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() } -func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() } -func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() } -func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() } -func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() } -func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() } -func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() } -func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() } -func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() } -func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() } -func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() } -func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() } -func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() } -func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() } -func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() } -func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() } -func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() } -func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() } -func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() } -func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() } -func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() } -func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() } -func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() } -func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() } -func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() } -func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() } -func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() } -func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() } -func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() } -func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() } -func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() } -func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() } -func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() } -func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() } -func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() } -func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() } -func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() } -func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() } -func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() } -func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() } -func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() } -func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() } -func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() } -func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() } -func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() } -func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() } -func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() } -func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() } -func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() } -func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() } -func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() } -func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() } -func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() } -func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() } -func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() } -func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() } -func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() } -func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() } -func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() } -func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() } -func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() } -func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() } -func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() } -func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() } -func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() } -func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() } -func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() } -func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() } -func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() } -func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() } -func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() } -func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() } -func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() } -func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() } -func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() } -func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() } -func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() } -func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() } -func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() } -func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() } -func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() } -func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() } -func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() } -func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() } -func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() } -func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() } -func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() } -func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() } -func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() } -func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() } -func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() } -func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() } -func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() } -func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() } -func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() } -func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() } -func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() } -func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() } -func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() } -func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() } -func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() } -func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() } -func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() } -func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() } -func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() } -func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() } -func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() } -func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() } -func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() } -func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() } -func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() } -func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() } -func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() } -func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() } -func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() } -func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() } -func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() } -func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() } -func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() } -func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() } -func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() } -func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() } -func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() } -func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() } -func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() } -func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() } -func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() } -func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() } -func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() } -func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() } -func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() } -func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() } -func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() } -func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() } -func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() } -func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() } -func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() } -func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() } -func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() } -func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() } -func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() } diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go index 7b9412af42..cd525a3fc5 100644 --- a/src/runtime/stack_test.go +++ b/src/runtime/stack_test.go @@ -10,62 +10,8 @@ import ( "sync" "testing" "time" - "unsafe" ) -// See stack.h. -const ( - StackGuard = 256 - StackSmall = 64 - StackLimit = StackGuard - StackSmall -) - -// Test stack split logic by calling functions of every frame size -// from near 0 up to and beyond the default segment size (4k). -// Each of those functions reports its SP + stack limit, and then -// the test (the caller) checks that those make sense. By not -// doing the actual checking and reporting from the suspect functions, -// we minimize the possibility of crashes during the test itself. -// -// Exhaustive test for http://golang.org/issue/3310. -// The linker used to get a few sizes near the segment size wrong: -// -// --- FAIL: TestStackSplit (0.01 seconds) -// stack_test.go:22: after runtime_test.stack3812: sp=0x7f7818d5d078 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3816: sp=0x7f7818d5d078 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3820: sp=0x7f7818d5d070 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3824: sp=0x7f7818d5d070 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3828: sp=0x7f7818d5d068 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3832: sp=0x7f7818d5d068 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3836: sp=0x7f7818d5d060 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3840: sp=0x7f7818d5d060 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3844: sp=0x7f7818d5d058 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3848: sp=0x7f7818d5d058 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3852: sp=0x7f7818d5d050 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3856: sp=0x7f7818d5d050 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3860: sp=0x7f7818d5d048 < limit=0x7f7818d5d080 -// stack_test.go:22: after runtime_test.stack3864: sp=0x7f7818d5d048 < limit=0x7f7818d5d080 -// FAIL -func TestStackSplit(t *testing.T) { - for _, f := range splitTests { - sp, guard := f() - bottom := guard - StackGuard - if sp < bottom+StackLimit { - fun := FuncForPC(**(**uintptr)(unsafe.Pointer(&f))) - t.Errorf("after %s: sp=%#x < limit=%#x (guard=%#x, bottom=%#x)", - fun.Name(), sp, bottom+StackLimit, guard, bottom) - } - } -} - -var Used byte - -func use(buf []byte) { - for _, c := range buf { - Used += c - } -} - // TestStackMem measures per-thread stack segment cache behavior. // The test consumed up to 500MB in the past. func TestStackMem(t *testing.T) { diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index f8ea1092e9..f3af34a584 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -219,7 +219,6 @@ const _NoArgs = ^uintptr(0) func newstack() func newproc() -func lessstack() func morestack() func mstart() func rt0_go() diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index c1a019296f..ca3b862102 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -34,7 +34,6 @@ var ( deferprocPC = funcPC(deferproc) goexitPC = funcPC(goexit) jmpdeferPC = funcPC(jmpdefer) - lessstackPC = funcPC(lessstack) mcallPC = funcPC(mcall) morestackPC = funcPC(morestack) mstartPC = funcPC(mstart) @@ -57,7 +56,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf g := getg() gotraceback := gotraceback(nil) if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp. - if gp.syscallstack != 0 { + if gp.syscallsp != 0 { pc0 = gp.syscallpc sp0 = gp.syscallsp if usesLR { @@ -115,7 +114,6 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf frame.fn = f n := 0 - stk := (*stktop)(unsafe.Pointer(gp.stackbase)) for n < max { // Typically: // pc is the PC of the running function. @@ -123,39 +121,8 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf // fp is the frame pointer (caller's stack pointer) at that program counter, or nil if unknown. // stk is the stack containing sp. // The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp. - if frame.pc == lessstackPC { - // Hit top of stack segment. Unwind to next segment. - frame.pc = stk.gobuf.pc - frame.sp = stk.gobuf.sp - frame.lr = 0 - frame.fp = 0 - if printing && showframe(nil, gp) { - print("----- stack segment boundary -----\n") - } - stk = (*stktop)(unsafe.Pointer(stk.stackbase)) - f = findfunc(frame.pc) - if f == nil { - print("runtime: unknown pc ", hex(frame.pc), " after stack split\n") - if callback != nil { - gothrow("unknown pc") - } - } - frame.fn = f - continue - } f = frame.fn - // Hook for handling Windows exception handlers. See traceback_windows.go. - if systraceback != nil { - changed, aborted := systraceback(f, (*stkframe)(noescape(unsafe.Pointer(&frame))), gp, printing, callback, v) - if aborted { - return n - } - if changed { - continue - } - } - // Found an actual function. // Derive frame pointer and link register. if frame.fp == 0 { @@ -224,8 +191,6 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf frame.arglen = uintptr(f.args) } else if flr == nil { frame.arglen = 0 - } else if frame.lr == lessstackPC { - frame.arglen = uintptr(stk.argsize) } else { i := funcarglen(flr, frame.lr) if i >= 0 { @@ -617,7 +582,6 @@ func topofstack(f *_func) bool { pc == mstartPC || pc == mcallPC || pc == morestackPC || - pc == lessstackPC || pc == rt0_goPC || externalthreadhandlerp != 0 && pc == externalthreadhandlerp } diff --git a/src/runtime/traceback_windows.go b/src/runtime/traceback_windows.go deleted file mode 100644 index 89dc1336e3..0000000000 --- a/src/runtime/traceback_windows.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2009 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 runtime - -import "unsafe" - -// sigtrampPC is the PC at the beginning of the jmpdefer assembly function. -// The traceback needs to recognize it on link register architectures. -var sigtrampPC uintptr - -func sigtramp() - -func init() { - sigtrampPC = funcPC(sigtramp) - systraceback = traceback_windows -} - -func traceback_windows(f *_func, frame *stkframe, gp *g, printing bool, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) (changed, aborted bool) { - // The main traceback thinks it has found a function. Check this. - - // Windows exception handlers run on the actual g stack (there is room - // dedicated to this below the usual "bottom of stack"), not on a separate - // stack. As a result, we have to be able to unwind past the exception - // handler when called to unwind during stack growth inside the handler. - // Recognize the frame at the call to sighandler in sigtramp and unwind - // using the context argument passed to the call. This is awful. - if f != nil && f.entry == sigtrampPC && frame.pc > f.entry { - var r *context - // Invoke callback so that stack copier sees an uncopyable frame. - if callback != nil { - frame.continpc = frame.pc - frame.argp = 0 - frame.arglen = 0 - if !callback(frame, v) { - aborted = true - return - } - } - r = (*context)(unsafe.Pointer(frame.sp + ptrSize)) - frame.pc = contextPC(r) - frame.sp = contextSP(r) - frame.lr = 0 - frame.fp = 0 - frame.fn = nil - if printing && showframe(nil, gp) { - print("----- exception handler -----\n") - } - f = findfunc(frame.pc) - if f == nil { - print("runtime: unknown pc ", hex(frame.pc), " after exception handler\n") - if callback != nil { - gothrow("unknown pc") - } - } - frame.fn = f - changed = true - return - } - - return -} From 8ac35be145c407896a3c799dddb155c2a22c88ef Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 14:02:37 -0400 Subject: [PATCH 027/430] runtime: fix build failures after CL 137410043 No promise about correctness, but they do build. TBR=khr CC=golang-codereviews https://golang.org/cl/143720043 --- src/runtime/asm_386.s | 2 +- src/runtime/asm_amd64p32.s | 2 +- src/runtime/os_freebsd.c | 4 ++-- src/runtime/os_solaris.c | 5 ++++- src/runtime/sys_plan9_386.s | 2 +- src/runtime/sys_plan9_amd64.s | 2 +- src/runtime/sys_solaris_amd64.s | 6 ++++-- src/runtime/sys_windows_386.s | 16 +++++++++++----- src/runtime/sys_windows_amd64.s | 16 +++++++++++----- 9 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index fc01b995b1..2376ab92ba 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -811,7 +811,7 @@ TEXT setg_gcc<>(SB), NOSPLIT, $0 MOVL DX, g(AX) RET -// check that SP is in range [g->stackbase, g->stackguard) +// check that SP is in range [g->stack.lo, g->stack.hi) TEXT runtime·stackcheck(SB), NOSPLIT, $0-0 get_tls(CX) MOVL g(CX), AX diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 046eb1cd6f..5d82d84aa4 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -590,7 +590,7 @@ TEXT runtime·setg(SB), NOSPLIT, $0-4 MOVL 0, AX RET -// check that SP is in range [g->stackbase, g->stackguard) +// check that SP is in range [g->stack.lo, g->stack.hi) TEXT runtime·stackcheck(SB), NOSPLIT, $0-0 get_tls(CX) MOVL g(CX), AX diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c index cde6936de5..a513cb6044 100644 --- a/src/runtime/os_freebsd.c +++ b/src/runtime/os_freebsd.c @@ -153,8 +153,8 @@ runtime·newosproc(M *mp, void *stk) // NOTE(rsc): This code is confused. stackbase is the top of the stack // and is equal to stk. However, it's working, so I'm not changing it. - param.stack_base = (void*)mp->g0->stackbase; - param.stack_size = (byte*)stk - (byte*)mp->g0->stackbase; + param.stack_base = (void*)mp->g0->stack.hi; + param.stack_size = (byte*)stk - (byte*)mp->g0->stack.hi; param.child_tid = (void*)&mp->procid; param.parent_tid = nil; diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c index 4b382b731b..99c38d8be6 100644 --- a/src/runtime/os_solaris.c +++ b/src/runtime/os_solaris.c @@ -121,14 +121,17 @@ runtime·newosproc(M *mp, void *stk) Sigset oset; Pthread tid; int32 ret; + uint64 size; USED(stk); if(runtime·pthread_attr_init(&attr) != 0) runtime·throw("pthread_attr_init"); if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0) runtime·throw("pthread_attr_setstack"); - if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stackbase, &mp->g0->stacksize) != 0) + size = 0; + if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stack.hi, &size) != 0) runtime·throw("pthread_attr_getstack"); + mp->g0->stack.lo = mp->g0->stack.hi - size; if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) runtime·throw("pthread_attr_setdetachstate"); diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s index 7432981813..1256347963 100644 --- a/src/runtime/sys_plan9_386.s +++ b/src/runtime/sys_plan9_386.s @@ -192,7 +192,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0 // change stack MOVL g_m(BX), BX MOVL m_gsignal(BX), BP - MOVL g_stackbase(BP), BP + MOVL (g_stack+stack_hi)(BP), BP MOVL BP, SP // make room for args and g diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s index 954c0c27bb..d0586a5ae9 100644 --- a/src/runtime/sys_plan9_amd64.s +++ b/src/runtime/sys_plan9_amd64.s @@ -190,7 +190,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0 // change stack MOVQ g_m(BX), BX MOVQ m_gsignal(BX), R10 - MOVQ g_stackbase(R10), BP + MOVQ (g_stack+stack_hi)(R10), BP MOVQ BP, SP // make room for args and g diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s index 093315c4a4..0ebdab6ee2 100644 --- a/src/runtime/sys_solaris_amd64.s +++ b/src/runtime/sys_solaris_amd64.s @@ -129,10 +129,12 @@ TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0 // Layout new m scheduler stack on os stack. MOVQ SP, AX - MOVQ AX, g_stackbase(DX) + MOVQ AX, (g_stack+stack_hi)(DX) SUBQ $(0x100000), AX // stack size - MOVQ AX, g_stackguard(DX) + MOVQ AX, (g_stack+stack_lo)(DX) + ADDQ $const_StackGuard, AX MOVQ AX, g_stackguard0(DX) + MOVQ AX, g_stackguard1(DX) // Someday the convention will be D is always cleared. CLD diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index fc19f5650a..ebcfdf4e0d 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -192,8 +192,11 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 LEAL g_end(SP), BX MOVL BX, g_m(SP) LEAL -4096(SP), CX - MOVL CX, g_stackguard(SP) - MOVL DX, g_stackbase(SP) + MOVL CX, (g_stack+stack_lo)(SP) + ADDL $const_StackGuard, CX + MOVL CX, g_stackguard0(SP) + MOVL CX, g_stackguard1(SP) + MOVL DX, (g_stack+stack_hi)(SP) PUSHL 16(BP) // arg for handler CALL 8(BP) @@ -201,7 +204,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 get_tls(CX) MOVL g(CX), CX - MOVL g_stackbase(CX), SP + MOVL (g_stack+stack_hi)(CX), SP POPL 0x14(FS) POPL DI POPL SI @@ -293,9 +296,12 @@ TEXT runtime·tstart(SB),NOSPLIT,$0 // Layout new m scheduler stack on os stack. MOVL SP, AX - MOVL AX, g_stackbase(DX) + MOVL AX, (g_stack+stack_hi)(DX) SUBL $(64*1024), AX // stack size - MOVL AX, g_stackguard(DX) + MOVL AX, (g_stack+stack_lo)(DX) + ADDL $const_StackGuard, AX + MOVL AX, g_stackguard0(DX) + MOVL AX, g_stackguard1(DX) // Set up tls. LEAL m_tls(CX), SI diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 3d63a04de9..f701d157ed 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -229,8 +229,11 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 MOVQ BX, g_m(SP) LEAQ -8192(SP), CX - MOVQ CX, g_stackguard(SP) - MOVQ DX, g_stackbase(SP) + MOVQ CX, (g_stack+stack_lo)(SP) + ADDQ $const_StackGuard, CX + MOVQ CX, g_stackguard0(SP) + MOVQ CX, g_stackguard1(SP) + MOVQ DX, (g_stack+stack_hi)(SP) PUSHQ 32(BP) // arg for handler CALL 16(BP) @@ -238,7 +241,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 get_tls(CX) MOVQ g(CX), CX - MOVQ g_stackbase(CX), SP + MOVQ (g_stack+stack_hi)(CX), SP POPQ 0x28(GS) POPQ DI POPQ SI @@ -334,9 +337,12 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0 // Layout new m scheduler stack on os stack. MOVQ SP, AX - MOVQ AX, g_stackbase(DX) + MOVQ AX, (g_stack+stack_hi)(DX) SUBQ $(64*1024), AX // stack size - MOVQ AX, g_stackguard(DX) + MOVQ AX, (g_stack+stack_lo)(DX) + ADDQ $const_StackGuard, AX + MOVQ AX, g_stackguard0(DX) + MOVQ AX, g_stackguard1(DX) // Set up tls. LEAQ m_tls(CX), SI From b6571a0713416ae0d26816af2c1e92f90fe266a6 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 9 Sep 2014 11:45:36 -0700 Subject: [PATCH 028/430] strconv: fix documentation for CanBackquote. Space is not a control character. Fixes #8571. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/137380043 --- src/strconv/quote.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strconv/quote.go b/src/strconv/quote.go index 4469c688b0..53d51b5a46 100644 --- a/src/strconv/quote.go +++ b/src/strconv/quote.go @@ -143,7 +143,7 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { // CanBackquote reports whether the string s can be represented // unchanged as a single-line backquoted string without control -// characters other than space and tab. +// characters other than tab. func CanBackquote(s string) bool { for len(s) > 0 { r, wid := utf8.DecodeRuneInString(s) From eafa4fff5257ed286618d9027eeaf3cce7c6b8d0 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 9 Sep 2014 11:45:46 -0700 Subject: [PATCH 029/430] fmt: fix allocation test With new interface allocation rules, the old counts were wrong and so was the commentary. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/142760044 --- src/fmt/fmt_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 8c577949a1..89dde2b64a 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -855,6 +855,7 @@ func BenchmarkManyArgs(b *testing.B) { } var mallocBuf bytes.Buffer +var mallocPointer *int // A pointer so we know the interface value won't allocate. var mallocTest = []struct { count int @@ -866,11 +867,13 @@ var mallocTest = []struct { {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }}, {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }}, - // For %g we use a float32, not float64, to guarantee passing the argument - // does not need to allocate memory to store the result in a pointer-sized word. - {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, - {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }}, + {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1? {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, + // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. + {0, `Fprintf(buf, "%x %x %x")`, func() { + mallocBuf.Reset() + Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer) + }}, } var _ bytes.Buffer From d33ee0c5e52cbdc66066f54b9b2e2c930268784a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 9 Sep 2014 12:31:07 -0700 Subject: [PATCH 030/430] testing: read coverage counters atomically For -mode=atomic, we need to read the counters using an atomic load to avoid a race. Not worth worrying about when -mode=atomic is set during generation of the profile, so we use atomic loads always. Fixes #8630. LGTM=rsc R=dvyukov, rsc CC=golang-codereviews https://golang.org/cl/141800043 --- src/testing/cover.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/testing/cover.go b/src/testing/cover.go index eb7249dccd..a4ce37f7c2 100644 --- a/src/testing/cover.go +++ b/src/testing/cover.go @@ -9,6 +9,7 @@ package testing import ( "fmt" "os" + "sync/atomic" ) // CoverBlock records the coverage data for a single basic block. @@ -44,8 +45,8 @@ type Cover struct { func Coverage() float64 { var n, d int64 for _, counters := range cover.Counters { - for _, c := range counters { - if c > 0 { + for i := range counters { + if atomic.LoadUint32(&counters[i]) > 0 { n++ } d++ @@ -84,11 +85,13 @@ func coverReport() { } var active, total int64 + var count uint32 for name, counts := range cover.Counters { blocks := cover.Blocks[name] - for i, count := range counts { + for i := range counts { stmts := int64(blocks[i].Stmts) total += stmts + count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. if count > 0 { active += stmts } From 16c59acb9790b0d1d17ed45256b95fa60c2e55f1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 15:38:55 -0400 Subject: [PATCH 031/430] runtime: avoid read overrun in heapdump Start the stack a few words below the actual top, so that if something tries to read goexit's caller PC from the stack, it won't fault on a bad memory address. Today, heapdump does that. Maybe tomorrow, traceback or something else will do that. Make it not a bug. TBR=khr R=khr CC=golang-codereviews https://golang.org/cl/136450043 --- src/runtime/proc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index a7f9db410f..54efb035bf 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -1047,6 +1047,7 @@ runtime·newextram(void) gp = runtime·malg(4096); gp->sched.pc = (uintptr)runtime·goexit; gp->sched.sp = gp->stack.hi; + gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame gp->sched.lr = 0; gp->sched.g = gp; gp->syscallpc = gp->sched.pc; @@ -2229,6 +2230,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp runtime·throw("newproc1: new g is not Gdead"); sp = (byte*)newg->stack.hi; + sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame sp -= siz; runtime·memmove(sp, argp, narg); if(thechar == '5') { From ee6c6d96b652cb7003bdb705dcfa617e04777b3d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 17:12:05 -0400 Subject: [PATCH 032/430] runtime: fix windows/386 build The difference between the old and the new (from earlier) code is that we set stackguard = stack.lo + StackGuard, while the old code set stackguard = stack.lo. That 512 bytes appears to be the difference between the profileloop function running and not running. We don't know how big the system stack is, but it is likely MUCH bigger than 4k. Give Go/C 8k. TBR=iant CC=golang-codereviews https://golang.org/cl/140440044 --- src/runtime/memclr_386.s | 2 ++ src/runtime/memclr_amd64.s | 2 ++ src/runtime/sys_windows_386.s | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s index 8b163923e9..1520aea2e0 100644 --- a/src/runtime/memclr_386.s +++ b/src/runtime/memclr_386.s @@ -6,6 +6,8 @@ #include "textflag.h" +// NOTE: Windows externalthreadhandler expects memclr to preserve DX. + // void runtime·memclr(void*, uintptr) TEXT runtime·memclr(SB), NOSPLIT, $0-8 MOVL ptr+0(FP), DI diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s index 35b3b4beef..94a2c7f236 100644 --- a/src/runtime/memclr_amd64.s +++ b/src/runtime/memclr_amd64.s @@ -6,6 +6,8 @@ #include "textflag.h" +// NOTE: Windows externalthreadhandler expects memclr to preserve DX. + // void runtime·memclr(void*, uintptr) TEXT runtime·memclr(SB), NOSPLIT, $0-16 MOVQ ptr+0(FP), DI diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index ebcfdf4e0d..9b1fc7a205 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -191,7 +191,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 CALL runtime·memclr(SB) // smashes AX,BX,CX LEAL g_end(SP), BX MOVL BX, g_m(SP) - LEAL -4096(SP), CX + LEAL -8192(SP), CX MOVL CX, (g_stack+stack_lo)(SP) ADDL $const_StackGuard, CX MOVL CX, g_stackguard0(SP) From f9829e92e196cdae33e256dd82c690c7beba76ed Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 9 Sep 2014 17:16:31 -0400 Subject: [PATCH 033/430] runtime: fix plan9/amd64 build? The only thing I can see that is really Plan 9-specific is that the stack pointer used for signal handling used to have more mapped memory above it. Specifically it used to have at most 88 bytes (StackTop), so change the allocation of a 40-byte frame to a 128-byte frame. No idea if this will work, but worth a try. Note that "fix" here means get it back to timing out instead of crashing. TBR=iant CC=golang-codereviews https://golang.org/cl/142840043 --- src/runtime/sys_plan9_amd64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s index d0586a5ae9..36d2d97e20 100644 --- a/src/runtime/sys_plan9_amd64.s +++ b/src/runtime/sys_plan9_amd64.s @@ -194,7 +194,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0 MOVQ BP, SP // make room for args and g - SUBQ $40, SP + SUBQ $128, SP // save g MOVQ g(AX), BP From 251daf8650218ee2fce297280016e696d859f780 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 9 Sep 2014 14:22:58 -0700 Subject: [PATCH 034/430] runtime: map iterators: always use intrabucket randomess Fixes #8688 LGTM=rsc R=golang-codereviews, bradfitz, rsc, khr CC=golang-codereviews https://golang.org/cl/135660043 --- src/runtime/hashmap.go | 20 ++++++++----------- src/runtime/map_test.go | 43 ++++++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index cbcc6c4041..b4e624423f 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -59,7 +59,8 @@ import ( const ( // Maximum number of key/value pairs a bucket can hold. - bucketCnt = 8 + bucketCntBits = 3 + bucketCnt = 1 << bucketCntBits // Maximum average load of a bucket that triggers growth. loadFactor = 6.5 @@ -138,7 +139,7 @@ type hiter struct { offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) wrapped bool // already wrapped around from end of bucket array to beginning B uint8 - i uint8 + i uint8 bucket uintptr checkBucket uintptr } @@ -562,17 +563,12 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { it.buckets = h.buckets // decide where to start - switch { - case h.B == 0: - it.startBucket = 0 - it.offset = uint8(fastrand1()) & (bucketCnt - 1) - case h.B <= 31: - it.startBucket = uintptr(fastrand1()) & (uintptr(1)< 31-bucketCntBits { + r += uintptr(fastrand1()) << 31 } + it.startBucket = r & (uintptr(1)<> h.B & (bucketCnt - 1)) // iterator state it.bucket = it.startBucket diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 2e87a94a03..e2f1481ad5 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -412,30 +412,33 @@ func TestMapNanGrowIterator(t *testing.T) { func TestMapIterOrder(t *testing.T) { for _, n := range [...]int{3, 7, 9, 15} { - // Make m be {0: true, 1: true, ..., n-1: true}. - m := make(map[int]bool) - for i := 0; i < n; i++ { - m[i] = true - } - // Check that iterating over the map produces at least two different orderings. - ord := func() []int { - var s []int - for key := range m { - s = append(s, key) + for i := 0; i < 1000; i++ { + // Make m be {0: true, 1: true, ..., n-1: true}. + m := make(map[int]bool) + for i := 0; i < n; i++ { + m[i] = true } - return s - } - first := ord() - ok := false - for try := 0; try < 100; try++ { - if !reflect.DeepEqual(first, ord()) { - ok = true + // Check that iterating over the map produces at least two different orderings. + ord := func() []int { + var s []int + for key := range m { + s = append(s, key) + } + return s + } + first := ord() + ok := false + for try := 0; try < 100; try++ { + if !reflect.DeepEqual(first, ord()) { + ok = true + break + } + } + if !ok { + t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first) break } } - if !ok { - t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first) - } } } From 1a5e394ab74672f59dd10623717fc3e08b17f0ab Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 9 Sep 2014 14:32:53 -0700 Subject: [PATCH 035/430] runtime: more cleanups Move timenow thunk into time.s Move declarations for generic c/asm services into stubs.go LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/137360043 --- src/runtime/asm_386.s | 3 --- src/runtime/asm_amd64.s | 3 --- src/runtime/asm_amd64p32.s | 3 --- src/runtime/asm_arm.s | 3 --- src/runtime/extern.go | 2 -- src/runtime/mgc0.go | 2 -- src/runtime/mprof.go | 3 --- src/runtime/stubs.go | 7 +++++++ src/runtime/thunk.s | 3 +++ 9 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 2376ab92ba..3e93025faf 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -2241,9 +2241,6 @@ TEXT runtime·duffcopy(SB), NOSPLIT, $0-0 RET -TEXT runtime·timenow(SB), NOSPLIT, $0-0 - JMP time·now(SB) - TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 get_tls(CX) MOVL g(CX), AX diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index a32e03e4ee..1a106dc1f1 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -2186,9 +2186,6 @@ TEXT runtime·duffcopy(SB), NOSPLIT, $0-0 RET -TEXT runtime·timenow(SB), NOSPLIT, $0-0 - JMP time·now(SB) - TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 get_tls(CX) MOVQ g(CX), AX diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 5d82d84aa4..32276c8952 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -1069,9 +1069,6 @@ eqret: MOVB AX, ret+24(FP) RET -TEXT runtime·timenow(SB), NOSPLIT, $0-0 - JMP time·now(SB) - TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 get_tls(CX) MOVL g(CX), AX diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index ac78bd9dc5..73d23fce34 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -848,9 +848,6 @@ _sib_notfound: MOVW R0, ret+12(FP) RET -TEXT runtime·timenow(SB),NOSPLIT,$0-0 - B time·now(SB) - // A Duff's device for zeroing memory. // The compiler jumps to computed addresses within // this routine to zero chunks of memory. Do not diff --git a/src/runtime/extern.go b/src/runtime/extern.go index 3d06a23fce..b8db5d0c4b 100644 --- a/src/runtime/extern.go +++ b/src/runtime/extern.go @@ -126,8 +126,6 @@ func Callers(skip int, pc []uintptr) int { return callers(skip, &pc[0], len(pc)) } -func getgoroot() string - // GOROOT returns the root of the Go tree. // It uses the GOROOT environment variable, if set, // or else the root used during the Go build. diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 0984fc58d6..ec5edb0244 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -28,8 +28,6 @@ func gc_notype_ptr(ret *interface{}) { *ret = x } -func timenow() (sec int64, nsec int32) - func gc_unixnanotime(now *int64) { sec, nsec := timenow() *now = sec*1e9 + int64(nsec) diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index 7177c84592..89e9915236 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -295,9 +295,6 @@ func SetBlockProfileRate(rate int) { atomicstore64(&blockprofilerate, uint64(r)) } -func fastrand1() uint32 // assembly -func readgstatus(*g) uint32 // proc.c - func blockevent(cycles int64, skip int) { if cycles <= 0 { return diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index f3af34a584..8bae98c73d 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -28,6 +28,7 @@ func getg() *g func acquirem() *m func releasem(mp *m) func gomcache() *mcache +func readgstatus(*g) uint32 // proc.c // mcall switches from the g to the g0 stack and invokes fn(g), // where g is the goroutine that made the call. @@ -121,6 +122,9 @@ func unlockOSThread() // exported value for testing var hashLoad = loadFactor +// in asm_*.s +func fastrand1() uint32 + // in asm_*.s //go:noescape func memeq(a, b unsafe.Pointer, size uintptr) bool @@ -229,3 +233,6 @@ func rt0_go() // to deferreturn. // in asm_*.s func return0() + +// thunk to call time.now. +func timenow() (sec int64, nsec int32) diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index 35b250f8c5..7ba22d705e 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -157,3 +157,6 @@ TEXT runtime·main_init(SB),NOSPLIT,$0-0 TEXT runtime·main_main(SB),NOSPLIT,$0-0 JMP main·main(SB) + +TEXT runtime·timenow(SB), NOSPLIT, $0-0 + JMP time·now(SB) From 9f012e100210b6fb4e9bf8972e3d3b04c44b863a Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Tue, 9 Sep 2014 17:19:01 -0700 Subject: [PATCH 036/430] runtime: call rfork on scheduler stack on Plan 9 A race exists between the parent and child processes after a fork. The child needs to access the new M pointer passed as an argument but the parent may have already returned and clobbered it. Previously, we avoided this by saving the necessary data into registers before the rfork system call but this isn't guaranteed to work because Plan 9 makes no promises about the register state after a system call. Only the 386 kernel seems to save them. For amd64 and arm, this method won't work. We eliminate the race by allocating stack space for the scheduler goroutines (g0) in the per-process copy-on-write stack segment and by only calling rfork on the scheduler stack. LGTM=aram, 0intro, rsc R=aram, 0intro, mischief, rsc CC=golang-codereviews https://golang.org/cl/110680044 --- src/runtime/os_plan9.c | 16 +++++----- src/runtime/os_plan9.go | 3 +- src/runtime/os_plan9.h | 3 +- src/runtime/proc.c | 4 +-- src/runtime/runtime.h | 9 ++++++ src/runtime/sys_plan9_386.s | 57 +++++++++++++++-------------------- src/runtime/sys_plan9_amd64.s | 48 +++++++++++++---------------- 7 files changed, 69 insertions(+), 71 deletions(-) diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c index fe92e5b269..f8c543f6f6 100644 --- a/src/runtime/os_plan9.c +++ b/src/runtime/os_plan9.c @@ -280,14 +280,16 @@ exit(void) void runtime·newosproc(M *mp, void *stk) { - mp->tls[0] = mp->id; // so 386 asm can find it - if(0){ - runtime·printf("newosproc stk=%p m=%p g=%p rfork=%p id=%d/%d ostk=%p\n", - stk, mp, mp->g0, runtime·rfork, mp->id, (int32)mp->tls[0], &mp); - } + int32 pid; - if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, mp->g0, runtime·mstart) < 0) - runtime·throw("newosproc: rfork failed"); + if(0) + runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp); + + USED(stk); + if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0) + runtime·throw("newosproc: rfork failed\n"); + if(pid == 0) + runtime·tstart_plan9(mp); } #pragma textflag NOSPLIT diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 09cb3d93ff..c7b5bf7050 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -12,7 +12,7 @@ func seek(fd int32, offset int64, whence int32) int64 func exits(msg *byte) func brk_(addr unsafe.Pointer) uintptr func sleep(ms int32) int32 -func rfork(flags int32, stk, mm, gg, fn unsafe.Pointer) int32 +func rfork(flags int32) int32 func plan9_semacquire(addr *uint32, block int32) int32 func plan9_tsemacquire(addr *uint32, ms int32) int32 func plan9_semrelease(addr *uint32, count int32) int32 @@ -21,6 +21,7 @@ func noted(mode int32) int32 func nsec(*int64) int64 func sigtramp(ureg, msg unsafe.Pointer) func setfpmasks() +func tstart_plan9(newm *m) func errstr() string // The size of the note handler frame varies among architectures, diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h index 57a2cafa72..7ebaa9c0c6 100644 --- a/src/runtime/os_plan9.h +++ b/src/runtime/os_plan9.h @@ -9,7 +9,7 @@ int64 runtime·seek(int32 fd, int64 offset, int32 whence); void runtime·exits(int8* msg); intptr runtime·brk_(void*); int32 runtime·sleep(int32 ms); -int32 runtime·rfork(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void)); +int32 runtime·rfork(int32 flags); int32 runtime·plan9_semacquire(uint32 *addr, int32 block); int32 runtime·plan9_tsemacquire(uint32 *addr, int32 ms); int32 runtime·plan9_semrelease(uint32 *addr, int32 count); @@ -20,6 +20,7 @@ void runtime·sigtramp(void*, int8*); void runtime·sigpanic(void); void runtime·goexitsall(int8*); void runtime·setfpmasks(void); +void runtime·tstart_plan9(M *newm); /* open */ enum diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 54efb035bf..e3f24a7e67 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -917,8 +917,8 @@ runtime·allocm(P *p) mcommoninit(mp); // In case of cgo or Solaris, pthread_create will make us a stack. - // Windows will layout sched stack on OS stack. - if(runtime·iscgo || Solaris || Windows) + // Windows and Plan 9 will layout sched stack on OS stack. + if(runtime·iscgo || Solaris || Windows || Plan9) mp->g0 = runtime·malg(-1); else mp->g0 = runtime·malg(8192); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4622a2c3d7..da9b2b7514 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -522,6 +522,15 @@ enum { Solaris = 0 }; #endif +#ifdef GOOS_plan9 +enum { + Plan9 = 1 +}; +#else +enum { + Plan9 = 0 +}; +#endif // Lock-free stack node. struct LFNode diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s index 1256347963..a41b56258a 100644 --- a/src/runtime/sys_plan9_386.s +++ b/src/runtime/sys_plan9_386.s @@ -131,47 +131,38 @@ TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0 INT $64 MOVL AX, ret+8(FP) RET - -TEXT runtime·rfork(SB),NOSPLIT,$0 - MOVL $19, AX // rfork - MOVL stack+8(SP), CX - MOVL mm+12(SP), BX // m - MOVL gg+16(SP), DX // g - MOVL fn+20(SP), SI // fn - INT $64 - // In parent, return. - CMPL AX, $0 - JEQ 3(PC) - MOVL AX, ret+20(FP) +TEXT runtime·rfork(SB),NOSPLIT,$0 + MOVL $19, AX + INT $64 + MOVL AX, ret+4(FP) RET - // set SP to be on the new child stack - MOVL CX, SP +TEXT runtime·tstart_plan9(SB),NOSPLIT,$0 + MOVL newm+0(FP), CX + MOVL m_g0(CX), DX - // Initialize m, g. - get_tls(AX) - MOVL DX, g(AX) - MOVL BX, g_m(DX) + // Layout new m scheduler stack on os stack. + MOVL SP, AX + MOVL AX, (g_stack+stack_hi)(DX) + SUBL $(64*1024), AX // stack size + MOVL AX, (g_stack+stack_lo)(DX) + MOVL AX, g_stackguard0(DX) + MOVL AX, g_stackguard1(DX) // Initialize procid from TOS struct. MOVL _tos(SB), AX - MOVL 48(AX), AX // procid - MOVL AX, m_procid(BX) // save pid as m->procid - + MOVL 48(AX), AX + MOVL AX, m_procid(CX) // save pid as m->procid + + // Finally, initialize g. + get_tls(BX) + MOVL DX, g(BX) + CALL runtime·stackcheck(SB) // smashes AX, CX - - MOVL 0(DX), DX // paranoia; check they are not nil - MOVL 0(BX), BX - - // more paranoia; check that stack splitting code works - PUSHL SI - CALL runtime·emptyfunc(SB) - POPL SI - - CALL SI // fn() - CALL runtime·exit(SB) - MOVL AX, ret+20(FP) + CALL runtime·mstart(SB) + + MOVL $0x1234, 0x1234 // not reached RET // void sigtramp(void *ureg, int8 *note) diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s index 36d2d97e20..b0e1864602 100644 --- a/src/runtime/sys_plan9_amd64.s +++ b/src/runtime/sys_plan9_amd64.s @@ -130,42 +130,36 @@ TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0 RET TEXT runtime·rfork(SB),NOSPLIT,$0 - MOVQ $19, BP // rfork + MOVQ $19, BP SYSCALL - - // In parent, return. - CMPQ AX, $0 - JEQ 3(PC) - MOVL AX, ret+40(FP) + MOVL AX, ret+8(FP) RET - // In child on forked stack. - MOVQ mm+24(SP), BX // m - MOVQ gg+32(SP), DX // g - MOVQ fn+40(SP), SI // fn +TEXT runtime·tstart_plan9(SB),NOSPLIT,$0 + MOVQ newm+0(FP), CX + MOVQ m_g0(CX), DX - // set SP to be on the new child stack - MOVQ stack+16(SP), CX - MOVQ CX, SP - - // Initialize m, g. - get_tls(AX) - MOVQ DX, g(AX) - MOVQ BX, g_m(DX) + // Layout new m scheduler stack on os stack. + MOVQ SP, AX + MOVQ AX, (g_stack+stack_hi)(DX) + SUBQ $(64*1024), AX // stack size + MOVQ AX, (g_stack+stack_lo)(DX) + MOVQ AX, g_stackguard0(DX) + MOVQ AX, g_stackguard1(DX) // Initialize procid from TOS struct. MOVQ _tos(SB), AX MOVQ 64(AX), AX - MOVQ AX, m_procid(BX) // save pid as m->procid - + MOVQ AX, m_procid(CX) // save pid as m->procid + + // Finally, initialize g. + get_tls(BX) + MOVQ DX, g(BX) + CALL runtime·stackcheck(SB) // smashes AX, CX - - MOVQ 0(DX), DX // paranoia; check they are not nil - MOVQ 0(BX), BX - - CALL SI // fn() - CALL runtime·exit(SB) - MOVL AX, ret+40(FP) + CALL runtime·mstart(SB) + + MOVQ $0x1234, 0x1234 // not reached RET // This is needed by asm_amd64.s From d955dfb0075addb844d1d683a96967bb7ea0dea7 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 9 Sep 2014 17:41:48 -0700 Subject: [PATCH 037/430] runtime: cleanup openbsd semasleep implementation The previous implementation had several subtle issues. It's not clear if any of these could actually be causing the flakiness problems on openbsd/386, but fixing them should only help. 1. thrsleep() is implemented internally as unlock, then test *abort (if abort != nil), then tsleep(). Under the current code, that makes it theoretically possible that semasleep()/thrsleep() could release waitsemalock, then a racing semawakeup() could acquire the lock, increment waitsemacount, and call thrwakeup()/wakeup() before thrsleep() reaches tsleep(). (In practice, OpenBSD's big kernel lock seems unlikely to let this actually happen.) The proper way to avoid this is to pass &waitsemacount as the abort pointer to thrsleep so thrsleep knows to re-check it before going to sleep, and to wakeup if it's non-zero. Then we avoid any races. (I actually suspect openbsd's sema{sleep,wakeup}() could be further simplified using cas/xadd instead of locks, but I don't want to be more intrusive than necessary so late in the 1.4 release cycle.) 2. semasleep() takes a relative sleep duration, but thrsleep() needs an absolute sleep deadline. Instead of recomputing the deadline each iteration, compute it once up front and use (*Timespec)(nil) to signify no deadline. Ensures we retry properly if there's a spurious wakeup. 3. Instead of assuming if thrsleep() woke up and waitsemacount wasn't available that we must have hit the deadline, check that the system call returned EWOULDBLOCK. 4. Instead of assuming that 64-bit systems are little-endian, compute timediv() using a temporary int32 nsec and then assign it to tv_nsec. LGTM=iant R=jsing, iant CC=golang-codereviews https://golang.org/cl/137960043 --- src/runtime/os_openbsd.c | 53 ++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c index 91bd9449a1..eebaa13eea 100644 --- a/src/runtime/os_openbsd.c +++ b/src/runtime/os_openbsd.c @@ -12,6 +12,8 @@ enum { ESRCH = 3, + EAGAIN = 35, + EWOULDBLOCK = EAGAIN, ENOTSUP = 91, // From OpenBSD's sys/time.h @@ -65,32 +67,24 @@ runtime·semacreate(void) int32 runtime·semasleep(int64 ns) { - Timespec ts; + Timespec ts, *tsp = nil; - // spin-mutex lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); + // Compute sleep deadline. + if(ns >= 0) { + int32 nsec; + ns += runtime·nanotime(); + ts.tv_sec = runtime·timediv(ns, 1000000000, &nsec); + ts.tv_nsec = nsec; // tv_nsec is int64 on amd64 + tsp = &ts; + } for(;;) { - // lock held - if(g->m->waitsemacount == 0) { - // sleep until semaphore != 0 or timeout. - // thrsleep unlocks m->waitsemalock. - if(ns < 0) - runtime·thrsleep(&g->m->waitsemacount, 0, nil, &g->m->waitsemalock, nil); - else { - ns += runtime·nanotime(); - // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system. - ts.tv_nsec = 0; - ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec); - runtime·thrsleep(&g->m->waitsemacount, CLOCK_MONOTONIC, &ts, &g->m->waitsemalock, nil); - } - // reacquire lock - while(runtime·xchg(&g->m->waitsemalock, 1)) - runtime·osyield(); - } + int32 ret; + + // spin-mutex lock + while(runtime·xchg(&g->m->waitsemalock, 1)) + runtime·osyield(); - // lock held (again) if(g->m->waitsemacount != 0) { // semaphore is available. g->m->waitsemacount--; @@ -99,17 +93,12 @@ runtime·semasleep(int64 ns) return 0; // semaphore acquired } - // semaphore not available. - // if there is a timeout, stop now. - // otherwise keep trying. - if(ns >= 0) - break; + // sleep until semaphore != 0 or timeout. + // thrsleep unlocks m->waitsemalock. + ret = runtime·thrsleep(&g->m->waitsemacount, CLOCK_MONOTONIC, tsp, &g->m->waitsemalock, (int32 *)&g->m->waitsemacount); + if(ret == EWOULDBLOCK) + return -1; } - - // lock held but giving up - // spin-mutex unlock - runtime·atomicstore(&g->m->waitsemalock, 0); - return -1; } static void badsemawakeup(void); From 2302b21bbeef1c0bca8fff62c2d34cd301ce38a0 Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Wed, 10 Sep 2014 06:25:05 -0700 Subject: [PATCH 038/430] runtime: stop plan9/amd64 build from crashing LGTM=iant R=rsc, 0intro, alex.brainman, iant CC=golang-codereviews https://golang.org/cl/140460044 --- src/runtime/asm_amd64.s | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 1a106dc1f1..e5702d074c 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -272,6 +272,7 @@ onm: // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT,$0-0 // Cannot grow scheduler stack (m->g0). + get_tls(CX) MOVQ g(CX), BX MOVQ g_m(BX), BX MOVQ m_g0(BX), SI From b78d7b75c793ee676d4d7700610bd5030c5fea2f Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 10 Sep 2014 12:37:28 -0700 Subject: [PATCH 039/430] reflect: use runtime's memmove instead of its own They will both need write barriers at some point. But until then, no reason why we shouldn't share. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/141330043 --- src/reflect/value.go | 29 +++-------------------------- src/runtime/thunk.s | 3 +++ 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/src/reflect/value.go b/src/reflect/value.go index 368116a507..20d0e92ed1 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -15,32 +15,6 @@ const bigEndian = false // can be smarter if we find a big-endian machine const ptrSize = unsafe.Sizeof((*byte)(nil)) const cannotSet = "cannot set value obtained from unexported struct field" -// TODO: This will have to go away when -// the new gc goes in. -func memmove(adst, asrc unsafe.Pointer, n uintptr) { - dst := uintptr(adst) - src := uintptr(asrc) - switch { - case src < dst && src+n > dst: - // byte copy backward - // careful: i is unsigned - for i := n; i > 0; { - i-- - *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) - } - case (n|src|dst)&(ptrSize-1) != 0: - // byte copy forward - for i := uintptr(0); i < n; i++ { - *(*byte)(unsafe.Pointer(dst + i)) = *(*byte)(unsafe.Pointer(src + i)) - } - default: - // word copy forward - for i := uintptr(0); i < n; i += ptrSize { - *(*uintptr)(unsafe.Pointer(dst + i)) = *(*uintptr)(unsafe.Pointer(src + i)) - } - } -} - // Value is the reflection interface to a Go value. // // Not all methods apply to all kinds of values. Restrictions, @@ -2703,6 +2677,9 @@ func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) +//go:noescape +func memmove(adst, asrc unsafe.Pointer, n uintptr) + // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index 7ba22d705e..3b66cf47d3 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -74,6 +74,9 @@ TEXT reflect·chansend(SB), NOSPLIT, $0-0 TEXT reflect·chanrecv(SB), NOSPLIT, $0-0 JMP runtime·reflect_chanrecv(SB) +TEXT reflect·memmove(SB), NOSPLIT, $0-0 + JMP runtime·memmove(SB) + TEXT runtime∕debug·freeOSMemory(SB), NOSPLIT, $0-0 JMP runtime·freeOSMemory(SB) From 689dc60c14cd63cb258c050542bcfc0cbc05e914 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 10 Sep 2014 22:54:07 -0700 Subject: [PATCH 040/430] runtime: add timing test for iterate/delete map idiom. LGTM=bradfitz, iant R=iant, bradfitz CC=golang-codereviews https://golang.org/cl/140510043 --- test/maplinear.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/maplinear.go b/test/maplinear.go index 56e50951af..8cc198b8fe 100644 --- a/test/maplinear.go +++ b/test/maplinear.go @@ -140,4 +140,22 @@ func main() { m[complex(float64(i), float64(i))] = 1 } }) + + // ~70ms on a 1.6GHz Zeon. + // The iterate/delete idiom currently takes expected + // O(n lg n) time. Fortunately, the checkLinear test + // leaves enough wiggle room to include n lg n time + // (it actually tests for O(n^log_2(3)). + checkLinear("iterdelete", 10000, func(n int) { + m := map[int]int{} + for i := 0; i < n; i++ { + m[i] = i + } + for i := 0; i < n; i++ { + for k := range m { + delete(m, k) + break + } + } + }) } From f956740163ad4b46237cea83357b962cada1c2df Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 11 Sep 2014 17:56:58 +0900 Subject: [PATCH 041/430] net: fix inconsistent behavior across platforms in SetKeepAlivePeriod The previous implementation used per-socket TCP keepalive options wrong. For example, it used another level socket option to control TCP and it didn't use TCP_KEEPINTVL option when possible. Fixes #8683. Fixes #8701. Update #8679 LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/136480043 --- src/net/tcpsockopt_darwin.go | 12 +++++---- src/net/tcpsockopt_dragonfly.go | 13 ++++----- src/net/tcpsockopt_solaris.go | 27 ------------------- ...psockopt_openbsd.go => tcpsockopt_stub.go} | 8 +++--- src/net/tcpsockopt_unix.go | 10 +++---- src/net/tcpsockopt_windows.go | 12 ++++----- 6 files changed, 25 insertions(+), 57 deletions(-) delete mode 100644 src/net/tcpsockopt_solaris.go rename src/net/{tcpsockopt_openbsd.go => tcpsockopt_stub.go} (66%) diff --git a/src/net/tcpsockopt_darwin.go b/src/net/tcpsockopt_darwin.go index 33140849c9..1f1609088b 100644 --- a/src/net/tcpsockopt_darwin.go +++ b/src/net/tcpsockopt_darwin.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TCP socket options for darwin - package net import ( @@ -12,16 +10,20 @@ import ( "time" ) -// Set keep alive period. +const sysTCP_KEEPINTVL = 0x101 + func setKeepAlivePeriod(fd *netFD, d time.Duration) error { if err := fd.incref(); err != nil { return err } defer fd.decref() - // The kernel expects seconds so round to next highest second. d += (time.Second - time.Nanosecond) secs := int(d.Seconds()) - + switch err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err { + case nil, syscall.ENOPROTOOPT: // OS X 10.7 and earlier don't support this option + default: + return os.NewSyscallError("setsockopt", err) + } return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs)) } diff --git a/src/net/tcpsockopt_dragonfly.go b/src/net/tcpsockopt_dragonfly.go index d10a77773d..0aa213239d 100644 --- a/src/net/tcpsockopt_dragonfly.go +++ b/src/net/tcpsockopt_dragonfly.go @@ -10,20 +10,17 @@ import ( "time" ) -// Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { if err := fd.incref(); err != nil { return err } defer fd.decref() - - // The kernel expects milliseconds so round to next highest millisecond. + // The kernel expects milliseconds so round to next highest + // millisecond. d += (time.Millisecond - time.Nanosecond) - msecs := int(time.Duration(d.Nanoseconds()) / time.Millisecond) - - err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs)) - if err != nil { - return err + msecs := int(d / time.Millisecond) + if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil { + return os.NewSyscallError("setsockopt", err) } return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs)) } diff --git a/src/net/tcpsockopt_solaris.go b/src/net/tcpsockopt_solaris.go deleted file mode 100644 index eaab6b6787..0000000000 --- a/src/net/tcpsockopt_solaris.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013 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. - -// TCP socket options for solaris - -package net - -import ( - "os" - "syscall" - "time" -) - -// Set keep alive period. -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - - // The kernel expects seconds so round to next highest second. - d += (time.Second - time.Nanosecond) - secs := int(d.Seconds()) - - return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs)) -} diff --git a/src/net/tcpsockopt_openbsd.go b/src/net/tcpsockopt_stub.go similarity index 66% rename from src/net/tcpsockopt_openbsd.go rename to src/net/tcpsockopt_stub.go index 1644343114..346293ca46 100644 --- a/src/net/tcpsockopt_openbsd.go +++ b/src/net/tcpsockopt_stub.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build nacl openbsd + package net import ( @@ -10,7 +12,7 @@ import ( ) func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // OpenBSD has no user-settable per-socket TCP keepalive - // options. - return syscall.EPROTONOSUPPORT + // NaCl and OpenBSD have no user-settable per-socket TCP + // keepalive options. + return syscall.ENOPROTOOPT } diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go index 2693a541d2..c9f604cad7 100644 --- a/src/net/tcpsockopt_unix.go +++ b/src/net/tcpsockopt_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build freebsd linux nacl netbsd +// +build freebsd linux netbsd solaris package net @@ -12,20 +12,16 @@ import ( "time" ) -// Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { if err := fd.incref(); err != nil { return err } defer fd.decref() - // The kernel expects seconds so round to next highest second. d += (time.Second - time.Nanosecond) secs := int(d.Seconds()) - - err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)) - if err != nil { - return err + if err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil { + return os.NewSyscallError("setsockopt", err) } return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs)) } diff --git a/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go index 8ef1407977..091f5233f2 100644 --- a/src/net/tcpsockopt_windows.go +++ b/src/net/tcpsockopt_windows.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TCP socket options for windows - package net import ( @@ -18,14 +16,14 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error { return err } defer fd.decref() - - // Windows expects milliseconds so round to next highest millisecond. + // The kernel expects milliseconds so round to next highest + // millisecond. d += (time.Millisecond - time.Nanosecond) - millis := uint32(d / time.Millisecond) + msecs := uint32(d / time.Millisecond) ka := syscall.TCPKeepalive{ OnOff: 1, - Time: millis, - Interval: millis, + Time: msecs, + Interval: msecs, } ret := uint32(0) size := uint32(unsafe.Sizeof(ka)) From 1d550b87dbbe711a1bf2e54e0ba065a27165d2c1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 11 Sep 2014 12:08:30 -0400 Subject: [PATCH 042/430] runtime: allow crash from gsignal stack The uses of onM in dopanic/startpanic are okay even from the signal stack. Fixes #8666. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/134710043 --- src/runtime/asm_386.s | 17 +++++++++++++++++ src/runtime/asm_amd64.s | 17 +++++++++++++++++ src/runtime/asm_amd64p32.s | 17 +++++++++++++++++ src/runtime/asm_arm.s | 15 +++++++++++++++ src/runtime/crash_test.go | 16 ++++++++++++++++ src/runtime/panic.go | 4 ++-- src/runtime/proc.c | 1 + src/runtime/runtime.h | 1 + src/runtime/stubs.go | 18 ++++++++++++++++++ 9 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 3e93025faf..062a668e3e 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -209,6 +209,23 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 TEXT runtime·switchtoM(SB), NOSPLIT, $0-4 RET +// func onM_signalok(fn func()) +TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4 + get_tls(CX) + MOVL g(CX), AX // AX = g + MOVL g_m(AX), BX // BX = m + MOVL m_gsignal(BX), DX // DX = gsignal + CMPL AX, DX + JEQ ongsignal + JMP runtime·onM(SB) + +ongsignal: + MOVL fn+0(FP), DI // DI = fn + MOVL DI, DX + MOVL 0(DI), DI + CALL DI + RET + // func onM(fn func()) TEXT runtime·onM(SB), NOSPLIT, $0-4 MOVL fn+0(FP), DI // DI = fn diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index e5702d074c..bf0f490ae3 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -200,6 +200,23 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8 TEXT runtime·switchtoM(SB), NOSPLIT, $0-8 RET +// func onM_signalok(fn func()) +TEXT runtime·onM_signalok(SB), NOSPLIT, $0-8 + get_tls(CX) + MOVQ g(CX), AX // AX = g + MOVQ g_m(AX), BX // BX = m + MOVQ m_gsignal(BX), DX // DX = gsignal + CMPQ AX, DX + JEQ ongsignal + JMP runtime·onM(SB) + +ongsignal: + MOVQ fn+0(FP), DI // DI = fn + MOVQ DI, DX + MOVQ 0(DI), DI + CALL DI + RET + // func onM(fn func()) TEXT runtime·onM(SB), NOSPLIT, $0-8 MOVQ fn+0(FP), DI // DI = fn diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 32276c8952..62fa4ff868 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -175,6 +175,23 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 TEXT runtime·switchtoM(SB), NOSPLIT, $0-4 RET +// func onM_signalok(fn func()) +TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4 + get_tls(CX) + MOVL g(CX), AX // AX = g + MOVL g_m(AX), BX // BX = m + MOVL m_gsignal(BX), DX // DX = gsignal + CMPL AX, DX + JEQ ongsignal + JMP runtime·onM(SB) + +ongsignal: + MOVL fn+0(FP), DI // DI = fn + MOVL DI, DX + MOVL 0(DI), DI + CALL DI + RET + // func onM(fn func()) TEXT runtime·onM(SB), NOSPLIT, $0-4 MOVL fn+0(FP), DI // DI = fn diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 73d23fce34..bddffc9e77 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -202,6 +202,21 @@ TEXT runtime·switchtoM(SB),NOSPLIT,$0-4 BL (R0) // clobber lr to ensure push {lr} is kept RET +// func onM_signalok(fn func()) +TEXT runtime·onM_signalok(SB), NOSPLIT, $-4-4 + MOVW g_m(g), R1 + MOVW m_gsignal(R1), R2 + CMP g, R2 + B.EQ ongsignal + B runtime·onM(SB) + +ongsignal: + MOVW fn+0(FP), R0 + MOVW R0, R7 + MOVW 0(R0), R0 + BL (R0) + RET + // func onM(fn func()) TEXT runtime·onM(SB),NOSPLIT,$0-4 MOVW fn+0(FP), R0 // R0 = fn diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index c61fa162f0..a86a3b7904 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -175,6 +175,14 @@ func TestMainGoroutineId(t *testing.T) { } } +func TestBreakpoint(t *testing.T) { + output := executeTest(t, breakpointSource, nil) + want := "runtime.Breakpoint()" + if !strings.Contains(output, want) { + t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want) + } +} + const crashSource = ` package main @@ -380,3 +388,11 @@ func main() { panic("test") } ` + +const breakpointSource = ` +package main +import "runtime" +func main() { + runtime.Breakpoint() +} +` diff --git a/src/runtime/panic.go b/src/runtime/panic.go index ac0a7541e8..017f5d4896 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -371,7 +371,7 @@ func gorecover(argp uintptr) interface{} { //go:nosplit func startpanic() { - onM(startpanic_m) + onM_signalok(startpanic_m) } //go:nosplit @@ -381,7 +381,7 @@ func dopanic(unused int) { mp.ptrarg[0] = unsafe.Pointer(gp) mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused)) mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused)) - onM(dopanic_m) // should never return + onM_signalok(dopanic_m) // should never return *(*int)(nil) = 0 } diff --git a/src/runtime/proc.c b/src/runtime/proc.c index e3f24a7e67..03deb7abb1 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2398,6 +2398,7 @@ gfpurge(P *p) runtime·unlock(&runtime·sched.gflock); } +#pragma textflag NOSPLIT void runtime·Breakpoint(void) { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index da9b2b7514..4f9656457d 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -823,6 +823,7 @@ int32 runtime·mcount(void); int32 runtime·gcount(void); void runtime·mcall(void(**)(G*)); void runtime·onM(void(**)(void)); +void runtime·onMsignal(void(**)(void)); uint32 runtime·fastrand1(void); void runtime·rewindmorestack(Gobuf*); int32 runtime·timediv(int64, int32, int32*); diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 8bae98c73d..45fc877e51 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -73,6 +73,24 @@ func mcall(fn func(*g)) //go:noescape func onM(fn func()) +// onMsignal is like onM but is allowed to be used in code that +// might run on the gsignal stack. Code running on a signal stack +// may be interrupting an onM sequence on the main stack, so +// if the onMsignal calling sequence writes to ptrarg/scalararg, +// it must first save the old values and then restore them when +// finished. As an exception to the rule, it is fine not to save and +// restore the values if the program is trying to crash rather than +// return from the signal handler. +// Once all the runtime is written in Go, there will be no ptrarg/scalararg +// and the distinction between onM and onMsignal (and perhaps mcall) +// can go away. +// +// If onMsignal is called from a gsignal stack, it invokes fn directly, +// without a stack switch. Otherwise onMsignal behaves like onM. +// +//go:noescape +func onM_signalok(fn func()) + func badonm() { gothrow("onM called from signal goroutine") } From fcb4cabba4efd78905939b7e0ceab2e9eb3c60a8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 11 Sep 2014 12:17:45 -0400 Subject: [PATCH 043/430] cmd/gc: emit write barriers A write *p = x that needs a write barrier (not all do) now turns into runtime.writebarrierptr(p, x) or one of the other variants. The write barrier implementations are trivial. The goal here is to emit the calls in the correct places and to incur the cost of those function calls in the Go 1.4 cycle. Performance on the Go 1 benchmark suite below. Remember, the goal is to slow things down (and be correct). We will look into optimizations in separate CLs, as part of the process of comparing Go 1.3 against tip in order to make sure Go 1.4 runs at least as fast as Go 1.3. benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 3118336716 3452876110 +10.73% BenchmarkFannkuch11 3184497677 3211552284 +0.85% BenchmarkFmtFprintfEmpty 89.9 107 +19.02% BenchmarkFmtFprintfString 236 287 +21.61% BenchmarkFmtFprintfInt 246 278 +13.01% BenchmarkFmtFprintfIntInt 395 458 +15.95% BenchmarkFmtFprintfPrefixedInt 343 378 +10.20% BenchmarkFmtFprintfFloat 477 525 +10.06% BenchmarkFmtManyArgs 1446 1707 +18.05% BenchmarkGobDecode 14398047 14685958 +2.00% BenchmarkGobEncode 12557718 12947104 +3.10% BenchmarkGzip 453462345 472413285 +4.18% BenchmarkGunzip 114226016 115127398 +0.79% BenchmarkHTTPClientServer 114689 112122 -2.24% BenchmarkJSONEncode 24914536 26135942 +4.90% BenchmarkJSONDecode 86832877 103620289 +19.33% BenchmarkMandelbrot200 4833452 4898780 +1.35% BenchmarkGoParse 4317976 4835474 +11.98% BenchmarkRegexpMatchEasy0_32 150 166 +10.67% BenchmarkRegexpMatchEasy0_1K 393 402 +2.29% BenchmarkRegexpMatchEasy1_32 125 142 +13.60% BenchmarkRegexpMatchEasy1_1K 1010 1236 +22.38% BenchmarkRegexpMatchMedium_32 232 301 +29.74% BenchmarkRegexpMatchMedium_1K 76963 102721 +33.47% BenchmarkRegexpMatchHard_32 3833 5463 +42.53% BenchmarkRegexpMatchHard_1K 119668 161614 +35.05% BenchmarkRevcomp 763449047 706768534 -7.42% BenchmarkTemplate 124954724 134834549 +7.91% BenchmarkTimeParse 517 511 -1.16% BenchmarkTimeFormat 501 514 +2.59% benchmark old MB/s new MB/s speedup BenchmarkGobDecode 53.31 52.26 0.98x BenchmarkGobEncode 61.12 59.28 0.97x BenchmarkGzip 42.79 41.08 0.96x BenchmarkGunzip 169.88 168.55 0.99x BenchmarkJSONEncode 77.89 74.25 0.95x BenchmarkJSONDecode 22.35 18.73 0.84x BenchmarkGoParse 13.41 11.98 0.89x BenchmarkRegexpMatchEasy0_32 213.30 191.72 0.90x BenchmarkRegexpMatchEasy0_1K 2603.92 2542.74 0.98x BenchmarkRegexpMatchEasy1_32 254.00 224.93 0.89x BenchmarkRegexpMatchEasy1_1K 1013.53 827.98 0.82x BenchmarkRegexpMatchMedium_32 4.30 3.31 0.77x BenchmarkRegexpMatchMedium_1K 13.30 9.97 0.75x BenchmarkRegexpMatchHard_32 8.35 5.86 0.70x BenchmarkRegexpMatchHard_1K 8.56 6.34 0.74x BenchmarkRevcomp 332.92 359.62 1.08x BenchmarkTemplate 15.53 14.39 0.93x LGTM=rlh R=rlh CC=dvyukov, golang-codereviews, iant, khr, r https://golang.org/cl/136380043 --- src/cmd/gc/builtin.c | 5 ++ src/cmd/gc/go.h | 3 + src/cmd/gc/lex.c | 2 + src/cmd/gc/order.c | 4 +- src/cmd/gc/runtime.go | 7 ++ src/cmd/gc/sinit.c | 18 +++-- src/cmd/gc/walk.c | 157 ++++++++++++++++++++++++++++++++++++++++-- src/runtime/mgc0.go | 33 +++++++++ test/live.go | 2 +- test/live2.go | 2 +- 10 files changed, 218 insertions(+), 15 deletions(-) diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 60b7c2f977..ee1ac1da42 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -83,6 +83,11 @@ char *runtimeimport = "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" "func @\"\".closechan (@\"\".hchan·1 any)\n" + "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 12c1e98539..8178f7272f 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -973,6 +973,7 @@ EXTERN int funcdepth; EXTERN int typecheckok; EXTERN int compiling_runtime; EXTERN int compiling_wrappers; +EXTERN int use_writebarrier; EXTERN int pure_go; EXTERN char* flag_installsuffix; EXTERN int flag_race; @@ -1284,6 +1285,7 @@ LSym* linksym(Sym*); * order.c */ void order(Node *fn); +void orderstmtinplace(Node **stmt); /* * range.c @@ -1464,6 +1466,7 @@ void walkstmt(Node **np); void walkstmtlist(NodeList *l); Node* conv(Node*, Type*); int candiscard(Node*); +int needwritebarrier(Node*, Node*); Node* outervalue(Node*); void usefield(Node*); diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index b8252a225e..6d83177477 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -312,6 +312,8 @@ main(int argc, char *argv[]) flagcount("u", "reject unsafe code", &safemode); flagcount("v", "increase debug verbosity", &debug['v']); flagcount("w", "debug type checking", &debug['w']); + use_writebarrier = 1; + flagcount("wb", "enable write barrier", &use_writebarrier); flagcount("x", "debug lexer", &debug['x']); flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']); if(thechar == '6') diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index d11e9828cb..9e64eb7759 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -317,7 +317,7 @@ orderexprinplace(Node **np, Order *outer) // Orderstmtinplace orders the side effects of the single statement *np // and replaces it with the resulting statement list. -static void +void orderstmtinplace(Node **np) { Node *n; @@ -451,7 +451,7 @@ ordermapassign(Node *n, Order *order) case OAS: order->out = list(order->out, n); - if(n->left->op == OINDEXMAP && !isaddrokay(n->right)) { + if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > widthptr)) && !isaddrokay(n->right)) { m = n->left; n->left = ordertemp(m->type, order, 0); a = nod(OAS, m, n->left); diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 128fd1a31c..fa927a58ac 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -107,6 +107,13 @@ func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool func chansend1(chanType *byte, hchan chan<- any, elem *any) func closechan(hchan any) +// *byte is really *runtime.Type +func writebarrierptr(dst *any, src any) +func writebarrierstring(dst *any, src any) +func writebarrierslice(dst *any, src any) +func writebarrieriface(dst *any, src any) +func writebarrierfat(typ *byte, dst *any, src *any) + func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 59804cd8d0..508747e5a0 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -633,11 +633,14 @@ structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init) a = nod(ODOT, var, newname(index->sym)); a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); if(pass == 1) { + walkexpr(&a, init); // add any assignments in r to top if(a->op != OAS) fatal("structlit: not as"); a->dodata = 2; + } else { + orderstmtinplace(&a); + walkstmt(&a); } *init = list(*init, a); } @@ -693,11 +696,14 @@ arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init) a = nod(OINDEX, var, index); a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); // add any assignments in r to top if(pass == 1) { + walkexpr(&a, init); if(a->op != OAS) - fatal("structlit: not as"); + fatal("arraylit: not as"); a->dodata = 2; + } else { + orderstmtinplace(&a); + walkstmt(&a); } *init = list(*init, a); } @@ -807,7 +813,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); - walkexpr(&a, init); + orderstmtinplace(&a); + walkstmt(&a); *init = list(*init, a); // put dynamics into slice (6) @@ -839,7 +846,8 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); - walkexpr(&a, init); + orderstmtinplace(&a); + walkstmt(&a); *init = list(*init, a); } } diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 5f24db2b0b..ce0f3eb955 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -8,6 +8,8 @@ #include "../ld/textflag.h" static Node* walkprint(Node*, NodeList**, int); +static Node* writebarrierfn(char*, Type*, Type*); +static Node* applywritebarrier(Node*, NodeList**); static Node* mapfn(char*, Type*); static Node* mapfndel(char*, Type*); static Node* ascompatee1(int, Node*, Node*, NodeList**); @@ -633,6 +635,7 @@ walkexpr(Node **np, NodeList **init) r = convas(nod(OAS, n->left, n->right), init); r->dodata = n->dodata; n = r; + n = applywritebarrier(n, init); } goto ret; @@ -644,6 +647,8 @@ walkexpr(Node **np, NodeList **init) walkexprlistsafe(n->rlist, init); ll = ascompatee(OAS, n->list, n->rlist, init); ll = reorder3(ll); + for(lr = ll; lr != nil; lr = lr->next) + lr->n = applywritebarrier(lr->n, init); n = liststmt(ll); goto ret; @@ -656,6 +661,8 @@ walkexpr(Node **np, NodeList **init) walkexpr(&r, init); ll = ascompatet(n->op, n->list, &r->type, 0, init); + for(lr = ll; lr != nil; lr = lr->next) + lr->n = applywritebarrier(lr->n, init); n = liststmt(concat(list1(r), ll)); goto ret; @@ -1481,8 +1488,13 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) static int fncall(Node *l, Type *rt) { + Node r; + if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; + r.op = 0; + if(needwritebarrier(l, &r)) + return 1; if(eqtype(l->type, rt)) return 0; return 1; @@ -1533,8 +1545,10 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) a = nod(OAS, l, nodarg(r, fp)); a = convas(a, init); ullmancalc(a); - if(a->ullman >= UINF) + if(a->ullman >= UINF) { + dump("ascompatet ucount", a); ucount++; + } nn = list(nn, a); r = structnext(&saver); } @@ -1932,6 +1946,127 @@ callnew(Type *t) return mkcall1(fn, ptrto(t), nil, typename(t)); } +static int +isstack(Node *n) +{ + while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type)) + n = n->left; + + switch(n->op) { + case OINDREG: + // OINDREG only ends up in walk if it's indirect of SP. + return 1; + + case ONAME: + switch(n->class) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + return 1; + } + break; + } + + return 0; +} + +static int +isglobal(Node *n) +{ + while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type)) + n = n->left; + + switch(n->op) { + case ONAME: + switch(n->class) { + case PEXTERN: + return 1; + } + break; + } + + return 0; +} + +// Do we need a write barrier for the assignment l = r? +int +needwritebarrier(Node *l, Node *r) +{ + if(!use_writebarrier) + return 0; + + if(l == N || isblank(l)) + return 0; + + // No write barrier for write of non-pointers. + dowidth(l->type); + if(!haspointers(l->type)) + return 0; + + // No write barrier for write to stack. + if(isstack(l)) + return 0; + + // No write barrier for zeroing. + if(r == N) + return 0; + + // No write barrier for initialization to constant. + if(r->op == OLITERAL) + return 0; + + // No write barrier for storing static (read-only) data. + if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0) + return 0; + + // No write barrier for storing address of stack values, + // which are guaranteed only to be written to the stack. + if(r->op == OADDR && isstack(r->left)) + return 0; + + // No write barrier for storing address of global, which + // is live no matter what. + if(r->op == OADDR && isglobal(r->left)) + return 0; + + // Otherwise, be conservative and use write barrier. + return 1; +} + +// TODO(rsc): Perhaps componentgen should run before this. +static Node* +applywritebarrier(Node *n, NodeList **init) +{ + Node *l, *r; + + if(n->left && n->right && needwritebarrier(n->left, n->right)) { + l = nod(OADDR, n->left, N); + l->etype = 1; // addr does not escape + if(n->left->type->width == widthptr) { + n = mkcall1(writebarrierfn("writebarrierptr", n->left->type, n->right->type), T, init, + l, n->right); + } else if(n->left->type->etype == TSTRING) { + n = mkcall1(writebarrierfn("writebarrierstring", n->left->type, n->right->type), T, init, + l, n->right); + } else if(isslice(n->left->type)) { + n = mkcall1(writebarrierfn("writebarrierslice", n->left->type, n->right->type), T, init, + l, n->right); + } else if(isinter(n->left->type)) { + n = mkcall1(writebarrierfn("writebarrieriface", n->left->type, n->right->type), T, init, + l, n->right); + } else { + r = n->right; + while(r->op == OCONVNOP) + r = r->left; + r = nod(OADDR, r, N); + r->etype = 1; // addr does not escape + n = mkcall1(writebarrierfn("writebarrierfat", n->left->type, r->left->type), T, init, + typename(n->left->type), l, r); + } + } + return n; +} + static Node* convas(Node *n, NodeList **init) { @@ -1971,11 +2106,10 @@ convas(Node *n, NodeList **init) goto out; } - if(eqtype(lt, rt)) - goto out; - - n->right = assignconv(n->right, lt, "assignment"); - walkexpr(&n->right, init); + if(!eqtype(lt, rt)) { + n->right = assignconv(n->right, lt, "assignment"); + walkexpr(&n->right, init); + } out: ullmancalc(n); @@ -2526,6 +2660,17 @@ mapfndel(char *name, Type *t) return fn; } +static Node* +writebarrierfn(char *name, Type *l, Type *r) +{ + Node *fn; + + fn = syslook(name, 1); + argtype(fn, l); + argtype(fn, r); + return fn; +} + static Node* addstr(Node *n, NodeList **init) { diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index ec5edb0244..5d6d91875f 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + // Called from C. Returns the Go type *m. func gc_m_ptr(ret *interface{}) { *ret = (*m)(nil) @@ -101,3 +103,34 @@ func bgsweep() { goparkunlock(&gclock, "GC sweep wait") } } + +// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer, +// but if we do that, Go inserts a write barrier on *dst = src. +//go:nosplit +func writebarrierptr(dst *uintptr, src uintptr) { + *dst = src +} + +//go:nosplit +func writebarrierstring(dst *[2]uintptr, src [2]uintptr) { + dst[0] = src[0] + dst[1] = src[1] +} + +//go:nosplit +func writebarrierslice(dst *[3]uintptr, src [3]uintptr) { + dst[0] = src[0] + dst[1] = src[1] + dst[2] = src[2] +} + +//go:nosplit +func writebarrieriface(dst *[2]uintptr, src [2]uintptr) { + dst[0] = src[0] + dst[1] = src[1] +} + +//go:nosplit +func writebarrierfat(typ *_type, dst, src unsafe.Pointer) { + memmove(dst, src, typ.size) +} diff --git a/test/live.go b/test/live.go index 35099d18ba..ad2db27fa9 100644 --- a/test/live.go +++ b/test/live.go @@ -1,4 +1,4 @@ -// errorcheck -0 -l -live +// errorcheck -0 -l -live -wb=0 // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/test/live2.go b/test/live2.go index 1e32794026..5762b2e289 100644 --- a/test/live2.go +++ b/test/live2.go @@ -1,4 +1,4 @@ -// errorcheck -0 -live +// errorcheck -0 -live -wb=0 // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style From 8cc6cb2f17d7fac3cd180b60ab85beabe874b24d Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 11 Sep 2014 12:47:17 -0700 Subject: [PATCH 044/430] test: return errors earlier in run.go Fixes #8184. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/137510043 --- test/run.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/run.go b/test/run.go index 483775d841..28882cf54c 100644 --- a/test/run.go +++ b/test/run.go @@ -626,6 +626,7 @@ func (t *test) run() { out, err := runcmd(append([]string{"go", "run", t.goFileName()}, args...)...) if err != nil { t.err = err + return } if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() { t.err = fmt.Errorf("incorrect output\n%s", out) @@ -640,6 +641,7 @@ func (t *test) run() { out, err := runcmd(append([]string{"go", "run", t.goFileName()}, args...)...) if err != nil { t.err = err + return } tfile := filepath.Join(t.tempDir, "tmp__.go") if err := ioutil.WriteFile(tfile, out, 0666); err != nil { @@ -649,6 +651,7 @@ func (t *test) run() { out, err = runcmd("go", "run", tfile) if err != nil { t.err = err + return } if string(out) != t.expectedOutput() { t.err = fmt.Errorf("incorrect output\n%s", out) @@ -659,6 +662,7 @@ func (t *test) run() { out, err := runcmd(append([]string{"go", "run", t.goFileName()}, args...)...) if err != nil { t.err = err + return } tfile := filepath.Join(t.tempDir, "tmp__.go") err = ioutil.WriteFile(tfile, out, 0666) From 724fa12f91959d083e6165079463f5502e5df835 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 11 Sep 2014 12:57:51 -0700 Subject: [PATCH 045/430] go/printer, gofmt: don't align map entries for irregular inputs Details: Until now, when we saw a key:value pair that fit onto a single line, we assumed that it should be formatted with a vtab after the ':' for alignment of its value. This leads to odd behavior if there are more than one such pair on a line. This CL changes the behavior such that alignment is only used for the first pair on a line. This preserves existing behavior (in the std lib we have composite literals where the last line contains multiple entries and the first entry's value is aligned with the values on previous lines), and resolves this issue. No impact on formatting of std lib, go.tools, go.exp, go.net. Fixes #8685. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/139430043 --- src/go/printer/nodes.go | 16 ++++++++----- src/go/printer/testdata/declarations.golden | 25 ++++++++++++++++++++- src/go/printer/testdata/declarations.input | 25 +++++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index 6e26f9a636..e52236ddc6 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -163,8 +163,8 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp size := 0 // print all list elements + prevLine := prev.Line for i, x := range list { - prevLine := line line = p.lineFor(x.Pos()) // determine if the next linebreak, if any, needs to use formfeed: @@ -207,8 +207,8 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } } + needsLinebreak := 0 < prevLine && prevLine < line if i > 0 { - needsLinebreak := prevLine < line && prevLine > 0 && line > 0 // use position of expression following the comma as // comma position for correct comment placement, but // only if the expression is on the same line @@ -232,16 +232,20 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } } - if isPair && size > 0 && len(list) > 1 { - // we have a key:value expression that fits onto one line and - // is in a list with more then one entry: use a column for the - // key such that consecutive entries can align if possible + if len(list) > 1 && isPair && size > 0 && needsLinebreak { + // we have a key:value expression that fits onto one line + // and it's not on the same line as the prior expression: + // use a column for the key such that consecutive entries + // can align if possible + // (needsLinebreak is set if we started a new line before) p.expr(pair.Key) p.print(pair.Colon, token.COLON, vtab) p.expr(pair.Value) } else { p.expr0(x, depth) } + + prevLine = line } if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line { diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden index a27f21fc8c..9acd41b7d2 100644 --- a/src/go/printer/testdata/declarations.golden +++ b/src/go/printer/testdata/declarations.golden @@ -593,7 +593,7 @@ var ( ) func _() { - var privateKey2 = &Block{Type: "RSA PRIVATE KEY", + var privateKey2 = &Block{Type: "RSA PRIVATE KEY", Headers: map[string]string{}, Bytes: []uint8{0x30, 0x82, 0x1, 0x3a, 0x2, 0x1, 0x0, 0x2, 0x41, 0x0, 0xb2, 0x99, 0xf, 0x49, 0xc4, 0x7d, 0xfa, 0x8c, @@ -698,6 +698,29 @@ var _ = T4{ c: z, } +// no alignment of map composite entries if they are not the first entry on a line +var _ = T{0: 0} // not aligned +var _ = T{0: 0, // not aligned + 1: 1, // aligned + 22: 22, // aligned + 333: 333, 1234: 12, 12345: 0, // first on line aligned +} + +// test cases form issue 8685 +// not aligned +var _ = map[int]string{1: "spring", 2: "summer", + 3: "autumn", 4: "winter"} + +// not aligned +var _ = map[string]string{"a": "spring", "b": "summer", + "c": "autumn", "d": "winter"} + +// aligned +var _ = map[string]string{"a": "spring", + "b": "summer", + "c": "autumn", + "d": "winter"} + func _() { var _ = T{ a, // must introduce trailing comma diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input index d9951d3865..45beec25fc 100644 --- a/src/go/printer/testdata/declarations.input +++ b/src/go/printer/testdata/declarations.input @@ -715,6 +715,31 @@ var _ = T4{ } +// no alignment of map composite entries if they are not the first entry on a line +var _ = T{0: 0} // not aligned +var _ = T{0: 0, // not aligned + 1: 1, // aligned + 22: 22, // aligned + 333: 333, 1234: 12, 12345: 0, // first on line aligned +} + + +// test cases form issue 8685 +// not aligned +var _ = map[int]string{1: "spring", 2: "summer", + 3: "autumn", 4: "winter"} + +// not aligned +var _ = map[string]string{"a": "spring", "b": "summer", + "c": "autumn", "d": "winter"} + +// aligned +var _ = map[string]string{"a": "spring", +"b": "summer", + "c": "autumn", +"d": "winter"} + + func _() { var _ = T{ a, // must introduce trailing comma From 15a5c35cec35c09d276b0429b719a0f2cbb29189 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 11 Sep 2014 16:22:21 -0400 Subject: [PATCH 046/430] runtime: move gosched to Go, to add stack frame information LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/134520044 --- src/runtime/malloc.go | 2 +- src/runtime/mgc0.go | 2 +- src/runtime/proc.c | 13 +------------ src/runtime/runtime.h | 1 - src/runtime/stubs.go | 1 - 5 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 890ddea6d5..d6f1a1a4a2 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -477,7 +477,7 @@ func gogc(force int32) { // now that gc is done, kick off finalizer thread if needed if !concurrentSweep { // give the queued finalizers, if any, a chance to run - gosched() + Gosched() } } diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 5d6d91875f..130e8262ad 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -89,7 +89,7 @@ func bgsweep() { for { for gosweepone() != ^uintptr(0) { sweep.nbgsweep++ - gosched() + Gosched() } lock(&gclock) if !gosweepdone() { diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 03deb7abb1..004d93a973 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -1677,18 +1677,7 @@ runtime·park_m(G *gp) schedule(); } -// Scheduler yield. -#pragma textflag NOSPLIT -void -runtime·gosched(void) -{ - void (*fn)(G*); - - fn = runtime·gosched_m; - runtime·mcall(&fn); -} - -// runtime·gosched continuation on g0. +// Gosched continuation on g0. void runtime·gosched_m(G *gp) { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4f9656457d..01923c61e0 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -852,7 +852,6 @@ void runtime·setg(G*); void runtime·newextram(void); void runtime·exit(int32); void runtime·breakpoint(void); -void runtime·gosched(void); void runtime·gosched_m(G*); void runtime·schedtrace(bool); void runtime·park(bool(*)(G*, void*), void*, String); diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 45fc877e51..ff443c4cd4 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -130,7 +130,6 @@ func memclr(ptr unsafe.Pointer, n uintptr) //go:noescape func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) -func gosched() func starttheworld() func stoptheworld() func newextram() From 91baf5c65d50a1fd33097d2610e32d575d054e6f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 11 Sep 2014 16:33:01 -0400 Subject: [PATCH 047/430] runtime: make Gosched nosplit Replacing gosched with Gosched broke some builds because some of the call sites are at times when the stack cannot be grown. TBR=khr CC=golang-codereviews https://golang.org/cl/142000043 --- src/runtime/proc.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 27e84230a1..4e3d2855f6 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -104,6 +104,8 @@ func forcegchelper() { } } +//go:nosplit + // Gosched yields the processor, allowing other goroutines to run. It does not // suspend the current goroutine, so execution resumes automatically. func Gosched() { From 00365b13b45a7a0cbfd0752c44ef84dc4961ce76 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 11 Sep 2014 13:46:58 -0700 Subject: [PATCH 048/430] runtime: get rid of copyable check - all G frames are copyable. Just go ahead and do it, if something is wrong we'll throw. Also rip out cc-generated arg ptr maps, they are useless now. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/133690045 --- src/cmd/cc/bv.c | 45 ----------- src/cmd/cc/cc.h | 6 -- src/cmd/cc/pgen.c | 163 -------------------------------------- src/runtime/stack.c | 187 ++++++++------------------------------------ 4 files changed, 31 insertions(+), 370 deletions(-) delete mode 100644 src/cmd/cc/bv.c diff --git a/src/cmd/cc/bv.c b/src/cmd/cc/bv.c deleted file mode 100644 index db433de6a7..0000000000 --- a/src/cmd/cc/bv.c +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 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. - -#include -#include "cc.h" - -enum { - WORDSIZE = sizeof(uint32), - WORDBITS = 32, -}; - -uintptr -bvsize(uintptr n) -{ - return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE; -} - -Bvec* -bvalloc(int32 n) -{ - Bvec *bv; - uintptr nbytes; - - if(n < 0) - fatal(Z, "bvalloc: initial size is negative\n"); - nbytes = sizeof(Bvec) + bvsize(n); - bv = malloc(nbytes); - if(bv == nil) - fatal(Z, "bvalloc: malloc failed\n"); - memset(bv, 0, nbytes); - bv->n = n; - return bv; -} - -void -bvset(Bvec *bv, int32 i) -{ - uint32 mask; - - if(i < 0 || i >= bv->n) - fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1UL << (i % WORDBITS); - bv->b[i / WORDBITS] |= mask; -} diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index 1dae5acd90..9530f5cf66 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -761,12 +761,6 @@ Bits blsh(uint); int beq(Bits, Bits); int bset(Bits, uint); -/* - * bv.c - */ -Bvec* bvalloc(int32 n); -void bvset(Bvec *bv, int32 i); - /* * dpchk.c */ diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 4265b1b5ee..db9aae916c 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -31,30 +31,6 @@ #include "gc.h" #include "../../runtime/funcdata.h" -enum { BitsPerPointer = 2 }; - -static void dumpgcargs(Type *fn, Sym *sym); - -static Sym* -makefuncdatasym(char *namefmt, int64 funcdatakind) -{ - Node nod; - Sym *sym; - static int32 nsym; - static char namebuf[40]; - - snprint(namebuf, sizeof(namebuf), namefmt, nsym++); - sym = slookup(namebuf); - sym->class = CSTATIC; - memset(&nod, 0, sizeof nod); - nod.op = ONAME; - nod.sym = sym; - nod.class = CSTATIC; - gins(AFUNCDATA, nodconst(funcdatakind), &nod); - linksym(sym)->type = SRODATA; - return sym; -} - int hasdotdotdot(Type *t) { @@ -109,9 +85,6 @@ codgen(Node *n, Node *nn) { Prog *sp; Node *n1, nod, nod1; - Sym *gcargs; - Sym *gclocals; - int isvarargs; cursafe = 0; curarg = 0; @@ -134,16 +107,6 @@ codgen(Node *n, Node *nn) p->from.sym->cfunc = 1; sp = p; - /* - * generate funcdata symbol for this function. - * data is filled in at the end of codgen(). - */ - isvarargs = hasdotdotdot(thisfn); - gcargs = nil; - if(!isvarargs) - gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); - gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); - /* * isolate first argument */ @@ -178,22 +141,6 @@ codgen(Node *n, Node *nn) if(thechar=='6' || thechar=='7') /* [sic] */ maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; - - if(!isvarargs) - dumpgcargs(thisfn, gcargs); - - // TODO(rsc): "stkoff" is not right. It does not account for - // the possibility of data stored in .safe variables. - // Unfortunately those move up and down just like - // the argument frame (and in fact dovetail with it) - // so the number we need is not available or even - // well-defined. Probably we need to make the safe - // area its own section. - // That said, we've been using stkoff for months - // and nothing too terrible has happened. - gextern(gclocals, nodconst(-stkoff), 0, 4); // locals - gclocals->type = typ(0, T); - gclocals->type->width = 4; } void @@ -673,113 +620,3 @@ bcomplex(Node *n, Node *c) boolgen(n, 1, Z); return 0; } - -// Updates the bitvector with a set bit for each pointer containing -// value in the type description starting at offset. -static void -walktype1(Type *t, int32 offset, Bvec *bv, int param) -{ - Type *t1; - int32 o; - int32 widthptr; - - widthptr = ewidth[TIND]; - switch(t->etype) { - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TFLOAT: - case TDOUBLE: - // non-pointer types - for(o = 0; o < t->width; o++) - bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar - break; - - case TIND: - pointer: - // pointer types - if((offset + t->offset) % widthptr != 0) - yyerror("unaligned pointer"); - bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr - break; - - case TARRAY: - if(param) // unlike Go, C passes arrays by reference - goto pointer; - // array in struct or union is an actual array - for(o = 0; o < t->width; o += t->link->width) - walktype1(t->link, offset+o, bv, 0); - break; - - case TSTRUCT: - // build map recursively - for(t1 = t->link; t1 != T; t1 = t1->down) - walktype1(t1, offset, bv, 0); - break; - - case TUNION: - walktype1(t->link, offset, bv, 0); - break; - - default: - yyerror("can't handle arg type %s\n", tnames[t->etype]); - } -} - -// Compute a bit vector to describe the pointer containing locations -// in the argument list. Adds the data to gcsym and returns the offset -// of end of the bit vector. -static void -dumpgcargs(Type *fn, Sym *sym) -{ - Bvec *bv; - Type *t; - int32 i; - int32 argbytes; - int32 symoffset, argoffset; - - // Dump the length of the bitmap array. This value is always one for - // functions written in C. - symoffset = 0; - gextern(sym, nodconst(1), symoffset, 4); - symoffset += 4; - argbytes = (argsize(1) + ewidth[TIND] - 1); - bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); - argoffset = 0; - if(hasdotdotdot(thisfn)) - argoffset = align(0, fn->link, Aarg0, nil); - if(argoffset > 0) { - // The C calling convention returns structs by copying them to a - // location pointed to by a hidden first argument. This first - // argument is a pointer. - if(argoffset != ewidth[TIND]) - yyerror("passbyptr arg not the right size"); - bvset(bv, 1); // 2 = live ptr - } - for(t = fn->down; t != T; t = t->down) { - if(t->etype == TVOID) - continue; - argoffset = align(argoffset, t, Aarg1, nil); - walktype1(t, argoffset, bv, 1); - argoffset = align(argoffset, t, Aarg2, nil); - } - // Dump the length of the bitmap. - gextern(sym, nodconst(bv->n), symoffset, 4); - symoffset += 4; - // Dump the words of the bitmap. - for(i = 0; i < bv->n; i += 32) { - gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); - symoffset += 4; - } - free(bv); - // Finalize the gc symbol. - sym->type = typ(0, T); - sym->type->width = symoffset; -} diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 2e0c91de08..cc2857ac81 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -331,145 +331,22 @@ mapnames[] = { // | args to callee | // +------------------+ <- frame->sp // -// (arm: TODO) - -typedef struct CopyableInfo CopyableInfo; -struct CopyableInfo { - Stack stk; - int32 frames; // count of copyable frames (-1 = not copyable) -}; +// (arm) +// +------------------+ +// | args from caller | +// +------------------+ <- frame->argp +// | caller's retaddr | +// +------------------+ <- frame->varp +// | locals | +// +------------------+ +// | args to callee | +// +------------------+ +// | return address | +// +------------------+ <- frame->sp void runtime·main(void); void runtime·switchtoM(void(*)(void)); -static bool -checkframecopy(Stkframe *frame, void *arg) -{ - CopyableInfo *cinfo; - Func *f; - StackMap *stackmap; - - cinfo = arg; - f = frame->fn; - if(StackDebug >= 2) - runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk.lo, cinfo->stk.hi); - // if we're not in the segment any more, return immediately. - if(frame->varp < cinfo->stk.lo || frame->varp >= cinfo->stk.hi) { - if(StackDebug >= 2) - runtime·printf(" \n"); - return false; // stop traceback - } - if(f->entry == (uintptr)runtime·switchtoM) { - // A special routine at the bottom of stack of a goroutine that does onM call. - // We will allow it to be copied even though we don't - // have full GC info for it (because it is written in asm). - cinfo->frames++; - return true; - } - if((byte*)frame->varp != (byte*)frame->sp) { // not in prologue (and has at least one local or outarg) - stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - if(stackmap == nil) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f)); - return false; - } - if(stackmap->n <= 0) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f)); - return false; - } - } - if(frame->arglen != 0) { - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f)); - return false; - } - } - cinfo->frames++; - return true; // this frame is ok; keep going -} - -// If the top segment of the stack contains an uncopyable -// frame, return -1. Otherwise return the number of frames -// in the top segment, all of which are copyable. -static int32 -copyabletopsegment(G *gp) -{ - CopyableInfo cinfo; - Defer *d; - Func *f; - FuncVal *fn; - StackMap *stackmap; - bool (*cb)(Stkframe*, void*); - - if(gp->stack.lo == 0) - runtime·throw("missing stack in copyabletopsegment"); - cinfo.stk = gp->stack; - cinfo.frames = 0; - - // Check that each frame is copyable. As a side effect, - // count the frames. - cb = checkframecopy; - runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &cinfo, false); - if(StackDebug >= 1 && cinfo.frames != -1) - runtime·printf("copystack: %d copyable frames\n", cinfo.frames); - - if(cinfo.frames == -1) - return -1; - - // Check to make sure all Defers are copyable - for(d = gp->defer; d != nil; d = d->link) { - if(cinfo.stk.lo <= (uintptr)d && (uintptr)d < cinfo.stk.hi) { - // Defer is on the stack. Its copyableness has - // been established during stack walking. - // For now, this only happens with the Defer in runtime.main. - continue; - } - if(d->argp < cinfo.stk.lo || cinfo.stk.hi <= d->argp) - break; // a defer for the next segment - fn = d->fn; - if(fn == nil) // See issue 8047 - continue; - f = runtime·findfunc((uintptr)fn->fn); - if(f == nil) { - runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn); - return -1; - } - - // Check to make sure we have an args pointer map for the defer's args. - // We only need the args map, but we check - // for the locals map also, because when the locals map - // isn't provided it means the ptr map came from C and - // C (particularly, cgo) lies to us. See issue 7695. - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil || stackmap->n <= 0) { - runtime·printf("runtime: copystack: no arg info for deferred %s\n", runtime·funcname(f)); - return -1; - } - stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - if(stackmap == nil || stackmap->n <= 0) { - runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f)); - return -1; - } - - if(cinfo.stk.lo <= (uintptr)fn && (uintptr)fn < cinfo.stk.hi) { - // FuncVal is on the stack. Again, its copyableness - // was established during stack walking. - continue; - } - // The FuncVal may have pointers in it, but fortunately for us - // the compiler won't put pointers into the stack in a - // heap-allocated FuncVal. - // One day if we do need to check this, we'll need maps of the - // pointerness of the closure args. The only place we have that map - // right now is in the gc program for the FuncVal. Ugh. - } - - return cinfo.frames; -} - typedef struct AdjustInfo AdjustInfo; struct AdjustInfo { Stack old; @@ -573,8 +450,12 @@ adjustframe(Stkframe *frame, void *arg) f = frame->fn; if(StackDebug >= 2) runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); - if(f->entry == (uintptr)runtime·switchtoM) + if(f->entry == (uintptr)runtime·switchtoM) { + // A special routine at the bottom of stack of a goroutine that does an onM call. + // We will allow it to be copied even though we don't + // have full GC info for it (because it is written in asm). return true; + } targetpc = frame->continpc; if(targetpc == 0) { // Frame is dead. @@ -648,11 +529,10 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) runtime·printf("runtime: adjustdefers argp=%p stk=%p %p\n", d->argp, adjinfo->old.lo, adjinfo->old.hi); runtime·throw("adjustdefers: unexpected argp"); } + d->argp += adjinfo->delta; fn = d->fn; if(fn == nil) { - // Defer of nil function. It will panic when run, and there - // aren't any args to adjust. See issue 8047. - d->argp += adjinfo->delta; + // Defer of nil function. It will panic when run. See issue 8047. continue; } f = runtime·findfunc((uintptr)fn->fn); @@ -675,7 +555,11 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) bv = runtime·stackmapdata(stackmap, 0); adjustpointers(d->args, &bv, adjinfo, f); } - d->argp += adjinfo->delta; + // The FuncVal may have pointers in it, but fortunately for us + // the compiler won't put pointers into the stack in a + // heap-allocated FuncVal. + // One day if we do need to check this, we can use the gc bits in the + // heap to do the right thing (although getting the size will be expensive). } } @@ -707,10 +591,9 @@ adjustsudogs(G *gp, AdjustInfo *adjinfo) } } -// Copies the top stack segment of gp to a new stack segment of a -// different size. The top segment must contain nframes frames. +// Copies gp's stack to a new stack of a different size. static void -copystack(G *gp, uintptr nframes, uintptr newsize) +copystack(G *gp, uintptr newsize) { Stack old, new; uintptr used; @@ -735,7 +618,7 @@ copystack(G *gp, uintptr nframes, uintptr newsize) adjinfo.old = old; adjinfo.delta = new.hi - old.hi; cb = adjustframe; - runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, &cb, &adjinfo, false); + runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, false); // adjust other miscellaneous things that have pointers into stacks. adjustctxt(gp, &adjinfo); @@ -785,7 +668,7 @@ runtime·round2(int32 x) void runtime·newstack(void) { - int32 oldsize, newsize, nframes; + int32 oldsize, newsize; uintptr sp; G *gp; Gobuf morebuf; @@ -867,10 +750,6 @@ runtime·newstack(void) } // Allocate a bigger segment and move the stack. - nframes = copyabletopsegment(gp); - if(nframes == -1) - runtime·throw("unable to grow stack"); - oldsize = gp->stack.hi - gp->stack.lo; newsize = oldsize * 2; if(newsize > runtime·maxstacksize) { @@ -880,7 +759,7 @@ runtime·newstack(void) // Note that the concurrent GC might be scanning the stack as we try to replace it. // copystack takes care of the appropriate coordination with the stack scanner. - copystack(gp, nframes, newsize); + copystack(gp, newsize); if(StackDebug >= 1) runtime·printf("stack grow done\n"); runtime·casgstatus(gp, Gwaiting, Grunning); @@ -913,14 +792,13 @@ runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv) void runtime·shrinkstack(G *gp) { - int32 nframes; uintptr used, oldsize, newsize; if(runtime·readgstatus(gp) == Gdead) return; if(gp->stack.lo == 0) runtime·throw("missing stack in shrinkstack"); - //return; // TODO: why does this happen? + oldsize = gp->stack.hi - gp->stack.lo; newsize = oldsize / 2; if(newsize < FixedStack) @@ -938,10 +816,7 @@ runtime·shrinkstack(G *gp) #endif if(StackDebug > 0) runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize); - nframes = copyabletopsegment(gp); - if(nframes == -1) - return; - copystack(gp, nframes, newsize); + copystack(gp, newsize); } static void badc(void); From 6e55f7a87b8400073119612c0a3bd3f443b69f14 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 12 Sep 2014 09:15:58 +1000 Subject: [PATCH 049/430] doc: link directly to https://golang.org/dl/ Fixes #8705. LGTM=adg R=golang-codereviews, bradfitz, adg CC=golang-codereviews https://golang.org/cl/142890044 --- doc/go1.html | 2 +- doc/install.html | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/doc/go1.html b/doc/go1.html index 5cf5df9296..1665d74e95 100644 --- a/doc/go1.html +++ b/doc/go1.html @@ -2035,4 +2035,4 @@ They are available for many combinations of architecture and operating system Installation details are described on the Getting Started page, while the distributions themselves are listed on the -downloads page. +downloads page. diff --git a/doc/install.html b/doc/install.html index ae7a212655..d6984c2447 100644 --- a/doc/install.html +++ b/doc/install.html @@ -6,14 +6,14 @@

Download the Go distribution

- + Download Go Click here to visit the downloads page

-Official binary +Official binary distributions are available for the FreeBSD (release 8 and above), Linux, Mac OS X (Snow Leopard and above), and Windows operating systems and the 32-bit (386) and 64-bit (amd64) x86 processor architectures. @@ -70,7 +70,7 @@ first remove the existing version.

Linux, Mac OS X, and FreeBSD tarballs

-Download the archive +Download the archive and extract it into /usr/local, creating a Go tree in /usr/local/go. For example:

@@ -127,7 +127,7 @@ location.

Mac OS X package installer

-Download the package file, +Download the package file, open it, and follow the prompts to install the Go tools. The package installs the Go distribution to /usr/local/go.

@@ -150,7 +150,7 @@ MSI installer that configures your installation automatically.

MSI installer

-Open the MSI file +Open the MSI file and follow the prompts to install the Go tools. By default, the installer puts the Go distribution in c:\Go.

@@ -164,7 +164,7 @@ command prompts for the change to take effect.

Zip archive

-Download the zip file and extract it into the directory of your choice (we suggest c:\Go). +Download the zip file and extract it into the directory of your choice (we suggest c:\Go).

@@ -270,5 +270,3 @@ The official mailing list for discussion of the Go language is Report bugs using the Go issue tracker.

- - From bcd36e8857729f6f3306ab22c26e582f1d2f2932 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 11 Sep 2014 16:53:34 -0700 Subject: [PATCH 050/430] runtime: make gostringnocopy update maxstring Fixes #8706 LGTM=josharian R=josharian CC=golang-codereviews https://golang.org/cl/143880043 --- src/runtime/export_test.go | 3 +++ src/runtime/string.c | 7 ++++++- src/runtime/string_test.go | 13 +++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 1f1b5fc794..be352557fb 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -160,3 +160,6 @@ func GostringW(w []uint16) (s string) { }) return } + +var Gostringnocopy = gostringnocopy +var Maxstring = &maxstring diff --git a/src/runtime/string.c b/src/runtime/string.c index 811a289060..ed5debc33e 100644 --- a/src/runtime/string.c +++ b/src/runtime/string.c @@ -42,10 +42,15 @@ String runtime·gostringnocopy(byte *str) { String s; + uintptr ms; s.str = str; s.len = runtime·findnull(str); - return s; + while(true) { + ms = runtime·maxstring; + if(s.len <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)s.len)) + return s; + } } // TODO: move this elsewhere diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go index e7ac51a5f0..1551ecc82b 100644 --- a/src/runtime/string_test.go +++ b/src/runtime/string_test.go @@ -145,3 +145,16 @@ func main() { panic(s) } ` + +func TestGostringnocopy(t *testing.T) { + max := *runtime.Maxstring + b := make([]byte, max+10) + for i := uintptr(0); i < max+9; i++ { + b[i] = 'a' + } + _ = runtime.Gostringnocopy(&b[0]) + newmax := *runtime.Maxstring + if newmax != max+9 { + t.Errorf("want %d, got %d", max+9, newmax) + } +} From df1c2310f3ff93fd8c1c000ea44e80f960555286 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 11 Sep 2014 18:35:25 -0700 Subject: [PATCH 051/430] A+C: Michael MacInnis (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/140570043 --- AUTHORS | 3 ++- CONTRIBUTORS | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 2c3d945b1a..3f682cde69 100644 --- a/AUTHORS +++ b/AUTHORS @@ -189,7 +189,6 @@ Hong Ruiqi Icarus Sparry Ingo Oeser Isaac Wagner -JT Olds Jakob Borg Jakub Ryszard Czarnowicz James David Chalfant @@ -237,6 +236,7 @@ Josh Bleecher Snyder Josh Goebel Josh Holland Joshua Chase +JT Olds Jukka-Pekka Kekkonen Julian Phillips Julien Schmidt @@ -291,6 +291,7 @@ Michael Fraenkel Michael Gehring Michael Hoisie Michael Lewis +Michael MacInnis Michael Pearson Michael Stapelberg Michael Teichgräber diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b20cf055af..a5b4ff843b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -267,7 +267,6 @@ Icarus Sparry Ingo Oeser Isaac Wagner Ivan Krasin -JT Olds Jacob Baskin Jakob Borg Jakub Ryszard Czarnowicz @@ -338,6 +337,7 @@ Josh Hoak Josh Holland Joshua Chase JP Sugarbroad +JT Olds Jukka-Pekka Kekkonen Julian Phillips Julien Schmidt @@ -410,6 +410,7 @@ Michael Hoisie Michael Hudson-Doyle Michael Kelly Michael Lewis +Michael MacInnis Michael Matloob Michael Pearson Michael Piatek From aa168ed2cd0614afa7503e3b0eb2b1e38b43384a Mon Sep 17 00:00:00 2001 From: Michael MacInnis Date: Thu, 11 Sep 2014 18:39:51 -0700 Subject: [PATCH 052/430] syscall: SysProcAttr job control changes Making the child's process group the foreground process group and placing the child in a specific process group involves co-ordination between the parent and child that must be done post-fork but pre-exec. LGTM=iant R=golang-codereviews, gobot, iant, mikioh.mikioh CC=golang-codereviews https://golang.org/cl/131750044 --- src/syscall/exec_bsd.go | 40 +++++++++++++++++++++++++++++++++++++-- src/syscall/exec_linux.go | 40 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go index ff78f197f1..7c2c1f7071 100644 --- a/src/syscall/exec_bsd.go +++ b/src/syscall/exec_bsd.go @@ -19,6 +19,8 @@ type SysProcAttr struct { Setpgid bool // Set process group ID to new pid (SYSV setpgrp) Setctty bool // Set controlling terminal to fd 0 Noctty bool // Detach fd 0 from controlling terminal + Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) + Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) } // Implemented in runtime package. @@ -79,7 +81,22 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if r1 != 0 { // parent; return PID runtime_AfterFork() - return int(r1), 0 + pid = int(r1) + + if sys.Joinpgrp != 0 { + // Place the child in the specified process group. + RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) + } else if sys.Foreground || sys.Setpgid { + // Place the child in a new process group. + RawSyscall(SYS_SETPGID, 0, 0, 0) + + if sys.Foreground { + // Set new foreground process group. + RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) + } + } + + return pid, 0 } // Fork succeeded, now in child. @@ -101,11 +118,30 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Setpgid { + if sys.Joinpgrp != 0 { + // Place the child in the specified process group. + _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) + if err1 != 0 { + goto childerror + } + } else if sys.Foreground || sys.Setpgid { + // Place the child in a new process group. _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } + + if sys.Foreground { + r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) + + pid := int(r1) + + // Set new foreground process group. + _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) + if err1 != 0 { + goto childerror + } + } } // Chroot diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index f27950f730..f61dfc424a 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -21,6 +21,8 @@ type SysProcAttr struct { Ctty int // Controlling TTY fd (Linux only) Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) + Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) + Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) } // Implemented in runtime package. @@ -71,7 +73,22 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if r1 != 0 { // parent; return PID runtime_AfterFork() - return int(r1), 0 + pid = int(r1) + + if sys.Joinpgrp != 0 { + // Place the child in the specified process group. + RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) + } else if sys.Foreground || sys.Setpgid { + // Place the child in a new process group. + RawSyscall(SYS_SETPGID, 0, 0, 0) + + if sys.Foreground { + // Set new foreground process group. + RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) + } + } + + return pid, 0 } // Fork succeeded, now in child. @@ -113,11 +130,30 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Setpgid { + if sys.Joinpgrp != 0 { + // Place the child in the specified process group. + _, _, err1 = RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) + if err1 != 0 { + goto childerror + } + } else if sys.Foreground || sys.Setpgid { + // Place the child in a new process group. _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) if err1 != 0 { goto childerror } + + if sys.Foreground { + r1, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0) + + pid := int(r1) + + // Set new foreground process group. + _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(Stdin), TIOCSPGRP, uintptr(unsafe.Pointer(&pid))) + if err1 != 0 { + goto childerror + } + } } // Chroot From 47f251c1cede13dba3e478b2528fb89eede1b566 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 11 Sep 2014 20:36:23 -0700 Subject: [PATCH 053/430] runtime: fix cgo to handle the case where the G stack is copied. Tests will come in a separate CL after the funcdata stuff is resolved. Update #8696 LGTM=iant, rsc R=rsc, iant CC=golang-codereviews https://golang.org/cl/138330045 --- src/runtime/asm_386.s | 8 ++++++-- src/runtime/asm_amd64.s | 8 ++++++-- src/runtime/asm_arm.s | 9 +++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 062a668e3e..37ad092414 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -684,15 +684,19 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-12 SUBL $32, SP ANDL $~15, SP // alignment, perhaps unnecessary MOVL DI, 8(SP) // save g - MOVL DX, 4(SP) // save SP + MOVL (g_stack+stack_hi)(DI), DI + SUBL DX, DI + MOVL DI, 4(SP) // save depth in stack (can't just save SP, as stack might be copied during a callback) MOVL BX, 0(SP) // first argument in x86-32 ABI CALL AX // Restore registers, g, stack pointer. get_tls(CX) MOVL 8(SP), DI + MOVL (g_stack+stack_hi)(DI), SI + SUBL 4(SP), SI MOVL DI, g(CX) - MOVL 4(SP), SP + MOVL SI, SP RET // cgocallback(void (*fn)(void*), void *frame, uintptr framesize) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index bf0f490ae3..241d5feebf 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -670,7 +670,9 @@ nosave: SUBQ $64, SP ANDQ $~15, SP // alignment for gcc ABI MOVQ DI, 48(SP) // save g - MOVQ DX, 40(SP) // save SP + MOVQ (g_stack+stack_hi)(DI), DI + SUBQ DX, DI + MOVQ DI, 40(SP) // save depth in stack (can't just save SP, as stack might be copied during a callback) MOVQ BX, DI // DI = first argument in AMD64 ABI MOVQ BX, CX // CX = first argument in Win64 CALL AX @@ -678,8 +680,10 @@ nosave: // Restore registers, g, stack pointer. get_tls(CX) MOVQ 48(SP), DI + MOVQ (g_stack+stack_hi)(DI), SI + SUBQ 40(SP), SI MOVQ DI, g(CX) - MOVQ 40(SP), SP + MOVQ SI, SP RET // cgocallback(void (*fn)(void*), void *frame, uintptr framesize) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index bddffc9e77..a4524f919b 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -520,15 +520,20 @@ asmcgocall_g0: SUB $24, R13 BIC $0x7, R13 // alignment for gcc ABI MOVW R4, 20(R13) // save old g - MOVW R2, 16(R13) // save old SP + MOVW (g_stack+stack_hi)(R4), R4 + SUB R2, R4 + MOVW R4, 16(R13) // save depth in stack (can't just save SP, as stack might be copied during a callback) BL (R1) // Restore registers, g, stack pointer. MOVW R0, R5 MOVW 20(R13), R0 BL setg<>(SB) + MOVW (g_stack+stack_hi)(g), R1 + MOVW 16(R13), R2 + SUB R2, R1 MOVW R5, R0 - MOVW 16(R13), R13 + MOVW R1, R13 RET // cgocallback(void (*fn)(void*), void *frame, uintptr framesize) From 99f7df0598238b03d78cc6c89e0bd6b6b9feb246 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 00:18:20 -0400 Subject: [PATCH 054/430] cmd/gc: turn Go prototypes into ptr liveness maps for assembly functions The goal here is to allow assembly functions to appear in the middle of a Go stack (having called other code) and still record enough information about their pointers so that stack copying and garbage collection can handle them precisely. Today, these frames are handled only conservatively. If you write func myfunc(x *float64) (y *int) (with no body, an 'extern' declaration), then the Go compiler now emits a liveness bitmap for use from the assembly definition of myfunc. The bitmap symbol is myfunc.args_stackmap and it contains two bitmaps. The first bitmap, in effect at function entry, marks all inputs as live. The second bitmap, not in effect at function entry, marks the outputs live as well. In funcdata.h, define new assembly macros: GO_ARGS opts in to using the Go compiler-generated liveness bitmap for the current function. GO_RESULTS_INITIALIZED indicates that the results have been initialized and need to be kept live for the remainder of the function; it causes a switch to the second generated bitmap for the assembly code that follows. NO_LOCAL_POINTERS indicates that there are no pointers in the local variables being stored in the function's stack frame. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/137520043 --- src/cmd/dist/build.c | 2 ++ src/cmd/gc/pgen.c | 49 ++++++++++++++++++++++++++++++++++++++---- src/liblink/objfile.c | 12 +++++++++++ src/runtime/asm.s | 14 ++++++++++++ src/runtime/funcdata.h | 26 ++++++++++++++++++++++ 5 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 src/runtime/asm.s diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c index e4dc9ba56c..31c4da3817 100644 --- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -897,6 +897,8 @@ install(char *dir) bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0); copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch), bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0); + copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch), + bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0); } // Generate any missing files; regenerate existing ones. diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index ec50ada5b6..50c03788e8 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -14,6 +14,7 @@ #include "../../runtime/funcdata.h" static void allocauto(Prog* p); +static void emitptrargsmap(void); static Sym* makefuncdatasym(char *namefmt, int64 funcdatakind) @@ -173,9 +174,15 @@ compile(Node *fn) lno = setlineno(fn); + curfn = fn; + dowidth(curfn->type); + if(fn->nbody == nil) { - if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) + if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) { yyerror("missing function body", fn); + goto ret; + } + emitptrargsmap(); goto ret; } @@ -184,9 +191,6 @@ compile(Node *fn) // set up domain for labels clearlabels(); - curfn = fn; - dowidth(curfn->type); - if(curfn->type->outnamed) { // add clearing of the output parameters t = structfirst(&save, getoutarg(curfn->type)); @@ -329,6 +333,43 @@ ret: lineno = lno; } +static void +emitptrargsmap(void) +{ + int nptr, nbitmap, j, off; + vlong xoffset; + Bvec *bv; + Sym *sym; + + sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name)); + + nptr = curfn->type->argwid / widthptr; + bv = bvalloc(nptr*2); + nbitmap = 1; + if(curfn->type->outtuple > 0) + nbitmap = 2; + off = duint32(sym, 0, nbitmap); + off = duint32(sym, off, bv->n); + if(curfn->type->thistuple > 0) { + xoffset = 0; + twobitwalktype1(getthisx(curfn->type), &xoffset, bv); + } + if(curfn->type->intuple > 0) { + xoffset = 0; + twobitwalktype1(getinargx(curfn->type), &xoffset, bv); + } + for(j = 0; j < bv->n; j += 32) + off = duint32(sym, off, bv->b[j/32]); + if(curfn->type->outtuple > 0) { + xoffset = 0; + twobitwalktype1(getoutargx(curfn->type), &xoffset, bv); + for(j = 0; j < bv->n; j += 32) + off = duint32(sym, off, bv->b[j/32]); + } + ggloblsym(sym, off, RODATA); + free(bv); +} + // Sort the list of stack variables. Autos after anything else, // within autos, unused after used, within used, things with // pointers first, zeroed things first, and then decreasing size. diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index dc463d474e..02cfae495a 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -103,6 +103,7 @@ #include #include #include "../cmd/ld/textflag.h" +#include "../runtime/funcdata.h" static void writesym(Link*, Biobuf*, LSym*); static void wrint(Biobuf*, int64); @@ -232,6 +233,17 @@ writeobj(Link *ctxt, Biobuf *b) continue; } + if(p->as == ctxt->arch->AFUNCDATA) { + // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information. + if(curtext == nil) // func _() {} + continue; + if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) { + if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps) + ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps"); + p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version); + } + } + if(curtext == nil) continue; s = curtext; diff --git a/src/runtime/asm.s b/src/runtime/asm.s new file mode 100644 index 0000000000..e6d782f37e --- /dev/null +++ b/src/runtime/asm.s @@ -0,0 +1,14 @@ +// 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. + +#include "textflag.h" + +// funcdata for functions with no local variables in frame. +// Define two zero-length bitmaps, because the same index is used +// for the local variables as for the argument frame, and assembly +// frames have two argument bitmaps, one without results and one with results. +DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2 +DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0 +GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8 + diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h index dc9c41363e..5ddc877c2b 100644 --- a/src/runtime/funcdata.h +++ b/src/runtime/funcdata.h @@ -9,6 +9,7 @@ // // symtab.go also contains a copy of these constants. +// TODO(rsc): Remove PCDATA_ArgSize, renumber StackMapIndex to 0. #define PCDATA_ArgSize 0 /* argument size at CALL instruction */ #define PCDATA_StackMapIndex 1 @@ -16,9 +17,34 @@ #define FUNCDATA_LocalsPointerMaps 1 #define FUNCDATA_DeadValueMaps 2 +// TODO(rsc): Remove ARGSIZE. // To be used in assembly. #define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n +// Pseudo-assembly statements. + +// GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros +// that communicate to the runtime information about the location and liveness +// of pointers in an assembly function's arguments, results, and stack frame. +// This communication is only required in assembly functions that make calls +// to other functions that might be preempted or grow the stack. +// NOSPLIT functions that make no calls do not need to use these macros. + +// GO_ARGS indicates that the Go prototype for this assembly function +// defines the pointer map for the function's arguments. +// GO_ARGS should be the first instruction in a function that uses it. +// It can be omitted if there are no arguments at all. +#define GO_ARGS FUNCDATA $FUNCDATA_ArgsPointerMaps, go_args_stackmap(SB) + +// GO_RESULTS_INITIALIZED indicates that the assembly function +// has initialized the stack space for its results and that those results +// should be considered live for the remainder of the function. +#define GO_RESULTS_INITIALIZED FUNCDATA PCDATA $PCDATA_StackMapIndex, 1 + +// NO_LOCAL_POINTERS indicates that the assembly function stores +// no pointers to heap objects in its local stack variables. +#define NO_LOCAL_POINTERS FUNCDATA $FUNCDATA_LocalsPointerMaps, runtime·no_pointers_stackmap(SB) + // ArgsSizeUnknown is set in Func.argsize to mark all functions // whose argument size is unknown (C vararg functions, and // assembly code without an explicit specification). From 4179439de8166ded9bf097c216e6596ead2ee433 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 00:23:03 -0400 Subject: [PATCH 055/430] syscall: make func Syscall use pointer maps from Go prototypes Before, Syscall and friends were having their arguments treated conservatively. Now they will use the Go prototype, which will mean the arguments are not considered pointers at all. This is safe because of CL 139360044. The fact that all these non-Solaris systems were using conservative scanning of the Syscall arguments is why the failure that prompted CL 139360044 was only observed on Solaris, which does something completely different. If we'd done this earlier, we'd have seen the Solaris failure in more places. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/144730043 --- src/syscall/asm_darwin_386.s | 5 +++++ src/syscall/asm_darwin_amd64.s | 5 +++++ src/syscall/asm_dragonfly_386.s | 5 +++++ src/syscall/asm_dragonfly_amd64.s | 5 +++++ src/syscall/asm_freebsd_386.s | 5 +++++ src/syscall/asm_freebsd_amd64.s | 5 +++++ src/syscall/asm_freebsd_arm.s | 5 +++++ src/syscall/asm_linux_386.s | 4 ++++ src/syscall/asm_linux_amd64.s | 4 ++++ src/syscall/asm_linux_arm.s | 4 ++++ src/syscall/asm_nacl_386.s | 1 + src/syscall/asm_nacl_amd64p32.s | 1 + src/syscall/asm_nacl_arm.s | 1 + src/syscall/asm_netbsd_386.s | 5 +++++ src/syscall/asm_netbsd_amd64.s | 5 +++++ src/syscall/asm_netbsd_arm.s | 5 +++++ src/syscall/asm_openbsd_386.s | 5 +++++ src/syscall/asm_openbsd_amd64.s | 5 +++++ src/syscall/asm_plan9_386.s | 4 ++++ src/syscall/asm_plan9_amd64.s | 4 ++++ 20 files changed, 83 insertions(+) diff --git a/src/syscall/asm_darwin_386.s b/src/syscall/asm_darwin_386.s index dfe94fb526..4d60a817ee 100644 --- a/src/syscall/asm_darwin_386.s +++ b/src/syscall/asm_darwin_386.s @@ -16,6 +16,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -67,6 +69,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -97,6 +100,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -118,6 +122,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s index d6f1c96f5f..a3b1bd5346 100644 --- a/src/syscall/asm_darwin_amd64.s +++ b/src/syscall/asm_darwin_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for AMD64, Darwin @@ -16,6 +17,7 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -40,6 +42,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -64,6 +67,7 @@ ok6: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -85,6 +89,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_dragonfly_386.s b/src/syscall/asm_dragonfly_386.s index 37d655fba9..59cb39e447 100644 --- a/src/syscall/asm_dragonfly_386.s +++ b/src/syscall/asm_dragonfly_386.s @@ -13,6 +13,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-32 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -37,6 +38,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-44 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -64,6 +66,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -94,6 +97,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-32 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -115,6 +119,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-44 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_dragonfly_amd64.s b/src/syscall/asm_dragonfly_amd64.s index c8434f96b7..764c7bda37 100644 --- a/src/syscall/asm_dragonfly_amd64.s +++ b/src/syscall/asm_dragonfly_amd64.s @@ -14,6 +14,7 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-64 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -37,6 +38,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-88 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -60,6 +62,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-112 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX MOVQ 16(SP), DI @@ -93,6 +96,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-64 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -113,6 +117,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-88 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_freebsd_386.s b/src/syscall/asm_freebsd_386.s index f50b5a09bf..b711aa5ad6 100644 --- a/src/syscall/asm_freebsd_386.s +++ b/src/syscall/asm_freebsd_386.s @@ -16,6 +16,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -67,6 +69,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -97,6 +100,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -118,6 +122,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s index 58cbfe1a99..95583b95c4 100644 --- a/src/syscall/asm_freebsd_amd64.s +++ b/src/syscall/asm_freebsd_amd64.s @@ -22,6 +22,7 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -45,6 +46,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -68,6 +70,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX MOVQ 16(SP), DI @@ -101,6 +104,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -121,6 +125,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_freebsd_arm.s b/src/syscall/asm_freebsd_arm.s index 5eb40334b9..5588eaaa43 100644 --- a/src/syscall/asm_freebsd_arm.s +++ b/src/syscall/asm_freebsd_arm.s @@ -13,6 +13,7 @@ // func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr) TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -35,6 +36,7 @@ error: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -61,6 +63,7 @@ error6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -87,6 +90,7 @@ error9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 MOVW 8(FP), R1 // a2 @@ -106,6 +110,7 @@ errorr: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 MOVW 8(FP), R1 // a2 diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s index 05cf89aa22..fb3a3b9bd8 100644 --- a/src/syscall/asm_linux_386.s +++ b/src/syscall/asm_linux_386.s @@ -15,6 +15,7 @@ // Trap # in AX, args in BX CX DX SI DI, return in AX TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX @@ -40,6 +41,7 @@ ok: // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX @@ -66,6 +68,7 @@ ok6: // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX MOVL 12(SP), CX @@ -88,6 +91,7 @@ ok1: // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX MOVL 12(SP), CX diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s index 514693283b..fb6672624c 100644 --- a/src/syscall/asm_linux_amd64.s +++ b/src/syscall/asm_linux_amd64.s @@ -17,6 +17,7 @@ // would pass 4th arg in CX, not R10. TEXT ·Syscall(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -42,6 +43,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -67,6 +69,7 @@ ok6: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -89,6 +92,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s index 3be0a13e17..edb5b21a74 100644 --- a/src/syscall/asm_linux_arm.s +++ b/src/syscall/asm_linux_arm.s @@ -13,6 +13,7 @@ // func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS BL runtime·entersyscall(SB) MOVW 4(SP), R7 MOVW 8(SP), R0 @@ -44,6 +45,7 @@ ok: // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); // Actually Syscall5 but the rest of the code expects it to be named Syscall6. TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS BL runtime·entersyscall(SB) MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 @@ -75,6 +77,7 @@ ok6: // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); // Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6. TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 MOVW 12(SP), R1 @@ -134,6 +137,7 @@ okseek: // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 MOVW 12(SP), R1 diff --git a/src/syscall/asm_nacl_386.s b/src/syscall/asm_nacl_386.s index 3c86decd39..655248b37f 100644 --- a/src/syscall/asm_nacl_386.s +++ b/src/syscall/asm_nacl_386.s @@ -16,6 +16,7 @@ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX TEXT syscall·Syscall(SB),NOSPLIT,$12-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL trap+0(FP), AX MOVL a1+4(FP), BX diff --git a/src/syscall/asm_nacl_amd64p32.s b/src/syscall/asm_nacl_amd64p32.s index b91e09bd6d..33f8220134 100644 --- a/src/syscall/asm_nacl_amd64p32.s +++ b/src/syscall/asm_nacl_amd64p32.s @@ -16,6 +16,7 @@ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX TEXT syscall·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL trap+0(FP), AX MOVL a1+4(FP), DI diff --git a/src/syscall/asm_nacl_arm.s b/src/syscall/asm_nacl_arm.s index cc4b9cd2d6..536d751b50 100644 --- a/src/syscall/asm_nacl_arm.s +++ b/src/syscall/asm_nacl_arm.s @@ -16,6 +16,7 @@ MOVW $(0x10000 + ((code)<<5)), R8; B (R8) TEXT syscall·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS BL runtime·entersyscall(SB) MOVW trap+0(FP), R8 MOVW a1+4(FP), R0 diff --git a/src/syscall/asm_netbsd_386.s b/src/syscall/asm_netbsd_386.s index c58263254a..9dc6a9242a 100644 --- a/src/syscall/asm_netbsd_386.s +++ b/src/syscall/asm_netbsd_386.s @@ -16,6 +16,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -67,6 +69,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -97,6 +100,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -118,6 +122,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_netbsd_amd64.s b/src/syscall/asm_netbsd_amd64.s index 8285382ce2..d6bb1dd091 100644 --- a/src/syscall/asm_netbsd_amd64.s +++ b/src/syscall/asm_netbsd_amd64.s @@ -17,6 +17,7 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -63,6 +65,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -95,6 +98,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -115,6 +119,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_netbsd_arm.s b/src/syscall/asm_netbsd_arm.s index b061180491..357e28d947 100644 --- a/src/syscall/asm_netbsd_arm.s +++ b/src/syscall/asm_netbsd_arm.s @@ -13,6 +13,7 @@ // func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32) TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -35,6 +36,7 @@ error: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -60,6 +62,7 @@ error6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -85,6 +88,7 @@ error9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 MOVW 8(FP), R2 // a2 @@ -104,6 +108,7 @@ errorr: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 MOVW 8(FP), R2 // a2 diff --git a/src/syscall/asm_openbsd_386.s b/src/syscall/asm_openbsd_386.s index 17fbb65c80..6c51f197ee 100644 --- a/src/syscall/asm_openbsd_386.s +++ b/src/syscall/asm_openbsd_386.s @@ -16,6 +16,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -67,6 +69,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -97,6 +100,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -118,6 +122,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_openbsd_amd64.s b/src/syscall/asm_openbsd_amd64.s index fe61482cd5..4ba5844e49 100644 --- a/src/syscall/asm_openbsd_amd64.s +++ b/src/syscall/asm_openbsd_amd64.s @@ -17,6 +17,7 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -40,6 +41,7 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -63,6 +65,7 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -95,6 +98,7 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -115,6 +119,7 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_plan9_386.s b/src/syscall/asm_plan9_386.s index aaa8b9a692..30726b4d00 100644 --- a/src/syscall/asm_plan9_386.s +++ b/src/syscall/asm_plan9_386.s @@ -18,6 +18,7 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-32 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -53,6 +54,7 @@ copyresult3: RET TEXT ·Syscall6(SB),NOSPLIT,$0-44 + GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -91,6 +93,7 @@ copyresult4: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -106,6 +109,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28 RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 + GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_plan9_amd64.s b/src/syscall/asm_plan9_amd64.s index 22dc5f9576..3e61318cd5 100644 --- a/src/syscall/asm_plan9_amd64.s +++ b/src/syscall/asm_plan9_amd64.s @@ -17,6 +17,7 @@ //func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) TEXT ·Syscall(SB),NOSPLIT,$0-64 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number @@ -52,6 +53,7 @@ copyresult3: RET TEXT ·Syscall6(SB),NOSPLIT,$0-88 + GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number @@ -90,6 +92,7 @@ copyresult4: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + GO_ARGS MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number LEAQ 16(SP), SI @@ -105,6 +108,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56 RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + GO_ARGS MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number LEAQ 16(SP), SI From 860a645927479c89e41a157ab446f0f3f66951df Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 00:55:24 -0400 Subject: [PATCH 056/430] syscall: add #include "funcdata.h" to files modified in last CL That's what defines GO_ARGS. TBR=khr CC=golang-codereviews https://golang.org/cl/141460043 --- src/syscall/asm_darwin_386.s | 1 + src/syscall/asm_dragonfly_386.s | 1 + src/syscall/asm_dragonfly_amd64.s | 1 + src/syscall/asm_freebsd_386.s | 1 + src/syscall/asm_freebsd_amd64.s | 1 + src/syscall/asm_freebsd_arm.s | 1 + src/syscall/asm_linux_386.s | 1 + src/syscall/asm_linux_amd64.s | 1 + src/syscall/asm_linux_arm.s | 1 + src/syscall/asm_nacl_386.s | 1 + src/syscall/asm_nacl_amd64p32.s | 1 + src/syscall/asm_nacl_arm.s | 1 + src/syscall/asm_netbsd_386.s | 1 + src/syscall/asm_netbsd_amd64.s | 1 + src/syscall/asm_netbsd_arm.s | 1 + src/syscall/asm_openbsd_386.s | 1 + src/syscall/asm_openbsd_amd64.s | 1 + src/syscall/asm_plan9_386.s | 1 + src/syscall/asm_plan9_amd64.s | 1 + 19 files changed, 19 insertions(+) diff --git a/src/syscall/asm_darwin_386.s b/src/syscall/asm_darwin_386.s index 4d60a817ee..7d8ddf4378 100644 --- a/src/syscall/asm_darwin_386.s +++ b/src/syscall/asm_darwin_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, Darwin diff --git a/src/syscall/asm_dragonfly_386.s b/src/syscall/asm_dragonfly_386.s index 59cb39e447..0d7d6ba1e7 100644 --- a/src/syscall/asm_dragonfly_386.s +++ b/src/syscall/asm_dragonfly_386.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, FreeBSD diff --git a/src/syscall/asm_dragonfly_amd64.s b/src/syscall/asm_dragonfly_amd64.s index 764c7bda37..b81cf8dda9 100644 --- a/src/syscall/asm_dragonfly_amd64.s +++ b/src/syscall/asm_dragonfly_amd64.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // // System call support for AMD64, DragonFly diff --git a/src/syscall/asm_freebsd_386.s b/src/syscall/asm_freebsd_386.s index b711aa5ad6..ff5f9f4a2a 100644 --- a/src/syscall/asm_freebsd_386.s +++ b/src/syscall/asm_freebsd_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, FreeBSD diff --git a/src/syscall/asm_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s index 95583b95c4..47ceb9287b 100644 --- a/src/syscall/asm_freebsd_amd64.s +++ b/src/syscall/asm_freebsd_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for AMD64, FreeBSD diff --git a/src/syscall/asm_freebsd_arm.s b/src/syscall/asm_freebsd_arm.s index 5588eaaa43..ed369ce73e 100644 --- a/src/syscall/asm_freebsd_arm.s +++ b/src/syscall/asm_freebsd_arm.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // // System call support for ARM, FreeBSD diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s index fb3a3b9bd8..bcb85add64 100644 --- a/src/syscall/asm_linux_386.s +++ b/src/syscall/asm_linux_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System calls for 386, Linux diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s index fb6672624c..6c9e654519 100644 --- a/src/syscall/asm_linux_amd64.s +++ b/src/syscall/asm_linux_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System calls for AMD64, Linux diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s index edb5b21a74..0060a2171c 100644 --- a/src/syscall/asm_linux_arm.s +++ b/src/syscall/asm_linux_arm.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // // System calls for arm, Linux diff --git a/src/syscall/asm_nacl_386.s b/src/syscall/asm_nacl_386.s index 655248b37f..5352b7697c 100644 --- a/src/syscall/asm_nacl_386.s +++ b/src/syscall/asm_nacl_386.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" #include "../runtime/syscall_nacl.h" // diff --git a/src/syscall/asm_nacl_amd64p32.s b/src/syscall/asm_nacl_amd64p32.s index 33f8220134..637fafab45 100644 --- a/src/syscall/asm_nacl_amd64p32.s +++ b/src/syscall/asm_nacl_amd64p32.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" #include "../runtime/syscall_nacl.h" // diff --git a/src/syscall/asm_nacl_arm.s b/src/syscall/asm_nacl_arm.s index 536d751b50..3e4479432b 100644 --- a/src/syscall/asm_nacl_arm.s +++ b/src/syscall/asm_nacl_arm.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" #include "../runtime/syscall_nacl.h" // diff --git a/src/syscall/asm_netbsd_386.s b/src/syscall/asm_netbsd_386.s index 9dc6a9242a..29442ca9dd 100644 --- a/src/syscall/asm_netbsd_386.s +++ b/src/syscall/asm_netbsd_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, NetBSD diff --git a/src/syscall/asm_netbsd_amd64.s b/src/syscall/asm_netbsd_amd64.s index d6bb1dd091..6d0f311f41 100644 --- a/src/syscall/asm_netbsd_amd64.s +++ b/src/syscall/asm_netbsd_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for AMD64, NetBSD diff --git a/src/syscall/asm_netbsd_arm.s b/src/syscall/asm_netbsd_arm.s index 357e28d947..c4190ea332 100644 --- a/src/syscall/asm_netbsd_arm.s +++ b/src/syscall/asm_netbsd_arm.s @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // // System call support for ARM, NetBSD diff --git a/src/syscall/asm_openbsd_386.s b/src/syscall/asm_openbsd_386.s index 6c51f197ee..e448a70ca1 100644 --- a/src/syscall/asm_openbsd_386.s +++ b/src/syscall/asm_openbsd_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, OpenBSD diff --git a/src/syscall/asm_openbsd_amd64.s b/src/syscall/asm_openbsd_amd64.s index 4ba5844e49..654e3df742 100644 --- a/src/syscall/asm_openbsd_amd64.s +++ b/src/syscall/asm_openbsd_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for AMD64, OpenBSD diff --git a/src/syscall/asm_plan9_386.s b/src/syscall/asm_plan9_386.s index 30726b4d00..8585385bcd 100644 --- a/src/syscall/asm_plan9_386.s +++ b/src/syscall/asm_plan9_386.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for 386, Plan 9 diff --git a/src/syscall/asm_plan9_amd64.s b/src/syscall/asm_plan9_amd64.s index 3e61318cd5..afbd49152c 100644 --- a/src/syscall/asm_plan9_amd64.s +++ b/src/syscall/asm_plan9_amd64.s @@ -6,6 +6,7 @@ // so that go vet can check that they are correct. #include "textflag.h" +#include "funcdata.h" // // System call support for Plan 9 From 70f928698b8416efa544029cfa0f0f7178cdd51b Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Fri, 12 Sep 2014 01:21:51 -0700 Subject: [PATCH 057/430] runtime: save correct pid for new m's on plan9/amd64 The pid field in the Tos structure is a 32-bit value. Loading a 64-bit word also brings in the next field which is used for the profiling clock. LGTM=0intro, aram R=rsc, 0intro, aram CC=golang-codereviews, mischief https://golang.org/cl/139560044 --- src/runtime/sys_plan9_amd64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s index b0e1864602..3a96c2bf91 100644 --- a/src/runtime/sys_plan9_amd64.s +++ b/src/runtime/sys_plan9_amd64.s @@ -149,7 +149,7 @@ TEXT runtime·tstart_plan9(SB),NOSPLIT,$0 // Initialize procid from TOS struct. MOVQ _tos(SB), AX - MOVQ 64(AX), AX + MOVL 64(AX), AX MOVQ AX, m_procid(CX) // save pid as m->procid // Finally, initialize g. From f0d44dbeaf28d157f8eba85ec9f9bffdc84ce3e0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 07:29:19 -0400 Subject: [PATCH 058/430] runtime: look up arg stackmap for makeFuncStub/methodValueStub during traceback makeFuncStub and methodValueStub are used by reflect as generic function implementations. Each call might have different arguments. Extract those arguments from the closure data instead of assuming it is the same each time. Because the argument map is now being extracted from the function itself, we don't need the special cases in reflect.Call anymore, so delete those. Fixes an occasional crash seen when stack copying does not update makeFuncStub's arguments correctly. Will also help make it safe to require stack maps in the garbage collector. Derived from CL 142000044 by khr. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/143890044 --- src/reflect/all_test.go | 25 ++++++++++++ src/reflect/asm_386.s | 3 ++ src/reflect/asm_amd64.s | 7 +++- src/reflect/asm_amd64p32.s | 3 ++ src/reflect/asm_arm.s | 3 ++ src/reflect/makefunc.go | 17 ++++++-- src/reflect/type.go | 82 +++++++++++++++++++++++++++++++++++--- src/reflect/value.go | 31 +------------- src/runtime/malloc.h | 1 - src/runtime/mgc0.c | 6 ++- src/runtime/runtime.h | 2 + src/runtime/stack.c | 14 ++++--- src/runtime/traceback.go | 16 ++++++++ 13 files changed, 161 insertions(+), 49 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 9a2a9f2668..688b5d3107 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -3860,3 +3860,28 @@ func TestCallMethodJump(t *testing.T) { // Stop garbage collecting during reflect.call. *CallGC = false } + +func TestMakeFuncStackCopy(t *testing.T) { + target := func(in []Value) []Value { + runtime.GC() + useStack(16) + return []Value{ValueOf(9)} + } + + var concrete func(*int, int) int + fn := MakeFunc(ValueOf(concrete).Type(), target) + ValueOf(&concrete).Elem().Set(fn) + x := concrete(nil, 7) + if x != 9 { + t.Errorf("have %#q want 9", x) + } +} + +// use about n KB of stack +func useStack(n int) { + if n == 0 { + return + } + var b [1024]byte // makes frame about 1KB + useStack(n - 1 + int(b[99])) +} diff --git a/src/reflect/asm_386.s b/src/reflect/asm_386.s index c028113a0c..0ffccf7d42 100644 --- a/src/reflect/asm_386.s +++ b/src/reflect/asm_386.s @@ -3,12 +3,14 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // makeFuncStub is the code half of the function returned by MakeFunc. // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVL DX, 0(SP) LEAL argframe+0(FP), CX MOVL CX, 4(SP) @@ -20,6 +22,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVL DX, 0(SP) LEAL argframe+0(FP), CX MOVL CX, 4(SP) diff --git a/src/reflect/asm_amd64.s b/src/reflect/asm_amd64.s index b3c54f0482..5a6c27ac93 100644 --- a/src/reflect/asm_amd64.s +++ b/src/reflect/asm_amd64.s @@ -3,12 +3,14 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // makeFuncStub is the code half of the function returned by MakeFunc. // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. -// No argsize here, gc generates argsize info at call site. +// No arg size here; runtime pulls arg map out of the func value. TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16 + NO_LOCAL_POINTERS MOVQ DX, 0(SP) LEAQ argframe+0(FP), CX MOVQ CX, 8(SP) @@ -18,8 +20,9 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16 // methodValueCall is the code half of the function returned by makeMethodValue. // See the comment on the declaration of methodValueCall in makefunc.go // for more details. -// No argsize here, gc generates argsize info at call site. +// No arg size here; runtime pulls arg map out of the func value. TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16 + NO_LOCAL_POINTERS MOVQ DX, 0(SP) LEAQ argframe+0(FP), CX MOVQ CX, 8(SP) diff --git a/src/reflect/asm_amd64p32.s b/src/reflect/asm_amd64p32.s index c028113a0c..0ffccf7d42 100644 --- a/src/reflect/asm_amd64p32.s +++ b/src/reflect/asm_amd64p32.s @@ -3,12 +3,14 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // makeFuncStub is the code half of the function returned by MakeFunc. // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVL DX, 0(SP) LEAL argframe+0(FP), CX MOVL CX, 4(SP) @@ -20,6 +22,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVL DX, 0(SP) LEAL argframe+0(FP), CX MOVL CX, 4(SP) diff --git a/src/reflect/asm_arm.s b/src/reflect/asm_arm.s index 6bd5d48ec9..5a14c6f81d 100644 --- a/src/reflect/asm_arm.s +++ b/src/reflect/asm_arm.s @@ -3,12 +3,14 @@ // license that can be found in the LICENSE file. #include "textflag.h" +#include "funcdata.h" // makeFuncStub is jumped to by the code generated by MakeFunc. // See the comment on the declaration of makeFuncStub in makefunc.go // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVW R7, 4(R13) MOVW $argframe+0(FP), R1 MOVW R1, 8(R13) @@ -20,6 +22,7 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8 // for more details. // No argsize here, gc generates argsize info at call site. TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8 + NO_LOCAL_POINTERS MOVW R7, 4(R13) MOVW $argframe+0(FP), R1 MOVW R1, 8(R13) diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go index 0e61fdea7a..bdb8c21d76 100644 --- a/src/reflect/makefunc.go +++ b/src/reflect/makefunc.go @@ -13,9 +13,10 @@ import ( // makeFuncImpl is the closure value implementing the function // returned by MakeFunc. type makeFuncImpl struct { - code uintptr - typ *funcType - fn func([]Value) []Value + code uintptr + stack *bitVector // stack bitmap for args - offset known to runtime + typ *funcType + fn func([]Value) []Value } // MakeFunc returns a new function of the given Type @@ -54,7 +55,10 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { dummy := makeFuncStub code := **(**uintptr)(unsafe.Pointer(&dummy)) - impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn} + // makeFuncImpl contains a stack map for use by the runtime + _, _, _, stack := funcLayout(t, nil) + + impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn} return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift} } @@ -68,6 +72,7 @@ func makeFuncStub() type methodValue struct { fn uintptr + stack *bitVector // stack bitmap for args - offset known to runtime method int rcvr Value } @@ -98,8 +103,12 @@ func makeMethodValue(op string, v Value) Value { dummy := methodValueCall code := **(**uintptr)(unsafe.Pointer(&dummy)) + // methodValue contains a stack map for use by the runtime + _, _, _, stack := funcLayout(funcType, nil) + fv := &methodValue{ fn: code, + stack: stack, method: int(v.flag) >> flagMethodShift, rcvr: rcvr, } diff --git a/src/reflect/type.go b/src/reflect/type.go index 6817cd74d7..67818f7f4c 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -242,7 +242,7 @@ const ( // with a unique tag like `reflect:"array"` or `reflect:"ptr"` // so that code cannot convert from, say, *arrayType to *ptrType. type rtype struct { - size uintptr // size in bytes + size uintptr hash uint32 // hash of type; avoids computation in hash tables _ uint8 // unused/padding align uint8 // alignment of variable with this type @@ -1726,6 +1726,7 @@ type layoutType struct { t *rtype argSize uintptr // size of arguments retOffset uintptr // offset of return values. + stack *bitVector } var layoutCache struct { @@ -1739,7 +1740,7 @@ var layoutCache struct { // The returned type exists only for GC, so we only fill out GC relevant info. // Currently, that's just size and the GC program. We also fill in // the name for possible debugging use. -func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) { +func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector) { if t.Kind() != Func { panic("reflect: funcLayout of non-func type") } @@ -1750,19 +1751,21 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin layoutCache.RLock() if x := layoutCache.m[k]; x.t != nil { layoutCache.RUnlock() - return x.t, x.argSize, x.retOffset + return x.t, x.argSize, x.retOffset, x.stack } layoutCache.RUnlock() layoutCache.Lock() if x := layoutCache.m[k]; x.t != nil { layoutCache.Unlock() - return x.t, x.argSize, x.retOffset + return x.t, x.argSize, x.retOffset, x.stack } tt := (*funcType)(unsafe.Pointer(t)) - // compute gc program for arguments + // compute gc program & stack bitmap for arguments + stack = new(bitVector) var gc gcProg + var offset uintptr if rcvr != nil { // Reflect uses the "interface" calling convention for // methods, where receivers take one word of argument @@ -1770,16 +1773,21 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin if !isDirectIface(rcvr) { // we pass a pointer to the receiver. gc.append(bitsPointer) + stack.append2(bitsPointer) } else if rcvr.pointers() { // rcvr is a one-word pointer object. Its gc program // is just what we need here. gc.append(bitsPointer) + stack.append2(bitsPointer) } else { gc.append(bitsScalar) + stack.append2(bitsScalar) } + offset += ptrSize } for _, arg := range tt.in { gc.appendProg(arg) + addTypeBits(stack, &offset, arg) } argSize = gc.size if runtime.GOARCH == "amd64p32" { @@ -1789,6 +1797,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin retOffset = gc.size for _, res := range tt.out { gc.appendProg(res) + // stack map does not need result bits } gc.align(ptrSize) @@ -1813,12 +1822,73 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin t: x, argSize: argSize, retOffset: retOffset, + stack: stack, } layoutCache.Unlock() - return x, argSize, retOffset + return x, argSize, retOffset, stack } // isDirectIface reports whether t is stored directly in an interface value. func isDirectIface(t *rtype) bool { return t.kind&kindDirectIface != 0 } + +// Layout matches runtime.BitVector (well enough). +type bitVector struct { + n uint32 // number of bits + data []byte +} + +// append a bit pair to the bitmap. +func (bv *bitVector) append2(bits uint8) { + // assume bv.n is a multiple of 2, since append2 is the only operation. + if bv.n%8 == 0 { + bv.data = append(bv.data, 0) + } + bv.data[bv.n/8] |= bits << (bv.n % 8) + bv.n += 2 +} + +func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { + *offset = align(*offset, uintptr(t.align)) + if t.kind&kindNoPointers != 0 { + *offset += t.size + return + } + + switch Kind(t.kind & kindMask) { + case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: + // 1 pointer at start of representation + for bv.n < uint32(*offset/uintptr(ptrSize)) { + bv.append2(bitsScalar) + } + bv.append2(bitsPointer) + + case Interface: + // 2 pointers + for bv.n < uint32(*offset/uintptr(ptrSize)) { + bv.append2(bitsScalar) + } + bv.append2(bitsPointer) + bv.append2(bitsPointer) + + case Array: + // repeat inner type + tt := (*arrayType)(unsafe.Pointer(t)) + for i := 0; i < int(tt.len); i++ { + addTypeBits(bv, offset, tt.elem) + } + + case Struct: + // apply fields + tt := (*structType)(unsafe.Pointer(t)) + start := *offset + for i := range tt.fields { + f := &tt.fields[i] + off := start + f.offset + addTypeBits(bv, &off, f.typ) + } + } + + *offset += t.size +} diff --git a/src/reflect/value.go b/src/reflect/value.go index 20d0e92ed1..b0dfe840b6 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -403,11 +403,6 @@ func (v Value) CallSlice(in []Value) []Value { var callGC bool // for testing; see TestCallMethodJump -var makeFuncStubFn = makeFuncStub -var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn)) -var methodValueCallFn = methodValueCall -var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn)) - func (v Value) call(op string, in []Value) []Value { // Get function pointer, type. t := v.typ @@ -486,30 +481,8 @@ func (v Value) call(op string, in []Value) []Value { } nout := t.NumOut() - // If target is makeFuncStub, short circuit the unpack onto stack / - // pack back into []Value for the args and return values. Just do the - // call directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls makeFuncStub, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - x := (*makeFuncImpl)(fn) - if x.code == makeFuncStubCode { - return x.fn(in) - } - - // If the target is methodValueCall, do its work here: add the receiver - // argument and call the real target directly. - // We need to do this here because otherwise we have a situation where - // reflect.callXX calls methodValueCall, neither of which knows the - // layout of the args. That's bad for precise gc & stack copying. - y := (*methodValue)(fn) - if y.fn == methodValueCallCode { - rcvr = y.rcvr - rcvrtype, t, fn = methodReceiver("call", rcvr, y.method) - } - // Compute frame type, allocate a chunk of memory for frame - frametype, _, retOffset := funcLayout(t, rcvrtype) + frametype, _, retOffset, _ := funcLayout(t, rcvrtype) args := unsafe_New(frametype) off := uintptr(0) @@ -725,7 +698,7 @@ func align(x, n uintptr) uintptr { func callMethod(ctxt *methodValue, frame unsafe.Pointer) { rcvr := ctxt.rcvr rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method) - frametype, argSize, retOffset := funcLayout(t, rcvrtype) + frametype, argSize, retOffset, _ := funcLayout(t, rcvrtype) // Make a new frame that is one word bigger so we can store the receiver. args := unsafe_New(frametype) diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index 5441691940..b6856768db 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -586,7 +586,6 @@ void runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, Ptr bool runtime·freespecial(Special *s, void *p, uintptr size, bool freed); // Information from the compiler about the layout of stack frames. -typedef struct BitVector BitVector; struct BitVector { int32 n; // # of bits diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index da0455d923..af0b6285a3 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -673,8 +673,10 @@ scanframe(Stkframe *frame, void *unused) // Scan arguments. // Use pointer information if known. - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap != nil) { + if(frame->argmap != nil) { + bv = *frame->argmap; + scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); + } else if((stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps)) != nil) { bv = runtime·stackmapdata(stackmap, pcdata); scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); } else { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 01923c61e0..6300b83c97 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -666,6 +666,7 @@ struct Panic * stack traces */ typedef struct Stkframe Stkframe; +typedef struct BitVector BitVector; struct Stkframe { Func* fn; // function being run @@ -677,6 +678,7 @@ struct Stkframe uintptr varp; // top of local variables uintptr argp; // pointer to function arguments uintptr arglen; // number of bytes at argp + BitVector* argmap; // force use of this argmap }; intgo runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, bool); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index cc2857ac81..53ad90a5de 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -481,12 +481,16 @@ adjustframe(Stkframe *frame, void *arg) } // adjust inargs and outargs if(frame->arglen != 0) { - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil) { - runtime·printf("size %d\n", (int32)frame->arglen); - runtime·throw("no arg info"); + if(frame->argmap != nil) { + bv = *frame->argmap; + } else { + stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); + if(stackmap == nil) { + runtime·printf("size %d\n", (int32)frame->arglen); + runtime·throw("no arg info"); + } + bv = runtime·stackmapdata(stackmap, pcdata); } - bv = runtime·stackmapdata(stackmap, pcdata); if(StackDebug >= 3) runtime·printf(" args\n"); adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index ca3b862102..84cb08c9e1 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -189,6 +189,21 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf } if f.args != _ArgsSizeUnknown { frame.arglen = uintptr(f.args) + } else if callback != nil && (gofuncname(f) == "reflect.makeFuncStub" || gofuncname(f) == "reflect.methodValueCall") { + // NOTE: Two calls to gofuncname on line above will be + // collapsed to one when we pull out all the imprecise fallback code. + arg0 := frame.sp + if usesLR { + arg0 += ptrSize + } + fn := *(**[2]uintptr)(unsafe.Pointer(arg0)) + if fn[0] != f.entry { + print("runtime: confused by ", gofuncname(f), "\n") + gothrow("reflect mismatch") + } + bv := (*bitvector)(unsafe.Pointer(fn[1])) + frame.arglen = uintptr(bv.n / 2 * ptrSize) + frame.argmap = bv } else if flr == nil { frame.arglen = 0 } else { @@ -332,6 +347,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf frame.lr = 0 frame.sp = frame.fp frame.fp = 0 + frame.argmap = nil // On link register architectures, sighandler saves the LR on stack // before faking a call to sigpanic. From a7c6d89166fd7bf6c9af6013cbfaa21971ba28f0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 07:36:23 -0400 Subject: [PATCH 059/430] runtime: tell the truth about BitVector type Dmitriy changed all the execution to interpret the BitVector as an array of bytes. Update the declaration and generation of the bitmaps to match, to avoid problems on big-endian machines. LGTM=khr R=khr CC=dvyukov, golang-codereviews https://golang.org/cl/140570044 --- src/cmd/gc/plive.c | 6 +++++- src/runtime/heapdump.c | 10 +++++----- src/runtime/malloc.h | 4 ++-- src/runtime/mgc0.c | 20 ++++++++++---------- src/runtime/stack.c | 6 +++--- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c index d2f384b2dd..0feb2c710a 100644 --- a/src/cmd/gc/plive.c +++ b/src/cmd/gc/plive.c @@ -1936,7 +1936,11 @@ twobitwritesymbol(Array *arr, Sym *sym) break; for(j = 0; j < bv->n; j += 32) { word = bv->b[j/32]; - off = duint32(sym, off, word); + // Runtime reads the bitmaps as byte arrays. Oblige. + off = duint8(sym, off, word); + off = duint8(sym, off, word>>8); + off = duint8(sym, off, word>>16); + off = duint8(sym, off, word>>24); } } duint32(sym, 0, i); // number of bitmaps diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index db2c552b72..3d7960aab0 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -250,7 +250,7 @@ dumpbv(BitVector *bv, uintptr offset) uintptr i; for(i = 0; i < bv->n; i += BitsPerPointer) { - switch(bv->data[i/32] >> i%32 & 3) { + switch(bv->bytedata[i/8] >> i%8 & 3) { case BitsDead: case BitsScalar: break; @@ -259,7 +259,7 @@ dumpbv(BitVector *bv, uintptr offset) dumpint(offset + i / BitsPerPointer * PtrSize); break; case BitsMultiWord: - switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { + switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) { default: runtime·throw("unexpected garbage collection bits"); case BitsIface: @@ -813,9 +813,9 @@ dumpbvtypes(BitVector *bv, byte *base) uintptr i; for(i = 0; i < bv->n; i += BitsPerPointer) { - if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord) + if((bv->bytedata[i/8] >> i%8 & 3) != BitsMultiWord) continue; - switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { + switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) { default: runtime·throw("unexpected garbage collection bits"); case BitsIface: @@ -860,5 +860,5 @@ makeheapobjbv(byte *p, uintptr size) tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((i*BitsPerPointer)%8)); tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8); } - return (BitVector){i*BitsPerPointer, (uint32*)tmpbuf}; + return (BitVector){i*BitsPerPointer, tmpbuf}; } diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index b6856768db..60b87da78c 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -589,14 +589,14 @@ bool runtime·freespecial(Special *s, void *p, uintptr size, bool freed); struct BitVector { int32 n; // # of bits - uint32 *data; + uint8 *bytedata; }; typedef struct StackMap StackMap; struct StackMap { int32 n; // number of bitmaps int32 nbit; // number of bits in each bitmap - uint32 data[]; + uint8 bytedata[]; // bitmaps, each starting on a 32-bit boundary }; // Returns pointer map data for the given stackmap index // (the index is encoded in PCDATA_StackMapIndex). diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index af0b6285a3..4221aaab2f 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -438,11 +438,11 @@ markroot(ParFor *desc, uint32 i) // Note: if you add a case here, please also update heapdump.c:dumproots. switch(i) { case RootData: - scanblock(runtime·data, runtime·edata - runtime·data, (byte*)runtime·gcdatamask.data); + scanblock(runtime·data, runtime·edata - runtime·data, runtime·gcdatamask.bytedata); break; case RootBss: - scanblock(runtime·bss, runtime·ebss - runtime·bss, (byte*)runtime·gcbssmask.data); + scanblock(runtime·bss, runtime·ebss - runtime·bss, runtime·gcbssmask.bytedata); break; case RootFinalizers: @@ -610,7 +610,7 @@ runtime·stackmapdata(StackMap *stackmap, int32 n) { if(n < 0 || n >= stackmap->n) runtime·throw("stackmapdata: index out of range"); - return (BitVector){stackmap->nbit, stackmap->data + n*((stackmap->nbit+31)/32)}; + return (BitVector){stackmap->nbit, stackmap->bytedata + n*((stackmap->nbit+31)/32*4)}; } // Scan a stack frame: local variables and function arguments/results. @@ -668,17 +668,17 @@ scanframe(Stkframe *frame, void *unused) } bv = runtime·stackmapdata(stackmap, pcdata); size = (bv.n * PtrSize) / BitsPerPointer; - scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); + scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, bv.bytedata); } // Scan arguments. // Use pointer information if known. if(frame->argmap != nil) { bv = *frame->argmap; - scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); + scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata); } else if((stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps)) != nil) { bv = runtime·stackmapdata(stackmap, pcdata); - scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); + scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata); } else { if(Debug > 2) runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen); @@ -1642,7 +1642,7 @@ unrollglobgcprog(byte *prog, uintptr size) runtime·throw("unrollglobgcprog: program does not end with insEnd"); if(mask[masksize] != 0xa1) runtime·throw("unrollglobgcprog: overflow"); - return (BitVector){masksize*8, (uint32*)mask}; + return (BitVector){masksize*8, mask}; } void @@ -1833,7 +1833,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-runtime·data)/PtrSize; - bits = (((byte*)runtime·gcdatamask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; + bits = (runtime·gcdatamask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; (*mask)[i/PtrSize] = bits; } return; @@ -1845,7 +1845,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-runtime·bss)/PtrSize; - bits = (((byte*)runtime·gcbssmask.data)[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; + bits = (runtime·gcbssmask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; (*mask)[i/PtrSize] = bits; } return; @@ -1895,7 +1895,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) *mask = runtime·mallocgc(*len, nil, FlagNoScan); for(i = 0; i < n; i += PtrSize) { off = (p+i-(byte*)frame.varp+size)/PtrSize; - bits = (bv.data[off*BitsPerPointer/32] >> ((off*BitsPerPointer)%32))&BitsMask; + bits = (bv.bytedata[off*BitsPerPointer/8] >> ((off*BitsPerPointer)%8))&BitsMask; (*mask)[i/PtrSize] = bits; } } diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 53ad90a5de..f29266eb6b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -370,8 +370,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) num = bv->n / BitsPerPointer; for(i = 0; i < num; i++) { if(StackDebug >= 4) - runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3], scanp[i]); - switch(bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3) { + runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3], scanp[i]); + switch(bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3) { case BitsDead: if(runtime·debug.gcdead) scanp[i] = (byte*)PoisonStack; @@ -394,7 +394,7 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) } break; case BitsMultiWord: - switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) { + switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) { default: runtime·throw("unexpected garbage collection bits"); case BitsEface: From e844f53a0198e81b359d198fc0dcf15cf01d6ed1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 07:46:11 -0400 Subject: [PATCH 060/430] runtime: stop scanning stack frames/args conservatively The goal here is to commit fully to having precise information about stack frames. If we need information we don't have, crash instead of assuming we should scan conservatively. Since the stack copying assumes fully precise information, any crashes during garbage collection that are introduced by this CL are crashes that could have happened during stack copying instead. Those are harder to find because stacks are copied much less often than the garbage collector is invoked. In service of that goal, remove ARGSIZE macros from asm_*.s, change switchtoM to have no arguments (it doesn't have any live arguments), and add args and locals information to some frames that can call back into Go. LGTM=khr R=khr, rlh CC=golang-codereviews https://golang.org/cl/137540043 --- src/runtime/asm_386.s | 9 ++--- src/runtime/asm_amd64.s | 10 +++--- src/runtime/asm_amd64p32.s | 6 +--- src/runtime/asm_arm.s | 9 ++--- src/runtime/mgc0.c | 74 +++++++++++++++++--------------------- src/runtime/runtime.h | 1 - src/runtime/symtab.go | 7 ---- src/runtime/traceback.go | 48 ++++++++----------------- 8 files changed, 64 insertions(+), 100 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 37ad092414..c9fd75bfc4 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -102,9 +102,7 @@ ok: // create a new goroutine to start program PUSHL $runtime·main·f(SB) // entry PUSHL $0 // arg size - ARGSIZE(8) CALL runtime·newproc(SB) - ARGSIZE(-1) POPL AX POPL AX @@ -206,7 +204,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 // lives at the bottom of the G stack from the one that lives // at the top of the M stack because the one at the top of // the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-4 +TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 RET // func onM_signalok(fn func()) @@ -263,7 +261,6 @@ oncurg: MOVL BX, SP // call target function - ARGSIZE(0) MOVL DI, DX MOVL 0(DI), DI CALL DI @@ -656,6 +653,7 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 RET TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12 + GO_ARGS MOVL fn+0(FP), AX MOVL arg+4(FP), BX CALL asmcgocall<>(SB) @@ -716,6 +714,9 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // See cgocall.c for more details. TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$12-12 + GO_ARGS + NO_LOCAL_POINTERS + // If g is nil, Go did not create the current thread. // Call needm to obtain one for temporary use. // In this case, we're running on the thread stack, so there's diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 241d5feebf..d5e2f56ef0 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -98,9 +98,7 @@ ok: MOVQ $runtime·main·f(SB), BP // entry PUSHQ BP PUSHQ $0 // arg size - ARGSIZE(16) CALL runtime·newproc(SB) - ARGSIZE(-1) POPQ AX POPQ AX @@ -183,7 +181,6 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8 MOVQ SI, g(CX) // g = m->g0 MOVQ (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp PUSHQ AX - ARGSIZE(8) MOVQ DI, DX MOVQ 0(DI), DI CALL DI @@ -197,7 +194,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8 // lives at the bottom of the G stack from the one that lives // at the top of the M stack because the one at the top of // the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-8 +TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 RET // func onM_signalok(fn func()) @@ -255,7 +252,6 @@ oncurg: MOVQ BX, SP // call target function - ARGSIZE(0) MOVQ DI, DX MOVQ 0(DI), DI CALL DI @@ -634,6 +630,7 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16 RET TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-20 + GO_ARGS MOVQ fn+0(FP), AX MOVQ arg+8(FP), BX CALL asmcgocall<>(SB) @@ -703,6 +700,9 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$24-24 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // See cgocall.c for more details. TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-24 + GO_ARGS + NO_LOCAL_POINTERS + // If g is nil, Go did not create the current thread. // Call needm to obtain one m for temporary use. // In this case, we're running on the thread stack, so there's diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 62fa4ff868..bbbd886a53 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -75,9 +75,7 @@ ok: MOVL $runtime·main·f(SB), AX // entry MOVL $0, 0(SP) MOVL AX, 4(SP) - ARGSIZE(8) CALL runtime·newproc(SB) - ARGSIZE(-1) // start this M CALL runtime·mstart(SB) @@ -158,7 +156,6 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 MOVL SI, g(CX) // g = m->g0 MOVL (g_sched+gobuf_sp)(SI), SP // sp = m->g0->sched.sp PUSHQ AX - ARGSIZE(8) MOVL DI, DX MOVL 0(DI), DI CALL DI @@ -172,7 +169,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4 // lives at the bottom of the G stack from the one that lives // at the top of the M stack because the one at the top of // the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB), NOSPLIT, $0-4 +TEXT runtime·switchtoM(SB), NOSPLIT, $0-0 RET // func onM_signalok(fn func()) @@ -225,7 +222,6 @@ oncurg: MOVL (g_sched+gobuf_sp)(DX), SP // call target function - ARGSIZE(0) MOVL DI, DX MOVL 0(DI), DI CALL DI diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index a4524f919b..368b4ad8e8 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -77,9 +77,7 @@ nocgo: MOVW.W R0, -4(R13) MOVW $0, R0 MOVW.W R0, -4(R13) // push $0 as guard - ARGSIZE(12) BL runtime·newproc(SB) - ARGSIZE(-1) MOVW $12(R13), R13 // pop args and LR // start this M @@ -197,7 +195,7 @@ TEXT runtime·mcall(SB),NOSPLIT,$-4-4 // lives at the bottom of the G stack from the one that lives // at the top of the M stack because the one at the top of // the M stack terminates the stack walk (see topofstack()). -TEXT runtime·switchtoM(SB),NOSPLIT,$0-4 +TEXT runtime·switchtoM(SB),NOSPLIT,$0-0 MOVW $0, R0 BL (R0) // clobber lr to ensure push {lr} is kept RET @@ -258,7 +256,6 @@ oncurg: MOVW R3, SP // call target function - ARGSIZE(0) MOVW R0, R7 MOVW 0(R0), R0 BL (R0) @@ -490,6 +487,7 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 RET TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12 + GO_ARGS MOVW fn+0(FP), R1 MOVW arg+4(FP), R0 BL asmcgocall<>(SB) @@ -553,6 +551,9 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12 // cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize) // See cgocall.c for more details. TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-12 + GO_ARGS + NO_LOCAL_POINTERS + // Load m and g from thread-local storage. MOVB runtime·iscgo(SB), R0 CMP $0, R0 diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 4221aaab2f..47659be266 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -65,7 +65,6 @@ enum { Debug = 0, ConcurrentSweep = 1, - PreciseScan = 1, WorkbufSize = 4*1024, FinBlockSize = 4*1024, @@ -239,16 +238,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask) ptrmask = nil; // use GC bitmap for pointer info scanobj: - if(!PreciseScan) { - if(ptrmask == nil) { - // Heap obj, obtain real size. - if(!runtime·mlookup(b, &p, &n, nil)) - continue; // not an allocated obj - if(b != p) - runtime·throw("bad heap object"); - } - ptrmask = ScanConservatively; - } // Find bits of the beginning of the object. if(ptrmask == nil) { off = (uintptr*)b - (uintptr*)arena_start; @@ -620,7 +609,7 @@ scanframe(Stkframe *frame, void *unused) Func *f; StackMap *stackmap; BitVector bv; - uintptr size; + uintptr size, minsize; uintptr targetpc; int32 pcdata; @@ -644,25 +633,21 @@ scanframe(Stkframe *frame, void *unused) } // Scan local variables if stack frame has been allocated. - // Use pointer information if known. - stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - if(stackmap == nil) { - // No locals information, scan everything. - size = frame->varp - frame->sp; - if(Debug > 2) - runtime·printf("frame %s unsized locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size); - scanblock((byte*)(frame->varp - size), size, ScanConservatively); - } else if(stackmap->n < 0) { - // Locals size information, scan just the locals. - size = -stackmap->n; - if(Debug > 2) - runtime·printf("frame %s conservative locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size); - scanblock((byte*)(frame->varp - size), size, ScanConservatively); - } else if(stackmap->n > 0) { + size = frame->varp - frame->sp; + minsize = 0; + if(thechar != '6' && thechar != '8') + minsize = sizeof(uintptr); + if(size > minsize) { + stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); + if(stackmap == nil || stackmap->n <= 0) { + runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size); + runtime·throw("missing stackmap"); + } + // Locals bitmap information, scan just the pointers in locals. if(pcdata < 0 || pcdata >= stackmap->n) { // don't know where we are - runtime·printf("pcdata is %d and %d stack map entries for %s (targetpc=%p)\n", + runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n", pcdata, stackmap->n, runtime·funcname(f), targetpc); runtime·throw("scanframe: bad symbol table"); } @@ -672,19 +657,26 @@ scanframe(Stkframe *frame, void *unused) } // Scan arguments. - // Use pointer information if known. - if(frame->argmap != nil) { - bv = *frame->argmap; - scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata); - } else if((stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps)) != nil) { - bv = runtime·stackmapdata(stackmap, pcdata); - scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata); - } else { - if(Debug > 2) - runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen); - scanblock((byte*)frame->argp, frame->arglen, ScanConservatively); - } - return true; + if(frame->arglen > 0) { + if(frame->argmap != nil) + bv = *frame->argmap; + else { + stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); + if(stackmap == nil || stackmap->n <= 0) { + runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen); + runtime·throw("missing stackmap"); + } + if(pcdata < 0 || pcdata >= stackmap->n) { + // don't know where we are + runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n", + pcdata, stackmap->n, runtime·funcname(f), targetpc); + runtime·throw("scanframe: bad symbol table"); + } + bv = runtime·stackmapdata(stackmap, pcdata); + } + scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata); + } + return true; } static void diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 6300b83c97..8c2b09b317 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -806,7 +806,6 @@ void runtime·signalstack(byte*, int32); void runtime·symtabinit(void); Func* runtime·findfunc(uintptr); int32 runtime·funcline(Func*, uintptr, String*); -int32 runtime·funcarglen(Func*, uintptr); int32 runtime·funcspdelta(Func*, uintptr); int8* runtime·funcname(Func*); int32 runtime·pcdatavalue(Func*, int32, uintptr); diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index bd9e9924c4..48d4023b9a 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -237,13 +237,6 @@ func pcdatavalue(f *_func, table int32, targetpc uintptr) int32 { return pcvalue(f, off, targetpc, true) } -func funcarglen(f *_func, targetpc uintptr) int32 { - if targetpc == f.entry { - return 0 - } - return pcdatavalue(f, _PCDATA_ArgSize, targetpc-_PCQuantum) -} - func funcdata(f *_func, i int32) unsafe.Pointer { if i < 0 || i >= f.nfuncdata { return nil diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 84cb08c9e1..eaf54db319 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -187,41 +187,23 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf if usesLR { frame.argp += ptrSize } - if f.args != _ArgsSizeUnknown { - frame.arglen = uintptr(f.args) - } else if callback != nil && (gofuncname(f) == "reflect.makeFuncStub" || gofuncname(f) == "reflect.methodValueCall") { - // NOTE: Two calls to gofuncname on line above will be - // collapsed to one when we pull out all the imprecise fallback code. - arg0 := frame.sp - if usesLR { - arg0 += ptrSize - } - fn := *(**[2]uintptr)(unsafe.Pointer(arg0)) - if fn[0] != f.entry { - print("runtime: confused by ", gofuncname(f), "\n") - gothrow("reflect mismatch") - } - bv := (*bitvector)(unsafe.Pointer(fn[1])) - frame.arglen = uintptr(bv.n / 2 * ptrSize) - frame.argmap = bv - } else if flr == nil { - frame.arglen = 0 - } else { - i := funcarglen(flr, frame.lr) - if i >= 0 { - frame.arglen = uintptr(i) - } else { - var tmp string - if flr != nil { - tmp = gofuncname(flr) - } else { - tmp = "?" + frame.arglen = uintptr(f.args) + if callback != nil && f.args == _ArgsSizeUnknown { + // Extract argument bitmaps for reflect stubs from the calls they made to reflect. + switch gofuncname(f) { + case "reflect.makeFuncStub", "reflect.methodValueCall": + arg0 := frame.sp + if usesLR { + arg0 += ptrSize } - print("runtime: unknown argument frame size for ", gofuncname(f), " called from ", hex(frame.lr), " [", tmp, "]\n") - if callback != nil { - gothrow("invalid stack") + fn := *(**[2]uintptr)(unsafe.Pointer(arg0)) + if fn[0] != f.entry { + print("runtime: confused by ", gofuncname(f), "\n") + gothrow("reflect mismatch") } - frame.arglen = 0 + bv := (*bitvector)(unsafe.Pointer(fn[1])) + frame.arglen = uintptr(bv.n / 2 * ptrSize) + frame.argmap = bv } } } From 68c1c6afa002074219792689fef714d095f40fd6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 07:51:00 -0400 Subject: [PATCH 061/430] cmd/cc, cmd/gc: stop generating 'argsize' PCDATA The argsize PCDATA was specifying the number of bytes passed to a function call, so that if the function did not specify its argument count, the garbage collector could use the call site information to scan those bytes conservatively. We don't do that anymore, so stop generating the information. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/139530043 --- src/cmd/5c/cgen.c | 2 -- src/cmd/5g/gg.h | 1 - src/cmd/5g/ggen.c | 19 ------------------- src/cmd/5g/gsubr.c | 10 ---------- src/cmd/6c/cgen.c | 4 ---- src/cmd/6g/gg.h | 1 - src/cmd/6g/ggen.c | 19 ------------------- src/cmd/6g/gsubr.c | 10 ---------- src/cmd/8c/cgen.c | 2 -- src/cmd/8g/gg.h | 1 - src/cmd/8g/ggen.c | 18 ------------------ src/cmd/8g/gsubr.c | 10 ---------- src/runtime/funcdata.h | 8 +------- 13 files changed, 1 insertion(+), 104 deletions(-) diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c index 9be10bf452..5a049ae628 100644 --- a/src/cmd/5c/cgen.c +++ b/src/cmd/5c/cgen.c @@ -366,14 +366,12 @@ _cgen(Node *n, Node *nn, int inrel) if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index 62f73c8659..00914bfa34 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -109,7 +109,6 @@ void split64(Node*, Node*, Node*); void splitclean(void); Node* ncon(uint32 i); void gtrack(Sym*); -void gargsize(int32); /* * obj.c diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 6174e760c4..53cddb7605 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -179,28 +179,12 @@ fixautoused(Prog* p) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node n1, r, r1, con; if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 3*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -297,9 +281,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index ebd2c70a05..93bfafef66 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -205,16 +205,6 @@ ggloblnod(Node *nam) p->reg |= NOPTR; } -void -gargsize(int32 size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - void ggloblsym(Sym *s, int32 width, int8 flags) { diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c index bb09ec05d3..68dd7bb5fa 100644 --- a/src/cmd/6c/cgen.c +++ b/src/cmd/6c/cgen.c @@ -945,7 +945,6 @@ cgen(Node *n, Node *nn) return; } gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; @@ -953,12 +952,9 @@ cgen(Node *n, Node *nn) regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0 && reg[REGARG]) reg[REGARG]--; regret(&nod, n, l->type, 1); // update maxarg if nothing else - gpcdata(PCDATA_ArgSize, curarg); - gpcdata(PCDATA_ArgSize, -1); if(nn != Z) gmove(&nod, nn); if(nod.op == OREGISTER) diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 27f6c01fee..fe69d5c968 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -99,7 +99,6 @@ int sudoaddable(int, Node*, Addr*); void afunclit(Addr*, Node*); void nodfconst(Node*, Type*, Mpflt*); void gtrack(Sym*); -void gargsize(vlong); void fixlargeoffset(Node *n); /* diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 5a9b8418c4..987473ccab 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -175,7 +175,6 @@ fixautoused(Prog *p) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node reg, con; Node r1; @@ -183,21 +182,6 @@ ginscall(Node *f, int proc) if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 2*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -275,9 +259,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index e1ed3b3b86..5bd9246607 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -214,16 +214,6 @@ gtrack(Sym *s) p->from.sym = linksym(s); } -void -gargsize(vlong size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - void ggloblsym(Sym *s, int32 width, int8 flags) { diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c index 6f0f7c97fe..87e8fdad8b 100644 --- a/src/cmd/8c/cgen.c +++ b/src/cmd/8c/cgen.c @@ -938,7 +938,6 @@ cgen(Node *n, Node *nn) return; } gargs(r, &nod, &nod1); - gpcdata(PCDATA_ArgSize, curarg); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; @@ -946,7 +945,6 @@ cgen(Node *n, Node *nn) regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); - gpcdata(PCDATA_ArgSize, -1); if(REGARG >= 0 && reg[REGARG]) reg[REGARG]--; regret(&nod, n, l->type, 1); // update maxarg if nothing else diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h index bdefa93b5b..238f927656 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -114,7 +114,6 @@ void split64(Node*, Node*, Node*); void splitclean(void); void nswap(Node*, Node*); void gtrack(Sym*); -void gargsize(int32); /* * cplx.c */ diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 6038731f7b..a095be36e9 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -217,21 +217,6 @@ ginscall(Node *f, int proc) if(f->type != T) setmaxarg(f->type); - arg = -1; - // Most functions have a fixed-size argument block, so traceback uses that during unwind. - // Not all, though: there are some variadic functions in package runtime, - // and for those we emit call-specific metadata recorded by caller. - // Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub), - // so we do this for all indirect calls as well. - if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) { - arg = f->type->argwid; - if(proc == 1 || proc == 2) - arg += 2*widthptr; - } - - if(arg != -1) - gargsize(arg); - switch(proc) { default: fatal("ginscall: bad proc %d", proc); @@ -293,9 +278,6 @@ ginscall(Node *f, int proc) } break; } - - if(arg != -1) - gargsize(-1); } /* diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 9f923cc9aa..a83d048f40 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -205,16 +205,6 @@ ggloblnod(Node *nam) p->from.scale |= NOPTR; } -void -gargsize(int32 size) -{ - Node n1, n2; - - nodconst(&n1, types[TINT32], PCDATA_ArgSize); - nodconst(&n2, types[TINT32], size); - gins(APCDATA, &n1, &n2); -} - void ggloblsym(Sym *s, int32 width, int8 flags) { diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h index 5ddc877c2b..a2667a4c02 100644 --- a/src/runtime/funcdata.h +++ b/src/runtime/funcdata.h @@ -9,18 +9,12 @@ // // symtab.go also contains a copy of these constants. -// TODO(rsc): Remove PCDATA_ArgSize, renumber StackMapIndex to 0. -#define PCDATA_ArgSize 0 /* argument size at CALL instruction */ -#define PCDATA_StackMapIndex 1 +#define PCDATA_StackMapIndex 0 #define FUNCDATA_ArgsPointerMaps 0 /* garbage collector blocks */ #define FUNCDATA_LocalsPointerMaps 1 #define FUNCDATA_DeadValueMaps 2 -// TODO(rsc): Remove ARGSIZE. -// To be used in assembly. -#define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n - // Pseudo-assembly statements. // GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros From fbd1b5f98f1bbe0c992b7a99719f0ec38a7033bc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 12 Sep 2014 07:52:56 -0700 Subject: [PATCH 062/430] runtime: fix typo in comment LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/140590043 --- src/runtime/mgc0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 47659be266..c976b09c36 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -997,7 +997,7 @@ runtime·MSpan_Sweep(MSpan *s, bool preserve) } // State of background runtime·sweep. -// Pretected by runtime·gclock. +// Protected by runtime·gclock. // Must match mgc0.go. struct { From a14c1c986eba6ca6a35bfb9feb833b8eff53c7b1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 12 Sep 2014 11:18:12 -0700 Subject: [PATCH 063/430] go/printer: don't reduce nesting depth twice if parentheses are present around an expr No impact on formatting on our repos. Fixes #8021. LGTM=adonovan R=adonovan, dvyukov CC=golang-codereviews https://golang.org/cl/142020043 --- src/go/printer/nodes.go | 2 +- src/go/printer/testdata/expressions.golden | 5 +++++ src/go/printer/testdata/expressions.input | 5 +++++ src/go/printer/testdata/expressions.raw | 5 +++++ src/go/printer/testdata/statements.golden | 2 +- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go index e52236ddc6..d5a69349be 100644 --- a/src/go/printer/nodes.go +++ b/src/go/printer/nodes.go @@ -736,7 +736,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { if _, hasParens := x.X.(*ast.ParenExpr); hasParens { // don't print parentheses around an already parenthesized expression // TODO(gri) consider making this more general and incorporate precedence levels - p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth + p.expr0(x.X, depth) } else { p.print(token.LPAREN) p.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth diff --git a/src/go/printer/testdata/expressions.golden b/src/go/printer/testdata/expressions.golden index fbe8275b3a..e3d17a4653 100644 --- a/src/go/printer/testdata/expressions.golden +++ b/src/go/printer/testdata/expressions.golden @@ -94,6 +94,11 @@ func _() { _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666) _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx) + // test case for issue 8021 + // want: + // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]] + _ = ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]] + // the parser does not restrict expressions that may appear as statements true 42 diff --git a/src/go/printer/testdata/expressions.input b/src/go/printer/testdata/expressions.input index f4d20fa0f7..d20a59350e 100644 --- a/src/go/printer/testdata/expressions.input +++ b/src/go/printer/testdata/expressions.input @@ -95,6 +95,11 @@ func _() { _ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666) _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx) + // test case for issue 8021 + // want: + // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]] + _ = ([]bool{})[([]int{})[((1) + (((((1) + (((((((1) * (((((1) + (1))) + (1))))) + (1))) * (1))))) + (1))))]] + // the parser does not restrict expressions that may appear as statements true 42 diff --git a/src/go/printer/testdata/expressions.raw b/src/go/printer/testdata/expressions.raw index 97bc81dad8..2357336957 100644 --- a/src/go/printer/testdata/expressions.raw +++ b/src/go/printer/testdata/expressions.raw @@ -94,6 +94,11 @@ func _() { _ = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666) _ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx) + // test case for issue 8021 + // want: + // ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]] + _ = ([]bool{})[([]int{})[((1)+(((1)+((((1)*(((1)+(1))+(1)))+(1))*(1)))+(1)))]] + // the parser does not restrict expressions that may appear as statements true 42 diff --git a/src/go/printer/testdata/statements.golden b/src/go/printer/testdata/statements.golden index 324b6cdd0f..4b13460473 100644 --- a/src/go/printer/testdata/statements.golden +++ b/src/go/printer/testdata/statements.golden @@ -444,7 +444,7 @@ func _() { } if x == a+b*(T{42}[0]) { } - if x == a+(b * (T{42}[0])) { + if x == a+(b*(T{42}[0])) { } if x == a+b*(T{42}[0]) { } From 44753479c60f66ee3051ddc0bf5d420b2a1bf662 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 12 Sep 2014 16:12:39 -0400 Subject: [PATCH 064/430] runtime: remove a few untyped allocations LGTM=iant, khr, rlh R=khr, iant, bradfitz, rlh CC=dvyukov, golang-codereviews https://golang.org/cl/142030044 --- src/cmd/api/goapi.go | 9 +++---- src/runtime/os_windows.c | 6 ++--- src/runtime/proc.c | 52 ++++++++++------------------------------ src/runtime/proc.go | 16 +++++++++++++ src/runtime/runtime.c | 12 ++++------ src/runtime/runtime.go | 4 ++++ src/runtime/runtime.h | 2 ++ 7 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index fb0e984f72..da0dc4a923 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -377,7 +377,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { } } if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) { - // Just enough to keep the api checker happy. + // Just enough to keep the api checker happy. Keep sorted. src := "package runtime; type (" + " _defer struct{};" + " _func struct{};" + @@ -388,6 +388,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { " chantype struct{};" + " context struct{};" + // windows " eface struct{};" + + " epollevent struct{};" + " funcval struct{};" + " g struct{};" + " gobuf struct{};" + @@ -395,20 +396,20 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { " iface struct{};" + " interfacetype struct{};" + " itab struct{};" + + " keventt struct{};" + " m struct{};" + " maptype struct{};" + " mcache struct{};" + " mspan struct{};" + " mutex struct{};" + " note struct{};" + + " p struct{};" + " slicetype struct{};" + " stkframe struct{};" + " sudog struct{};" + + " timespec struct{};" + " waitq struct{};" + " wincallbackcontext struct{};" + - " keventt struct{};" + - " timespec struct{};" + - " epollevent struct{};" + "); " + "const (" + " cb_max = 2000;" + diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 8d069d3ee3..61cfdb5bf1 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -146,16 +146,14 @@ runtime·goenvs(void) for(p=env; *p; n++) p += runtime·findnullw(p)+1; - s = runtime·mallocgc(n*sizeof s[0], runtime·conservative, 0); + syscall·envs = runtime·makeStringSlice(n); + s = (String*)syscall·envs.array; p = env; for(i=0; iracectx = runtime·racegostart(runtime·newextram); // put on allg for garbage collector - allgadd(gp); + runtime·allgadd(gp); // Add m to the extra list. mnext = lockextra(true); @@ -2210,7 +2209,7 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp if((newg = gfget(p)) == nil) { newg = runtime·malg(StackMin); runtime·casgstatus(newg, Gidle, Gdead); - allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. + runtime·allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. } if(newg->stack.hi == 0) runtime·throw("newproc1: newg missing stack"); @@ -2257,35 +2256,6 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp return newg; } -static void -allgadd(G *gp) -{ - G **new; - uintptr cap; - - if(runtime·readgstatus(gp) == Gidle) - runtime·throw("allgadd: bad status Gidle"); - - runtime·lock(&allglock); - if(runtime·allglen >= allgcap) { - cap = 4096/sizeof(new[0]); - if(cap < 2*allgcap) - cap = 2*allgcap; - new = runtime·mallocgc(cap*sizeof(new[0]), runtime·conservative, 0); - if(new == nil) - runtime·throw("runtime: cannot allocate memory"); - if(runtime·allg != nil) - runtime·memmove(new, runtime·allg, runtime·allglen*sizeof(new[0])); - runtime·allg = new; - runtime·allgs.array = (void*)runtime·allg; - allgcap = cap; - runtime·allgs.cap = allgcap; - } - runtime·allg[runtime·allglen++] = gp; - runtime·allgs.len = runtime·allglen; - runtime·unlock(&allglock); -} - // Put on gfree list. // If local list is too long, transfer a batch to the global list. static void @@ -2713,6 +2683,8 @@ runtime·setcpuprofilerate_m(void) g->m->locks--; } +P *runtime·newP(void); + // Change number of processors. The world is stopped, sched is locked. static void procresize(int32 new) @@ -2729,7 +2701,7 @@ procresize(int32 new) for(i = 0; i < new; i++) { p = runtime·allp[i]; if(p == nil) { - p = (P*)runtime·mallocgc(sizeof(*p), runtime·conservative, 0); + p = runtime·newP(); p->id = i; p->status = Pgcstop; runtime·atomicstorep(&runtime·allp[i], p); @@ -2875,7 +2847,7 @@ checkdead(void) runtime·throw("checkdead: inconsistent counts"); } grunning = 0; - runtime·lock(&allglock); + runtime·lock(&runtime·allglock); for(i = 0; i < runtime·allglen; i++) { gp = runtime·allg[i]; if(gp->issystem) @@ -2888,13 +2860,13 @@ checkdead(void) case Grunnable: case Grunning: case Gsyscall: - runtime·unlock(&allglock); + runtime·unlock(&runtime·allglock); runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s); runtime·throw("checkdead: runnable g"); break; } } - runtime·unlock(&allglock); + runtime·unlock(&runtime·allglock); if(grunning == 0) // possible if main goroutine calls runtime·Goexit() runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!"); g->m->throwing = -1; // do not dump full stacks @@ -3198,7 +3170,7 @@ runtime·schedtrace(bool detailed) mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc, mp->spinning, g->m->blocked, id3); } - runtime·lock(&allglock); + runtime·lock(&runtime·allglock); for(gi = 0; gi < runtime·allglen; gi++) { gp = runtime·allg[gi]; mp = gp->m; @@ -3207,7 +3179,7 @@ runtime·schedtrace(bool detailed) gp->goid, runtime·readgstatus(gp), gp->waitreason, mp ? mp->id : -1, lockedm ? lockedm->id : -1); } - runtime·unlock(&allglock); + runtime·unlock(&runtime·allglock); runtime·unlock(&runtime·sched.lock); } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 4e3d2855f6..2f07c8a0b3 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -196,3 +196,19 @@ func lockedOSThread() bool { gp := getg() return gp.lockedm != nil && gp.m.lockedg != nil } + +func newP() *p { + return new(p) +} + +func allgadd(gp *g) { + if readgstatus(gp) == _Gidle { + gothrow("allgadd: bad status Gidle") + } + + lock(&allglock) + allgs = append(allgs, gp) + allg = &allgs[0] + allglen = uintptr(len(allgs)) + unlock(&allglock) +} diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 97d040664b..ae754dc5cd 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -97,12 +97,10 @@ runtime·goargs(void) if(Windows) return; - s = runtime·mallocgc(argc*sizeof s[0], runtime·conservative, 0); + os·Args = runtime·makeStringSlice(argc); + s = (String*)os·Args.array; for(i=0; i Date: Fri, 12 Sep 2014 15:05:41 -0700 Subject: [PATCH 065/430] cmd/gc: fix racewalk after writebarrier change Instrument dst argument of writebarrier calls. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/139560045 --- src/cmd/gc/racewalk.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c index 27581702cc..cb98ca2471 100644 --- a/src/cmd/gc/racewalk.c +++ b/src/cmd/gc/racewalk.c @@ -208,6 +208,31 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) goto ret; case OCALLFUNC: + // Instrument dst argument of runtime.writebarrier* calls + // as we do not instrument runtime code. + if(n->left->sym != S && n->left->sym->pkg == runtimepkg && + (strcmp(n->left->sym->name, "writebarrierptr") == 0 || + strcmp(n->left->sym->name, "writebarrierstring") == 0 || + strcmp(n->left->sym->name, "writebarrierslice") == 0 || + strcmp(n->left->sym->name, "writebarrieriface") == 0 || + strcmp(n->left->sym->name, "writebarrierfat") == 0)) { + // Find the dst argument. + // The list can be reordered, so it's not necessary just the first or the second element. + for(l = n->list; l; l = l->next) { + if(strcmp(n->left->sym->name, "writebarrierfat") == 0) { + if(l->n->left->xoffset == widthptr) + break; + } else { + if(l->n->left->xoffset == 0) + break; + } + } + if(l == nil) + fatal("racewalk: writebarrier no arg"); + if(l->n->right->op != OADDR) + fatal("racewalk: writebarrier bad arg"); + callinstr(&l->n->right->left, init, 1, 0); + } racewalknode(&n->left, init, 0, 0); goto ret; From d6cd230c985b5216ea6059ab69738c59658801ae Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 12 Sep 2014 16:16:09 -0700 Subject: [PATCH 066/430] runtime: test iteration order of sparse maps The behavior was fixed in CL 141270043. Add a test. Fixes #8410. LGTM=khr R=khr, remyoudompheng CC=golang-codereviews https://golang.org/cl/137560044 --- src/runtime/map_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index e2f1481ad5..9b76a5bbf2 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -442,6 +442,41 @@ func TestMapIterOrder(t *testing.T) { } } +// Issue 8410 +func TestMapSparseIterOrder(t *testing.T) { + // Run several rounds to increase the probability + // of failure. One is not enough. +NextRound: + for round := 0; round < 10; round++ { + m := make(map[int]bool) + // Add 1000 items, remove 980. + for i := 0; i < 1000; i++ { + m[i] = true + } + for i := 20; i < 1000; i++ { + delete(m, i) + } + + var first []int + for i := range m { + first = append(first, i) + } + + // 80 chances to get a different iteration order. + for n := 0; n < 80; n++ { + idx := 0 + for i := range m { + if i != first[idx] { + // iteration order changed. + continue NextRound + } + idx++ + } + } + t.Fatalf("constant iteration order on round %d: %v", round, first) + } +} + func TestMapStringBytesLookup(t *testing.T) { // Use large string keys to avoid small-allocation coalescing, // which can cause AllocsPerRun to report lower counts than it should. From e3d2e5550e525308e9e9323fbaf05c4ea6588215 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 12 Sep 2014 16:35:40 -0700 Subject: [PATCH 067/430] cmd/8g: remove unused variable (fix build) http://build.golang.org/log/0434a945e3351eedaf56aa824d2bfe9c0d5e6735 LGTM=dave R=bradfitz, dave CC=golang-codereviews https://golang.org/cl/144800043 --- src/cmd/8g/ggen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index a095be36e9..7c986cc645 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -210,7 +210,6 @@ clearfat(Node *nl) void ginscall(Node *f, int proc) { - int32 arg; Prog *p; Node reg, r1, con; From 40dd6bf38e06bf26aa1c15438cdf0965cf778050 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 13:57:28 -0400 Subject: [PATCH 068/430] runtime: mark asmcgocall<>(SB) as having no arguments It doesn't. Fixes 386 build. While we're here, mark runtime.asmcgocall as GO_ARGS, so that it will work with stack copying. I don't think anything that uses it can lead to a stack copy, but better safe than sorry. Certainly the runtime.asmcgocall_errno variant needs (and already has) GO_ARGS. TBR=iant CC=golang-codereviews https://golang.org/cl/138400043 --- src/runtime/asm_386.s | 3 ++- src/runtime/asm_amd64.s | 1 + src/runtime/asm_arm.s | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index c9fd75bfc4..21065b6d6f 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -647,6 +647,7 @@ TEXT gosave<>(SB),NOSPLIT,$0 // aligned appropriately for the gcc ABI. // See cgocall.c for more details. TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 + GO_ARGS MOVL fn+0(FP), AX MOVL arg+4(FP), BX CALL asmcgocall<>(SB) @@ -660,7 +661,7 @@ TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12 MOVL AX, ret+8(FP) RET -TEXT asmcgocall<>(SB),NOSPLIT,$0-12 +TEXT asmcgocall<>(SB),NOSPLIT,$0-0 // fn in AX, arg in BX MOVL SP, DX diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index d5e2f56ef0..da29f61ed8 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -624,6 +624,7 @@ TEXT gosave<>(SB),NOSPLIT,$0 // aligned appropriately for the gcc ABI. // See cgocall.c for more details. TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16 + GO_ARGS MOVQ fn+0(FP), AX MOVQ arg+8(FP), BX CALL asmcgocall<>(SB) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 368b4ad8e8..3e78d91143 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -481,6 +481,7 @@ TEXT gosave<>(SB),NOSPLIT,$0 // aligned appropriately for the gcc ABI. // See cgocall.c for more details. TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 + GO_ARGS MOVW fn+0(FP), R1 MOVW arg+4(FP), R0 BL asmcgocall<>(SB) From d889f5f01efc9f8da8865f5987f6a8f3029928c0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 20:39:08 +0000 Subject: [PATCH 069/430] runtime: fix traceback of trap on ARM The merged traceback was wrong for LR machines, because traceback didn't pass lr to gentraceback. Now that we have a test looking at traceback output for a trap (the test of runtime.Breakpoint), we caught this. While we're here, fix a 'set and not used' warning. Fixes arm build. TBR=r R=r CC=golang-codereviews https://golang.org/cl/143040043 --- src/runtime/mgc0.c | 3 ++- src/runtime/traceback.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index c976b09c36..30a8ea2c9c 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -634,9 +634,10 @@ scanframe(Stkframe *frame, void *unused) // Scan local variables if stack frame has been allocated. size = frame->varp - frame->sp; - minsize = 0; if(thechar != '6' && thechar != '8') minsize = sizeof(uintptr); + else + minsize = 0; if(size > minsize) { stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); if(stackmap == nil || stackmap->n <= 0) { diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index eaf54db319..07b68d29b5 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -451,9 +451,9 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) { } // Print traceback. By default, omits runtime frames. // If that means we print nothing at all, repeat forcing all frames printed. - n = gentraceback(pc, sp, 0, gp, 0, nil, _TracebackMaxFrames, nil, nil, false) + n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, false) if n == 0 { - n = gentraceback(pc, sp, 0, gp, 0, nil, _TracebackMaxFrames, nil, nil, true) + n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, true) } if n == _TracebackMaxFrames { print("...additional frames elided...\n") From 8e77a7ef6bce15e81b9a6ce5cb2fcbe47cd7ab84 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Mon, 15 Sep 2014 08:41:59 +1000 Subject: [PATCH 070/430] image/jpeg: reject invalid Ta and Td values. Fixes #8693. LGTM=crawshaw R=crawshaw CC=golang-codereviews https://golang.org/cl/141470043 --- src/image/jpeg/scan.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go index 8d81b08080..2bd1d9d531 100644 --- a/src/image/jpeg/scan.go +++ b/src/image/jpeg/scan.go @@ -65,7 +65,13 @@ func (d *decoder) processSOS(n int) error { } scan[i].compIndex = uint8(compIndex) scan[i].td = d.tmp[2+2*i] >> 4 + if scan[i].td > maxTh { + return FormatError("bad Td value") + } scan[i].ta = d.tmp[2+2*i] & 0x0f + if scan[i].ta > maxTh { + return FormatError("bad Ta value") + } } // zigStart and zigEnd are the spectral selection bounds. From 2eccf0d18fcbb2f369b80567bb43da58054313b5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 21:25:44 -0400 Subject: [PATCH 071/430] runtime: convert syscall_windows.c to Go This is necessary because syscall.Syscall blocks, and the garbage collector needs to be able to scan that frame while it is blocked, and C frames have no garbage collection information. Windows builders are broken now due to this problem: http://build.golang.org/log/152ca9a4be6783d3a8bf6e2f5b9fc265089728b6 LGTM=alex.brainman R=alex.brainman CC=golang-codereviews https://golang.org/cl/144830043 --- src/runtime/os_windows.c | 32 +++++-- src/runtime/runtime.h | 4 +- src/runtime/syscall_windows.c | 166 --------------------------------- src/runtime/syscall_windows.go | 82 ++++++++++++++++ src/runtime/thunk_windows.s | 30 ++++++ src/syscall/asm_windows.s | 13 --- src/syscall/dll_windows.go | 2 +- 7 files changed, 138 insertions(+), 191 deletions(-) delete mode 100644 src/runtime/syscall_windows.c create mode 100644 src/runtime/thunk_windows.s delete mode 100644 src/syscall/asm_windows.s diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 61cfdb5bf1..6c8f137ee5 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -78,6 +78,20 @@ extern uintptr runtime·externalthreadhandlerp; void runtime·externalthreadhandler(void); void runtime·sigtramp(void); +#pragma textflag NOSPLIT +uintptr +runtime·getLoadLibrary(void) +{ + return (uintptr)runtime·LoadLibrary; +} + +#pragma textflag NOSPLIT +uintptr +runtime·getGetProcAddress(void) +{ + return (uintptr)runtime·GetProcAddress; +} + static int32 getproccount(void) { @@ -326,7 +340,7 @@ runtime·nanotime(void) static void* stdcall(void *fn) { - g->m->libcall.fn = fn; + g->m->libcall.fn = (uintptr)fn; if(g->m->profilehz != 0) { // leave pc/sp for cpu profiler g->m->libcallg = g; @@ -345,7 +359,7 @@ void* runtime·stdcall0(void *fn) { g->m->libcall.n = 0; - g->m->libcall.args = &fn; // it's unused but must be non-nil, otherwise crashes + g->m->libcall.args = (uintptr)&fn; // it's unused but must be non-nil, otherwise crashes return stdcall(fn); } @@ -355,7 +369,7 @@ runtime·stdcall1(void *fn, uintptr a0) { USED(a0); g->m->libcall.n = 1; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -365,7 +379,7 @@ runtime·stdcall2(void *fn, uintptr a0, uintptr a1) { USED(a0, a1); g->m->libcall.n = 2; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -375,7 +389,7 @@ runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2) { USED(a0, a1, a2); g->m->libcall.n = 3; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -385,7 +399,7 @@ runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3) { USED(a0, a1, a2, a3); g->m->libcall.n = 4; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -395,7 +409,7 @@ runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uint { USED(a0, a1, a2, a3, a4); g->m->libcall.n = 5; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -405,7 +419,7 @@ runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uint { USED(a0, a1, a2, a3, a4, a5); g->m->libcall.n = 6; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } @@ -415,7 +429,7 @@ runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uint { USED(a0, a1, a2, a3, a4, a5, a6); g->m->libcall.n = 7; - g->m->libcall.args = &a0; + g->m->libcall.args = (uintptr)&a0; return stdcall(fn); } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 37728b4130..abd53c4ba1 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -248,9 +248,9 @@ struct GCStats struct LibCall { - void* fn; + uintptr fn; uintptr n; // number of parameters - void* args; // parameters + uintptr args; // parameters uintptr r1; // return values uintptr r2; uintptr err; // error number diff --git a/src/runtime/syscall_windows.c b/src/runtime/syscall_windows.c deleted file mode 100644 index e7903b5171..0000000000 --- a/src/runtime/syscall_windows.c +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2009 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. - -#include "runtime.h" -#include "os_GOOS.h" -#include "cgocall.h" -#include "textflag.h" - -typedef struct HandleErr HandleErr; -typedef struct SyscallErr SyscallErr; - -struct HandleErr { - uintptr handle; - uintptr err; -}; - -struct SyscallErr { - uintptr r1; - uintptr r2; - uintptr err; -}; - -#pragma textflag NOSPLIT -HandleErr -syscall·loadlibrary(uint16 *filename) -{ - LibCall c; - HandleErr r; - - c.fn = runtime·LoadLibrary; - c.n = 1; - c.args = &filename; - runtime·cgocall_errno(runtime·asmstdcall, &c); - r.handle = c.r1; - if(r.handle == 0) - r.err = c.err; - else - r.err = 0; - return r; -} - -#pragma textflag NOSPLIT -HandleErr -syscall·getprocaddress(uintptr handle, int8 *procname) -{ - LibCall c; - HandleErr r; - - USED(procname); - c.fn = runtime·GetProcAddress; - c.n = 2; - c.args = &handle; - runtime·cgocall_errno(runtime·asmstdcall, &c); - r.handle = c.r1; - if(r.handle == 0) - r.err = c.err; - else - r.err = 0; - return r; -} - -#pragma textflag NOSPLIT -SyscallErr -syscall·Syscall(uintptr fn, uintptr nargs, uintptr a1, uintptr a2, uintptr a3) -{ - LibCall c; - - USED(a2); - USED(a3); - c.fn = (void*)fn; - c.n = nargs; - c.args = &a1; - runtime·cgocall_errno(runtime·asmstdcall, &c); - return (SyscallErr){c.r1, c.r2, c.err}; -} - -#pragma textflag NOSPLIT -SyscallErr -syscall·Syscall6(uintptr fn, uintptr nargs, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6) -{ - LibCall c; - - USED(a2); - USED(a3); - USED(a4); - USED(a5); - USED(a6); - c.fn = (void*)fn; - c.n = nargs; - c.args = &a1; - runtime·cgocall_errno(runtime·asmstdcall, &c); - return (SyscallErr){c.r1, c.r2, c.err}; -} - -#pragma textflag NOSPLIT -SyscallErr -syscall·Syscall9(uintptr fn, uintptr nargs, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6, uintptr a7, uintptr a8, uintptr a9) -{ - LibCall c; - - USED(a2); - USED(a3); - USED(a4); - USED(a5); - USED(a6); - USED(a7); - USED(a8); - USED(a9); - c.fn = (void*)fn; - c.n = nargs; - c.args = &a1; - runtime·cgocall_errno(runtime·asmstdcall, &c); - return (SyscallErr){c.r1, c.r2, c.err}; -} - -#pragma textflag NOSPLIT -SyscallErr -syscall·Syscall12(uintptr fn, uintptr nargs, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6, uintptr a7, uintptr a8, uintptr a9, uintptr a10, uintptr a11, uintptr a12) -{ - LibCall c; - - USED(a2); - USED(a3); - USED(a4); - USED(a5); - USED(a6); - USED(a7); - USED(a8); - USED(a9); - USED(a10); - USED(a11); - USED(a12); - c.fn = (void*)fn; - c.n = nargs; - c.args = &a1; - runtime·cgocall_errno(runtime·asmstdcall, &c); - return (SyscallErr){c.r1, c.r2, c.err}; -} - -#pragma textflag NOSPLIT -SyscallErr -syscall·Syscall15(uintptr fn, uintptr nargs, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6, uintptr a7, uintptr a8, uintptr a9, uintptr a10, uintptr a11, uintptr a12, uintptr a13, uintptr a14, uintptr a15) -{ - LibCall c; - - USED(a2); - USED(a3); - USED(a4); - USED(a5); - USED(a6); - USED(a7); - USED(a8); - USED(a9); - USED(a10); - USED(a11); - USED(a12); - USED(a13); - USED(a14); - USED(a15); - c.fn = (void*)fn; - c.n = nargs; - c.args = &a1; - runtime·cgocall_errno(runtime·asmstdcall, &c); - return (SyscallErr){c.r1, c.r2, c.err}; -} diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 0592c57e1d..959c675f4f 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -86,3 +86,85 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { return callbackasmAddr(n) } + +func getLoadLibrary() uintptr + +//go:nosplit +func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { + var c libcall + c.fn = getLoadLibrary() + c.n = 1 + c.args = uintptr(unsafe.Pointer(&filename)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + handle = c.r1 + if handle == 0 { + err = c.err + } + return +} + +func getGetProcAddress() uintptr + +//go:nosplit +func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { + var c libcall + c.fn = getGetProcAddress() + c.n = 2 + c.args = uintptr(unsafe.Pointer(&handle)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + outhandle = c.r1 + if outhandle == 0 { + err = c.err + } + return +} + +//go:nosplit +func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { + var c libcall + c.fn = fn + c.n = nargs + c.args = uintptr(unsafe.Pointer(&a1)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + return c.r1, c.r2, c.err +} + +//go:nosplit +func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { + var c libcall + c.fn = fn + c.n = nargs + c.args = uintptr(unsafe.Pointer(&a1)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + return c.r1, c.r2, c.err +} + +//go:nosplit +func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { + var c libcall + c.fn = fn + c.n = nargs + c.args = uintptr(unsafe.Pointer(&a1)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + return c.r1, c.r2, c.err +} + +//go:nosplit +func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { + var c libcall + c.fn = fn + c.n = nargs + c.args = uintptr(unsafe.Pointer(&a1)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + return c.r1, c.r2, c.err +} + +//go:nosplit +func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { + var c libcall + c.fn = fn + c.n = nargs + c.args = uintptr(unsafe.Pointer(&a1)) + cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) + return c.r1, c.r2, c.err +} diff --git a/src/runtime/thunk_windows.s b/src/runtime/thunk_windows.s new file mode 100644 index 0000000000..7ccb98fd4d --- /dev/null +++ b/src/runtime/thunk_windows.s @@ -0,0 +1,30 @@ +// 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. + +#include "zasm_GOOS_GOARCH.h" +#include "textflag.h" + +TEXT syscall·Syscall(SB),NOSPLIT,$0-0 + JMP runtime·syscall_Syscall(SB) + +TEXT syscall·Syscall6(SB),NOSPLIT,$0-0 + JMP runtime·syscall_Syscall6(SB) + +TEXT syscall·Syscall9(SB),NOSPLIT,$0-0 + JMP runtime·syscall_Syscall9(SB) + +TEXT syscall·Syscall12(SB),NOSPLIT,$0-0 + JMP runtime·syscall_Syscall12(SB) + +TEXT syscall·Syscall15(SB),NOSPLIT,$0-0 + JMP runtime·syscall_Syscall15(SB) + +TEXT syscall·loadlibrary(SB),NOSPLIT,$0-0 + JMP runtime·syscall_loadlibrary(SB) + +TEXT syscall·getprocaddress(SB),NOSPLIT,$0-0 + JMP runtime·syscall_getprocaddress(SB) + +TEXT syscall·compileCallback(SB),NOSPLIT,$0 + JMP runtime·compileCallback(SB) diff --git a/src/syscall/asm_windows.s b/src/syscall/asm_windows.s deleted file mode 100644 index abb6641a25..0000000000 --- a/src/syscall/asm_windows.s +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2009 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. - -// -// System calls for Windows are implemented in ../runtime/syscall_windows.goc -// - -#include "textflag.h" - -// func compileCallback(fn interface{}, cleanstack bool) uintptr -TEXT ·compileCallback(SB),NOSPLIT,$0 - JMP runtime·compileCallback(SB) diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go index c2394682d9..18663b486b 100644 --- a/src/syscall/dll_windows.go +++ b/src/syscall/dll_windows.go @@ -19,7 +19,7 @@ type DLLError struct { func (e *DLLError) Error() string { return e.Msg } -// Implemented in ../runtime/syscall_windows.goc. +// Implemented in ../runtime/syscall_windows.go. func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) From 6c59cdcf34634309b2eb4f12ff3d6f14646f6545 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 22:20:01 -0400 Subject: [PATCH 072/430] runtime: fix solaris build CL 144830043 changed LibCall for Windows. I didn't realize Solaris used it too. TBR=iant CC=golang-codereviews https://golang.org/cl/142100043 --- src/runtime/os_solaris.c | 12 ++--- src/runtime/syscall_solaris.go | 88 +++++++++++++++++----------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c index 99c38d8be6..e16b8e6370 100644 --- a/src/runtime/os_solaris.c +++ b/src/runtime/os_solaris.c @@ -292,11 +292,11 @@ runtime·semacreate(void) // Call libc's malloc rather than runtime·malloc. This will // allocate space on the C heap. We can't call runtime·malloc // here because it could cause a deadlock. - g->m->libcall.fn = (void*)libc·malloc; + g->m->libcall.fn = (uintptr)(void*)libc·malloc; g->m->libcall.n = 1; runtime·memclr((byte*)&g->m->scratch, sizeof(g->m->scratch)); g->m->scratch.v[0] = (uintptr)sizeof(*sem); - g->m->libcall.args = (uintptr*)&g->m->scratch; + g->m->libcall.args = (uintptr)(uintptr*)&g->m->scratch; runtime·asmcgocall(runtime·asmsysvicall6, &g->m->libcall); sem = (void*)g->m->libcall.r1; if(runtime·sem_init(sem, 0, 0) != 0) @@ -315,12 +315,12 @@ runtime·semasleep(int64 ns) m->ts.tv_sec = ns / 1000000000LL; m->ts.tv_nsec = ns % 1000000000LL; - m->libcall.fn = (void*)libc·sem_reltimedwait_np; + m->libcall.fn = (uintptr)(void*)libc·sem_reltimedwait_np; m->libcall.n = 2; runtime·memclr((byte*)&m->scratch, sizeof(m->scratch)); m->scratch.v[0] = m->waitsema; m->scratch.v[1] = (uintptr)&m->ts; - m->libcall.args = (uintptr*)&m->scratch; + m->libcall.args = (uintptr)(uintptr*)&m->scratch; runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall); if(*m->perrno != 0) { if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR) @@ -330,11 +330,11 @@ runtime·semasleep(int64 ns) return 0; } for(;;) { - m->libcall.fn = (void*)libc·sem_wait; + m->libcall.fn = (uintptr)(void*)libc·sem_wait; m->libcall.n = 1; runtime·memclr((byte*)&m->scratch, sizeof(m->scratch)); m->scratch.v[0] = m->waitsema; - m->libcall.args = (uintptr*)&m->scratch; + m->libcall.args = (uintptr)(uintptr*)&m->scratch; runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall); if(m->libcall.r1 == 0) break; diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go index d0a3fc8dd0..50d3a1d36d 100644 --- a/src/runtime/syscall_solaris.go +++ b/src/runtime/syscall_solaris.go @@ -34,9 +34,9 @@ var ( //go:nosplit func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { call := libcall{ - fn: unsafe.Pointer(fn), + fn: fn, n: nargs, - args: unsafe.Pointer(&a1), + args: uintptr(unsafe.Pointer(&a1)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -47,9 +47,9 @@ func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err //go:nosplit func syscall_rawsysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { call := libcall{ - fn: unsafe.Pointer(fn), + fn: fn, n: nargs, - args: unsafe.Pointer(&a1), + args: uintptr(unsafe.Pointer(&a1)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.r2, call.err @@ -62,9 +62,9 @@ func syscall_rawsysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, e //go:nosplit func syscall_chdir(path uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_chdir), + fn: uintptr(unsafe.Pointer(&libc_chdir)), n: 1, - args: unsafe.Pointer(&path), + args: uintptr(unsafe.Pointer(&path)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -73,9 +73,9 @@ func syscall_chdir(path uintptr) (err uintptr) { //go:nosplit func syscall_chroot(path uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_chroot), + fn: uintptr(unsafe.Pointer(&libc_chroot)), n: 1, - args: unsafe.Pointer(&path), + args: uintptr(unsafe.Pointer(&path)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -89,9 +89,9 @@ func syscall_close(fd int32) int32 { func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_dlopen), + fn: uintptr(unsafe.Pointer(&libc_dlopen)), n: 2, - args: unsafe.Pointer(&name), + args: uintptr(unsafe.Pointer(&name)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -104,9 +104,9 @@ func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) { func syscall_dlclose(handle uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_dlclose), + fn: uintptr(unsafe.Pointer(&libc_dlclose)), n: 1, - args: unsafe.Pointer(&handle), + args: uintptr(unsafe.Pointer(&handle)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -116,9 +116,9 @@ func syscall_dlclose(handle uintptr) (err uintptr) { func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_dlsym), + fn: uintptr(unsafe.Pointer(&libc_dlsym)), n: 2, - args: unsafe.Pointer(&handle), + args: uintptr(unsafe.Pointer(&handle)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -132,9 +132,9 @@ func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) { //go:nosplit func syscall_execve(path, argv, envp uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_execve), + fn: uintptr(unsafe.Pointer(&libc_execve)), n: 3, - args: unsafe.Pointer(&path), + args: uintptr(unsafe.Pointer(&path)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -149,9 +149,9 @@ func syscall_exit(code uintptr) { //go:nosplit func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_fcntl), + fn: uintptr(unsafe.Pointer(&libc_fcntl)), n: 3, - args: unsafe.Pointer(&fd), + args: uintptr(unsafe.Pointer(&fd)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.err @@ -160,9 +160,9 @@ func syscall_fcntl(fd, cmd, arg uintptr) (val, err uintptr) { //go:nosplit func syscall_forkx(flags uintptr) (pid uintptr, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_forkx), + fn: uintptr(unsafe.Pointer(&libc_forkx)), n: 1, - args: unsafe.Pointer(&flags), + args: uintptr(unsafe.Pointer(&flags)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.err @@ -172,9 +172,9 @@ func syscall_gethostname() (name string, err uintptr) { cname := new([_MAXHOSTNAMELEN]byte) var args = [2]uintptr{uintptr(unsafe.Pointer(&cname[0])), _MAXHOSTNAMELEN} call := libcall{ - fn: unsafe.Pointer(&libc_gethostname), + fn: uintptr(unsafe.Pointer(&libc_gethostname)), n: 2, - args: unsafe.Pointer(&args[0]), + args: uintptr(unsafe.Pointer(&args[0])), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -189,9 +189,9 @@ func syscall_gethostname() (name string, err uintptr) { //go:nosplit func syscall_ioctl(fd, req, arg uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_ioctl), + fn: uintptr(unsafe.Pointer(&libc_ioctl)), n: 3, - args: unsafe.Pointer(&fd), + args: uintptr(unsafe.Pointer(&fd)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -199,9 +199,9 @@ func syscall_ioctl(fd, req, arg uintptr) (err uintptr) { func syscall_pipe() (r, w, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&pipe1), + fn: uintptr(unsafe.Pointer(&pipe1)), n: 0, - args: unsafe.Pointer(&pipe1), // it's unused but must be non-nil, otherwise crashes + args: uintptr(unsafe.Pointer(&pipe1)), // it's unused but must be non-nil, otherwise crashes } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -217,9 +217,9 @@ func syscall_pipe() (r, w, err uintptr) { // TODO(aram): make this panic once we stop calling fcntl(2) in net using it. func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_syscall), + fn: uintptr(unsafe.Pointer(&libc_syscall)), n: 4, - args: unsafe.Pointer(&trap), + args: uintptr(unsafe.Pointer(&trap)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.r2, call.err @@ -228,9 +228,9 @@ func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { //go:nosplit func syscall_setgid(gid uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_setgid), + fn: uintptr(unsafe.Pointer(&libc_setgid)), n: 1, - args: unsafe.Pointer(&gid), + args: uintptr(unsafe.Pointer(&gid)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -239,9 +239,9 @@ func syscall_setgid(gid uintptr) (err uintptr) { //go:nosplit func syscall_setgroups(ngid, gid uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_setgroups), + fn: uintptr(unsafe.Pointer(&libc_setgroups)), n: 2, - args: unsafe.Pointer(&ngid), + args: uintptr(unsafe.Pointer(&ngid)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -250,9 +250,9 @@ func syscall_setgroups(ngid, gid uintptr) (err uintptr) { //go:nosplit func syscall_setsid() (pid, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_setsid), + fn: uintptr(unsafe.Pointer(&libc_setsid)), n: 0, - args: unsafe.Pointer(&libc_setsid), // it's unused but must be non-nil, otherwise crashes + args: uintptr(unsafe.Pointer(&libc_setsid)), // it's unused but must be non-nil, otherwise crashes } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.err @@ -261,9 +261,9 @@ func syscall_setsid() (pid, err uintptr) { //go:nosplit func syscall_setuid(uid uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_setuid), + fn: uintptr(unsafe.Pointer(&libc_setuid)), n: 1, - args: unsafe.Pointer(&uid), + args: uintptr(unsafe.Pointer(&uid)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -272,9 +272,9 @@ func syscall_setuid(uid uintptr) (err uintptr) { //go:nosplit func syscall_setpgid(pid, pgid uintptr) (err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_setpgid), + fn: uintptr(unsafe.Pointer(&libc_setpgid)), n: 2, - args: unsafe.Pointer(&pid), + args: uintptr(unsafe.Pointer(&pid)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.err @@ -288,9 +288,9 @@ func syscall_setpgid(pid, pgid uintptr) (err uintptr) { // TODO(aram): make this panic once we stop calling fcntl(2) in net using it. func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_syscall), + fn: uintptr(unsafe.Pointer(&libc_syscall)), n: 4, - args: unsafe.Pointer(&trap), + args: uintptr(unsafe.Pointer(&trap)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -300,9 +300,9 @@ func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) { func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.Pointer) (wpid int, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_wait4), + fn: uintptr(unsafe.Pointer(&libc_wait4)), n: 4, - args: unsafe.Pointer(&pid), + args: uintptr(unsafe.Pointer(&pid)), } entersyscallblock() asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) @@ -313,9 +313,9 @@ func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe. //go:nosplit func syscall_write(fd, buf, nbyte uintptr) (n, err uintptr) { call := libcall{ - fn: unsafe.Pointer(&libc_write), + fn: uintptr(unsafe.Pointer(&libc_write)), n: 3, - args: unsafe.Pointer(&fd), + args: uintptr(unsafe.Pointer(&fd)), } asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call)) return call.r1, call.err From e8a74dcad96b134ba29a7edbc3bc84ba597e7c64 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 22:24:29 -0400 Subject: [PATCH 073/430] runtime: fix solaris build, part 2 This file was already assigned to another CL so it didn't make it into the build fix CL. Sigh. TBR=iant CC=golang-codereviews https://golang.org/cl/144850043 --- src/runtime/os_solaris.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go index a5e6966781..3cffff3e29 100644 --- a/src/runtime/os_solaris.go +++ b/src/runtime/os_solaris.go @@ -31,9 +31,10 @@ var asmsysvicall6 libcFunc //go:nosplit func sysvicall0(fn *libcFunc) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 0 - libcall.args = unsafe.Pointer(fn) // it's unused but must be non-nil, otherwise crashes + // TODO(rsc): Why is noescape necessary here and below? + libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -41,9 +42,9 @@ func sysvicall0(fn *libcFunc) uintptr { //go:nosplit func sysvicall1(fn *libcFunc, a1 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 1 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -51,9 +52,9 @@ func sysvicall1(fn *libcFunc, a1 uintptr) uintptr { //go:nosplit func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 2 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -61,9 +62,9 @@ func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr { //go:nosplit func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 3 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -71,9 +72,9 @@ func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr { //go:nosplit func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 4 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -81,9 +82,9 @@ func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr { //go:nosplit func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 5 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } @@ -91,9 +92,9 @@ func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr { //go:nosplit func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr { libcall := &getg().m.libcall - libcall.fn = unsafe.Pointer(fn) + libcall.fn = uintptr(unsafe.Pointer(fn)) libcall.n = 6 - libcall.args = noescape(unsafe.Pointer(&a1)) + libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } From 3b4bccc82061fd1f9c70a1b6e85efbdd2ded51a2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 14 Sep 2014 22:27:03 -0400 Subject: [PATCH 074/430] syscall: add GO_ARGS to Go-called assembly Fixes sporadic linux/386 build failure (untyped args) and probably some others we haven't observed yet. Fixes #8727. TBR=iant R=golang-codereviews CC=bradfitz, golang-codereviews, iant, khr, r https://golang.org/cl/143930043 --- src/syscall/asm_linux_386.s | 3 +++ src/syscall/asm_linux_amd64.s | 1 + src/syscall/asm_linux_arm.s | 1 + src/syscall/asm_plan9_386.s | 3 +++ src/syscall/asm_plan9_amd64.s | 3 +++ 5 files changed, 11 insertions(+) diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s index bcb85add64..2ce51822da 100644 --- a/src/syscall/asm_linux_386.s +++ b/src/syscall/asm_linux_386.s @@ -119,6 +119,7 @@ ok2: // func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int) // Kernel interface gets call sub-number and pointer to a0. TEXT ·socketcall(SB),NOSPLIT,$0-36 + GO_ARGS CALL runtime·entersyscall(SB) MOVL $SYS_SOCKETCALL, AX // syscall entry MOVL 4(SP), BX // socket call number @@ -143,6 +144,7 @@ oksock: // func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int) // Kernel interface gets call sub-number and pointer to a0. TEXT ·rawsocketcall(SB),NOSPLIT,$0-36 + GO_ARGS MOVL $SYS_SOCKETCALL, AX // syscall entry MOVL 4(SP), BX // socket call number LEAL 8(SP), CX // pointer to call arguments @@ -168,6 +170,7 @@ oksock1: // Underlying system call is // llseek(int fd, int offhi, int offlo, int64 *result, int whence) TEXT ·seek(SB),NOSPLIT,$0-28 + GO_ARGS CALL runtime·entersyscall(SB) MOVL $SYS__LLSEEK, AX // syscall entry MOVL 4(SP), BX // fd diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s index 6c9e654519..0277c506c0 100644 --- a/src/syscall/asm_linux_amd64.s +++ b/src/syscall/asm_linux_amd64.s @@ -116,6 +116,7 @@ ok2: RET TEXT ·gettimeofday(SB),NOSPLIT,$0-16 + GO_ARGS MOVQ 8(SP), DI MOVQ $0, SI MOVQ runtime·__vdso_gettimeofday_sym(SB), AX diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s index 0060a2171c..9451013813 100644 --- a/src/syscall/asm_linux_arm.s +++ b/src/syscall/asm_linux_arm.s @@ -111,6 +111,7 @@ ok2: // Underlying system call is // llseek(int fd, int offhi, int offlo, int64 *result, int whence) TEXT ·seek(SB),NOSPLIT,$0-32 + GO_ARGS BL runtime·entersyscall(SB) MOVW $SYS__LLSEEK, R7 // syscall entry MOVW 4(SP), R0 // fd diff --git a/src/syscall/asm_plan9_386.s b/src/syscall/asm_plan9_386.s index 8585385bcd..46562de845 100644 --- a/src/syscall/asm_plan9_386.s +++ b/src/syscall/asm_plan9_386.s @@ -132,6 +132,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) TEXT ·seek(SB),NOSPLIT,$0-36 + GO_ARGS LEAL newoffset+24(SP), AX MOVL AX, placeholder+4(SP) @@ -163,6 +164,8 @@ copyresult6: //func exit(code int) // Import runtime·exit for cleanly exiting. TEXT ·exit(SB),NOSPLIT,$4-4 + GO_ARGS + NO_LOCAL_POINTERS MOVL code+0(FP), AX MOVL AX, 0(SP) CALL runtime·exit(SB) diff --git a/src/syscall/asm_plan9_amd64.s b/src/syscall/asm_plan9_amd64.s index afbd49152c..283e28999a 100644 --- a/src/syscall/asm_plan9_amd64.s +++ b/src/syscall/asm_plan9_amd64.s @@ -131,6 +131,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) TEXT ·seek(SB),NOSPLIT,$0-56 + GO_ARGS LEAQ newoffset+40(SP), AX MOVQ AX, placeholder+8(SP) @@ -161,6 +162,8 @@ copyresult6: //func exit(code int) // Import runtime·exit for cleanly exiting. TEXT ·exit(SB),NOSPLIT,$8-8 + GO_ARGS + NO_LOCAL_POINTERS MOVQ code+0(FP), AX MOVQ AX, 0(SP) CALL runtime·exit(SB) From 5d5312c5dd979f8ae37482f0fc938587aeb5a245 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 15 Sep 2014 12:58:28 +1000 Subject: [PATCH 075/430] runtime: fix parameter checking in syscall.NewCallback I have made mistake while converting it to Go (CL 132820043). Added test as penance for my sin. LGTM=rsc R=golang-codereviews, bradfitz, rsc CC=golang-codereviews https://golang.org/cl/136560043 --- src/runtime/syscall_windows.go | 2 +- src/runtime/syscall_windows_test.go | 39 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 959c675f4f..efbcab510d 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -53,7 +53,7 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) { } argsize := uintptr(0) for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { - if (*t).size != uintptrSize { + if (*t).size > uintptrSize { panic("compilecallback: input parameter size is wrong") } argsize += uintptrSize diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index fabf935d8e..a828512188 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -449,3 +449,42 @@ func TestStdcallAndCDeclCallbacks(t *testing.T) { } } } + +func TestRegisterClass(t *testing.T) { + kernel32 := GetDLL(t, "kernel32.dll") + user32 := GetDLL(t, "user32.dll") + mh, _, _ := kernel32.Proc("GetModuleHandleW").Call(0) + cb := syscall.NewCallback(func(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintptr) { + t.Fatal("callback should never get called") + return 0 + }) + type Wndclassex struct { + Size uint32 + Style uint32 + WndProc uintptr + ClsExtra int32 + WndExtra int32 + Instance syscall.Handle + Icon syscall.Handle + Cursor syscall.Handle + Background syscall.Handle + MenuName *uint16 + ClassName *uint16 + IconSm syscall.Handle + } + name := syscall.StringToUTF16Ptr("test_window") + wc := Wndclassex{ + WndProc: cb, + Instance: syscall.Handle(mh), + ClassName: name, + } + wc.Size = uint32(unsafe.Sizeof(wc)) + a, _, err := user32.Proc("RegisterClassExW").Call(uintptr(unsafe.Pointer(&wc))) + if a == 0 { + t.Fatalf("RegisterClassEx failed: %v", err) + } + r, _, err := user32.Proc("UnregisterClassW").Call(uintptr(unsafe.Pointer(name)), 0) + if r == 0 { + t.Fatalf("UnregisterClass failed: %v", err) + } +} From bb431245cc9a464797b9c58fdf066d3969f66384 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 15 Sep 2014 07:14:33 -0400 Subject: [PATCH 076/430] net/http: don't call FileSystem.Open with unclean index.html path Fixes #8722 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/142090043 --- src/net/http/fs.go | 2 +- src/net/http/fs_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/net/http/fs.go b/src/net/http/fs.go index bae902cd29..7bd777b712 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -381,7 +381,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec // use contents of index.html for directory, if present if d.IsDir() { - index := name + indexPage + index := strings.TrimSuffix(name, "/") + indexPage ff, err := fs.Open(index) if err == nil { defer ff.Close() diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index a6f33cc42d..8770d9b410 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -877,4 +877,41 @@ func TestLinuxSendfileChild(*testing.T) { } } +func TestFileServerCleanPath(t *testing.T) { + tests := []struct { + path string + wantCode int + wantOpen []string + }{ + {"/", 200, []string{"/", "/index.html"}}, + {"/dir", 301, []string{"/dir"}}, + {"/dir/", 200, []string{"/dir", "/dir/index.html"}}, + } + for _, tt := range tests { + var log []string + rr := httptest.NewRecorder() + req, _ := NewRequest("GET", "http://foo.localhost"+tt.path, nil) + FileServer(fileServerCleanPathDir{&log}).ServeHTTP(rr, req) + if !reflect.DeepEqual(log, tt.wantOpen) { + t.Logf("For %s: Opens = %q; want %q", tt.path, log, tt.wantOpen) + } + if rr.Code != tt.wantCode { + t.Logf("For %s: Response code = %d; want %d", tt.path, rr.Code, tt.wantCode) + } + } +} + +type fileServerCleanPathDir struct { + log *[]string +} + +func (d fileServerCleanPathDir) Open(path string) (File, error) { + *(d.log) = append(*(d.log), path) + if path == "/" || path == "/dir" || path == "/dir/" { + // Just return back something that's a directory. + return Dir(".").Open(".") + } + return nil, os.ErrNotExist +} + type panicOnSeek struct{ io.ReadSeeker } From 8d47b0825549b9ec55882e0d2c135048d88734b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Oudompheng?= Date: Mon, 15 Sep 2014 18:24:16 +0200 Subject: [PATCH 077/430] cmd/gc: generate type alg after calling dowidth. Previously it might happen before calling dowidth and result in a compiler crash. Fixes #8060. LGTM=dvyukov, rsc R=golang-codereviews, dvyukov, gobot, rsc CC=golang-codereviews https://golang.org/cl/110980044 --- src/cmd/gc/reflect.c | 2 +- test/fixedbugs/issue8060.dir/a.go | 7 +++++++ test/fixedbugs/issue8060.dir/b.go | 13 +++++++++++++ test/fixedbugs/issue8060.go | 9 +++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue8060.dir/a.go create mode 100644 test/fixedbugs/issue8060.dir/b.go create mode 100644 test/fixedbugs/issue8060.go diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 31e449e760..4892ab7570 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -727,12 +727,12 @@ dcommontype(Sym *s, int ot, Type *t) sizeofAlg = 2*widthptr; if(algarray == nil) algarray = pkglookup("algarray", runtimepkg); + dowidth(t); alg = algtype(t); algsym = S; if(alg < 0) algsym = dalgsym(t); - dowidth(t); if(t->sym != nil && !isptr[t->etype]) sptr = dtypesym(ptrto(t)); else diff --git a/test/fixedbugs/issue8060.dir/a.go b/test/fixedbugs/issue8060.dir/a.go new file mode 100644 index 0000000000..22ba69ee1b --- /dev/null +++ b/test/fixedbugs/issue8060.dir/a.go @@ -0,0 +1,7 @@ +// 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 a + +var A = []*[2][1]float64{} diff --git a/test/fixedbugs/issue8060.dir/b.go b/test/fixedbugs/issue8060.dir/b.go new file mode 100644 index 0000000000..85fb6ec7db --- /dev/null +++ b/test/fixedbugs/issue8060.dir/b.go @@ -0,0 +1,13 @@ +// 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 b + +import "a" + +var X = a.A + +func b() { + _ = [3][1]float64{} +} diff --git a/test/fixedbugs/issue8060.go b/test/fixedbugs/issue8060.go new file mode 100644 index 0000000000..ec52659e6e --- /dev/null +++ b/test/fixedbugs/issue8060.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 8060: internal compiler error. + +package ignored From e024ed5ca4186b915e9a227f022f9c7bcfded5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Oudompheng?= Date: Mon, 15 Sep 2014 18:31:47 +0200 Subject: [PATCH 078/430] cmd/gc: don't walk static nodes generated by anylit. During anylit run, nodes such as SLICEARR(statictmp, [:]) may be generated and are expected to be found unchanged by gen_as_init. In some walks (in particular walkselect), the statement may be walked again and lowered to its usual form, leading to a crash. Fixes #8017. Fixes #8024. Fixes #8058. LGTM=rsc R=golang-codereviews, dvyukov, gobot, rsc CC=golang-codereviews https://golang.org/cl/112080043 --- src/cmd/gc/walk.c | 2 ++ test/fixedbugs/issue8017.go | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/fixedbugs/issue8017.go diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index ce0f3eb955..a30fa62a6b 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -137,6 +137,8 @@ walkstmt(Node **np) n = *np; if(n == N) return; + if(n->dodata == 2) // don't walk, generated by anylit. + return; setlineno(n); diff --git a/test/fixedbugs/issue8017.go b/test/fixedbugs/issue8017.go new file mode 100644 index 0000000000..22056e08c5 --- /dev/null +++ b/test/fixedbugs/issue8017.go @@ -0,0 +1,26 @@ +// compile + +// 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. + +// Issues 8017 and 8058: walk modifies nodes generated +// by slicelit and causes an internal error afterwards +// when gen_as_init parses it back. + +package main + +func F() { + var ch chan int + select { + case <-ch: + case <-make(chan int, len([2][]int{([][]int{})[len(ch)], []int{}})): + } +} + +func G() { + select { + case <-([1][]chan int{[]chan int{}})[0][0]: + default: + } +} From f197988ca596e87f1e971d5873bc3cee5c650b98 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 15 Sep 2014 10:56:37 -0700 Subject: [PATCH 079/430] test: make maplinear iterdelete test less flaky iterdelete's run time varies; occasionally we get unlucky. To reduce spurious failures, average away some of the variation. On my machine, 8 of 5000 runs (0.15%) failed before this CL. After this CL, there were no failures after 35,000 runs. I confirmed that this adjusted test still fails before CL 141270043. LGTM=khr R=khr CC=bradfitz, golang-codereviews https://golang.org/cl/140610043 --- test/maplinear.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/maplinear.go b/test/maplinear.go index 8cc198b8fe..06da968ef0 100644 --- a/test/maplinear.go +++ b/test/maplinear.go @@ -146,15 +146,19 @@ func main() { // O(n lg n) time. Fortunately, the checkLinear test // leaves enough wiggle room to include n lg n time // (it actually tests for O(n^log_2(3)). - checkLinear("iterdelete", 10000, func(n int) { - m := map[int]int{} - for i := 0; i < n; i++ { - m[i] = i - } - for i := 0; i < n; i++ { - for k := range m { - delete(m, k) - break + // To prevent false positives, average away variation + // by doing multiple rounds within a single run. + checkLinear("iterdelete", 2500, func(n int) { + for round := 0; round < 4; round++ { + m := map[int]int{} + for i := 0; i < n; i++ { + m[i] = i + } + for i := 0; i < n; i++ { + for k := range m { + delete(m, k) + break + } } } }) From 1e4f86e48550c1d04a3778948613f38a078e2801 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 15 Sep 2014 12:30:57 -0700 Subject: [PATCH 080/430] runtime: try harder to get different iteration orders. Fixes #8736. LGTM=iant, josharian R=golang-codereviews, iant, josharian CC=golang-codereviews https://golang.org/cl/144910044 --- src/runtime/map_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 9b76a5bbf2..92da2d8209 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -462,8 +462,9 @@ NextRound: first = append(first, i) } - // 80 chances to get a different iteration order. - for n := 0; n < 80; n++ { + // 800 chances to get a different iteration order. + // See bug 8736 for why we need so many tries. + for n := 0; n < 800; n++ { idx := 0 for i := range m { if i != first[idx] { From 7e62316b849aea96e65c9bb2293a788cd9722b37 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 15 Sep 2014 15:09:17 -0700 Subject: [PATCH 081/430] runtime: test Goexit/defer iteraction. Make sure Goexit runs defers. Make sure recover() during a Goexit defer returns nil. LGTM=dvyukov, bradfitz R=golang-codereviews, dvyukov, bradfitz, khr CC=golang-codereviews https://golang.org/cl/140650043 --- src/runtime/crash_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index a86a3b7904..d1577fb5fe 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -159,6 +159,22 @@ func TestGoexitCrash(t *testing.T) { } } +func TestGoexitDefer(t *testing.T) { + c := make(chan struct{}) + go func() { + defer func() { + r := recover() + if r != nil { + t.Errorf("non-nil recover during Goexit") + } + c <- struct{}{} + }() + runtime.Goexit() + }() + // Note: if the defer fails to run, we will get a deadlock here + <-c +} + func TestGoNil(t *testing.T) { output := executeTest(t, goNilSource, nil) want := "go of nil func value" From 2bb0a5e085bda1812b7be711335fc43baf1af52e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 15 Sep 2014 16:40:43 -0700 Subject: [PATCH 082/430] cmd/api: internal debugging supprt Document that the package cache has an issue (8425) to speed up future debugging. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/143980043 --- src/cmd/api/goapi.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index da0dc4a923..8494a3f61b 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -450,6 +450,11 @@ func contains(list []string, s string) bool { return false } +// The package cache doesn't operate correctly in rare (so far artificial) +// circumstances (issue 8425). Disable before debugging non-obvious errors +// from the type-checker. +const usePkgCache = true + var ( pkgCache = map[string]*types.Package{} // map tagKey to package pkgTags = map[string][]string{} // map import dir to list of relevant tags @@ -511,11 +516,13 @@ func (w *Walker) Import(name string) (pkg *types.Package) { // If we've already done an import with the same set // of relevant tags, reuse the result. var key string - if tags, ok := pkgTags[dir]; ok { - key = tagKey(dir, context, tags) - if pkg := pkgCache[key]; pkg != nil { - w.imported[name] = pkg - return pkg + if usePkgCache { + if tags, ok := pkgTags[dir]; ok { + key = tagKey(dir, context, tags) + if pkg := pkgCache[key]; pkg != nil { + w.imported[name] = pkg + return pkg + } } } @@ -528,9 +535,11 @@ func (w *Walker) Import(name string) (pkg *types.Package) { } // Save tags list first time we see a directory. - if _, ok := pkgTags[dir]; !ok { - pkgTags[dir] = info.AllTags - key = tagKey(dir, context, info.AllTags) + if usePkgCache { + if _, ok := pkgTags[dir]; !ok { + pkgTags[dir] = info.AllTags + key = tagKey(dir, context, info.AllTags) + } } filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...) @@ -583,7 +592,9 @@ func (w *Walker) Import(name string) (pkg *types.Package) { log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt) } - pkgCache[key] = pkg + if usePkgCache { + pkgCache[key] = pkg + } w.imported[name] = pkg return From c3dbf56a14e8d9dffab7330c203a82a66cf9722e Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Mon, 15 Sep 2014 18:16:45 -0700 Subject: [PATCH 083/430] cmd/ld: document that -X overwrites initialized variables Fixes #7626. LGTM=iant R=rsc, iant CC=golang-codereviews https://golang.org/cl/144870045 --- src/cmd/ld/doc.go | 6 +++--- test/linkx.go | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go index 8135bd549c..5b5833db5d 100644 --- a/src/cmd/ld/doc.go +++ b/src/cmd/ld/doc.go @@ -63,9 +63,9 @@ Options new in this version: -w Omit the DWARF symbol table. -X symbol value - Set the value of an otherwise uninitialized string variable. - The symbol name should be of the form importpath.name, - as displayed in the symbol table printed by "go tool nm". + Set the value of a string variable. The symbol name + should be of the form importpath.name, as displayed + in the symbol table printed by "go tool nm". -race Link with race detection libraries. -B value diff --git a/test/linkx.go b/test/linkx.go index 12d446ffc1..36d16aec9b 100644 --- a/test/linkx.go +++ b/test/linkx.go @@ -1,4 +1,4 @@ -// $G $D/$F.go && $L -X main.tbd hello $F.$A && ./$A.out +// $G $D/$F.go && $L -X main.tbd hello -X main.overwrite trumped $F.$A && ./$A.out // NOTE: This test is not run by 'run.go' and so not run by all.bash. // To run this test you must use the ./run shell script. @@ -12,9 +12,13 @@ package main var tbd string +var overwrite string = "dibs" func main() { if tbd != "hello" { - println("BUG: test/linkx", len(tbd), tbd) + println("BUG: test/linkx tbd", len(tbd), tbd) + } + if overwrite != "trumped" { + println("BUG: test/linkx overwrite", len(overwrite), overwrite) } } From 337fe4134fe733377db6025d67cfe01a9608099a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 09:58:17 -0400 Subject: [PATCH 084/430] cmd/gc: make runtime escape an error, not a fatal error It is more useful to report all the errors instead of just the first. LGTM=dave, khr R=khr, dave CC=golang-codereviews https://golang.org/cl/143940043 --- src/cmd/gc/gen.c | 2 +- src/cmd/gc/walk.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 86acd88259..83c46c6504 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -585,7 +585,7 @@ cgen_dcl(Node *n) if(!(n->class & PHEAP)) return; if(compiling_runtime) - fatal("%N escapes to heap, not allowed in runtime.", n); + yyerror("%N escapes to heap, not allowed in runtime.", n); if(n->alloc == nil) n->alloc = callnew(n->type); cgen_as(n->heapaddr, n->alloc); diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index a30fa62a6b..713348c0c0 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2505,7 +2505,7 @@ paramstoheap(Type **argin, int out) // generate allocation & copying code if(compiling_runtime) - fatal("%N escapes to heap, not allowed in runtime.", v); + yyerror("%N escapes to heap, not allowed in runtime.", v); if(v->alloc == nil) v->alloc = callnew(v->type); nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); From 3d2321f639452afbccc2249153c16abec2a6607f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 10:01:28 -0400 Subject: [PATCH 085/430] io: clarify Reader returning 0, nil Fixes #8317. LGTM=bradfitz R=bradfitz, iant, r CC=golang-codereviews https://golang.org/cl/143100043 --- src/io/io.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/io/io.go b/src/io/io.go index e8bbad537c..7507a84929 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -62,8 +62,11 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error") // allowed EOF behaviors. // // Implementations of Read are discouraged from returning a -// zero byte count with a nil error, and callers should treat -// that situation as a no-op. Implementations must not retain p. +// zero byte count with a nil error, except when len(p) == 0. +// Callers should treat a return of 0 and nil as indicating that +// nothing happened; in particular it does not indicate EOF. +// +// Implementations must not retain p. type Reader interface { Read(p []byte) (n int, err error) } From 8d61334dd5b08c8076e343aa33197bd219cdf922 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 10:21:54 -0400 Subject: [PATCH 086/430] cmd/gc: say 'non-constant array bound' instead of 'invalid array bound' Fixes #8196. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/141510044 --- src/cmd/gc/typecheck.c | 5 ++++- test/fixedbugs/bug255.go | 19 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 746feb4d1b..18d20cdd16 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -408,7 +408,10 @@ reswitch: v = toint(l->val); break; default: - yyerror("invalid array bound %N", l); + if(l->type != T && isint[l->type->etype] && l->op != OLITERAL) + yyerror("non-constant array bound %N", l); + else + yyerror("invalid array bound %N", l); goto error; } t->bound = mpgetfix(v.u.xval); diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go index acf4f23910..65ed1b8f6f 100644 --- a/test/fixedbugs/bug255.go +++ b/test/fixedbugs/bug255.go @@ -6,10 +6,15 @@ package main -var a [10]int // ok -var b [1e1]int // ok -var c [1.5]int // ERROR "truncated" -var d ["abc"]int // ERROR "invalid array bound|not numeric" -var e [nil]int // ERROR "invalid array bound|not numeric" -var f [e]int // ERROR "invalid array bound|not constant" -var g [1<<65]int // ERROR "array bound is too large|overflows" +var a [10]int // ok +var b [1e1]int // ok +var c [1.5]int // ERROR "truncated" +var d ["abc"]int // ERROR "invalid array bound|not numeric" +var e [nil]int // ERROR "invalid array bound|not numeric" +var f [e]int // ERROR "invalid array bound|not constant" +var g [1 << 65]int // ERROR "array bound is too large|overflows" +var h [len(a)]int // ok + +func ff() string + +var i [len([1]string{ff()})]int // ERROR "non-constant array bound|not constant" From d2574e2adb658b46ea2d8e22b3195cc14da1affe Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 10:22:15 -0400 Subject: [PATCH 087/430] runtime: remove duplicated Go constants The C header files are the single point of truth: every C enum constant Foo is available to Go as _Foo. Remove or redirect duplicate Go declarations so they cannot be out of sync. Eventually we will need to put constants in Go, but for now having them be out of sync with C is too risky. These predate the build support for auto-generating Go constants from the C definitions. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/141510043 --- src/cmd/api/goapi.go | 46 +++++++++++++++++++++++++++ src/cmd/dist/buildruntime.c | 6 ++-- src/runtime/arch_386.go | 4 --- src/runtime/arch_amd64.go | 4 --- src/runtime/arch_amd64p32.go | 4 --- src/runtime/arch_arm.go | 4 --- src/runtime/chan.go | 2 +- src/runtime/malloc.c | 6 ++-- src/runtime/malloc.go | 48 ++++++++++++----------------- src/runtime/mgc0.c | 2 +- src/runtime/mgc0.go | 12 -------- src/runtime/mgc0.h | 12 ++++---- src/runtime/os_darwin.go | 2 -- src/runtime/os_freebsd.go | 2 -- src/runtime/os_linux.go | 2 -- src/runtime/os_nacl.go | 2 -- src/runtime/os_netbsd.go | 2 -- src/runtime/os_openbsd.go | 2 -- src/runtime/os_plan9.go | 4 --- src/runtime/os_solaris.go | 2 -- src/runtime/os_windows.go | 2 -- src/runtime/runtime.h | 1 - src/runtime/sema.go | 2 +- src/runtime/slice.go | 8 ++--- src/runtime/string.go | 2 +- src/runtime/typekind.go | 60 ++++++++++++++++++------------------ src/runtime/typekind.h | 3 -- 27 files changed, 117 insertions(+), 129 deletions(-) diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 8494a3f61b..78b7d6edf1 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -423,6 +423,52 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { " _Genqueue = 7;" + " _Gcopystack = 8;" + " _NSIG = 32;" + + " _FlagNoScan = iota;" + + " _FlagNoZero;" + + " _TinySize;" + + " _TinySizeClass;" + + " _MaxSmallSize;" + + " _PageShift;" + + " _PageSize;" + + " _PageMask;" + + " _BitsPerPointer;" + + " _BitsMask;" + + " _PointersPerByte;" + + " _MaxGCMask;" + + " _BitsDead;" + + " _BitsPointer;" + + " _MSpanInUse;" + + " _ConcurrentSweep;" + + " _KindBool;" + + " _KindInt;" + + " _KindInt8;" + + " _KindInt16;" + + " _KindInt32;" + + " _KindInt64;" + + " _KindUint;" + + " _KindUint8;" + + " _KindUint16;" + + " _KindUint32;" + + " _KindUint64;" + + " _KindUintptr;" + + " _KindFloat32;" + + " _KindFloat64;" + + " _KindComplex64;" + + " _KindComplex128;" + + " _KindArray;" + + " _KindChan;" + + " _KindFunc;" + + " _KindInterface;" + + " _KindMap;" + + " _KindPtr;" + + " _KindSlice;" + + " _KindString;" + + " _KindStruct;" + + " _KindUnsafePointer;" + + " _KindDirectIface;" + + " _KindGCProg;" + + " _KindNoPointers;" + + " _KindMask;" + ")" f, err = parser.ParseFile(fset, filename, src, 0) if err != nil { diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c index 36efb5711c..1257d5b811 100644 --- a/src/cmd/dist/buildruntime.c +++ b/src/cmd/dist/buildruntime.c @@ -329,6 +329,8 @@ mkzsys(char *dir, char *file) static char *runtimedefs[] = { "defs.c", + "malloc.c", + "mgc0.c", "proc.c", "parfor.c", }; @@ -337,8 +339,8 @@ static char *runtimedefs[] = { // which contains Go struct definitions equivalent to the C ones. // Mostly we just write the output of 6c -q to the file. // However, we run it on multiple files, so we have to delete -// the duplicated definitions, and we don't care about the funcs -// and consts, so we delete those too. +// the duplicated definitions, and we don't care about the funcs, +// so we delete those too. // void mkzruntimedefs(char *dir, char *file) diff --git a/src/runtime/arch_386.go b/src/runtime/arch_386.go index 287b67e270..79d38c7ab1 100644 --- a/src/runtime/arch_386.go +++ b/src/runtime/arch_386.go @@ -4,9 +4,5 @@ package runtime -const ( - cacheLineSize = 64 -) - type uintreg uint32 type intptr int32 // TODO(rsc): remove diff --git a/src/runtime/arch_amd64.go b/src/runtime/arch_amd64.go index fe60c70660..270cd7b957 100644 --- a/src/runtime/arch_amd64.go +++ b/src/runtime/arch_amd64.go @@ -4,9 +4,5 @@ package runtime -const ( - cacheLineSize = 64 -) - type uintreg uint64 type intptr int64 // TODO(rsc): remove diff --git a/src/runtime/arch_amd64p32.go b/src/runtime/arch_amd64p32.go index 90766b404f..5c636aeab2 100644 --- a/src/runtime/arch_amd64p32.go +++ b/src/runtime/arch_amd64p32.go @@ -4,9 +4,5 @@ package runtime -const ( - cacheLineSize = 64 -) - type uintreg uint64 type intptr int32 // TODO(rsc): remove diff --git a/src/runtime/arch_arm.go b/src/runtime/arch_arm.go index 23f2711f6d..79d38c7ab1 100644 --- a/src/runtime/arch_arm.go +++ b/src/runtime/arch_arm.go @@ -4,9 +4,5 @@ package runtime -const ( - cacheLineSize = 32 -) - type uintreg uint32 type intptr int32 // TODO(rsc): remove diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 226b824065..48925b2e3e 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -26,7 +26,7 @@ func makechan(t *chantype, size int64) *hchan { if hchanSize%maxAlign != 0 || elem.align > maxAlign { gothrow("makechan: bad alignment") } - if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxMem-hchanSize)/uintptr(elem.size)) { + if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxmem-hchanSize)/uintptr(elem.size)) { panic("makechan: size out of range") } diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index b56f42531e..e5c7e09592 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -102,9 +102,9 @@ uintptr runtime·sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * size #define MaxArena32 (2U<<30) -// For use by Go. It can't be a constant in Go, unfortunately, -// because it depends on the OS. -uintptr runtime·maxMem = MaxMem; +// For use by Go. If it were a C enum it would be made available automatically, +// but the value of MaxMem is too large for enum. +uintptr runtime·maxmem = MaxMem; void runtime·mallocinit(void) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index d6f1a1a4a2..7bb85057f4 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -11,49 +11,41 @@ import ( const ( debugMalloc = false - flagNoScan = 1 << 0 // GC doesn't have to scan object - flagNoZero = 1 << 1 // don't zero memory + flagNoScan = _FlagNoScan + flagNoZero = _FlagNoZero - maxTinySize = 16 - tinySizeClass = 2 - maxSmallSize = 32 << 10 + maxTinySize = _TinySize + tinySizeClass = _TinySizeClass + maxSmallSize = _MaxSmallSize - pageShift = 13 - pageSize = 1 << pageShift - pageMask = pageSize - 1 + pageShift = _PageShift + pageSize = _PageSize + pageMask = _PageMask - bitsPerPointer = 2 - bitsMask = 1<>pageShift) type pageID uintptr -// All zero-sized allocations return a pointer to this byte. -var zeroObject byte - -// Maximum possible heap size. -var maxMem uintptr +// base address for all 0-byte allocations +var zerobase uintptr // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { if size == 0 { - return unsafe.Pointer(&zeroObject) + return unsafe.Pointer(&zerobase) } size0 := size @@ -357,7 +349,7 @@ func newarray(typ *_type, n uintptr) unsafe.Pointer { if typ.kind&kindNoPointers != 0 { flags |= flagNoScan } - if int(n) < 0 || (typ.size > 0 && n > maxMem/uintptr(typ.size)) { + if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) { panic("runtime: allocation size out of range") } return mallocgc(uintptr(typ.size)*n, typ, flags) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 30a8ea2c9c..eac6e704be 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -123,7 +123,7 @@ static FinBlock *allfin; // list of all blocks BitVector runtime·gcdatamask; BitVector runtime·gcbssmask; -extern Mutex runtime·gclock; +Mutex runtime·gclock; static Workbuf* getempty(Workbuf*); static Workbuf* getfull(Workbuf*); diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 130e8262ad..bd5ebab46e 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -69,18 +69,6 @@ func clearpools() { } } -// State of background sweep. -// Protected by gclock. -// Must match mgc0.c. -var sweep struct { - g *g - parked bool - spanidx uint32 // background sweeper position - nbgsweep uint32 - npausesweep uint32 -} - -var gclock mutex // also in mgc0.c func gosweepone() uintptr func gosweepdone() bool diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h index 0daf7511b6..10f24d009f 100644 --- a/src/runtime/mgc0.h +++ b/src/runtime/mgc0.h @@ -68,9 +68,9 @@ enum { // there. On a 64-bit system the off'th word in the arena is tracked by // the off/16+1'th word before mheap.arena_start. (On a 32-bit system, // the only difference is that the divisor is 8.) - -#define bitBoundary ((uintptr)1) // boundary of an object -#define bitMarked ((uintptr)2) // marked object - -#define bitMask ((uintptr)bitBoundary|bitMarked) -#define bitPtrMask ((uintptr)BitsMask<<2) +enum { + bitBoundary = 1, // boundary of an object + bitMarked = 2, // marked object + bitMask = bitBoundary | bitMarked, + bitPtrMask = BitsMask<<2, +}; diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index e0f63ddb90..4327ced914 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -22,5 +22,3 @@ func mach_semaphore_wait(sema uint32) int32 func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 func mach_semaphore_signal(sema uint32) int32 func mach_semaphore_signal_all(sema uint32) int32 - -const stackSystem = 0 diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index 96964f1e1e..59708049c8 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -15,5 +15,3 @@ func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, nds func getrlimit(kind int32, limit unsafe.Pointer) int32 func raise(sig int32) func sys_umtx_op(addr unsafe.Pointer, mode int32, val uint32, ptr2, ts unsafe.Pointer) int32 - -const stackSystem = 0 diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index a6799cd414..41123ad570 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -15,5 +15,3 @@ func rtsigprocmask(sig int32, new, old unsafe.Pointer, size int32) func getrlimit(kind int32, limit unsafe.Pointer) int32 func raise(sig int32) func sched_getaffinity(pid, len uintptr, buf *uintptr) int32 - -const stackSystem = 0 diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index a6c409c091..8dd43ff06f 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -23,8 +23,6 @@ func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32 func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32 func nacl_nanosleep(ts, extra unsafe.Pointer) int32 -const stackSystem = 0 - func os_sigpipe() { gothrow("too many writes on closed pipe") } diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 8792f497e4..f000c5e9f6 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -18,5 +18,3 @@ func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 func lwp_self() int32 - -const stackSystem = 0 diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 19e2b45a15..a000f963e3 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -15,5 +15,3 @@ func raise(sig int32) func tfork(param unsafe.Pointer, psize uintptr, mm, gg, fn unsafe.Pointer) int32 func thrsleep(ident unsafe.Pointer, clock_id int32, tsp, lock, abort unsafe.Pointer) int32 func thrwakeup(ident unsafe.Pointer, n int32) int32 - -const stackSystem = 0 diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index c7b5bf7050..20e47bf42e 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -24,10 +24,6 @@ func setfpmasks() func tstart_plan9(newm *m) func errstr() string -// The size of the note handler frame varies among architectures, -// but 512 bytes should be enough for every implementation. -const stackSystem = 512 - type _Plink uintptr func os_sigpipe() { diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go index 3cffff3e29..ca13151204 100644 --- a/src/runtime/os_solaris.go +++ b/src/runtime/os_solaris.go @@ -98,5 +98,3 @@ func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr { asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) return libcall.r1 } - -const stackSystem = 0 diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index da4c736add..1528d2fd13 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -26,8 +26,6 @@ func netpollopen(fd uintptr, pd *pollDesc) int32 func netpollclose(fd uintptr) int32 func netpollarm(pd *pollDesc, mode int) -const stackSystem = 512 * ptrSize - func os_sigpipe() { gothrow("too many writes on closed pipe") } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index abd53c4ba1..4aa9a963f5 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -697,7 +697,6 @@ enum * external data */ extern String runtime·emptystring; -extern uintptr runtime·zerobase; extern G** runtime·allg; extern Slice runtime·allgs; // []*G extern uintptr runtime·allglen; diff --git a/src/runtime/sema.go b/src/runtime/sema.go index 87ba5463b6..beacd67162 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -35,7 +35,7 @@ const semTabSize = 251 var semtable [semTabSize]struct { root semaRoot - pad [cacheLineSize - unsafe.Sizeof(semaRoot{})]byte + pad [_CacheLineSize - unsafe.Sizeof(semaRoot{})]byte } // Called from sync/net packages. diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 3b88927c64..171087d7f6 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -22,11 +22,11 @@ func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct { // but since the cap is only being supplied implicitly, saying len is clearer. // See issue 4085. len := int(len64) - if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxMem/uintptr(t.elem.size) { + if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) { panic(errorString("makeslice: len out of range")) } cap := int(cap64) - if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxMem/uintptr(t.elem.size) { + if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) { panic(errorString("makeslice: cap out of range")) } p := newarray(t.elem, uintptr(cap)) @@ -42,7 +42,7 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct { cap64 := int64(old.cap) + n cap := int(cap64) - if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxMem/uintptr(t.elem.size) { + if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) { panic(errorString("growslice: cap out of range")) } @@ -72,7 +72,7 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct { } } - if uintptr(newcap) >= maxMem/uintptr(et.size) { + if uintptr(newcap) >= maxmem/uintptr(et.size) { panic(errorString("growslice: cap out of range")) } lenmem := uintptr(old.len) * uintptr(et.size) diff --git a/src/runtime/string.go b/src/runtime/string.go index c84f673427..0809f89bc1 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -225,7 +225,7 @@ func rawbyteslice(size int) (b []byte) { // rawruneslice allocates a new rune slice. The rune slice is not zeroed. func rawruneslice(size int) (b []rune) { - if uintptr(size) > maxMem/4 { + if uintptr(size) > maxmem/4 { gothrow("out of memory") } mem := goroundupsize(uintptr(size) * 4) diff --git a/src/runtime/typekind.go b/src/runtime/typekind.go index 5985536289..b64ec44f9e 100644 --- a/src/runtime/typekind.go +++ b/src/runtime/typekind.go @@ -5,37 +5,37 @@ package runtime const ( - kindBool = 1 + iota - kindInt - kindInt8 - kindInt16 - kindInt32 - kindInt64 - kindUint - kindUint8 - kindUint16 - kindUint32 - kindUint64 - kindUintptr - kindFloat32 - kindFloat64 - kindComplex64 - kindComplex128 - kindArray - kindChan - kindFunc - kindInterface - kindMap - kindPtr - kindSlice - kindString - kindStruct - kindUnsafePointer + kindBool = _KindBool + kindInt = _KindInt + kindInt8 = _KindInt8 + kindInt16 = _KindInt16 + kindInt32 = _KindInt32 + kindInt64 = _KindInt64 + kindUint = _KindUint + kindUint8 = _KindUint8 + kindUint16 = _KindUint16 + kindUint32 = _KindUint32 + kindUint64 = _KindUint64 + kindUintptr = _KindUintptr + kindFloat32 = _KindFloat32 + kindFloat64 = _KindFloat64 + kindComplex64 = _KindComplex64 + kindComplex128 = _KindComplex128 + kindArray = _KindArray + kindChan = _KindChan + kindFunc = _KindFunc + kindInterface = _KindInterface + kindMap = _KindMap + kindPtr = _KindPtr + kindSlice = _KindSlice + kindString = _KindString + kindStruct = _KindStruct + kindUnsafePointer = _KindUnsafePointer - kindDirectIface = 1 << 5 - kindGCProg = 1 << 6 // Type.gc points to GC program - kindNoPointers = 1 << 7 - kindMask = (1 << 5) - 1 + kindDirectIface = _KindDirectIface + kindGCProg = _KindGCProg + kindNoPointers = _KindNoPointers + kindMask = _KindMask ) // isDirectIface reports whether t is stored directly in an interface value. diff --git a/src/runtime/typekind.h b/src/runtime/typekind.h index 7c611e8ba6..e0fe177bb7 100644 --- a/src/runtime/typekind.h +++ b/src/runtime/typekind.h @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// PtrSize vs sizeof(void*): This file is also included from src/cmd/ld/... -// which defines PtrSize to be different from sizeof(void*) when crosscompiling. - enum { KindBool = 1, KindInt, From f95beae61d21898710d7d405ac39bc7b3b205c79 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 10:36:38 -0400 Subject: [PATCH 088/430] runtime: use traceback to traverse defer structures This makes the GC and the stack copying agree about how to interpret the defer structures. Previously, only the stack copying treated them precisely. This removes an untyped memory allocation and fixes at least three copystack bugs. To make sure the GC can find the deferred argument frame until it has been copied, keep a Defer on the defer list during its execution. In addition to making it possible to remove the untyped memory allocation, keeping the Defer on the list fixes two races between copystack and execution of defers (in both gopanic and Goexit). The problem is that once the defer has been taken off the list, a stack copy that happens before the deferred arguments have been copied back to the stack will not update the arguments correctly. The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit (variations on the existing TestDeferPtrs) pass now but failed before this CL. In addition to those fixes, keeping the Defer on the list helps correct a dangling pointer error during copystack. The traceback routines walk the Defer chain to provide information about where a panic may resume execution. When the executing Defer was not on the Defer chain but instead linked from the Panic chain, the traceback had to walk the Panic chain too. But Panic structs are on the stack and being updated by copystack. Traceback's use of the Panic chain while copystack is updating those structs means that it can follow an updated pointer and find itself reading from the new stack. The new stack is usually all zeros, so it sees an incorrect early end to the chain. The new TestPanicUseStack makes this happen at tip and dies when adjustdefers finds an unexpected argp. The new StackCopyPoison mode causes an earlier bad dereference instead. By keeping the Defer on the list, traceback can avoid walking the Panic chain at all, making it okay for copystack to update the Panics. We'd have the same problem for any Defers on the stack. There was only one: gopanic's dabort. Since we are not taking the executing Defer off the chain, we can use it to do what dabort was doing, and then there are no Defers on the stack ever, so it is okay for traceback to use the Defer chain even while copystack is executing: copystack cannot modify the Defer chain. LGTM=khr R=khr CC=dvyukov, golang-codereviews, iant, rlh https://golang.org/cl/141490043 --- src/runtime/heapdump.c | 2 +- src/runtime/malloc.go | 10 +++ src/runtime/mgc0.c | 1 + src/runtime/panic.c | 5 +- src/runtime/panic.go | 108 ++++++++++++++++++------------ src/runtime/proc.go | 11 +-- src/runtime/runtime.h | 5 +- src/runtime/stack.c | 136 +++++++++++++++++--------------------- src/runtime/stack_test.go | 96 +++++++++++++++++++++++++-- src/runtime/traceback.go | 99 +++++++++++++++------------ 10 files changed, 298 insertions(+), 175 deletions(-) diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index 3d7960aab0..8bbc7d8a56 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -432,7 +432,7 @@ dumpgoroutine(G *gp) dumpint((uintptr)gp); dumpint((uintptr)p->arg.type); dumpint((uintptr)p->arg.data); - dumpint((uintptr)p->defer); + dumpint(0); // was p->defer, no longer recorded dumpint((uintptr)p->link); } } diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 7bb85057f4..acf6b48f84 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -209,6 +209,16 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { goto marked } + // If allocating a defer+arg block, now that we've picked a malloc size + // large enough to hold everything, cut the "asked for" size down to + // just the defer header, so that the GC bitmap will record the arg block + // as containing nothing at all (as if it were unused space at the end of + // a malloc block caused by size rounding). + // The defer arg areas are scanned as part of scanstack. + if typ == deferType { + size0 = unsafe.Sizeof(_defer{}) + } + // From here till marked label marking the object as allocated // and storing type info in the GC bitmap. { diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index eac6e704be..ba02700dea 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -713,6 +713,7 @@ scanstack(G *gp) fn = scanframe; runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, false); + runtime·tracebackdefers(gp, &fn, nil); } // The gp has been moved to a gc safepoint. If there is gcphase specific diff --git a/src/runtime/panic.c b/src/runtime/panic.c index e015e41cca..1cd0aa8654 100644 --- a/src/runtime/panic.c +++ b/src/runtime/panic.c @@ -18,7 +18,8 @@ uint32 runtime·panicking; static Mutex paniclk; void -runtime·deferproc_m(void) { +runtime·deferproc_m(void) +{ int32 siz; FuncVal *fn; uintptr argp; @@ -35,7 +36,7 @@ runtime·deferproc_m(void) { d->fn = fn; d->pc = callerpc; d->argp = argp; - runtime·memmove(d->args, (void*)argp, siz); + runtime·memmove(d+1, (void*)argp, siz); } // Unwind the stack after a deferred function calls recover diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 017f5d4896..12c85e7caf 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -90,19 +90,31 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn // been set and must not be clobbered. } -// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes. -// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header. -// This maps exactly to malloc size classes. +// Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ... +// Each P holds a pool for defers with small arg sizes. +// Assign defer allocations to pools by rounding to 16, to match malloc size classes. + +const ( + deferHeaderSize = unsafe.Sizeof(_defer{}) + minDeferAlloc = (deferHeaderSize + 15) &^ 15 + minDeferArgs = minDeferAlloc - deferHeaderSize +) // defer size class for arg size sz //go:nosplit func deferclass(siz uintptr) uintptr { - return (siz + 7) >> 4 + if siz <= minDeferArgs { + return 0 + } + return (siz - minDeferArgs + 15) / 16 } // total size of memory block for defer with arg size sz func totaldefersize(siz uintptr) uintptr { - return (unsafe.Sizeof(_defer{}) - unsafe.Sizeof(_defer{}.args)) + round(siz, ptrSize) + if siz <= minDeferArgs { + return minDeferAlloc + } + return deferHeaderSize + siz } // Ensure that defer arg sizes that map to the same defer size class @@ -130,6 +142,21 @@ func testdefersizes() { } } +// The arguments associated with a deferred call are stored +// immediately after the _defer header in memory. +//go:nosplit +func deferArgs(d *_defer) unsafe.Pointer { + return add(unsafe.Pointer(d), unsafe.Sizeof(*d)) +} + +var deferType *_type // type of _defer struct + +func init() { + var x interface{} + x = (*_defer)(nil) + deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem +} + // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. // Note: runs on M stack @@ -145,12 +172,11 @@ func newdefer(siz int32) *_defer { } } if d == nil { - // deferpool is empty or just a big defer + // Allocate new defer+args. total := goroundupsize(totaldefersize(uintptr(siz))) - d = (*_defer)(mallocgc(total, conservative, 0)) + d = (*_defer)(mallocgc(total, deferType, 0)) } d.siz = siz - d.special = false gp := mp.curg d.link = gp._defer gp._defer = d @@ -162,18 +188,14 @@ func newdefer(siz int32) *_defer { // The defer cannot be used after this call. //go:nosplit func freedefer(d *_defer) { - if d.special { - return - } sc := deferclass(uintptr(d.siz)) if sc < uintptr(len(p{}.deferpool)) { mp := acquirem() pp := mp.p + *d = _defer{} d.link = pp.deferpool[sc] pp.deferpool[sc] = d releasem(mp) - // No need to wipe out pointers in argp/pc/fn/args, - // because we empty the pool before GC. } } @@ -207,7 +229,7 @@ func deferreturn(arg0 uintptr) { // won't know the form of the arguments until the jmpdefer can // flip the PC over to fn. mp := acquirem() - memmove(unsafe.Pointer(argp), unsafe.Pointer(&d.args), uintptr(d.siz)) + memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz)) fn := d.fn gp._defer = d.link freedefer(d) @@ -227,8 +249,9 @@ func Goexit() { gp := getg() for gp._defer != nil { d := gp._defer + d.started = true + reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) gp._defer = d.link - reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) freedefer(d) // Note: we ignore recovers here because Goexit isn't a panic } @@ -258,55 +281,58 @@ func gopanic(e interface{}) { gothrow("panic on m stack") } var p _panic - var dabort _defer p.arg = e p.link = gp._panic gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) - fn := abortpanic - dabort.fn = *(**funcval)(unsafe.Pointer(&fn)) - dabort.siz = ptrSize - dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here? - dabort.argp = _NoArgs - dabort.special = true - for { d := gp._defer if d == nil { break } - // take defer off list in case of recursive panic - gp._defer = d.link - argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy - pc := d.pc - // The deferred function may cause another panic, - // so reflectcall may not return. Set up a defer - // to mark this panic aborted if that happens. - dabort.link = gp._defer - gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort))) - p._defer = d + // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic), + // take defer off list. The earlier panic or Goexit will not continue running. + if d.started { + if d._panic != nil { + d._panic.aborted = true + } + gp._defer = d.link + freedefer(d) + continue + } + + // Mark defer as started, but keep on list, so that traceback + // can find and update the defer's argument frame if stack growth + // or a garbage collection hapens before reflectcall starts executing d.fn. + d.started = true + + // Record the panic that is running the defer. + // If there is a new panic during the deferred call, that panic + // will find d in the list and will mark d._panic (this panic) aborted. + d._panic = (*_panic)(noescape((unsafe.Pointer)(&p))) p.argp = unsafe.Pointer(getargp(0)) - reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) + reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) p.argp = nil - // reflectcall did not panic. Remove dabort. - if gp._defer != &dabort { + // reflectcall did not panic. Remove d. + if gp._defer != d { gothrow("bad defer entry in panic") } - gp._defer = dabort.link + gp._defer = d.link // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic //GC() + pc := d.pc + argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy freedefer(d) if p.recovered { gp._panic = p.link // Aborted panics are marked but remain on the g.panic list. - // Remove them from the list and free the associated defers. + // Remove them from the list. for gp._panic != nil && gp._panic.aborted { - freedefer(gp._panic._defer) gp._panic = gp._panic.link } if gp._panic == nil { // must be done with signal @@ -342,10 +368,6 @@ func getargp(x int) uintptr { return uintptr(noescape(unsafe.Pointer(&x))) } -func abortpanic(p *_panic) { - p.aborted = true -} - // The implementation of the predeclared function recover. // Cannot split the stack because it needs to reliably // find the stack segment of its caller. diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 2f07c8a0b3..9b95868594 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -39,6 +39,12 @@ func main() { // to preserve the lock. lockOSThread() + if g.m != &m0 { + gothrow("runtime.main not on m0") + } + + runtime_init() // must be before defer + // Defer unlock so that runtime.Goexit during init does the unlock too. needUnlock := true defer func() { @@ -47,11 +53,6 @@ func main() { } }() - if g.m != &m0 { - gothrow("runtime.main not on m0") - } - - runtime_init() memstats.enablegc = true // now that runtime is initialized, GC is okay main_init() diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 4aa9a963f5..adc74cf417 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -638,12 +638,12 @@ void runtime·gcphasework(G*); struct Defer { int32 siz; - bool special; // not part of defer frame + bool started; uintptr argp; // where args were copied from uintptr pc; FuncVal* fn; + Panic* panic; // panic that is running defer Defer* link; - void* args[1]; // padded to actual size }; // argp used in Defer structs when there is no argp. @@ -657,7 +657,6 @@ struct Panic void* argp; // pointer to arguments of deferred call run during panic; cannot move - known to liblink Eface arg; // argument to panic Panic* link; // link to earlier panic - Defer* defer; // current executing defer bool recovered; // whether this panic is over bool aborted; // the panic was aborted }; diff --git a/src/runtime/stack.c b/src/runtime/stack.c index f29266eb6b..143b645e42 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -23,6 +23,7 @@ enum StackDebug = 0, StackFromSystem = 0, // allocate stacks from system memory instead of the heap StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free + StackPoisonCopy = 0, // fill stack that should not be accessed with garbage, to detect bad dereferences during copy StackCache = 1, }; @@ -353,6 +354,24 @@ struct AdjustInfo { uintptr delta; // ptr distance from old to new stack (newbase - oldbase) }; +// Adjustpointer checks whether *vpp is in the old stack described by adjinfo. +// If so, it rewrites *vpp to point into the new stack. +static void +adjustpointer(AdjustInfo *adjinfo, void *vpp) +{ + byte **pp, *p; + + pp = vpp; + p = *pp; + if(StackDebug >= 4) + runtime·printf(" %p:%p\n", pp, p); + if(adjinfo->old.lo <= (uintptr)p && (uintptr)p < adjinfo->old.hi) { + *pp = p + adjinfo->delta; + if(StackDebug >= 3) + runtime·printf(" adjust ptr %p: %p -> %p\n", pp, p, *pp); + } +} + // bv describes the memory starting at address scanp. // Adjust any pointers contained therein. static void @@ -447,6 +466,11 @@ adjustframe(Stkframe *frame, void *arg) uintptr targetpc; adjinfo = arg; + targetpc = frame->continpc; + if(targetpc == 0) { + // Frame is dead. + return true; + } f = frame->fn; if(StackDebug >= 2) runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); @@ -456,11 +480,6 @@ adjustframe(Stkframe *frame, void *arg) // have full GC info for it (because it is written in asm). return true; } - targetpc = frame->continpc; - if(targetpc == 0) { - // Frame is dead. - return true; - } if(targetpc != f->entry) targetpc--; pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); @@ -495,103 +514,53 @@ adjustframe(Stkframe *frame, void *arg) runtime·printf(" args\n"); adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); } + return true; } static void adjustctxt(G *gp, AdjustInfo *adjinfo) { - if(adjinfo->old.lo <= (uintptr)gp->sched.ctxt && (uintptr)gp->sched.ctxt < adjinfo->old.hi) - gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta; + adjustpointer(adjinfo, &gp->sched.ctxt); } static void adjustdefers(G *gp, AdjustInfo *adjinfo) { - Defer *d, **dp; - Func *f; - FuncVal *fn; - StackMap *stackmap; - BitVector bv; + Defer *d; + bool (*cb)(Stkframe*, void*); - for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { - if(adjinfo->old.lo <= (uintptr)d && (uintptr)d < adjinfo->old.hi) { - // The Defer record is on the stack. Its fields will - // get adjusted appropriately. - // This only happens for runtime.main and runtime.gopanic now, - // but a compiler optimization could do more of this. - // If such an optimization were introduced, Defer.argp should - // change to have pointer type so that it will be updated by - // the stack copying. Today both of those on-stack defers - // set argp = NoArgs, so no adjustment is necessary. - *dp = (Defer*)((byte*)d + adjinfo->delta); - continue; - } - if(d->argp == NoArgs) - continue; - if(d->argp < adjinfo->old.lo || adjinfo->old.hi <= d->argp) { - runtime·printf("runtime: adjustdefers argp=%p stk=%p %p\n", d->argp, adjinfo->old.lo, adjinfo->old.hi); - runtime·throw("adjustdefers: unexpected argp"); - } - d->argp += adjinfo->delta; - fn = d->fn; - if(fn == nil) { - // Defer of nil function. It will panic when run. See issue 8047. - continue; - } - f = runtime·findfunc((uintptr)fn->fn); - if(f == nil) - runtime·throw("can't adjust unknown defer"); - if(StackDebug >= 4) - runtime·printf(" checking defer %s\n", runtime·funcname(f)); - // Defer's FuncVal might be on the stack - if(adjinfo->old.lo <= (uintptr)fn && (uintptr)fn < adjinfo->old.hi) { - if(StackDebug >= 3) - runtime·printf(" adjust defer fn %s\n", runtime·funcname(f)); - d->fn = (FuncVal*)((byte*)fn + adjinfo->delta); - } else { - // deferred function's args might point into the stack. - if(StackDebug >= 3) - runtime·printf(" adjust deferred args for %s\n", runtime·funcname(f)); - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil) - runtime·throw("runtime: deferred function has no arg ptr map"); - bv = runtime·stackmapdata(stackmap, 0); - adjustpointers(d->args, &bv, adjinfo, f); - } - // The FuncVal may have pointers in it, but fortunately for us - // the compiler won't put pointers into the stack in a - // heap-allocated FuncVal. - // One day if we do need to check this, we can use the gc bits in the - // heap to do the right thing (although getting the size will be expensive). + // Adjust defer argument blocks the same way we adjust active stack frames. + cb = adjustframe; + runtime·tracebackdefers(gp, &cb, adjinfo); + + // Adjust pointers in the Defer structs. + // Defer structs themselves are never on the stack. + for(d = gp->defer; d != nil; d = d->link) { + adjustpointer(adjinfo, &d->fn); + adjustpointer(adjinfo, &d->argp); + adjustpointer(adjinfo, &d->panic); } } static void adjustpanics(G *gp, AdjustInfo *adjinfo) { - // Panic structs are all on the stack - // and are adjusted by stack copying. - // The only pointer we need to update is gp->panic, the head of the list. - if(adjinfo->old.lo <= (uintptr)gp->panic && (uintptr)gp->panic < adjinfo->old.hi) - gp->panic = (Panic*)((byte*)gp->panic + adjinfo->delta); + // Panics are on stack and already adjusted. + // Update pointer to head of list in G. + adjustpointer(adjinfo, &gp->panic); } static void adjustsudogs(G *gp, AdjustInfo *adjinfo) { SudoG *s; - byte *e; // the data elements pointed to by a SudoG structure // might be in the stack. for(s = gp->waiting; s != nil; s = s->waitlink) { - e = s->elem; - if(adjinfo->old.lo <= (uintptr)e && (uintptr)e < adjinfo->old.hi) - s->elem = e + adjinfo->delta; - e = (byte*)s->selectdone; - if(adjinfo->old.lo <= (uintptr)e && (uintptr)e < adjinfo->old.hi) - s->selectdone = (uint32*)(e + adjinfo->delta); + adjustpointer(adjinfo, &s->elem); + adjustpointer(adjinfo, &s->selectdone); } } @@ -604,6 +573,7 @@ copystack(G *gp, uintptr newsize) AdjustInfo adjinfo; uint32 oldstatus; bool (*cb)(Stkframe*, void*); + byte *p, *ep; if(gp->syscallsp != 0) runtime·throw("stack growth not allowed in system call"); @@ -614,6 +584,12 @@ copystack(G *gp, uintptr newsize) // allocate new stack new = runtime·stackalloc(newsize); + if(StackPoisonCopy) { + p = (byte*)new.lo; + ep = (byte*)new.hi; + while(p < ep) + *p++ = 0xfd; + } if(StackDebug >= 1) runtime·printf("copystack gp=%p [%p %p %p]/%d -> [%p %p %p]/%d\n", gp, old.lo, old.hi-used, old.hi, (int32)(old.hi-old.lo), new.lo, new.hi-used, new.hi, (int32)newsize); @@ -631,6 +607,12 @@ copystack(G *gp, uintptr newsize) adjustsudogs(gp, &adjinfo); // copy the stack to the new location + if(StackPoisonCopy) { + p = (byte*)new.lo; + ep = (byte*)new.hi; + while(p < ep) + *p++ = 0xfb; + } runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used); oldstatus = runtime·readgstatus(gp); @@ -648,6 +630,12 @@ copystack(G *gp, uintptr newsize) runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable // free old stack + if(StackPoisonCopy) { + p = (byte*)old.lo; + ep = (byte*)old.hi; + while(p < ep) + *p++ = 0xfc; + } runtime·stackfree(old); } diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go index cd525a3fc5..3a0802a1c2 100644 --- a/src/runtime/stack_test.go +++ b/src/runtime/stack_test.go @@ -141,7 +141,7 @@ func growStack() { GC() } -// This function is not an anonimous func, so that the compiler can do escape +// This function is not an anonymous func, so that the compiler can do escape // analysis and place x on stack (and subsequently stack growth update the pointer). func growStackIter(p *int, n int) { if n == 0 { @@ -230,13 +230,101 @@ func TestDeferPtrs(t *testing.T) { growStack() } -// use about n KB of stack -func useStack(n int) { +type bigBuf [4 * 1024]byte + +// TestDeferPtrsGoexit is like TestDeferPtrs but exercises the possibility that the +// stack grows as part of starting the deferred function. It calls Goexit at various +// stack depths, forcing the deferred function (with >4kB of args) to be run at +// the bottom of the stack. The goal is to find a stack depth less than 4kB from +// the end of the stack. Each trial runs in a different goroutine so that an earlier +// stack growth does not invalidate a later attempt. +func TestDeferPtrsGoexit(t *testing.T) { + for i := 0; i < 100; i++ { + c := make(chan int, 1) + go testDeferPtrsGoexit(c, i) + if n := <-c; n != 42 { + t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n) + } + } +} + +func testDeferPtrsGoexit(c chan int, i int) { + var y int + defer func() { + c <- y + }() + defer setBig(&y, 42, bigBuf{}) + useStackAndCall(i, Goexit) +} + +func setBig(p *int, x int, b bigBuf) { + *p = x +} + +// TestDeferPtrsPanic is like TestDeferPtrsGoexit, but it's using panic instead +// of Goexit to run the Defers. Those two are different execution paths +// in the runtime. +func TestDeferPtrsPanic(t *testing.T) { + for i := 0; i < 100; i++ { + c := make(chan int, 1) + go testDeferPtrsGoexit(c, i) + if n := <-c; n != 42 { + t.Fatalf("defer's stack references were not adjusted appropriately (i=%d n=%d)", i, n) + } + } +} + +func testDeferPtrsPanic(c chan int, i int) { + var y int + defer func() { + if recover() == nil { + c <- -1 + return + } + c <- y + }() + defer setBig(&y, 42, bigBuf{}) + useStackAndCall(i, func() { panic(1) }) +} + +// TestPanicUseStack checks that a chain of Panic structs on the stack are +// updated correctly if the stack grows during the deferred execution that +// happens as a result of the panic. +func TestPanicUseStack(t *testing.T) { + pc := make([]uintptr, 10000) + defer func() { + recover() + Callers(0, pc) // force stack walk + useStackAndCall(100, func() { + defer func() { + recover() + Callers(0, pc) // force stack walk + useStackAndCall(200, func() { + defer func() { + recover() + Callers(0, pc) // force stack walk + }() + panic(3) + }) + }() + panic(2) + }) + }() + panic(1) +} + +// use about n KB of stack and call f +func useStackAndCall(n int, f func()) { if n == 0 { + f() return } var b [1024]byte // makes frame about 1KB - useStack(n - 1 + int(b[99])) + useStackAndCall(n-1+int(b[99]), f) +} + +func useStack(n int) { + useStackAndCall(n, func() {}) } func growing(c chan int, done chan struct{}) { diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 07b68d29b5..9e95fa33d5 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -45,8 +45,36 @@ var ( externalthreadhandlerp uintptr // initialized elsewhere ) -// System-specific hook. See traceback_windows.go -var systraceback func(*_func, *stkframe, *g, bool, func(*stkframe, unsafe.Pointer) bool, unsafe.Pointer) (changed, aborted bool) +// Traceback over the deferred function calls. +// Report them like calls that have been invoked but not started executing yet. +func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) { + var frame stkframe + for d := gp._defer; d != nil; d = d.link { + fn := d.fn + if fn == nil { + // Defer of nil function. Args don't matter. + frame.pc = 0 + frame.fn = nil + frame.argp = 0 + frame.arglen = 0 + frame.argmap = nil + } else { + frame.pc = uintptr(fn.fn) + f := findfunc(frame.pc) + if f == nil { + print("runtime: unknown pc in defer ", hex(frame.pc), "\n") + gothrow("unknown pc") + } + frame.fn = f + frame.argp = uintptr(deferArgs(d)) + setArgInfo(&frame, f, true) + } + frame.continpc = frame.pc + if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) { + return + } + } +} // Generic traceback. Handles runtime stack prints (pcbuf == nil), // the runtime.Callers function (pcbuf != nil), as well as the garbage @@ -81,15 +109,11 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf waspanic := false wasnewproc := false printing := pcbuf == nil && callback == nil - panic := gp._panic _defer := gp._defer for _defer != nil && uintptr(_defer.argp) == _NoArgs { _defer = _defer.link } - for panic != nil && panic._defer == nil { - panic = panic.link - } // If the PC is zero, it's likely a nil function call. // Start in the caller's frame. @@ -187,25 +211,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf if usesLR { frame.argp += ptrSize } - frame.arglen = uintptr(f.args) - if callback != nil && f.args == _ArgsSizeUnknown { - // Extract argument bitmaps for reflect stubs from the calls they made to reflect. - switch gofuncname(f) { - case "reflect.makeFuncStub", "reflect.methodValueCall": - arg0 := frame.sp - if usesLR { - arg0 += ptrSize - } - fn := *(**[2]uintptr)(unsafe.Pointer(arg0)) - if fn[0] != f.entry { - print("runtime: confused by ", gofuncname(f), "\n") - gothrow("reflect mismatch") - } - bv := (*bitvector)(unsafe.Pointer(fn[1])) - frame.arglen = uintptr(bv.n / 2 * ptrSize) - frame.argmap = bv - } - } + setArgInfo(&frame, f, callback != nil) } // Determine function SP where deferproc would find its arguments. @@ -246,19 +252,14 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf // returns; everything live at earlier deferprocs is still live at that one. frame.continpc = frame.pc if waspanic { - if panic != nil && panic._defer.argp == sparg { - frame.continpc = panic._defer.pc - } else if _defer != nil && _defer.argp == sparg { + if _defer != nil && _defer.argp == sparg { frame.continpc = _defer.pc } else { frame.continpc = 0 } } - // Unwind our local panic & defer stacks past this frame. - for panic != nil && (panic._defer == nil || panic._defer.argp == sparg || panic._defer.argp == _NoArgs) { - panic = panic.link - } + // Unwind our local defer stack past this frame. for _defer != nil && (_defer.argp == sparg || _defer.argp == _NoArgs) { _defer = _defer.link } @@ -403,25 +404,37 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf if _defer != nil { print("runtime: g", gp.goid, ": leftover defer argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n") } - if panic != nil { - print("runtime: g", gp.goid, ": leftover panic argp=", hex(panic._defer.argp), " pc=", hex(panic._defer.pc), "\n") - } for _defer = gp._defer; _defer != nil; _defer = _defer.link { print("\tdefer ", _defer, " argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n") } - for panic = gp._panic; panic != nil; panic = panic.link { - print("\tpanic ", panic, " defer ", panic._defer) - if panic._defer != nil { - print(" argp=", hex(panic._defer.argp), " pc=", hex(panic._defer.pc)) - } - print("\n") - } - gothrow("traceback has leftover defers or panics") + gothrow("traceback has leftover defers") } return n } +func setArgInfo(frame *stkframe, f *_func, needArgMap bool) { + frame.arglen = uintptr(f.args) + if needArgMap && f.args == _ArgsSizeUnknown { + // Extract argument bitmaps for reflect stubs from the calls they made to reflect. + switch gofuncname(f) { + case "reflect.makeFuncStub", "reflect.methodValueCall": + arg0 := frame.sp + if usesLR { + arg0 += ptrSize + } + fn := *(**[2]uintptr)(unsafe.Pointer(arg0)) + if fn[0] != f.entry { + print("runtime: confused by ", gofuncname(f), "\n") + gothrow("reflect mismatch") + } + bv := (*bitvector)(unsafe.Pointer(fn[1])) + frame.arglen = uintptr(bv.n / 2 * ptrSize) + frame.argmap = bv + } + } +} + func printcreatedby(gp *g) { // Show what created goroutine, except main goroutine (goid 1). pc := gp.gopc From fc469314420f553906a283656ae39bafcf5af1b0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 11:03:11 -0400 Subject: [PATCH 089/430] runtime: remove untyped allocation of ParFor Now it's two allocations. I don't see much downside to that, since the two pieces were in different cache lines anyway. Rename 'conservative' to 'cgo_conservative_type' and make clear that _cgo_allocate is the only allowed user. This depends on CL 141490043, which removes the other use of conservative (in defer). LGTM=dvyukov, iant R=khr, dvyukov, iant CC=golang-codereviews, rlh https://golang.org/cl/139610043 --- misc/cgo/test/callback.go | 5 ++++ misc/cgo/test/callback_c_gc.c | 49 ++++++++++++++++++++++++++++++++ misc/cgo/test/callback_c_gccgo.c | 46 ++++++++++++++++++++++++++++++ misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/exports.go | 6 ++++ src/cmd/api/goapi.go | 1 + src/runtime/cgocallback.go | 2 +- src/runtime/malloc.c | 8 ------ src/runtime/malloc.h | 1 - src/runtime/mgc0.go | 9 ------ src/runtime/parfor.c | 13 --------- src/runtime/runtime.go | 8 ++++++ 12 files changed, 117 insertions(+), 32 deletions(-) diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go index 281e79494e..a7f1a3ecd6 100644 --- a/misc/cgo/test/callback.go +++ b/misc/cgo/test/callback.go @@ -9,6 +9,7 @@ void callback(void *f); void callGoFoo(void); void callGoStackCheck(void); void callPanic(void); +void callCgoAllocate(void); */ import "C" @@ -207,6 +208,10 @@ func testPanicFromC(t *testing.T) { C.callPanic() } +func testAllocateFromC(t *testing.T) { + C.callCgoAllocate() // crashes or exits on failure +} + func testCallbackStack(t *testing.T) { // Make cgo call and callback with different amount of stack stack available. // We do not do any explicit checks, just ensure that it does not crash. diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c index 8953b74a67..32bfed0c02 100644 --- a/misc/cgo/test/callback_c_gc.c +++ b/misc/cgo/test/callback_c_gc.c @@ -5,11 +5,15 @@ // +build gc #include "_cgo_export.h" +#include +#include +#include /* Test calling panic from C. This is what SWIG does. */ extern void crosscall2(void (*fn)(void *, int), void *, int); extern void _cgo_panic(void *, int); +extern void _cgo_allocate(void *, int); void callPanic(void) @@ -19,3 +23,48 @@ callPanic(void) crosscall2(_cgo_panic, &a, sizeof a); *(int*)1 = 1; } + +/* Test calling cgo_allocate from C. This is what SWIG does. */ + +typedef struct List List; +struct List +{ + List *next; + int x; +}; + +void +callCgoAllocate(void) +{ + int i; + struct { size_t n; void *ret; } a; + List *l, *head, **tail; + + head = 0; + tail = &head; + for(i=0; i<100; i++) { + a.n = sizeof *l; + crosscall2(_cgo_allocate, &a, sizeof a); + l = a.ret; + l->x = i; + l->next = 0; + *tail = l; + tail = &l->next; + } + + gc(); + + l = head; + for(i=0; i<100; i++) { + if(l->x != i) { + fprintf(stderr, "callCgoAllocate: lost memory\n"); + exit(2); + } + l = l->next; + } + if(l != 0) { + fprintf(stderr, "callCgoAllocate: lost memory\n"); + exit(2); + } +} + diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c index 0ea7296c62..d92dca0093 100644 --- a/misc/cgo/test/callback_c_gccgo.c +++ b/misc/cgo/test/callback_c_gccgo.c @@ -5,13 +5,59 @@ // +build gccgo #include "_cgo_export.h" +#include +#include +#include /* Test calling panic from C. This is what SWIG does. */ extern void _cgo_panic(const char *); +extern void *_cgo_allocate(size_t); void callPanic(void) { _cgo_panic("panic from C"); } + +/* Test calling cgo_allocate from C. This is what SWIG does. */ + +typedef struct List List; +struct List +{ + List *next; + int x; +}; + +void +callCgoAllocate(void) +{ + int i; + List *l, *head, **tail; + + head = 0; + tail = &head; + for(i=0; i<100; i++) { + l = _cgo_allocate(sizeof *l); + l->x = i; + l->next = 0; + *tail = l; + tail = &l->next; + } + + gc(); + + l = head; + for(i=0; i<100; i++) { + if(l->x != i) { + fprintf(stderr, "callCgoAllocate: lost memory\n"); + exit(2); + } + l = l->next; + } + if(l != 0) { + fprintf(stderr, "callCgoAllocate: lost memory\n"); + exit(2); + } +} + diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 3cc83060fc..3783af061c 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -23,6 +23,7 @@ func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) } func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) } func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) } func TestPanicFromC(t *testing.T) { testPanicFromC(t) } +func TestAllocateFromC(t *testing.T) { testAllocateFromC(t) } func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } func TestBlocking(t *testing.T) { testBlocking(t) } func Test1328(t *testing.T) { test1328(t) } diff --git a/misc/cgo/test/exports.go b/misc/cgo/test/exports.go index f96c60b004..4fe1703a60 100644 --- a/misc/cgo/test/exports.go +++ b/misc/cgo/test/exports.go @@ -5,8 +5,14 @@ package cgotest import "C" +import "runtime" //export ReturnIntLong func ReturnIntLong() (int, C.long) { return 1, 2 } + +//export gc +func gc() { + runtime.GC() +} diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 78b7d6edf1..5a8c876033 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -404,6 +404,7 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) { " mutex struct{};" + " note struct{};" + " p struct{};" + + " parfor struct{};" + " slicetype struct{};" + " stkframe struct{};" + " sudog struct{};" + diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go index b3edfb672a..1e1b576072 100644 --- a/src/runtime/cgocallback.go +++ b/src/runtime/cgocallback.go @@ -21,7 +21,7 @@ import "unsafe" // Either we need to add types or we need to stop using it. func _cgo_allocate_internal(len uintptr) unsafe.Pointer { - ret := mallocgc(len, conservative, 0) + ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0]) c := new(cgomal) c.alloc = ret gp := getg() diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index e5c7e09592..cfb698ac21 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -21,10 +21,6 @@ MHeap runtime·mheap; #pragma dataflag NOPTR MStats runtime·memstats; -Type* runtime·conservative; - -void runtime·gc_notype_ptr(Eface*); - int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp) { @@ -115,7 +111,6 @@ runtime·mallocinit(void) uintptr limit; uint64 i; bool reserved; - Eface notype_eface; p = nil; p_size = 0; @@ -243,9 +238,6 @@ runtime·mallocinit(void) // Initialize the rest of the allocator. runtime·MHeap_Init(&runtime·mheap); g->m->mcache = runtime·allocmcache(); - - runtime·gc_notype_ptr(¬ype_eface); - runtime·conservative = notype_eface.type; } void* diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index 60b87da78c..c496cc70e3 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -528,7 +528,6 @@ void* runtime·cnewarray(Type*, intgo); void runtime·tracealloc(void*, uintptr, Type*); void runtime·tracefree(void*, uintptr); void runtime·tracegc(void); -extern Type* runtime·conservative; int32 runtime·gcpercent; int32 runtime·readgogc(void); diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index bd5ebab46e..0e17599c2a 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -21,15 +21,6 @@ func gc_itab_ptr(ret *interface{}) { *ret = (*itab)(nil) } -// Type used for "conservative" allocations in C code. -type notype [8]*byte - -// Called from C. Returns the Go type used for C allocations w/o type. -func gc_notype_ptr(ret *interface{}) { - var x notype - *ret = x -} - func gc_unixnanotime(now *int64) { sec, nsec := timenow() *now = sec*1e9 + int64(nsec) diff --git a/src/runtime/parfor.c b/src/runtime/parfor.c index ba17303b23..e449568400 100644 --- a/src/runtime/parfor.c +++ b/src/runtime/parfor.c @@ -21,19 +21,6 @@ struct ParForThread byte pad[CacheLineSize]; }; -ParFor* -runtime·parforalloc(uint32 nthrmax) -{ - ParFor *desc; - - // The ParFor object is followed by CacheLineSize padding - // and then nthrmax ParForThread. - desc = (ParFor*)runtime·mallocgc(sizeof(ParFor) + CacheLineSize + nthrmax * sizeof(ParForThread), runtime·conservative, 0); - desc->thr = (ParForThread*)((byte*)(desc+1) + CacheLineSize); - desc->nthrmax = nthrmax; - return desc; -} - void runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32)) { diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index d4f7c64a52..dbaea45a66 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -39,3 +39,11 @@ func tickspersecond() int64 { func makeStringSlice(n int) []string { return make([]string, n) } + +// TODO: Move to parfor.go when parfor.c becomes parfor.go. +func parforalloc(nthrmax uint32) *parfor { + return &parfor{ + thr: &make([]parforthread, nthrmax)[0], + nthrmax: nthrmax, + } +} From d208361cde17ff65451ae1da5e273ef8c65ee7c0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 11:09:58 -0400 Subject: [PATCH 090/430] runtime: remove uses of ScanConservatively Along with CLs 139610043 and 141490043, this removes all conservative scanning during garbage collection, except _cgo_allocate, which is SWIG-only. LGTM=rlh, khr R=golang-codereviews, dvyukov, rlh, khr CC=golang-codereviews, iant https://golang.org/cl/144860043 --- src/runtime/malloc.h | 1 + src/runtime/mgc0.c | 55 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index c496cc70e3..3f1981f708 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -551,6 +551,7 @@ void runtime·createfing(void); G* runtime·wakefing(void); void runtime·getgcmask(byte*, Type*, byte**, uintptr*); +// NOTE: Layout known to queuefinalizer. typedef struct Finalizer Finalizer; struct Finalizer { diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index ba02700dea..7a3498ae1e 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -76,7 +76,8 @@ enum { RootCount = 5, }; -#define ScanConservatively ((byte*)1) +// ptrmask for an allocation containing a single pointer. +static byte oneptr[] = {BitsPointer}; // Initialized from $GOGC. GOGC=off means no gc. extern int32 runtime·gcpercent; @@ -116,6 +117,7 @@ Mutex runtime·finlock; // protects the following variables G* runtime·fing; // goroutine that runs finalizers FinBlock* runtime·finq; // list of finalizers that are to be executed FinBlock* runtime·finc; // cache of free blocks +static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte]; bool runtime·fingwait; bool runtime·fingwake; static FinBlock *allfin; // list of all blocks @@ -190,10 +192,9 @@ scanblock(byte *b, uintptr n, byte *ptrmask) cached = 0; ncached = 0; - // ptrmask can have 3 possible values: + // ptrmask can have 2 possible values: // 1. nil - obtain pointer mask from GC bitmap. - // 2. ScanConservatively - don't use any mask, scan conservatively. - // 3. pointer to a compact mask (for stacks and data). + // 2. pointer to a compact mask (for stacks and data). if(b != nil) goto scanobj; for(;;) { @@ -269,10 +270,8 @@ scanblock(byte *b, uintptr n, byte *ptrmask) bits = (bits>>2)&BitsMask; if(bits == BitsDead) break; // reached no-scan part of the object - } else if(ptrmask != ScanConservatively) // dense mask (stack or data) + } else // dense mask (stack or data) bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask; - else - bits = BitsPointer; if(bits == BitsScalar || bits == BitsDead) continue; @@ -436,7 +435,7 @@ markroot(ParFor *desc, uint32 i) case RootFinalizers: for(fb=allfin; fb; fb=fb->alllink) - scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), ScanConservatively); + scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), finptrmask); break; case RootSpans: @@ -462,7 +461,7 @@ markroot(ParFor *desc, uint32 i) // A finalizer can be set for an inner byte of an object, find object beginning. p = (void*)((s->start << PageShift) + spf->special.offset/s->elemsize*s->elemsize); scanblock(p, s->elemsize, nil); - scanblock((void*)&spf->fn, PtrSize, ScanConservatively); + scanblock((void*)&spf->fn, PtrSize, oneptr); } } break; @@ -739,11 +738,34 @@ runtime·gcphasework(G *gp) gp->gcworkdone = true; } +static byte finalizer1[] = { + // Each Finalizer is 5 words, ptr ptr uintptr ptr ptr. + // Each byte describes 4 words. + // Need 4 Finalizers described by 5 bytes before pattern repeats: + // ptr ptr uintptr ptr ptr + // ptr ptr uintptr ptr ptr + // ptr ptr uintptr ptr ptr + // ptr ptr uintptr ptr ptr + // aka + // ptr ptr uintptr ptr + // ptr ptr ptr uintptr + // ptr ptr ptr ptr + // uintptr ptr ptr ptr + // ptr uintptr ptr ptr + // Assumptions about Finalizer layout checked below. + BitsPointer | BitsPointer<<2 | BitsScalar<<4 | BitsPointer<<6, + BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsScalar<<6, + BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6, + BitsScalar | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6, + BitsPointer | BitsScalar<<2 | BitsPointer<<4 | BitsPointer<<6, +}; + void runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot) { FinBlock *block; Finalizer *f; + int32 i; runtime·lock(&runtime·finlock); if(runtime·finq == nil || runtime·finq->cnt == runtime·finq->cap) { @@ -752,6 +774,21 @@ runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType runtime·finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1; runtime·finc->alllink = allfin; allfin = runtime·finc; + if(finptrmask[0] == 0) { + // Build pointer mask for Finalizer array in block. + // Check assumptions made in finalizer1 array above. + if(sizeof(Finalizer) != 5*PtrSize || + offsetof(Finalizer, fn) != 0 || + offsetof(Finalizer, arg) != PtrSize || + offsetof(Finalizer, nret) != 2*PtrSize || + offsetof(Finalizer, fint) != 3*PtrSize || + offsetof(Finalizer, ot) != 4*PtrSize || + BitsPerPointer != 2) { + runtime·throw("finalizer out of sync"); + } + for(i=0; inext; From 99e8f40488b89f3e6c30ddcf94a2c5db61d7ab3d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 11:43:35 -0400 Subject: [PATCH 091/430] runtime: fix 386 build mark finalizer1 as having no pointers TBR=iant CC=golang-codereviews https://golang.org/cl/141570045 --- src/runtime/mgc0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 7a3498ae1e..fda3efcc18 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -738,6 +738,7 @@ runtime·gcphasework(G *gp) gp->gcworkdone = true; } +#pragma dataflag NOPTR static byte finalizer1[] = { // Each Finalizer is 5 words, ptr ptr uintptr ptr ptr. // Each byte describes 4 words. From c1c5d479bd9ead47f718156866c8bd188a8e19b8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 13:16:43 -0400 Subject: [PATCH 092/430] cmd/5g, cmd/8g: make 'out of registers' a fatal error There's no point in continuing. We will only get confused. 6g already makes this fatal. LGTM=dave, minux, iant R=iant, dave, minux CC=golang-codereviews https://golang.org/cl/140660043 --- src/cmd/5g/gsubr.c | 4 ++-- src/cmd/8g/gsubr.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index 93bfafef66..06e274e14d 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -361,7 +361,7 @@ regalloc(Node *n, Type *t, Node *o) print("registers allocated at\n"); for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) print("%d %p\n", i, regpc[i]); - yyerror("out of fixed registers"); + fatal("out of fixed registers"); goto err; case TFLOAT32: @@ -374,7 +374,7 @@ regalloc(Node *n, Type *t, Node *o) for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) if(reg[i] == 0) goto out; - yyerror("out of floating point registers"); + fatal("out of floating point registers"); goto err; case TCOMPLEX64: diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index a83d048f40..3077e0ad9c 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -938,7 +938,7 @@ regalloc(Node *n, Type *t, Node *o) fprint(2, "registers allocated at\n"); for(i=D_AX; i<=D_DI; i++) fprint(2, "\t%R\t%#lux\n", i, regpc[i]); - yyerror("out of fixed registers"); + fatal("out of fixed registers"); goto err; case TFLOAT32: From 95c899f03c0e19f498ef3b4a4820cf9121e249a1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 14:02:59 -0400 Subject: [PATCH 093/430] net: make TestSelfConnect less fragile We believe TestSelfConnect can accidentally connect to something else listening on or dialing from that port. Fixes #8680. LGTM=bradfitz R=bradfitz CC=golang-codereviews, rlh https://golang.org/cl/136700043 --- src/net/dial_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index c5c3236ccf..19e289f2e5 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -119,6 +119,7 @@ func TestSelfConnect(t *testing.T) { // TODO(brainman): do not know why it hangs. t.Skip("skipping known-broken test on windows") } + // Test that Dial does not honor self-connects. // See the comment in DialTCP. @@ -149,8 +150,12 @@ func TestSelfConnect(t *testing.T) { for i := 0; i < n; i++ { c, err := DialTimeout("tcp", addr, time.Millisecond) if err == nil { + if c.LocalAddr().String() == addr { + t.Errorf("#%d: Dial %q self-connect", i, addr) + } else { + t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr) + } c.Close() - t.Errorf("#%d: Dial %q succeeded", i, addr) } } } From c1e332020ddf1dd31f39d86464136fe06fe6d7fe Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 15:26:00 -0400 Subject: [PATCH 094/430] os/signal: increase timeout from 10ms to 100ms Might make test less flaky. Fixes #8682. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/143160043 --- src/os/signal/signal_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index 076fe3f93b..22337a72d4 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -125,7 +125,7 @@ func TestStop(t *testing.T) { if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 { syscall.Kill(syscall.Getpid(), sig) } - time.Sleep(10 * time.Millisecond) + time.Sleep(100 * time.Millisecond) // Ask for signal c := make(chan os.Signal, 1) @@ -140,7 +140,7 @@ func TestStop(t *testing.T) { select { case s := <-c: t.Fatalf("unexpected signal %v", s) - case <-time.After(10 * time.Millisecond): + case <-time.After(100 * time.Millisecond): // nothing to read - good } @@ -154,7 +154,7 @@ func TestStop(t *testing.T) { select { case s := <-c: t.Fatalf("unexpected signal %v", s) - case <-time.After(10 * time.Millisecond): + case <-time.After(100 * time.Millisecond): // nothing to read - good } } From 15274e5c9bd5393f67a77200f0669ab00f2ab0ed Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 16 Sep 2014 12:50:05 -0700 Subject: [PATCH 095/430] runtime: make it clear that Goexit cannot be recover'd. LGTM=r R=r, bradfitz, khr CC=golang-codereviews https://golang.org/cl/136660044 --- src/runtime/panic.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 12c85e7caf..927b6db44b 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -238,7 +238,8 @@ func deferreturn(arg0 uintptr) { } // Goexit terminates the goroutine that calls it. No other goroutine is affected. -// Goexit runs all deferred calls before terminating the goroutine. +// Goexit runs all deferred calls before terminating the goroutine. Because Goexit +// is not panic, however, any recover calls in those deferred functions will return nil. // // Calling Goexit from the main goroutine terminates that goroutine // without func main returning. Since func main has not returned, From b22dc6385d66ac2e74afb9a5d503394fc7273d81 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 16 Sep 2014 14:00:01 -0700 Subject: [PATCH 096/430] sync/once: panicking functions still marked as complete This is a corner case, and one that was even tested, but this CL changes the behavior to say that f is "complete" even if it panics. But don't think of it that way, think of it as sync.Once runs the function only the first time it is called, rather than repeatedly until a run of the function completes. Fixes #8118. LGTM=dvyukov R=golang-codereviews, dvyukov CC=golang-codereviews https://golang.org/cl/137350043 --- src/sync/once.go | 7 +++++-- src/sync/once_test.go | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sync/once.go b/src/sync/once.go index 161ae3b3e9..10b42fddc2 100644 --- a/src/sync/once.go +++ b/src/sync/once.go @@ -15,7 +15,7 @@ type Once struct { } // Do calls the function f if and only if Do is being called for the -// first time for this instance of Once. In other words, given +// first time for this instance of Once. In other words, given // var once Once // if once.Do(f) is called multiple times, only the first call will invoke f, // even if f has a different value in each invocation. A new instance of @@ -29,6 +29,9 @@ type Once struct { // Because no call to Do returns until the one call to f returns, if f causes // Do to be called, it will deadlock. // +// If f panics, Do considers it to have returned; future calls of Do return +// without calling f. +// func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 1 { return @@ -37,7 +40,7 @@ func (o *Once) Do(f func()) { o.m.Lock() defer o.m.Unlock() if o.done == 0 { + defer atomic.StoreUint32(&o.done, 1) f() - atomic.StoreUint32(&o.done, 1) } } diff --git a/src/sync/once_test.go b/src/sync/once_test.go index 8afda82f3e..10beefde35 100644 --- a/src/sync/once_test.go +++ b/src/sync/once_test.go @@ -44,8 +44,12 @@ func TestOncePanic(t *testing.T) { for i := 0; i < 2; i++ { func() { defer func() { - if recover() == nil { - t.Fatalf("Once.Do() has not panic'ed") + r := recover() + if r == nil && i == 0 { + t.Fatalf("Once.Do() has not panic'ed on first iteration") + } + if r != nil && i == 1 { + t.Fatalf("Once.Do() has panic'ed on second iteration") } }() once.Do(func() { From f1abe0d06bc94399c4abee041624efa36742fc1e Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Tue, 16 Sep 2014 14:22:33 -0700 Subject: [PATCH 097/430] sync: simplify TestOncePanic Follow-up to CL 137350043. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/141620043 --- src/sync/once_test.go | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/sync/once_test.go b/src/sync/once_test.go index 10beefde35..1eec8d18ea 100644 --- a/src/sync/once_test.go +++ b/src/sync/once_test.go @@ -40,26 +40,20 @@ func TestOnce(t *testing.T) { } func TestOncePanic(t *testing.T) { - once := new(Once) - for i := 0; i < 2; i++ { - func() { - defer func() { - r := recover() - if r == nil && i == 0 { - t.Fatalf("Once.Do() has not panic'ed on first iteration") - } - if r != nil && i == 1 { - t.Fatalf("Once.Do() has panic'ed on second iteration") - } - }() - once.Do(func() { - panic("failed") - }) + var once Once + func() { + defer func() { + if r := recover(); r == nil { + t.Fatalf("Once.Do did not panic") + } }() - } - once.Do(func() {}) + once.Do(func() { + panic("failed") + }) + }() + once.Do(func() { - t.Fatalf("Once called twice") + t.Fatalf("Once.Do called twice") }) } From 653fb6d872e31b05441f313911684d5cd351597e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 17:39:55 -0400 Subject: [PATCH 098/430] =?UTF-8?q?liblink:=20make=20GO=5FARGS=20the=20def?= =?UTF-8?q?ault=20for=20functions=20beginning=20with=20=C2=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is a leading ·, assume there is a Go prototype and attach the Go prototype information to the function. If the function is not called from Go and does not need a Go prototype, it can be made file-local instead (using name<>(SB)). This fixes the current BSD build failures, by giving functions like sync/atomic.StoreUint32 argument stack map information. Fixes #8753. LGTM=khr, iant R=golang-codereviews, iant, khr, bradfitz CC=golang-codereviews, r, rlh https://golang.org/cl/142150043 --- src/liblink/objfile.c | 23 ++++++++++++++++++++++- src/runtime/asm_386.s | 9 +++------ src/runtime/asm_amd64.s | 9 +++------ src/runtime/asm_arm.s | 9 +++------ src/syscall/asm_darwin_386.s | 5 ----- src/syscall/asm_darwin_amd64.s | 4 ---- src/syscall/asm_dragonfly_386.s | 5 ----- src/syscall/asm_dragonfly_amd64.s | 5 ----- src/syscall/asm_freebsd_386.s | 5 ----- src/syscall/asm_freebsd_amd64.s | 5 ----- src/syscall/asm_freebsd_arm.s | 5 ----- src/syscall/asm_linux_386.s | 7 ------- src/syscall/asm_linux_amd64.s | 5 ----- src/syscall/asm_linux_arm.s | 5 ----- src/syscall/asm_nacl_386.s | 1 - src/syscall/asm_nacl_amd64p32.s | 1 - src/syscall/asm_nacl_arm.s | 1 - src/syscall/asm_netbsd_386.s | 5 ----- src/syscall/asm_netbsd_amd64.s | 5 ----- src/syscall/asm_netbsd_arm.s | 5 ----- src/syscall/asm_openbsd_386.s | 5 ----- src/syscall/asm_openbsd_amd64.s | 5 ----- src/syscall/asm_plan9_386.s | 6 ------ src/syscall/asm_plan9_amd64.s | 6 ------ test/nosplit.go | 13 +++++++++++-- 25 files changed, 42 insertions(+), 112 deletions(-) diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index 02cfae495a..7d4b28c9ac 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -125,7 +125,7 @@ static LSym *rdsym(Link*, Biobuf*, char*); void writeobj(Link *ctxt, Biobuf *b) { - int flag; + int flag, found; Hist *h; LSym *s, *text, *etext, *curtext, *data, *edata; Plist *pl; @@ -251,6 +251,27 @@ writeobj(Link *ctxt, Biobuf *b) s->etext = p; } } + + // Add reference to Go arguments for C or assembly functions without them. + for(s = text; s != nil; s = s->next) { + if(strncmp(s->name, "\"\".", 3) != 0) + continue; + found = 0; + for(p = s->text; p != nil; p = p->link) { + if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) { + found = 1; + break; + } + } + if(!found) { + p = appendp(ctxt, s->text); + p->as = ctxt->arch->AFUNCDATA; + p->from.type = ctxt->arch->D_CONST; + p->from.offset = FUNCDATA_ArgsPointerMaps; + p->to.type = ctxt->arch->D_EXTERN; + p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version); + } + } // Turn functions into machine code images. for(s = text; s != nil; s = s->next) { diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 21065b6d6f..2961f10f2a 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -646,15 +646,13 @@ TEXT gosave<>(SB),NOSPLIT,$0 // Call fn(arg) on the scheduler stack, // aligned appropriately for the gcc ABI. // See cgocall.c for more details. -TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 - GO_ARGS +TEXT ·asmcgocall(SB),NOSPLIT,$0-8 MOVL fn+0(FP), AX MOVL arg+4(FP), BX CALL asmcgocall<>(SB) RET -TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12 - GO_ARGS +TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12 MOVL fn+0(FP), AX MOVL arg+4(FP), BX CALL asmcgocall<>(SB) @@ -714,8 +712,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // See cgocall.c for more details. -TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$12-12 - GO_ARGS +TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-12 NO_LOCAL_POINTERS // If g is nil, Go did not create the current thread. diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index da29f61ed8..44159bb57e 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -623,15 +623,13 @@ TEXT gosave<>(SB),NOSPLIT,$0 // Call fn(arg) on the scheduler stack, // aligned appropriately for the gcc ABI. // See cgocall.c for more details. -TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16 - GO_ARGS +TEXT ·asmcgocall(SB),NOSPLIT,$0-16 MOVQ fn+0(FP), AX MOVQ arg+8(FP), BX CALL asmcgocall<>(SB) RET -TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-20 - GO_ARGS +TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20 MOVQ fn+0(FP), AX MOVQ arg+8(FP), BX CALL asmcgocall<>(SB) @@ -700,8 +698,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$24-24 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) // See cgocall.c for more details. -TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-24 - GO_ARGS +TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24 NO_LOCAL_POINTERS // If g is nil, Go did not create the current thread. diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 3e78d91143..f67f94939b 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -480,15 +480,13 @@ TEXT gosave<>(SB),NOSPLIT,$0 // Call fn(arg) on the scheduler stack, // aligned appropriately for the gcc ABI. // See cgocall.c for more details. -TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8 - GO_ARGS +TEXT ·asmcgocall(SB),NOSPLIT,$0-8 MOVW fn+0(FP), R1 MOVW arg+4(FP), R0 BL asmcgocall<>(SB) RET -TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12 - GO_ARGS +TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12 MOVW fn+0(FP), R1 MOVW arg+4(FP), R0 BL asmcgocall<>(SB) @@ -551,8 +549,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12 // cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize) // See cgocall.c for more details. -TEXT runtime·cgocallback_gofunc(SB),NOSPLIT,$8-12 - GO_ARGS +TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-12 NO_LOCAL_POINTERS // Load m and g from thread-local storage. diff --git a/src/syscall/asm_darwin_386.s b/src/syscall/asm_darwin_386.s index 7d8ddf4378..7205deb12d 100644 --- a/src/syscall/asm_darwin_386.s +++ b/src/syscall/asm_darwin_386.s @@ -17,7 +17,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -70,7 +68,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -101,7 +98,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -123,7 +119,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s index a3b1bd5346..e57199d2b6 100644 --- a/src/syscall/asm_darwin_amd64.s +++ b/src/syscall/asm_darwin_amd64.s @@ -17,7 +17,6 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -67,7 +65,6 @@ ok6: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -89,7 +86,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_dragonfly_386.s b/src/syscall/asm_dragonfly_386.s index 0d7d6ba1e7..7012d23c21 100644 --- a/src/syscall/asm_dragonfly_386.s +++ b/src/syscall/asm_dragonfly_386.s @@ -14,7 +14,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-32 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -39,7 +38,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-44 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -67,7 +65,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -98,7 +95,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-32 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -120,7 +116,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-44 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_dragonfly_amd64.s b/src/syscall/asm_dragonfly_amd64.s index b81cf8dda9..004d36089a 100644 --- a/src/syscall/asm_dragonfly_amd64.s +++ b/src/syscall/asm_dragonfly_amd64.s @@ -15,7 +15,6 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-64 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -39,7 +38,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-88 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -63,7 +61,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-112 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX MOVQ 16(SP), DI @@ -97,7 +94,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-64 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -118,7 +114,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-88 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_freebsd_386.s b/src/syscall/asm_freebsd_386.s index ff5f9f4a2a..1400d5fea7 100644 --- a/src/syscall/asm_freebsd_386.s +++ b/src/syscall/asm_freebsd_386.s @@ -17,7 +17,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -70,7 +68,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -101,7 +98,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -123,7 +119,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s index 47ceb9287b..c52519098e 100644 --- a/src/syscall/asm_freebsd_amd64.s +++ b/src/syscall/asm_freebsd_amd64.s @@ -23,7 +23,6 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -47,7 +46,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -71,7 +69,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX MOVQ 16(SP), DI @@ -105,7 +102,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -126,7 +122,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_freebsd_arm.s b/src/syscall/asm_freebsd_arm.s index ed369ce73e..6b0c182a76 100644 --- a/src/syscall/asm_freebsd_arm.s +++ b/src/syscall/asm_freebsd_arm.s @@ -14,7 +14,6 @@ // func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr) TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -37,7 +36,6 @@ error: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -64,7 +62,6 @@ error6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 @@ -91,7 +88,6 @@ error9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 MOVW 8(FP), R1 // a2 @@ -111,7 +107,6 @@ errorr: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVW 0(FP), R7 // syscall number MOVW 4(FP), R0 // a1 MOVW 8(FP), R1 // a2 diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s index 2ce51822da..fa1b371206 100644 --- a/src/syscall/asm_linux_386.s +++ b/src/syscall/asm_linux_386.s @@ -16,7 +16,6 @@ // Trap # in AX, args in BX CX DX SI DI, return in AX TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX @@ -42,7 +41,6 @@ ok: // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX @@ -69,7 +67,6 @@ ok6: // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX MOVL 12(SP), CX @@ -92,7 +89,6 @@ ok1: // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry MOVL 8(SP), BX MOVL 12(SP), CX @@ -119,7 +115,6 @@ ok2: // func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int) // Kernel interface gets call sub-number and pointer to a0. TEXT ·socketcall(SB),NOSPLIT,$0-36 - GO_ARGS CALL runtime·entersyscall(SB) MOVL $SYS_SOCKETCALL, AX // syscall entry MOVL 4(SP), BX // socket call number @@ -144,7 +139,6 @@ oksock: // func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int) // Kernel interface gets call sub-number and pointer to a0. TEXT ·rawsocketcall(SB),NOSPLIT,$0-36 - GO_ARGS MOVL $SYS_SOCKETCALL, AX // syscall entry MOVL 4(SP), BX // socket call number LEAL 8(SP), CX // pointer to call arguments @@ -170,7 +164,6 @@ oksock1: // Underlying system call is // llseek(int fd, int offhi, int offlo, int64 *result, int whence) TEXT ·seek(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL $SYS__LLSEEK, AX // syscall entry MOVL 4(SP), BX // fd diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s index 0277c506c0..b3ce2165d6 100644 --- a/src/syscall/asm_linux_amd64.s +++ b/src/syscall/asm_linux_amd64.s @@ -18,7 +18,6 @@ // would pass 4th arg in CX, not R10. TEXT ·Syscall(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -44,7 +43,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 16(SP), DI MOVQ 24(SP), SI @@ -70,7 +68,6 @@ ok6: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -93,7 +90,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -116,7 +112,6 @@ ok2: RET TEXT ·gettimeofday(SB),NOSPLIT,$0-16 - GO_ARGS MOVQ 8(SP), DI MOVQ $0, SI MOVQ runtime·__vdso_gettimeofday_sym(SB), AX diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s index 9451013813..3526533019 100644 --- a/src/syscall/asm_linux_arm.s +++ b/src/syscall/asm_linux_arm.s @@ -14,7 +14,6 @@ // func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS BL runtime·entersyscall(SB) MOVW 4(SP), R7 MOVW 8(SP), R0 @@ -46,7 +45,6 @@ ok: // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); // Actually Syscall5 but the rest of the code expects it to be named Syscall6. TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS BL runtime·entersyscall(SB) MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 @@ -78,7 +76,6 @@ ok6: // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); // Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6. TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 MOVW 12(SP), R1 @@ -111,7 +108,6 @@ ok2: // Underlying system call is // llseek(int fd, int offhi, int offlo, int64 *result, int whence) TEXT ·seek(SB),NOSPLIT,$0-32 - GO_ARGS BL runtime·entersyscall(SB) MOVW $SYS__LLSEEK, R7 // syscall entry MOVW 4(SP), R0 // fd @@ -139,7 +135,6 @@ okseek: // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr); TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVW 4(SP), R7 // syscall entry MOVW 8(SP), R0 MOVW 12(SP), R1 diff --git a/src/syscall/asm_nacl_386.s b/src/syscall/asm_nacl_386.s index 5352b7697c..cb6fb44166 100644 --- a/src/syscall/asm_nacl_386.s +++ b/src/syscall/asm_nacl_386.s @@ -17,7 +17,6 @@ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX TEXT syscall·Syscall(SB),NOSPLIT,$12-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL trap+0(FP), AX MOVL a1+4(FP), BX diff --git a/src/syscall/asm_nacl_amd64p32.s b/src/syscall/asm_nacl_amd64p32.s index 637fafab45..72391c431a 100644 --- a/src/syscall/asm_nacl_amd64p32.s +++ b/src/syscall/asm_nacl_amd64p32.s @@ -17,7 +17,6 @@ MOVL $(0x10000 + ((code)<<5)), AX; JMP AX TEXT syscall·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL trap+0(FP), AX MOVL a1+4(FP), DI diff --git a/src/syscall/asm_nacl_arm.s b/src/syscall/asm_nacl_arm.s index 3e4479432b..78e10bf7a2 100644 --- a/src/syscall/asm_nacl_arm.s +++ b/src/syscall/asm_nacl_arm.s @@ -17,7 +17,6 @@ MOVW $(0x10000 + ((code)<<5)), R8; B (R8) TEXT syscall·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS BL runtime·entersyscall(SB) MOVW trap+0(FP), R8 MOVW a1+4(FP), R0 diff --git a/src/syscall/asm_netbsd_386.s b/src/syscall/asm_netbsd_386.s index 29442ca9dd..a8c4849f23 100644 --- a/src/syscall/asm_netbsd_386.s +++ b/src/syscall/asm_netbsd_386.s @@ -17,7 +17,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -70,7 +68,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -101,7 +98,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -123,7 +119,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_netbsd_amd64.s b/src/syscall/asm_netbsd_amd64.s index 6d0f311f41..b300148f43 100644 --- a/src/syscall/asm_netbsd_amd64.s +++ b/src/syscall/asm_netbsd_amd64.s @@ -18,7 +18,6 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -66,7 +64,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -99,7 +96,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -120,7 +116,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_netbsd_arm.s b/src/syscall/asm_netbsd_arm.s index c4190ea332..290bb58061 100644 --- a/src/syscall/asm_netbsd_arm.s +++ b/src/syscall/asm_netbsd_arm.s @@ -14,7 +14,6 @@ // func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32) TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -37,7 +36,6 @@ error: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -63,7 +61,6 @@ error6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS BL runtime·entersyscall(SB) MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 @@ -89,7 +86,6 @@ error9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 MOVW 8(FP), R2 // a2 @@ -109,7 +105,6 @@ errorr: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVW 0(FP), R0 // sigcall num MOVW 4(FP), R1 // a1 MOVW 8(FP), R2 // a2 diff --git a/src/syscall/asm_openbsd_386.s b/src/syscall/asm_openbsd_386.s index e448a70ca1..6458bdf020 100644 --- a/src/syscall/asm_openbsd_386.s +++ b/src/syscall/asm_openbsd_386.s @@ -17,7 +17,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-28 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-40 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -70,7 +68,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-52 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -101,7 +98,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -123,7 +119,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI diff --git a/src/syscall/asm_openbsd_amd64.s b/src/syscall/asm_openbsd_amd64.s index 654e3df742..1e981fc01d 100644 --- a/src/syscall/asm_openbsd_amd64.s +++ b/src/syscall/asm_openbsd_amd64.s @@ -18,7 +18,6 @@ // Trap # in AX, args in DI SI DX, return in AX DX TEXT ·Syscall(SB),NOSPLIT,$0-56 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -42,7 +41,6 @@ ok: RET TEXT ·Syscall6(SB),NOSPLIT,$0-80 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -66,7 +64,6 @@ ok6: RET TEXT ·Syscall9(SB),NOSPLIT,$0-104 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), AX // syscall entry MOVQ 16(SP), DI @@ -99,7 +96,6 @@ ok9: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX @@ -120,7 +116,6 @@ ok1: RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 16(SP), DI MOVQ 24(SP), SI MOVQ 32(SP), DX diff --git a/src/syscall/asm_plan9_386.s b/src/syscall/asm_plan9_386.s index 46562de845..fc13640b93 100644 --- a/src/syscall/asm_plan9_386.s +++ b/src/syscall/asm_plan9_386.s @@ -19,7 +19,6 @@ // Trap # in AX, args on stack above caller pc. TEXT ·Syscall(SB),NOSPLIT,$0-32 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -55,7 +54,6 @@ copyresult3: RET TEXT ·Syscall6(SB),NOSPLIT,$0-44 - GO_ARGS CALL runtime·entersyscall(SB) MOVL 4(SP), AX // syscall entry // slide args down on top of system call number @@ -94,7 +92,6 @@ copyresult4: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-28 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -110,7 +107,6 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28 RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 - GO_ARGS MOVL 4(SP), AX // syscall entry // slide args down on top of system call number LEAL 8(SP), SI @@ -132,7 +128,6 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) TEXT ·seek(SB),NOSPLIT,$0-36 - GO_ARGS LEAL newoffset+24(SP), AX MOVL AX, placeholder+4(SP) @@ -164,7 +159,6 @@ copyresult6: //func exit(code int) // Import runtime·exit for cleanly exiting. TEXT ·exit(SB),NOSPLIT,$4-4 - GO_ARGS NO_LOCAL_POINTERS MOVL code+0(FP), AX MOVL AX, 0(SP) diff --git a/src/syscall/asm_plan9_amd64.s b/src/syscall/asm_plan9_amd64.s index 283e28999a..92419b7172 100644 --- a/src/syscall/asm_plan9_amd64.s +++ b/src/syscall/asm_plan9_amd64.s @@ -18,7 +18,6 @@ //func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) TEXT ·Syscall(SB),NOSPLIT,$0-64 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number @@ -54,7 +53,6 @@ copyresult3: RET TEXT ·Syscall6(SB),NOSPLIT,$0-88 - GO_ARGS CALL runtime·entersyscall(SB) MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number @@ -93,7 +91,6 @@ copyresult4: RET TEXT ·RawSyscall(SB),NOSPLIT,$0-56 - GO_ARGS MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number LEAQ 16(SP), SI @@ -109,7 +106,6 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56 RET TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 - GO_ARGS MOVQ 8(SP), BP // syscall entry // slide args down on top of system call number LEAQ 16(SP), SI @@ -131,7 +127,6 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) TEXT ·seek(SB),NOSPLIT,$0-56 - GO_ARGS LEAQ newoffset+40(SP), AX MOVQ AX, placeholder+8(SP) @@ -162,7 +157,6 @@ copyresult6: //func exit(code int) // Import runtime·exit for cleanly exiting. TEXT ·exit(SB),NOSPLIT,$8-8 - GO_ARGS NO_LOCAL_POINTERS MOVQ code+0(FP), AX MOVQ AX, 0(SP) diff --git a/test/nosplit.go b/test/nosplit.go index c9d008acd3..953a5bf0a6 100644 --- a/test/nosplit.go +++ b/test/nosplit.go @@ -12,6 +12,7 @@ import ( "bytes" "fmt" "io/ioutil" + "log" "os" "os/exec" "path/filepath" @@ -190,7 +191,6 @@ func main() { return } defer os.RemoveAll(dir) - ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte("package main\nfunc main()\n"), 0666) tests = strings.Replace(tests, "\t", " ", -1) tests = commentRE.ReplaceAllString(tests, "") @@ -230,6 +230,9 @@ TestCases: continue } + var gobuf bytes.Buffer + fmt.Fprintf(&gobuf, "package main\n") + var buf bytes.Buffer if goarch == "arm" { fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n") @@ -277,11 +280,17 @@ TestCases: body = callRE.ReplaceAllString(body, "CALL ·$1(SB);") body = callindRE.ReplaceAllString(body, "CALL REGISTER;") + fmt.Fprintf(&gobuf, "func %s()\n", name) fmt.Fprintf(&buf, "TEXT ·%s(SB)%s,$%d-0\n\t%s\n\tRET\n\n", name, nosplit, size, body) } } - ioutil.WriteFile(filepath.Join(dir, "asm.s"), buf.Bytes(), 0666) + if err := ioutil.WriteFile(filepath.Join(dir, "asm.s"), buf.Bytes(), 0666); err != nil { + log.Fatal(err) + } + if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), gobuf.Bytes(), 0666); err != nil { + log.Fatal(err) + } cmd := exec.Command("go", "build") cmd.Dir = dir From a325f4f2b35d16724750c8c46857d0a840790fd2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 17:40:10 -0400 Subject: [PATCH 099/430] reflect: add Type.Comparable Like most of the Type methods, the definition of Comparable is what the Go spec says it is. Fixes #7911. LGTM=gri R=gri, r CC=golang-codereviews https://golang.org/cl/144020043 --- src/reflect/all_test.go | 38 ++++++++++++++++++++++++++++++++++++++ src/reflect/type.go | 18 +++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 688b5d3107..4be0e353df 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -3185,6 +3185,44 @@ func TestConvert(t *testing.T) { } } +type ComparableStruct struct { + X int +} + +type NonComparableStruct struct { + X int + Y map[string]int +} + +var comparableTests = []struct { + typ Type + ok bool +}{ + {TypeOf(1), true}, + {TypeOf("hello"), true}, + {TypeOf(new(byte)), true}, + {TypeOf((func())(nil)), false}, + {TypeOf([]byte{}), false}, + {TypeOf(map[string]int{}), false}, + {TypeOf(make(chan int)), true}, + {TypeOf(1.5), true}, + {TypeOf(false), true}, + {TypeOf(1i), true}, + {TypeOf(ComparableStruct{}), true}, + {TypeOf(NonComparableStruct{}), false}, + {TypeOf([10]map[string]int{}), false}, + {TypeOf([10]string{}), true}, + {TypeOf(new(interface{})).Elem(), true}, +} + +func TestComparable(t *testing.T) { + for _, tt := range comparableTests { + if ok := tt.typ.Comparable(); ok != tt.ok { + t.Errorf("TypeOf(%v).Comparable() = %v, want %v", tt.typ, ok, tt.ok) + } + } +} + func TestOverflow(t *testing.T) { if ovf := V(float64(0)).OverflowFloat(1e300); ovf { t.Errorf("%v wrongly overflows float64", 1e300) diff --git a/src/reflect/type.go b/src/reflect/type.go index 67818f7f4c..f099546d27 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -96,6 +96,9 @@ type Type interface { // ConvertibleTo returns true if a value of the type is convertible to type u. ConvertibleTo(u Type) bool + // Comparable returns true if values of this type are comparable. + Comparable() bool + // Methods applicable only to some types, depending on Kind. // The methods allowed for each kind are: // @@ -248,7 +251,7 @@ type rtype struct { align uint8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type kind uint8 // enumeration for C - alg *uintptr // algorithm table (../runtime/runtime.h:/Alg) + alg *typeAlg // algorithm table (../runtime/runtime.h:/Alg) gc [2]unsafe.Pointer // garbage collection data string *string // string form; unnecessary but undeniably useful *uncommonType // (relatively) uncommon fields @@ -256,6 +259,15 @@ type rtype struct { zero unsafe.Pointer // pointer to zero value } +type typeAlg struct { + // function for hashing objects of this type + // (ptr to object, size, seed) -> hash + hash func(unsafe.Pointer, uintptr, uintptr) uintptr + // function for comparing objects of this type + // (ptr to object A, ptr to object B, size) -> ==? + equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool +} + // Method on non-interface type type method struct { name *string // name of method @@ -1096,6 +1108,10 @@ func (t *rtype) ConvertibleTo(u Type) bool { return convertOp(uu, t) != nil } +func (t *rtype) Comparable() bool { + return t.alg != nil && t.alg.equal != nil +} + // implements returns true if the type V implements the interface type T. func implements(T, V *rtype) bool { if T.Kind() != Interface { From 06e4b06893941b75c3d3955fb6ee75b69e9eb1ae Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 17:40:33 -0400 Subject: [PATCH 100/430] net/mail: allow us-ascii encoding Fixes #6611. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/14990045 --- src/net/mail/message.go | 13 ++++++++++++- src/net/mail/message_test.go | 10 ++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/net/mail/message.go b/src/net/mail/message.go index ba0778caa7..19aa888d87 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -28,6 +28,7 @@ import ( "strconv" "strings" "time" + "unicode" ) var debug = debugT(false) @@ -445,7 +446,7 @@ func decodeRFC2047Word(s string) (string, error) { return "", errors.New("address not RFC 2047 encoded") } charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2]) - if charset != "iso-8859-1" && charset != "utf-8" { + if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" { return "", fmt.Errorf("charset not supported: %q", charset) } @@ -466,6 +467,16 @@ func decodeRFC2047Word(s string) (string, error) { } switch charset { + case "us-ascii": + b := new(bytes.Buffer) + for _, c := range dec { + if c >= 0x80 { + b.WriteRune(unicode.ReplacementChar) + } else { + b.WriteRune(rune(c)) + } + } + return b.String(), nil case "iso-8859-1": b := new(bytes.Buffer) for _, c := range dec { diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index eb9c8cbdc9..6ba48be04f 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -194,6 +194,16 @@ func TestAddressParsing(t *testing.T) { }, }, }, + // RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal. + { + `=?us-ascii?q?J=6Frg_Doe?= `, + []*Address{ + { + Name: `Jorg Doe`, + Address: "joerg@example.com", + }, + }, + }, // RFC 2047 "Q"-encoded UTF-8 address. { `=?utf-8?q?J=C3=B6rg_Doe?= `, From 4bf4d9f86ebeb5711464bd98b6823e3e2cca7bb7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 17:46:25 -0400 Subject: [PATCH 101/430] runtime: reenable TestStackGrowth on 32-bit systems If this needs to be turned back off, it should be done just before the '// in finalizer' comment, not at the top of the function. GC is more precise now than it was (the only imprecise stuff left is some global variables), so maybe the finalizer test will work now on 32-bit systems. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/144030043 --- src/runtime/stack_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go index 3a0802a1c2..652c72eeed 100644 --- a/src/runtime/stack_test.go +++ b/src/runtime/stack_test.go @@ -71,10 +71,6 @@ func TestStackMem(t *testing.T) { // Test stack growing in different contexts. func TestStackGrowth(t *testing.T) { - switch GOARCH { - case "386", "arm": - t.Skipf("skipping test on %q; see issue 8083", GOARCH) - } t.Parallel() var wg sync.WaitGroup From bbec4a146e050cb7ffd24749ca796fdc63766b16 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 16 Sep 2014 15:06:23 -0700 Subject: [PATCH 102/430] A+C: Ahmed Waheed Moanes (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/138550043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 3f682cde69..a835bab0df 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Abhinav Gupta Adrian Nos Adrian O'Grady Adrien Bustany +Ahmed Waheed Moanes Akshat Kumar Alan Shreve Albert Strasheim diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a5b4ff843b..4f70a4d572 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -38,6 +38,7 @@ Adam Langley Adrian Nos Adrian O'Grady Adrien Bustany +Ahmed Waheed Moanes Akshat Kumar Alan Donovan Alan Shreve From 4caf377e6ef53356414b185930e898acb896c562 Mon Sep 17 00:00:00 2001 From: Ahmed Waheed Moanes Date: Tue, 16 Sep 2014 15:06:52 -0700 Subject: [PATCH 103/430] cmd/go: use pkg-config include pathes in swig and don't double compile c++ files. Fixes #8566. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/126210045 --- src/cmd/go/build.go | 93 +++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 45b5bc3233..2e52731529 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -824,12 +824,17 @@ func (b *builder) build(a *action) (err error) { } } - var gofiles, cfiles, sfiles, objects, cgoObjects []string + var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.p.GoFiles...) cfiles = append(cfiles, a.p.CFiles...) sfiles = append(sfiles, a.p.SFiles...) + if a.p.usesCgo() || a.p.usesSwig() { + if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { + return + } + } // Run cgo. if a.p.usesCgo() { // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. @@ -860,7 +865,7 @@ func (b *builder) build(a *action) (err error) { if a.cgo != nil && a.cgo.target != "" { cgoExe = a.cgo.target } - outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles) if err != nil { return err } @@ -873,9 +878,18 @@ func (b *builder) build(a *action) (err error) { // In a package using SWIG, any .c or .s files are // compiled with gcc. gccfiles := append(cfiles, sfiles...) + cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles cfiles = nil sfiles = nil - outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles, a.p.MFiles) + + // Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config). + if a.p.usesCgo() { + cxxfiles = nil + gccfiles = nil + mfiles = nil + } + + outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles) if err != nil { return err } @@ -1019,6 +1033,34 @@ func (b *builder) build(a *action) (err error) { return nil } +// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. +func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) { + if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { + var out []byte + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + cflags = strings.Fields(string(out)) + } + out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) + if err != nil { + b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) + b.print(err.Error() + "\n") + err = errPrintedOutput + return + } + if len(out) > 0 { + ldflags = strings.Fields(string(out)) + } + } + return +} + // install is the action for installing a single package or executable. func (b *builder) install(a *action) (err error) { defer func() { @@ -2100,36 +2142,16 @@ var ( cgoLibGccFileOnce sync.Once ) -func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true) _, cgoexeCFLAGS, _, _ := b.cflags(p, false) - + cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) + cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) // If we are compiling Objective-C code, then we need to link against libobjc if len(mfiles) > 0 { cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") } - if pkgs := p.CgoPkgConfig; len(pkgs) > 0 { - out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoCPPFLAGS = append(cgoCPPFLAGS, strings.Fields(string(out))...) - } - out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs) - if err != nil { - b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out)) - b.print(err.Error() + "\n") - return nil, nil, errPrintedOutput - } - if len(out) > 0 { - cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...) - } - } - // Allows including _cgo_export.h from .[ch] files in the package. cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", obj) @@ -2344,7 +2366,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) @@ -2385,7 +2407,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } for _, f := range p.SwigFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, false, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) if err != nil { return nil, nil, err } @@ -2400,7 +2422,7 @@ func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []stri } } for _, f := range p.SwigCXXFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, true, intgosize) + goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) if err != nil { return nil, nil, err } @@ -2479,13 +2501,13 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { +func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) var cflags []string if cxx { - cflags = stringList(cgoCPPFLAGS, cgoCXXFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) } else { - cflags = stringList(cgoCPPFLAGS, cgoCFLAGS) + cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) } n := 5 // length of ".swig" @@ -2511,6 +2533,13 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri "-o", obj + gccBase + gccExt, "-outdir", obj, } + + for _, f := range cflags { + if len(f) > 3 && f[:2] == "-I" { + args = append(args, f) + } + } + if gccgo { args = append(args, "-gccgo") if pkgpath := gccgoPkgpath(p); pkgpath != "" { From e28746c44494030e9b44aa523cd5a21ebfe39ff5 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 16 Sep 2014 15:40:22 -0700 Subject: [PATCH 104/430] doc/go1.4.txt: reflect.Type.Comparable CC=golang-codereviews https://golang.org/cl/138530044 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 4fe71b4b9e..5656a5cc89 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -23,6 +23,7 @@ net/http: add Request.BasicAuth method (CL 76540043) net/http: add Transport.DialTLS hook (CL 137940043) net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043) os: implement symlink support for windows (CL 86160044) +reflect: add type.Comparable (CL 144020043) runtime: implement monotonic clocks on windows (CL 108700045) runtime/race: freebsd is supported (CL 107270043) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) From da8cf5438aa676a99e8bb55c94011b2581743e1a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 16 Sep 2014 17:26:16 -0700 Subject: [PATCH 105/430] runtime: always run semacquire on the G stack semacquire might need to park the currently running G. It can only park if called from the G stack (because it has no way of saving the M stack state). So all calls to semacquire must come from the G stack. The three violators are GOMAXPROCS, ReadMemStats, and WriteHeapDump. This change moves the semacquire call earlier, out of their C code and into their Go code. This seldom caused bugs because semacquire seldom actually had to park the caller. But it did happen intermittently. Fixes #8749 LGTM=dvyukov R=golang-codereviews, dvyukov, bradfitz CC=golang-codereviews https://golang.org/cl/144940043 --- src/runtime/debug.go | 30 +++++++++++----- src/runtime/heapdump.c | 25 +------------ src/runtime/mem.go | 37 +++++++++++++++++++- src/runtime/mgc0.c | 26 +------------- src/runtime/proc.c | 79 +++--------------------------------------- src/runtime/runtime.h | 39 +++++++++++++++++++++ src/runtime/sema.go | 5 +++ src/runtime/stubs.go | 2 ++ src/runtime/thunk.s | 3 ++ 9 files changed, 114 insertions(+), 132 deletions(-) diff --git a/src/runtime/debug.go b/src/runtime/debug.go index bb4bd60ed4..4414dd55d2 100644 --- a/src/runtime/debug.go +++ b/src/runtime/debug.go @@ -24,15 +24,29 @@ func UnlockOSThread() // The number of logical CPUs on the local machine can be queried with NumCPU. // This call will go away when the scheduler improves. func GOMAXPROCS(n int) int { - g := getg() - g.m.scalararg[0] = uintptr(n) - onM(gomaxprocs_m) - n = int(g.m.scalararg[0]) - g.m.scalararg[0] = 0 - return n -} + if n > _MaxGomaxprocs { + n = _MaxGomaxprocs + } + lock(&sched.lock) + ret := int(gomaxprocs) + unlock(&sched.lock) + if n <= 0 || n == ret { + return ret + } -func gomaxprocs_m() // proc.c + semacquire(&worldsema, false) + gp := getg() + gp.m.gcing = 1 + onM(stoptheworld) + + // newprocs will be processed by starttheworld + newprocs = int32(n) + + gp.m.gcing = 0 + semrelease(&worldsema) + onM(starttheworld) + return ret +} // NumCPU returns the number of logical CPUs on the local machine. func NumCPU() int { diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index 8bbc7d8a56..75897c3d35 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -737,33 +737,16 @@ mdump(void) flush(); } -static void writeheapdump_m(void); - -#pragma textflag NOSPLIT void -runtime∕debug·WriteHeapDump(uintptr fd) -{ - void (*fn)(void); - - g->m->scalararg[0] = fd; - fn = writeheapdump_m; - runtime·onM(&fn); -} - -static void -writeheapdump_m(void) +runtime·writeheapdump_m(void) { uintptr fd; fd = g->m->scalararg[0]; g->m->scalararg[0] = 0; - // Stop the world. runtime·casgstatus(g->m->curg, Grunning, Gwaiting); g->waitreason = runtime·gostringnocopy((byte*)"dumping heap"); - runtime·semacquire(&runtime·worldsema, false); - g->m->gcing = 1; - runtime·stoptheworld(); // Update stats so we can dump them. // As a side effect, flushes all the MCaches so the MSpan.freelist @@ -784,13 +767,7 @@ writeheapdump_m(void) tmpbufsize = 0; } - // Start up the world again. - g->m->gcing = 0; - g->m->locks++; - runtime·semrelease(&runtime·worldsema); - runtime·starttheworld(); runtime·casgstatus(g->m->curg, Gwaiting, Grunning); - g->m->locks--; } // dumpint() the kind & offset of each field in an object. diff --git a/src/runtime/mem.go b/src/runtime/mem.go index 34391b2eb2..99bb928511 100644 --- a/src/runtime/mem.go +++ b/src/runtime/mem.go @@ -69,4 +69,39 @@ func init() { } // ReadMemStats populates m with memory allocator statistics. -func ReadMemStats(m *MemStats) +func ReadMemStats(m *MemStats) { + // Have to acquire worldsema to stop the world, + // because stoptheworld can only be used by + // one goroutine at a time, and there might be + // a pending garbage collection already calling it. + semacquire(&worldsema, false) + gp := getg() + gp.m.gcing = 1 + onM(stoptheworld) + + gp.m.ptrarg[0] = noescape(unsafe.Pointer(m)) + onM(readmemstats_m) + + gp.m.gcing = 0 + gp.m.locks++ + semrelease(&worldsema) + onM(starttheworld) + gp.m.locks-- +} + +// Implementation of runtime/debug.WriteHeapDump +func writeHeapDump(fd uintptr) { + semacquire(&worldsema, false) + gp := getg() + gp.m.gcing = 1 + onM(stoptheworld) + + gp.m.scalararg[0] = fd + onM(writeheapdump_m) + + gp.m.gcing = 0 + gp.m.locks++ + semrelease(&worldsema) + onM(starttheworld) + gp.m.locks-- +} diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index fda3efcc18..35aed78a53 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1451,32 +1451,14 @@ extern uintptr runtime·sizeof_C_MStats; static void readmemstats_m(void); -#pragma textflag NOSPLIT void -runtime·ReadMemStats(MStats *stats) -{ - void (*fn)(void); - - g->m->ptrarg[0] = stats; - fn = readmemstats_m; - runtime·onM(&fn); -} - -static void -readmemstats_m(void) +runtime·readmemstats_m(void) { MStats *stats; stats = g->m->ptrarg[0]; g->m->ptrarg[0] = nil; - // Have to acquire worldsema to stop the world, - // because stoptheworld can only be used by - // one goroutine at a time, and there might be - // a pending garbage collection already calling it. - runtime·semacquire(&runtime·worldsema, false); - g->m->gcing = 1; - runtime·stoptheworld(); runtime·updatememstats(nil); // Size of the trailing by_size array differs between Go and C, // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. @@ -1486,12 +1468,6 @@ readmemstats_m(void) stats->stacks_sys = stats->stacks_inuse; stats->heap_inuse -= stats->stacks_inuse; stats->heap_sys -= stats->stacks_inuse; - - g->m->gcing = 0; - g->m->locks++; - runtime·semrelease(&runtime·worldsema); - runtime·starttheworld(); - g->m->locks--; } static void readgcstats_m(void); diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 25f9166403..0e677a9d28 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -24,42 +24,6 @@ // // Design doc at http://golang.org/s/go11sched. -typedef struct Sched Sched; -struct Sched { - Mutex lock; - - uint64 goidgen; - - M* midle; // idle m's waiting for work - int32 nmidle; // number of idle m's waiting for work - int32 nmidlelocked; // number of locked m's waiting for work - int32 mcount; // number of m's that have been created - int32 maxmcount; // maximum number of m's allowed (or die) - - P* pidle; // idle P's - uint32 npidle; - uint32 nmspinning; - - // Global runnable queue. - G* runqhead; - G* runqtail; - int32 runqsize; - - // Global cache of dead G's. - Mutex gflock; - G* gfree; - int32 ngfree; - - uint32 gcwaiting; // gc is waiting to run - int32 stopwait; - Note stopnote; - uint32 sysmonwait; - Note sysmonnote; - uint64 lastpoll; - - int32 profilehz; // cpu profiling rate -}; - enum { // Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once. @@ -67,7 +31,7 @@ enum GoidCacheBatch = 16, }; -Sched runtime·sched; +SchedType runtime·sched; int32 runtime·gomaxprocs; uint32 runtime·needextram; bool runtime·iscgo; @@ -79,7 +43,7 @@ M* runtime·extram; P* runtime·allp[MaxGomaxprocs+1]; int8* runtime·goos; int32 runtime·ncpu; -static int32 newprocs; +int32 runtime·newprocs; Mutex runtime·allglock; // the following vars are protected by this lock or by stoptheworld G** runtime·allg; @@ -763,9 +727,9 @@ runtime·starttheworld(void) injectglist(gp); add = needaddgcproc(); runtime·lock(&runtime·sched.lock); - if(newprocs) { - procresize(newprocs); - newprocs = 0; + if(runtime·newprocs) { + procresize(runtime·newprocs); + runtime·newprocs = 0; } else procresize(runtime·gomaxprocs); runtime·sched.gcwaiting = 0; @@ -2364,39 +2328,6 @@ runtime·Breakpoint(void) runtime·breakpoint(); } -// Implementation of runtime.GOMAXPROCS. -// delete when scheduler is even stronger -void -runtime·gomaxprocs_m(void) -{ - int32 n, ret; - - n = g->m->scalararg[0]; - g->m->scalararg[0] = 0; - - if(n > MaxGomaxprocs) - n = MaxGomaxprocs; - runtime·lock(&runtime·sched.lock); - ret = runtime·gomaxprocs; - if(n <= 0 || n == ret) { - runtime·unlock(&runtime·sched.lock); - g->m->scalararg[0] = ret; - return; - } - runtime·unlock(&runtime·sched.lock); - - runtime·semacquire(&runtime·worldsema, false); - g->m->gcing = 1; - runtime·stoptheworld(); - newprocs = n; - g->m->gcing = 0; - runtime·semrelease(&runtime·worldsema); - runtime·starttheworld(); - - g->m->scalararg[0] = ret; - return; -} - // lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below // after they modify m->locked. Do not allow preemption during this call, // or else the m might be different in this function than in the caller. diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index adc74cf417..c034f3aa97 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -60,6 +60,7 @@ typedef struct SudoG SudoG; typedef struct Mutex Mutex; typedef struct M M; typedef struct P P; +typedef struct SchedType SchedType; typedef struct Note Note; typedef struct Slice Slice; typedef struct String String; @@ -433,6 +434,42 @@ enum { MaxGomaxprocs = 1<<8, }; +struct SchedType +{ + Mutex lock; + + uint64 goidgen; + + M* midle; // idle m's waiting for work + int32 nmidle; // number of idle m's waiting for work + int32 nmidlelocked; // number of locked m's waiting for work + int32 mcount; // number of m's that have been created + int32 maxmcount; // maximum number of m's allowed (or die) + + P* pidle; // idle P's + uint32 npidle; + uint32 nmspinning; + + // Global runnable queue. + G* runqhead; + G* runqtail; + int32 runqsize; + + // Global cache of dead G's. + Mutex gflock; + G* gfree; + int32 ngfree; + + uint32 gcwaiting; // gc is waiting to run + int32 stopwait; + Note stopnote; + uint32 sysmonwait; + Note sysmonnote; + uint64 lastpoll; + + int32 profilehz; // cpu profiling rate +}; + // The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread. // The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active. // External locks are not recursive; a second lock is silently ignored. @@ -716,6 +753,8 @@ extern DebugVars runtime·debug; extern uintptr runtime·maxstacksize; extern Note runtime·signote; extern ForceGCState runtime·forcegc; +extern SchedType runtime·sched; +extern int32 runtime·newprocs; /* * common functions and data diff --git a/src/runtime/sema.go b/src/runtime/sema.go index beacd67162..504462de33 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -49,6 +49,11 @@ func asyncsemrelease(addr *uint32) { // Called from runtime. func semacquire(addr *uint32, profile bool) { + gp := getg() + if gp != gp.m.curg { + gothrow("semacquire not on the G stack") + } + // Easy case. if cansemacquire(addr) { return diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index ff443c4cd4..2e6aadca7a 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -119,6 +119,8 @@ func deferproc_m() func goexit_m() func startpanic_m() func dopanic_m() +func readmemstats_m() +func writeheapdump_m() // memclr clears n bytes starting at ptr. // in memclr_*.s diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index 3b66cf47d3..3dd86e9919 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -80,6 +80,9 @@ TEXT reflect·memmove(SB), NOSPLIT, $0-0 TEXT runtime∕debug·freeOSMemory(SB), NOSPLIT, $0-0 JMP runtime·freeOSMemory(SB) +TEXT runtime∕debug·WriteHeapDump(SB), NOSPLIT, $0-0 + JMP runtime·writeHeapDump(SB) + TEXT net·runtime_pollServerInit(SB),NOSPLIT,$0-0 JMP runtime·netpollServerInit(SB) From cbf97d9103b2bbfb8c798f06c751e74093062b57 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 16 Sep 2014 20:53:38 -0400 Subject: [PATCH 106/430] liblink, sync/atomic: fix arm build The liblink code to insert the FUNCDATA for a stack map from the Go prototype was not correct for ARM (different data structure layout). Also, sync/atomic was missing some Go prototypes for ARM-specific functions. TBR=r CC=golang-codereviews https://golang.org/cl/143160045 --- include/link.h | 1 + src/liblink/obj5.c | 1 + src/liblink/objfile.c | 7 ++++++- src/sync/atomic/64bit_arm.go | 6 ++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/link.h b/include/link.h index 8c73eab51e..292b077394 100644 --- a/include/link.h +++ b/include/link.h @@ -471,6 +471,7 @@ struct LinkArch int D_PARAM; int D_SCONST; int D_STATIC; + int D_OREG; int ACALL; int ADATA; diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c index a571d8f166..e192b082b5 100644 --- a/src/liblink/obj5.c +++ b/src/liblink/obj5.c @@ -1061,6 +1061,7 @@ LinkArch linkarm = { .D_PARAM = D_PARAM, .D_SCONST = D_SCONST, .D_STATIC = D_STATIC, + .D_OREG = D_OREG, .ACALL = ABL, .ADATA = ADATA, diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index 7d4b28c9ac..9b1e1b7a8f 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -268,7 +268,12 @@ writeobj(Link *ctxt, Biobuf *b) p->as = ctxt->arch->AFUNCDATA; p->from.type = ctxt->arch->D_CONST; p->from.offset = FUNCDATA_ArgsPointerMaps; - p->to.type = ctxt->arch->D_EXTERN; + if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8') + p->to.type = ctxt->arch->D_EXTERN; + else { + p->to.type = ctxt->arch->D_OREG; + p->to.name = ctxt->arch->D_EXTERN; + } p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version); } } diff --git a/src/sync/atomic/64bit_arm.go b/src/sync/atomic/64bit_arm.go index c08f214c7e..0aab7160e9 100644 --- a/src/sync/atomic/64bit_arm.go +++ b/src/sync/atomic/64bit_arm.go @@ -44,3 +44,9 @@ func swapUint64(addr *uint64, new uint64) (old uint64) { } return } + +// Additional ARM-specific assembly routines. +// Declaration here to give assembly routines correct stack maps for arguments. +func armCompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) +func armCompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) +func generalCAS64(addr *uint64, old, new uint64) (swapped bool) From 98a1e207e29359dba86769877021838bb77b12c3 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 16 Sep 2014 19:54:26 -0700 Subject: [PATCH 107/430] sync/atomic: add Value A Value provides an atomic load and store of a consistently typed value. It's intended to be used with copy-on-write idiom (see the example). Performance: BenchmarkValueRead 50000000 21.7 ns/op BenchmarkValueRead-2 200000000 8.63 ns/op BenchmarkValueRead-4 300000000 4.33 ns/op TBR=rsc R=golang-codereviews CC=golang-codereviews https://golang.org/cl/136710045 --- src/runtime/thunk.s | 6 ++ src/sync/atomic/norace.go | 17 +++ src/sync/atomic/race.go | 22 ++++ src/sync/atomic/value.go | 91 ++++++++++++++++ src/sync/atomic/value_test.go | 195 ++++++++++++++++++++++++++++++++++ 5 files changed, 331 insertions(+) create mode 100644 src/sync/atomic/norace.go create mode 100644 src/sync/atomic/race.go create mode 100644 src/sync/atomic/value.go create mode 100644 src/sync/atomic/value_test.go diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index 3dd86e9919..5e8e674f54 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -166,3 +166,9 @@ TEXT runtime·main_main(SB),NOSPLIT,$0-0 TEXT runtime·timenow(SB), NOSPLIT, $0-0 JMP time·now(SB) + +TEXT sync∕atomic·runtime_procPin(SB),NOSPLIT,$0-0 + JMP sync·runtime_procPin(SB) + +TEXT sync∕atomic·runtime_procUnpin(SB),NOSPLIT,$0-0 + JMP sync·runtime_procUnpin(SB) diff --git a/src/sync/atomic/norace.go b/src/sync/atomic/norace.go new file mode 100644 index 0000000000..1866fd16cb --- /dev/null +++ b/src/sync/atomic/norace.go @@ -0,0 +1,17 @@ +// 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. + +// +build !race + +package atomic + +import "unsafe" + +const raceenabled = false + +func raceAcquire(addr unsafe.Pointer) { +} + +func raceReleaseMerge(addr unsafe.Pointer) { +} diff --git a/src/sync/atomic/race.go b/src/sync/atomic/race.go new file mode 100644 index 0000000000..a833d9e7f4 --- /dev/null +++ b/src/sync/atomic/race.go @@ -0,0 +1,22 @@ +// 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. + +// +build race + +package atomic + +import ( + "runtime" + "unsafe" +) + +const raceenabled = true + +func raceAcquire(addr unsafe.Pointer) { + runtime.RaceAcquire(addr) +} + +func raceReleaseMerge(addr unsafe.Pointer) { + runtime.RaceReleaseMerge(addr) +} diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go new file mode 100644 index 0000000000..c290fdab85 --- /dev/null +++ b/src/sync/atomic/value.go @@ -0,0 +1,91 @@ +// 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 atomic + +import ( + "unsafe" +) + +// A Value provides an atomic load and store of a consistently typed value. +// Values can be created as part of other data structures. +// The zero value for a Value returns nil from Load. +// Once Store has been called, a Value must not be copied. +type Value struct { + v interface{} +} + +// ifaceWords is interface{} internal representation. +type ifaceWords struct { + typ unsafe.Pointer + data unsafe.Pointer +} + +// Load returns the value set by the most recent Store. +// It returns nil if there has been no call to Store for this Value. +func (v *Value) Load() (x interface{}) { + vp := (*ifaceWords)(unsafe.Pointer(v)) + typ := LoadPointer(&vp.typ) + if typ == nil || uintptr(typ) == ^uintptr(0) { + // First store not yet completed. + return nil + } + data := LoadPointer(&vp.data) + xp := (*ifaceWords)(unsafe.Pointer(&x)) + xp.typ = typ + xp.data = data + if raceenabled { + raceAcquire(unsafe.Pointer(v)) + } + return +} + +// Store sets the value of the Value to v. +// All calls to Store for a given Value must use values of the same concrete type. +// Store of an inconsistent type panics, as does Store(nil). +func (v *Value) Store(x interface{}) { + if x == nil { + panic("sync/atomic: store of nil value into Value") + } + if raceenabled { + raceReleaseMerge(unsafe.Pointer(v)) + } + vp := (*ifaceWords)(unsafe.Pointer(v)) + xp := (*ifaceWords)(unsafe.Pointer(&x)) + for { + typ := LoadPointer(&vp.typ) + if typ == nil { + // Attempt to start first store. + // Disable preemption so that other goroutines can use + // active spin wait to wait for completion; and so that + // GC does not see the fake type accidentally. + runtime_procPin() + if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) { + runtime_procUnpin() + continue + } + // Complete first store. + StorePointer(&vp.data, xp.data) + StorePointer(&vp.typ, xp.typ) + runtime_procUnpin() + return + } + if uintptr(typ) == ^uintptr(0) { + // First store in progress. Wait. + // Since we disable preemption around the first store, + // we can wait with active spinning. + continue + } + // First store completed. Check type and overwrite data. + if typ != xp.typ { + panic("sync/atomic: store of inconsistently typed value into Value") + } + StorePointer(&vp.data, xp.data) + return + } +} + +// Disable/enable preemption, implemented in runtime. +func runtime_procPin() +func runtime_procUnpin() diff --git a/src/sync/atomic/value_test.go b/src/sync/atomic/value_test.go new file mode 100644 index 0000000000..382dc6854d --- /dev/null +++ b/src/sync/atomic/value_test.go @@ -0,0 +1,195 @@ +// 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 atomic_test + +import ( + "math/rand" + "runtime" + "sync" + . "sync/atomic" + "testing" + "time" +) + +func TestValue(t *testing.T) { + var v Value + if v.Load() != nil { + t.Fatal("initial Value is not nil") + } + v.Store(42) + x := v.Load() + if xx, ok := x.(int); !ok || xx != 42 { + t.Fatalf("wrong value: got %+v, want 42", x) + } + v.Store(84) + x = v.Load() + if xx, ok := x.(int); !ok || xx != 84 { + t.Fatalf("wrong value: got %+v, want 84", x) + } +} + +func TestValueLarge(t *testing.T) { + var v Value + v.Store("foo") + x := v.Load() + if xx, ok := x.(string); !ok || xx != "foo" { + t.Fatalf("wrong value: got %+v, want foo", x) + } + v.Store("barbaz") + x = v.Load() + if xx, ok := x.(string); !ok || xx != "barbaz" { + t.Fatalf("wrong value: got %+v, want barbaz", x) + } +} + +func TestValuePanic(t *testing.T) { + const nilErr = "sync/atomic: store of nil value into Value" + const badErr = "sync/atomic: store of inconsistently typed value into Value" + var v Value + func() { + defer func() { + err := recover() + if err != nilErr { + t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, nilErr) + } + }() + v.Store(nil) + }() + v.Store(42) + func() { + defer func() { + err := recover() + if err != badErr { + t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, badErr) + } + }() + v.Store("foo") + }() + func() { + defer func() { + err := recover() + if err != nilErr { + t.Fatalf("inconsistent store panic: got '%v', want '%v'", err, nilErr) + } + }() + v.Store(nil) + }() +} + +func TestValueConcurrent(t *testing.T) { + tests := [][]interface{}{ + {uint16(0), ^uint16(0), uint16(1 + 2<<8), uint16(3 + 4<<8)}, + {uint32(0), ^uint32(0), uint32(1 + 2<<16), uint32(3 + 4<<16)}, + {uint64(0), ^uint64(0), uint64(1 + 2<<32), uint64(3 + 4<<32)}, + {complex(0, 0), complex(1, 2), complex(3, 4), complex(5, 6)}, + } + p := 4 * runtime.GOMAXPROCS(0) + for _, test := range tests { + var v Value + done := make(chan bool) + for i := 0; i < p; i++ { + go func() { + r := rand.New(rand.NewSource(rand.Int63())) + loop: + for j := 0; j < 1e5; j++ { + x := test[r.Intn(len(test))] + v.Store(x) + x = v.Load() + for _, x1 := range test { + if x == x1 { + continue loop + } + } + t.Logf("loaded unexpected value %+v, want %+v", x, test) + done <- false + } + done <- true + }() + } + for i := 0; i < p; i++ { + if !<-done { + t.FailNow() + } + } + } +} + +func BenchmarkValueRead(b *testing.B) { + var v Value + v.Store(new(int)) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + x := v.Load().(*int) + if *x != 0 { + b.Fatalf("wrong value: got %v, want 0", *x) + } + } + }) +} + +// The following example shows how to use Value for periodic program config updates +// and propagation of the changes to worker goroutines. +func ExampleValue_config() { + var config Value // holds current server configuration + // Create initial config value and store into config. + config.Store(loadConfig()) + go func() { + // Reload config every 10 seconds + // and update config value with the new version. + for { + time.Sleep(10 * time.Second) + config.Store(loadConfig()) + } + }() + // Create worker goroutines that handle incoming requests + // using the latest config value. + for i := 0; i < 10; i++ { + go func() { + for r := range requests() { + c := config.Load() + // Handle request r using config c. + _, _ = r, c + } + }() + } +} + +func loadConfig() map[string]string { + return make(map[string]string) +} + +func requests() chan int { + return make(chan int) +} + +// The following example shows how to maintain a scalable frequently read, +// but infrequently updated data structure using copy-on-write idiom. +func ExampleValue_readMostly() { + type Map map[string]string + var m Value + m.Store(make(Map)) + var mu sync.Mutex // used only by writers + // read function can be used to read the data without further synchronization + read := func(key string) (val string) { + m1 := m.Load().(Map) + return m1[key] + } + // insert function can be used to update the data without further synchronization + insert := func(key, val string) { + mu.Lock() // synchronize with other potential writers + defer mu.Unlock() + m1 := m.Load().(Map) // load current value of the data structure + m2 := make(Map) // create a new value + for k, v := range m1 { + m2[k] = v // copy all data from the current object to the new one + } + m2[key] = val // do the update that we need + m.Store(m2) // atomically replace the current object with the new one + // At this point all new readers start working with the new version. + // The old version will be garbage collected once the existing readers + // (if any) are done with it. + } + _, _ = read, insert +} From 2107b30e58b4650e14f5ceb8230c5573597d607d Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 16 Sep 2014 21:49:10 -0700 Subject: [PATCH 108/430] doc/go1.4.txt: add sync/atomic.Value CC=golang-codereviews https://golang.org/cl/145800043 --- doc/go1.4.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 5656a5cc89..f441a80238 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -26,8 +26,9 @@ os: implement symlink support for windows (CL 86160044) reflect: add type.Comparable (CL 144020043) runtime: implement monotonic clocks on windows (CL 108700045) runtime/race: freebsd is supported (CL 107270043) +sync/atomic: add Value (CL 136710045) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) -syscal: now frozen (CL 129820043) +syscall: now frozen (CL 129820043) testing: add Coverage (CL 98150043) text/scanner: add IsIdentRune field of Scanner. (CL 108030044) time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046) From 72a2539c38d06be486b180310d5703700f9f1f5f Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Wed, 17 Sep 2014 05:44:42 +0000 Subject: [PATCH 109/430] sync: fix linux/arm build For real this time. LGTM=minux R=golang-codereviews, minux CC=golang-codereviews https://golang.org/cl/141640043 --- src/sync/atomic/export_linux_arm_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sync/atomic/export_linux_arm_test.go b/src/sync/atomic/export_linux_arm_test.go index 5cd43353ee..9f0c856a79 100644 --- a/src/sync/atomic/export_linux_arm_test.go +++ b/src/sync/atomic/export_linux_arm_test.go @@ -4,6 +4,4 @@ package atomic -func generalCAS64(addr *uint64, old uint64, new uint64) bool - var GeneralCAS64 = generalCAS64 From 6c934238c93f8f60775409f1ab410ce9c9ea2357 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 17 Sep 2014 08:32:15 -0700 Subject: [PATCH 110/430] runtime: change minimum stack size to 2K. It will be 8K on windows because it needs 4K for the OS. Similarly, plan9 will be 4K. On linux/amd64, reduces size of 100,000 goroutines from ~819MB to ~245MB. Update #7514 LGTM=dvyukov R=golang-codereviews, dvyukov, khr, aram CC=golang-codereviews https://golang.org/cl/145790043 --- src/runtime/proc.c | 8 ++++---- src/runtime/stack.h | 21 ++++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 0e677a9d28..4282a145e1 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2162,11 +2162,11 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp siz = narg + nret; siz = (siz+7) & ~7; - // We could instead create a secondary stack frame - // and make it look like goexit was on the original but - // the call to the actual goroutine function was split. + // We could allocate a larger initial stack if necessary. // Not worth it: this is almost always an error. - if(siz > StackMin - 1024) + // 4*sizeof(uintreg): extra space added below + // sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall). + if(siz >= StackMin - 4*sizeof(uintreg) - sizeof(uintreg)) runtime·throw("runtime.newproc: function arguments too large for new goroutine"); p = g->m->p; diff --git a/src/runtime/stack.h b/src/runtime/stack.h index b30e322166..f97dc4ed8d 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -69,16 +69,19 @@ enum { #endif // Plan 9 #endif // Windows - // The amount of extra stack to allocate beyond the size - // needed for the single frame that triggered the split. - StackExtra = 2048, + // The minimum size of stack used by Go code + StackMin = 2048, - // The minimum stack segment size to allocate. - // If the amount needed for the splitting frame + StackExtra - // is less than this number, the stack will have this size instead. - StackMin = 8192, - StackSystemRounded = StackSystem + (-StackSystem & (StackMin-1)), - FixedStack = StackMin + StackSystemRounded, + // The minimum stack size to allocate. + // The hackery here rounds FixedStack0 up to a power of 2. + FixedStack0 = StackMin + StackSystem, + FixedStack1 = FixedStack0 - 1, + FixedStack2 = FixedStack1 | (FixedStack1 >> 1), + FixedStack3 = FixedStack2 | (FixedStack2 >> 2), + FixedStack4 = FixedStack3 | (FixedStack3 >> 4), + FixedStack5 = FixedStack4 | (FixedStack4 >> 8), + FixedStack6 = FixedStack5 | (FixedStack5 >> 16), + FixedStack = FixedStack6 + 1, // Functions that need frames bigger than this use an extra // instruction to do the stack split check, to avoid overflow From a883f117a9dda5f218bb08dc1c4e181ab1679e11 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 17 Sep 2014 08:39:18 -0700 Subject: [PATCH 111/430] doc/go1.4.txt: reduced stack size CC=golang-codereviews https://golang.org/cl/144050043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index f441a80238..a3a4598138 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -25,6 +25,7 @@ net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043) os: implement symlink support for windows (CL 86160044) reflect: add type.Comparable (CL 144020043) runtime: implement monotonic clocks on windows (CL 108700045) +runtime: stack size 2K (4K on plan 9 and windows) (CL 145790043) runtime/race: freebsd is supported (CL 107270043) sync/atomic: add Value (CL 136710045) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) From e19d8a47d1803a19446c658712c4bdff84d0da31 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Sep 2014 14:49:32 -0400 Subject: [PATCH 112/430] runtime: account for tiny allocs, for testing.AllocsPerRun Fixes #8734. LGTM=r, bradfitz, dvyukov R=bradfitz, r, dvyukov CC=golang-codereviews, iant, khr https://golang.org/cl/143150043 --- src/runtime/malloc.c | 5 ++++- src/runtime/malloc.go | 2 +- src/runtime/malloc.h | 3 +++ src/runtime/mem.go | 2 +- src/runtime/mgc0.c | 1 + src/runtime/mheap.c | 4 ++++ src/testing/allocs_test.go | 29 +++++++++++++++++++++++++++++ 7 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/testing/allocs_test.go diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index cfb698ac21..d5f2b9ab80 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -79,6 +79,8 @@ runtime·purgecachedstats(MCache *c) h = &runtime·mheap; mstats.heap_alloc += c->local_cachealloc; c->local_cachealloc = 0; + mstats.tinyallocs += c->local_tinyallocs; + c->local_tinyallocs = 0; mstats.nlookup += c->local_nlookup; c->local_nlookup = 0; h->largefree += c->local_largefree; @@ -92,9 +94,10 @@ runtime·purgecachedstats(MCache *c) } // Size of the trailing by_size array differs between Go and C, +// and all data after by_size is local to C, not exported to Go. // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. // sizeof_C_MStats is what C thinks about size of Go struct. -uintptr runtime·sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]); +uintptr runtime·sizeof_C_MStats = offsetof(MStats, by_size[61]); #define MaxArena32 (2U<<30) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index acf6b48f84..fc22cc29e4 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -103,7 +103,6 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { // standalone escaping variables. On a json benchmark // the allocator reduces number of allocations by ~12% and // reduces heap size by ~20%. - tinysize := uintptr(c.tinysize) if size <= tinysize { tiny := unsafe.Pointer(c.tiny) @@ -121,6 +120,7 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { x = tiny c.tiny = (*byte)(add(x, size)) c.tinysize -= uintptr(size1) + c.local_tinyallocs++ if debugMalloc { mp := acquirem() if mp.mallocing == 0 { diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index 3f1981f708..410a007173 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -278,6 +278,8 @@ struct MStats uint64 nmalloc; uint64 nfree; } by_size[NumSizeClasses]; + + uint64 tinyallocs; // number of tiny allocations that didn't cause actual allocation; not exported to Go directly }; #define mstats runtime·memstats @@ -331,6 +333,7 @@ struct MCache // See "Tiny allocator" comment in malloc.goc. byte* tiny; uintptr tinysize; + uintptr local_tinyallocs; // number of tiny allocs not counted in other stats // The rest is not accessed on every malloc. MSpan* alloc[NumSizeClasses]; // spans to allocate from diff --git a/src/runtime/mem.go b/src/runtime/mem.go index 99bb928511..b3c216f18e 100644 --- a/src/runtime/mem.go +++ b/src/runtime/mem.go @@ -64,7 +64,7 @@ func init() { var memStats MemStats if sizeof_C_MStats != unsafe.Sizeof(memStats) { println(sizeof_C_MStats, unsafe.Sizeof(memStats)) - panic("MStats vs MemStatsType size mismatch") + gothrow("MStats vs MemStatsType size mismatch") } } diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 35aed78a53..4e901726f6 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1245,6 +1245,7 @@ runtime·updatememstats(GCStats *stats) mstats.by_size[i].nmalloc += runtime·mheap.nsmallfree[i]; smallfree += runtime·mheap.nsmallfree[i] * runtime·class_to_size[i]; } + mstats.nfree += mstats.tinyallocs; mstats.nmalloc += mstats.nfree; // Calculate derived stats. diff --git a/src/runtime/mheap.c b/src/runtime/mheap.c index 902a5c71a2..bb203d5ce5 100644 --- a/src/runtime/mheap.c +++ b/src/runtime/mheap.c @@ -184,6 +184,8 @@ mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large) // transfer stats from cache to global mstats.heap_alloc += g->m->mcache->local_cachealloc; g->m->mcache->local_cachealloc = 0; + mstats.tinyallocs += g->m->mcache->local_tinyallocs; + g->m->mcache->local_tinyallocs = 0; s = MHeap_AllocSpanLocked(h, npage); if(s != nil) { @@ -465,6 +467,8 @@ mheap_free(MHeap *h, MSpan *s, int32 acct) runtime·lock(&h->lock); mstats.heap_alloc += g->m->mcache->local_cachealloc; g->m->mcache->local_cachealloc = 0; + mstats.tinyallocs += g->m->mcache->local_tinyallocs; + g->m->mcache->local_tinyallocs = 0; if(acct) { mstats.heap_alloc -= s->npages< Date: Wed, 17 Sep 2014 14:50:49 -0400 Subject: [PATCH 113/430] doc/go1.4.txt: add tinyallocs change CC=golang-codereviews https://golang.org/cl/145050043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index a3a4598138..6180bc5b92 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -26,6 +26,7 @@ os: implement symlink support for windows (CL 86160044) reflect: add type.Comparable (CL 144020043) runtime: implement monotonic clocks on windows (CL 108700045) runtime: stack size 2K (4K on plan 9 and windows) (CL 145790043) +runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043). runtime/race: freebsd is supported (CL 107270043) sync/atomic: add Value (CL 136710045) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) From 735289ff76df92c9ff1178c1417c1ad640962d8b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Sep 2014 15:30:48 -0400 Subject: [PATCH 114/430] sync/atomic: add more missing Go prototype Should fix nacl/arm build. TBR=minux CC=golang-codereviews https://golang.org/cl/145070043 --- src/sync/atomic/64bit_arm.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sync/atomic/64bit_arm.go b/src/sync/atomic/64bit_arm.go index 0aab7160e9..b98e60827e 100644 --- a/src/sync/atomic/64bit_arm.go +++ b/src/sync/atomic/64bit_arm.go @@ -50,3 +50,9 @@ func swapUint64(addr *uint64, new uint64) (old uint64) { func armCompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool) func armCompareAndSwapUint64(addr *uint64, old, new uint64) (swapped bool) func generalCAS64(addr *uint64, old, new uint64) (swapped bool) +func armAddUint32(addr *uint32, delta uint32) (new uint32) +func armAddUint64(addr *uint64, delta uint64) (new uint64) +func armSwapUint32(addr *uint32, new uint32) (old uint32) +func armSwapUint64(addr *uint64, new uint64) (old uint64) +func armLoadUint64(addr *uint64) (val uint64) +func armStoreUint64(addr *uint64, val uint64) From 6fb9d50d154c4a8ac4db11e91a3d221322859191 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Sep 2014 16:12:17 -0400 Subject: [PATCH 115/430] runtime: print more detail in adjustframe crash The logic here is copied from mgc0.c's scanframe. Mostly it is messages although the minsize code is new (and I believe necessary). I am hoping to get more information about the current arm build failures (or, if it's the minsize thing, fix them). TBR=khr R=khr CC=golang-codereviews https://golang.org/cl/143180043 --- src/runtime/stack.c | 46 ++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 143b645e42..b38ee31d48 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -463,7 +463,7 @@ adjustframe(Stkframe *frame, void *arg) StackMap *stackmap; int32 pcdata; BitVector bv; - uintptr targetpc; + uintptr targetpc, size, minsize; adjinfo = arg; targetpc = frame->continpc; @@ -486,27 +486,47 @@ adjustframe(Stkframe *frame, void *arg) if(pcdata == -1) pcdata = 0; // in prologue - // adjust local pointers - if((byte*)frame->varp != (byte*)frame->sp) { + // Adjust local variables if stack frame has been allocated. + size = frame->varp - frame->sp; + if(thechar != '6' && thechar != '8') + minsize = sizeof(uintptr); + else + minsize = 0; + if(size > minsize) { stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - if(stackmap == nil) - runtime·throw("no locals info"); - if(stackmap->n <= 0) - runtime·throw("locals size info only"); + if(stackmap == nil || stackmap->n <= 0) { + runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size); + runtime·throw("missing stackmap"); + } + // Locals bitmap information, scan just the pointers in locals. + if(pcdata < 0 || pcdata >= stackmap->n) { + // don't know where we are + runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n", + pcdata, stackmap->n, runtime·funcname(f), targetpc); + runtime·throw("bad symbol table"); + } bv = runtime·stackmapdata(stackmap, pcdata); + size = (bv.n * PtrSize) / BitsPerPointer; if(StackDebug >= 3) runtime·printf(" locals\n"); - adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv, adjinfo, f); + adjustpointers((byte**)(frame->varp - size), &bv, adjinfo, f); } - // adjust inargs and outargs - if(frame->arglen != 0) { + + // Adjust arguments. + if(frame->arglen > 0) { if(frame->argmap != nil) { bv = *frame->argmap; } else { stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil) { - runtime·printf("size %d\n", (int32)frame->arglen); - runtime·throw("no arg info"); + if(stackmap == nil || stackmap->n <= 0) { + runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen); + runtime·throw("missing stackmap"); + } + if(pcdata < 0 || pcdata >= stackmap->n) { + // don't know where we are + runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n", + pcdata, stackmap->n, runtime·funcname(f), targetpc); + runtime·throw("bad symbol table"); } bv = runtime·stackmapdata(stackmap, pcdata); } From 92eb1e1600c3770d2ec669a8d6b7947cac551305 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 17 Sep 2014 13:25:46 -0700 Subject: [PATCH 116/430] runtime: free stacks of Gdead goroutines at GC time We could probably free the G structures as well, but for the allg list. Leaving that for another day. Fixes #8287 LGTM=rsc R=golang-codereviews, dvyukov, khr, rsc CC=golang-codereviews https://golang.org/cl/145010043 --- src/runtime/stack.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index b38ee31d48..95a5a123d9 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -806,8 +806,16 @@ runtime·shrinkstack(G *gp) { uintptr used, oldsize, newsize; - if(runtime·readgstatus(gp) == Gdead) + if(runtime·readgstatus(gp) == Gdead) { + if(gp->stack.lo != 0) { + // Free whole stack - it will get reallocated + // if G is used again. + runtime·stackfree(gp->stack); + gp->stack.lo = 0; + gp->stack.hi = 0; + } return; + } if(gp->stack.lo == 0) runtime·throw("missing stack in shrinkstack"); From a2e7fd0fc140dbe92f6cf564afaa6770a0e60544 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 17 Sep 2014 16:52:01 -0400 Subject: [PATCH 117/430] A+C: John Tuley (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/142200043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index a835bab0df..5d7b870459 100644 --- a/AUTHORS +++ b/AUTHORS @@ -226,6 +226,7 @@ John C Barstow John Graham-Cumming John Howard Palevich John Shahid +John Tuley Jonathan Gold Jonathan Mark Jonathan Rudenberg diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 4f70a4d572..09fec9f7ae 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -318,6 +318,7 @@ John Graham-Cumming John Howard Palevich John Newlin John Shahid +John Tuley Jonathan Allie Jonathan Feinberg Jonathan Gold From a2910958a2bcc360e811d1f6f476784b213bb0f1 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Thu, 18 Sep 2014 12:43:01 +1000 Subject: [PATCH 118/430] image/gif: fix GIF encoding of sub-images. benchmark old ns/op new ns/op delta BenchmarkEncode 8641055 8646829 +0.07% Fixes #7792. LGTM=r R=r CC=dbathgate, golang-codereviews https://golang.org/cl/147730043 --- src/image/gif/writer.go | 18 ++++++++++++++---- src/image/gif/writer_test.go | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go index 15cd40fadf..49abde704c 100644 --- a/src/image/gif/writer.go +++ b/src/image/gif/writer.go @@ -233,10 +233,20 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) { e.writeByte(uint8(litWidth)) // LZW Minimum Code Size. lzww := lzw.NewWriter(blockWriter{e: e}, lzw.LSB, litWidth) - _, e.err = lzww.Write(pm.Pix) - if e.err != nil { - lzww.Close() - return + if dx := b.Dx(); dx == pm.Stride { + _, e.err = lzww.Write(pm.Pix) + if e.err != nil { + lzww.Close() + return + } + } else { + for i, y := 0, b.Min.Y; y < b.Max.Y; i, y = i+pm.Stride, y+1 { + _, e.err = lzww.Write(pm.Pix[i : i+dx]) + if e.err != nil { + lzww.Close() + return + } + } } lzww.Close() e.writeByte(0x00) // Block Terminator. diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go index bc5d37845b..93306ffdb3 100644 --- a/src/image/gif/writer_test.go +++ b/src/image/gif/writer_test.go @@ -102,6 +102,29 @@ func TestWriter(t *testing.T) { } } +func TestSubImage(t *testing.T) { + m0, err := readImg("../testdata/video-001.gif") + if err != nil { + t.Fatalf("readImg: %v", err) + } + m0 = m0.(*image.Paletted).SubImage(image.Rect(0, 0, 50, 30)) + var buf bytes.Buffer + err = Encode(&buf, m0, nil) + if err != nil { + t.Fatalf("Encode: %v", err) + } + m1, err := Decode(&buf) + if err != nil { + t.Fatalf("Decode: %v", err) + } + if m0.Bounds() != m1.Bounds() { + t.Fatalf("bounds differ: %v and %v", m0.Bounds(), m1.Bounds()) + } + if averageDelta(m0, m1) != 0 { + t.Fatalf("images differ") + } +} + var frames = []string{ "../testdata/video-001.gif", "../testdata/video-005.gray.gif", From ed7db89b90409c1ef0be44f4e5cea7dd6475ba4e Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 17 Sep 2014 20:38:50 -0700 Subject: [PATCH 119/430] runtime: output number of goroutines in GC trace Example output: gc26(1): 1+0+1038+0 us, 0 -> 1 MB, 19074 (88777-69703) objects, 5 gs, 184/0/0 sweeps, 0(0) handoff, 0(0) steal, 0/0/0 yields It's useful to understand long scan times, because goroutine traceback is slow. LGTM=khr R=golang-codereviews, khr CC=golang-codereviews, rsc https://golang.org/cl/136310044 --- src/runtime/mgc0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 4e901726f6..88c8d0f3c9 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1401,11 +1401,13 @@ gc(struct gc_args *args) stats.nsleep += work.markfor->nsleep; runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects," + " %d goroutines," " %d/%d/%d sweeps," " %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n", mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000, heap0>>20, heap1>>20, obj, mstats.nmalloc, mstats.nfree, + runtime·gcount(), work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep, stats.nhandoff, stats.nhandoffcnt, work.markfor->nsteal, work.markfor->nstealcnt, From 8c2484ec11d27324423e3cf27cc9ac6b34394c7d Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 17 Sep 2014 21:22:11 -0700 Subject: [PATCH 120/430] sync/atomic: remove unnecessary race instrumentation in Value It is left from the time when Value was implemented in assembly. Now it is implemented in Go and race detector understands Go. In particular the atomic operations must provide all necessary synchronization. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews, khr, rsc https://golang.org/cl/145880043 --- src/sync/atomic/norace.go | 17 ----------------- src/sync/atomic/race.go | 22 ---------------------- src/sync/atomic/value.go | 6 ------ 3 files changed, 45 deletions(-) delete mode 100644 src/sync/atomic/norace.go delete mode 100644 src/sync/atomic/race.go diff --git a/src/sync/atomic/norace.go b/src/sync/atomic/norace.go deleted file mode 100644 index 1866fd16cb..0000000000 --- a/src/sync/atomic/norace.go +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -// +build !race - -package atomic - -import "unsafe" - -const raceenabled = false - -func raceAcquire(addr unsafe.Pointer) { -} - -func raceReleaseMerge(addr unsafe.Pointer) { -} diff --git a/src/sync/atomic/race.go b/src/sync/atomic/race.go deleted file mode 100644 index a833d9e7f4..0000000000 --- a/src/sync/atomic/race.go +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -// +build race - -package atomic - -import ( - "runtime" - "unsafe" -) - -const raceenabled = true - -func raceAcquire(addr unsafe.Pointer) { - runtime.RaceAcquire(addr) -} - -func raceReleaseMerge(addr unsafe.Pointer) { - runtime.RaceReleaseMerge(addr) -} diff --git a/src/sync/atomic/value.go b/src/sync/atomic/value.go index c290fdab85..ab46d9a240 100644 --- a/src/sync/atomic/value.go +++ b/src/sync/atomic/value.go @@ -35,9 +35,6 @@ func (v *Value) Load() (x interface{}) { xp := (*ifaceWords)(unsafe.Pointer(&x)) xp.typ = typ xp.data = data - if raceenabled { - raceAcquire(unsafe.Pointer(v)) - } return } @@ -48,9 +45,6 @@ func (v *Value) Store(x interface{}) { if x == nil { panic("sync/atomic: store of nil value into Value") } - if raceenabled { - raceReleaseMerge(unsafe.Pointer(v)) - } vp := (*ifaceWords)(unsafe.Pointer(v)) xp := (*ifaceWords)(unsafe.Pointer(&x)) for { From 484cc6715192efd4bfea57647eeb66c93aecfb0c Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Thu, 18 Sep 2014 19:17:55 +0900 Subject: [PATCH 121/430] net: separate NaCl dependent placeholders from BSD's To clarify the dependency of NaCl platform. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/143830044 --- src/net/dial_test.go | 5 +++ src/net/dnsclient_unix.go | 2 +- src/net/dnsconfig_unix.go | 2 +- src/net/file_stub.go | 38 ++++++++++++++++++ src/net/file_test.go | 2 +- src/net/file_unix.go | 2 +- src/net/ipraw_test.go | 5 +++ src/net/lookup_stub.go | 49 +++++++++++++++++++++++ src/net/lookup_unix.go | 2 +- src/net/port_test.go | 6 +++ src/net/port_unix.go | 2 +- src/net/sock_bsd.go | 2 +- src/net/{sock_solaris.go => sock_stub.go} | 2 + src/net/sockopt_bsd.go | 2 +- src/net/sockopt_posix.go | 2 +- src/net/sockopt_stub.go | 37 +++++++++++++++++ src/net/sockoptip_bsd.go | 2 +- src/net/sockoptip_posix.go | 2 +- src/net/sockoptip_stub.go | 14 +++---- src/net/tcpsockopt_openbsd.go | 16 ++++++++ src/net/tcpsockopt_posix.go | 2 +- src/net/tcpsockopt_stub.go | 10 +++-- src/os/exec/exec_test.go | 5 ++- 23 files changed, 186 insertions(+), 25 deletions(-) create mode 100644 src/net/file_stub.go create mode 100644 src/net/lookup_stub.go rename src/net/{sock_solaris.go => sock_stub.go} (93%) create mode 100644 src/net/sockopt_stub.go create mode 100644 src/net/tcpsockopt_openbsd.go diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 19e289f2e5..abeb500098 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -465,6 +465,11 @@ func TestDialer(t *testing.T) { } func TestDialDualStackLocalhost(t *testing.T) { + switch runtime.GOOS { + case "nacl": + t.Skipf("skipping test on %q", runtime.GOOS) + } + if ips, err := LookupIP("localhost"); err != nil { t.Fatalf("LookupIP failed: %v", err) } else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 { diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go index abe7da05cb..7511083f79 100644 --- a/src/net/dnsclient_unix.go +++ b/src/net/dnsclient_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris // DNS client: see RFC 1035. // Has to be linked into package net for Dial. diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go index ebb6e673f1..66ab7c4dd3 100644 --- a/src/net/dnsconfig_unix.go +++ b/src/net/dnsconfig_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris // Read system DNS config from /etc/resolv.conf diff --git a/src/net/file_stub.go b/src/net/file_stub.go new file mode 100644 index 0000000000..4281072ef9 --- /dev/null +++ b/src/net/file_stub.go @@ -0,0 +1,38 @@ +// Copyright 2011 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. + +// +build nacl + +package net + +import ( + "os" + "syscall" +) + +// FileConn returns a copy of the network connection corresponding to +// the open file f. It is the caller's responsibility to close f when +// finished. Closing c does not affect f, and closing f does not +// affect c. +func FileConn(f *os.File) (c Conn, err error) { + return nil, syscall.ENOPROTOOPT + +} + +// FileListener returns a copy of the network listener corresponding +// to the open file f. It is the caller's responsibility to close l +// when finished. Closing l does not affect f, and closing f does not +// affect l. +func FileListener(f *os.File) (l Listener, err error) { + return nil, syscall.ENOPROTOOPT + +} + +// FilePacketConn returns a copy of the packet network connection +// corresponding to the open file f. It is the caller's +// responsibility to close f when finished. Closing c does not affect +// f, and closing f does not affect c. +func FilePacketConn(f *os.File) (c PacketConn, err error) { + return nil, syscall.ENOPROTOOPT +} diff --git a/src/net/file_test.go b/src/net/file_test.go index d81bca7824..6fab06a9c6 100644 --- a/src/net/file_test.go +++ b/src/net/file_test.go @@ -89,7 +89,7 @@ var fileListenerTests = []struct { func TestFileListener(t *testing.T) { switch runtime.GOOS { - case "windows": + case "nacl", "windows": t.Skipf("skipping test on %q", runtime.GOOS) } diff --git a/src/net/file_unix.go b/src/net/file_unix.go index 07b3ecf626..214a4196c8 100644 --- a/src/net/file_unix.go +++ b/src/net/file_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go index 0632dafc65..92dc8dc569 100644 --- a/src/net/ipraw_test.go +++ b/src/net/ipraw_test.go @@ -68,6 +68,11 @@ func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) { } func TestResolveIPAddr(t *testing.T) { + switch runtime.GOOS { + case "nacl": + t.Skipf("skipping test on %q", runtime.GOOS) + } + for _, tt := range resolveIPAddrTests { addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName) if err != tt.err { diff --git a/src/net/lookup_stub.go b/src/net/lookup_stub.go new file mode 100644 index 0000000000..502aafb270 --- /dev/null +++ b/src/net/lookup_stub.go @@ -0,0 +1,49 @@ +// Copyright 2011 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. + +// +build nacl + +package net + +import "syscall" + +func lookupProtocol(name string) (proto int, err error) { + return 0, syscall.ENOPROTOOPT +} + +func lookupHost(host string) (addrs []string, err error) { + return nil, syscall.ENOPROTOOPT +} + +func lookupIP(host string) (ips []IP, err error) { + return nil, syscall.ENOPROTOOPT +} + +func lookupPort(network, service string) (port int, err error) { + return 0, syscall.ENOPROTOOPT +} + +func lookupCNAME(name string) (cname string, err error) { + return "", syscall.ENOPROTOOPT +} + +func lookupSRV(service, proto, name string) (cname string, srvs []*SRV, err error) { + return "", nil, syscall.ENOPROTOOPT +} + +func lookupMX(name string) (mxs []*MX, err error) { + return nil, syscall.ENOPROTOOPT +} + +func lookupNS(name string) (nss []*NS, err error) { + return nil, syscall.ENOPROTOOPT +} + +func lookupTXT(name string) (txts []string, err error) { + return nil, syscall.ENOPROTOOPT +} + +func lookupAddr(addr string) (ptrs []string, err error) { + return nil, syscall.ENOPROTOOPT +} diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go index b1d2f8f31a..a54578456d 100644 --- a/src/net/lookup_unix.go +++ b/src/net/lookup_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net diff --git a/src/net/port_test.go b/src/net/port_test.go index 9e8968f359..4811ade69e 100644 --- a/src/net/port_test.go +++ b/src/net/port_test.go @@ -5,6 +5,7 @@ package net import ( + "runtime" "testing" ) @@ -43,6 +44,11 @@ var porttests = []portTest{ } func TestLookupPort(t *testing.T) { + switch runtime.GOOS { + case "nacl": + t.Skipf("skipping test on %q", runtime.GOOS) + } + for i := 0; i < len(porttests); i++ { tt := porttests[i] if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok { diff --git a/src/net/port_unix.go b/src/net/port_unix.go index 89558c1f02..348c771c35 100644 --- a/src/net/port_unix.go +++ b/src/net/port_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin dragonfly freebsd linux netbsd openbsd solaris // Read system port mappings from /etc/services diff --git a/src/net/sock_bsd.go b/src/net/sock_bsd.go index 48fb785275..6c37109f5e 100644 --- a/src/net/sock_bsd.go +++ b/src/net/sock_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd nacl netbsd openbsd +// +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/sock_solaris.go b/src/net/sock_stub.go similarity index 93% rename from src/net/sock_solaris.go rename to src/net/sock_stub.go index 90fe9de894..ed6b089489 100644 --- a/src/net/sock_solaris.go +++ b/src/net/sock_stub.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build nacl solaris + package net import "syscall" diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go index 2d36a55953..00e4dbf376 100644 --- a/src/net/sockopt_bsd.go +++ b/src/net/sockopt_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd nacl netbsd openbsd +// +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go index 921918c37f..1654d1b85e 100644 --- a/src/net/sockopt_posix.go +++ b/src/net/sockopt_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows +// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/sockopt_stub.go b/src/net/sockopt_stub.go new file mode 100644 index 0000000000..de5ee0bb63 --- /dev/null +++ b/src/net/sockopt_stub.go @@ -0,0 +1,37 @@ +// Copyright 2011 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. + +// +build nacl + +package net + +import "syscall" + +func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { + return nil +} + +func setDefaultListenerSockopts(s int) error { + return nil +} + +func setDefaultMulticastSockopts(s int) error { + return nil +} + +func setReadBuffer(fd *netFD, bytes int) error { + return syscall.ENOPROTOOPT +} + +func setWriteBuffer(fd *netFD, bytes int) error { + return syscall.ENOPROTOOPT +} + +func setKeepAlive(fd *netFD, keepalive bool) error { + return syscall.ENOPROTOOPT +} + +func setLinger(fd *netFD, sec int) error { + return syscall.ENOPROTOOPT +} diff --git a/src/net/sockoptip_bsd.go b/src/net/sockoptip_bsd.go index 87132f0f46..2199e480d4 100644 --- a/src/net/sockoptip_bsd.go +++ b/src/net/sockoptip_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd nacl netbsd openbsd +// +build darwin dragonfly freebsd netbsd openbsd package net diff --git a/src/net/sockoptip_posix.go b/src/net/sockoptip_posix.go index b5c80e4490..c2579be911 100644 --- a/src/net/sockoptip_posix.go +++ b/src/net/sockoptip_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows +// +build darwin dragonfly freebsd linux netbsd openbsd windows package net diff --git a/src/net/sockoptip_stub.go b/src/net/sockoptip_stub.go index dcd3a22b57..32ec5ddb85 100644 --- a/src/net/sockoptip_stub.go +++ b/src/net/sockoptip_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build solaris +// +build nacl solaris package net @@ -10,30 +10,30 @@ import "syscall" func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } func setIPv4MulticastLoopback(fd *netFD, v bool) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } func setIPv6MulticastLoopback(fd *netFD, v bool) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { // See golang.org/issue/7399. - return syscall.EINVAL + return syscall.ENOPROTOOPT } diff --git a/src/net/tcpsockopt_openbsd.go b/src/net/tcpsockopt_openbsd.go new file mode 100644 index 0000000000..041e1786a9 --- /dev/null +++ b/src/net/tcpsockopt_openbsd.go @@ -0,0 +1,16 @@ +// Copyright 2009 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 net + +import ( + "syscall" + "time" +) + +func setKeepAlivePeriod(fd *netFD, d time.Duration) error { + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} diff --git a/src/net/tcpsockopt_posix.go b/src/net/tcpsockopt_posix.go index 6484bad4b4..0abf3f97f6 100644 --- a/src/net/tcpsockopt_posix.go +++ b/src/net/tcpsockopt_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows +// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package net diff --git a/src/net/tcpsockopt_stub.go b/src/net/tcpsockopt_stub.go index 346293ca46..b413a764d8 100644 --- a/src/net/tcpsockopt_stub.go +++ b/src/net/tcpsockopt_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build nacl openbsd +// +build nacl package net @@ -11,8 +11,10 @@ import ( "time" ) -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // NaCl and OpenBSD have no user-settable per-socket TCP - // keepalive options. +func setNoDelay(fd *netFD, noDelay bool) error { + return syscall.ENOPROTOOPT +} + +func setKeepAlivePeriod(fd *netFD, d time.Duration) error { return syscall.ENOPROTOOPT } diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 6f77ac38ae..5fd439b8bb 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -383,8 +383,9 @@ func TestExtraFilesFDShuffle(t *testing.T) { } func TestExtraFiles(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("no operating system support; skipping") + switch runtime.GOOS { + case "nacl", "windows": + t.Skipf("skipping test on %q", runtime.GOOS) } // Ensure that file descriptors have not already been leaked into From 73a82db1c8eec314700e2d0f92074a901fa112ed Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 18 Sep 2014 09:45:58 -0700 Subject: [PATCH 122/430] fmt: fix allocation tests Converting an integer to an interface{} allocates as of CL 130240043. Fixes #8617. LGTM=r R=r CC=golang-codereviews, khr https://golang.org/cl/141700043 --- src/fmt/fmt_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 89dde2b64a..a212c9f702 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -864,9 +864,9 @@ var mallocTest = []struct { }{ {0, `Sprintf("")`, func() { Sprintf("") }}, {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }}, - {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, + {2, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }}, - {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }}, + {3, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }}, {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1? {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. From dfd4123edc1863a5b3b6d7cfabba6856c319ba5b Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 18 Sep 2014 10:13:15 -0700 Subject: [PATCH 123/430] encoding/gob: speedup encoding Replace typeLock with copy-on-write map using atomic.Value. benchmark old ns/op new ns/op delta BenchmarkEndToEndPipe 7722 7709 -0.17% BenchmarkEndToEndPipe-2 5114 4344 -15.06% BenchmarkEndToEndPipe-4 3192 2429 -23.90% BenchmarkEndToEndPipe-8 1833 1438 -21.55% BenchmarkEndToEndPipe-16 1332 983 -26.20% BenchmarkEndToEndPipe-32 1444 675 -53.25% BenchmarkEndToEndByteBuffer 6474 6019 -7.03% BenchmarkEndToEndByteBuffer-2 4280 2810 -34.35% BenchmarkEndToEndByteBuffer-4 2264 1774 -21.64% BenchmarkEndToEndByteBuffer-8 1275 979 -23.22% BenchmarkEndToEndByteBuffer-16 1257 753 -40.10% BenchmarkEndToEndByteBuffer-32 1342 644 -52.01% BenchmarkEndToEndArrayByteBuffer 727725 671349 -7.75% BenchmarkEndToEndArrayByteBuffer-2 394079 320473 -18.68% BenchmarkEndToEndArrayByteBuffer-4 211785 178175 -15.87% BenchmarkEndToEndArrayByteBuffer-8 141003 118857 -15.71% BenchmarkEndToEndArrayByteBuffer-16 139249 86367 -37.98% BenchmarkEndToEndArrayByteBuffer-32 144128 73454 -49.04% LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/147720043 --- src/encoding/gob/encode.go | 75 ++++++++++++++++++------------------ src/encoding/gob/encoder.go | 4 -- src/encoding/gob/type.go | 76 ++++++++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 65 deletions(-) diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index 5d35db20e6..b7bf8b0022 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -470,7 +470,7 @@ var encOpTable = [...]encOp{ // encOpFor returns (a pointer to) the encoding op for the base type under rt and // the indirection count to reach it. -func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) { +func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[*typeInfo]bool) (*encOp, int) { ut := userType(rt) // If the type implements GobEncoder, we handle it without further processing. if ut.externalEnc != 0 { @@ -498,7 +498,7 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) break } // Slices have a header; we decode it to find the underlying array. - elemOp, elemIndir := encOpFor(t.Elem(), inProgress) + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) op = func(i *encInstr, state *encoderState, slice reflect.Value) { if !state.sendZero && slice.Len() == 0 { return @@ -508,14 +508,14 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) } case reflect.Array: // True arrays have size in the type. - elemOp, elemIndir := encOpFor(t.Elem(), inProgress) + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) op = func(i *encInstr, state *encoderState, array reflect.Value) { state.update(i) state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len()) } case reflect.Map: - keyOp, keyIndir := encOpFor(t.Key(), inProgress) - elemOp, elemIndir := encOpFor(t.Elem(), inProgress) + keyOp, keyIndir := encOpFor(t.Key(), inProgress, building) + elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) op = func(i *encInstr, state *encoderState, mv reflect.Value) { // We send zero-length (but non-nil) maps because the // receiver might want to use the map. (Maps don't use append.) @@ -527,12 +527,13 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp) (*encOp, int) } case reflect.Struct: // Generate a closure that calls out to the engine for the nested type. - getEncEngine(userType(typ)) + getEncEngine(userType(typ), building) info := mustGetTypeInfo(typ) op = func(i *encInstr, state *encoderState, sv reflect.Value) { state.update(i) // indirect through info to delay evaluation for recursive structs - state.enc.encodeStruct(state.b, info.encoder, sv) + enc := info.encoder.Load().(*encEngine) + state.enc.encodeStruct(state.b, enc, sv) } case reflect.Interface: op = func(i *encInstr, state *encoderState, iv reflect.Value) { @@ -579,7 +580,7 @@ func gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { } // compileEnc returns the engine to compile the type. -func compileEnc(ut *userTypeInfo) *encEngine { +func compileEnc(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { srt := ut.base engine := new(encEngine) seen := make(map[reflect.Type]*encOp) @@ -593,7 +594,7 @@ func compileEnc(ut *userTypeInfo) *encEngine { if !isSent(&f) { continue } - op, indir := encOpFor(f.Type, seen) + op, indir := encOpFor(f.Type, seen, building) engine.instr = append(engine.instr, encInstr{*op, wireFieldNum, f.Index, indir}) wireFieldNum++ } @@ -603,49 +604,47 @@ func compileEnc(ut *userTypeInfo) *encEngine { engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, nil, 0}) } else { engine.instr = make([]encInstr, 1) - op, indir := encOpFor(rt, seen) + op, indir := encOpFor(rt, seen, building) engine.instr[0] = encInstr{*op, singletonField, nil, indir} } return engine } // getEncEngine returns the engine to compile the type. -// typeLock must be held (or we're in initialization and guaranteed single-threaded). -func getEncEngine(ut *userTypeInfo) *encEngine { - info, err1 := getTypeInfo(ut) - if err1 != nil { - error_(err1) +func getEncEngine(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { + info, err := getTypeInfo(ut) + if err != nil { + error_(err) } - if info.encoder == nil { - // Assign the encEngine now, so recursive types work correctly. But... - info.encoder = new(encEngine) - // ... if we fail to complete building the engine, don't cache the half-built machine. - // Doing this here means we won't cache a type that is itself OK but - // that contains a nested type that won't compile. The result is consistent - // error behavior when Encode is called multiple times on the top-level type. - ok := false - defer func() { - if !ok { - info.encoder = nil - } - }() - info.encoder = compileEnc(ut) - ok = true + enc, ok := info.encoder.Load().(*encEngine) + if !ok { + enc = buildEncEngine(info, ut, building) } - return info.encoder + return enc } -// lockAndGetEncEngine is a function that locks and compiles. -// This lets us hold the lock only while compiling, not when encoding. -func lockAndGetEncEngine(ut *userTypeInfo) *encEngine { - typeLock.Lock() - defer typeLock.Unlock() - return getEncEngine(ut) +func buildEncEngine(info *typeInfo, ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { + // Check for recursive types. + if building != nil && building[info] { + return nil + } + info.encInit.Lock() + defer info.encInit.Unlock() + enc, ok := info.encoder.Load().(*encEngine) + if !ok { + if building == nil { + building = make(map[*typeInfo]bool) + } + building[info] = true + enc = compileEnc(ut, building) + info.encoder.Store(enc) + } + return enc } func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) { defer catchError(&enc.err) - engine := lockAndGetEncEngine(ut) + engine := getEncEngine(ut, nil) indir := ut.indir if ut.externalEnc != 0 { indir = int(ut.encIndir) diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go index a3301c3bd3..4b5dc16c79 100644 --- a/src/encoding/gob/encoder.go +++ b/src/encoding/gob/encoder.go @@ -88,9 +88,7 @@ func (enc *Encoder) sendActualType(w io.Writer, state *encoderState, ut *userTyp if _, alreadySent := enc.sent[actual]; alreadySent { return false } - typeLock.Lock() info, err := getTypeInfo(ut) - typeLock.Unlock() if err != nil { enc.setError(err) return @@ -191,9 +189,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use // a singleton basic type (int, []byte etc.) at top level. We don't // need to send the type info but we do need to update enc.sent. if !sent { - typeLock.Lock() info, err := getTypeInfo(ut) - typeLock.Unlock() if err != nil { enc.setError(err) return diff --git a/src/encoding/gob/type.go b/src/encoding/gob/type.go index cad1452795..a49b71a867 100644 --- a/src/encoding/gob/type.go +++ b/src/encoding/gob/type.go @@ -11,6 +11,7 @@ import ( "os" "reflect" "sync" + "sync/atomic" "unicode" "unicode/utf8" ) @@ -681,29 +682,51 @@ func (w *wireType) string() string { type typeInfo struct { id typeId - encoder *encEngine + encInit sync.Mutex // protects creation of encoder + encoder atomic.Value // *encEngine wire *wireType } -var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock +// typeInfoMap is an atomic pointer to map[reflect.Type]*typeInfo. +// It's updated copy-on-write. Readers just do an atomic load +// to get the current version of the map. Writers make a full copy of +// the map and atomically update the pointer to point to the new map. +// Under heavy read contention, this is significantly faster than a map +// protected by a mutex. +var typeInfoMap atomic.Value + +func lookupTypeInfo(rt reflect.Type) *typeInfo { + m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo) + return m[rt] +} -// typeLock must be held. func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) { rt := ut.base if ut.externalEnc != 0 { // We want the user type, not the base type. rt = ut.user } - info, ok := typeInfoMap[rt] - if ok { + if info := lookupTypeInfo(rt); info != nil { return info, nil } - info = new(typeInfo) + return buildTypeInfo(ut, rt) +} + +// buildTypeInfo constructs the type information for the type +// and stores it in the type info map. +func buildTypeInfo(ut *userTypeInfo, rt reflect.Type) (*typeInfo, error) { + typeLock.Lock() + defer typeLock.Unlock() + + if info := lookupTypeInfo(rt); info != nil { + return info, nil + } + gt, err := getBaseType(rt.Name(), rt) if err != nil { return nil, err } - info.id = gt.id() + info := &typeInfo{id: gt.id()} if ut.externalEnc != 0 { userType, err := getType(rt.Name(), ut, rt) @@ -719,25 +742,32 @@ func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) { case xText: info.wire = &wireType{TextMarshalerT: gt} } - typeInfoMap[ut.user] = info - return info, nil + rt = ut.user + } else { + t := info.id.gobType() + switch typ := rt; typ.Kind() { + case reflect.Array: + info.wire = &wireType{ArrayT: t.(*arrayType)} + case reflect.Map: + info.wire = &wireType{MapT: t.(*mapType)} + case reflect.Slice: + // []byte == []uint8 is a special case handled separately + if typ.Elem().Kind() != reflect.Uint8 { + info.wire = &wireType{SliceT: t.(*sliceType)} + } + case reflect.Struct: + info.wire = &wireType{StructT: t.(*structType)} + } } - t := info.id.gobType() - switch typ := rt; typ.Kind() { - case reflect.Array: - info.wire = &wireType{ArrayT: t.(*arrayType)} - case reflect.Map: - info.wire = &wireType{MapT: t.(*mapType)} - case reflect.Slice: - // []byte == []uint8 is a special case handled separately - if typ.Elem().Kind() != reflect.Uint8 { - info.wire = &wireType{SliceT: t.(*sliceType)} - } - case reflect.Struct: - info.wire = &wireType{StructT: t.(*structType)} + // Create new map with old contents plus new entry. + newm := make(map[reflect.Type]*typeInfo) + m, _ := typeInfoMap.Load().(map[reflect.Type]*typeInfo) + for k, v := range m { + newm[k] = v } - typeInfoMap[rt] = info + newm[rt] = info + typeInfoMap.Store(newm) return info, nil } From 76c7548162a42666f76359a4f5cb819624b86ae2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 14:48:26 -0400 Subject: [PATCH 124/430] net: disable TestDialMultiFDLeak It fails about 25% of the time on OS X. I don't know what it's trying to do. Created issue 8764 to correct this, but for now disable. LGTM=bradfitz, mikioh.mikioh R=bradfitz, mikioh.mikioh CC=golang-codereviews https://golang.org/cl/144070044 --- src/net/dial_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/net/dial_test.go b/src/net/dial_test.go index abeb500098..42898d669f 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -339,6 +339,8 @@ func numTCP() (ntcp, nopen, nclose int, err error) { } func TestDialMultiFDLeak(t *testing.T) { + t.Skip("flaky test - golang.org/issue/8764") + if !supportsIPv4 || !supportsIPv6 { t.Skip("neither ipv4 nor ipv6 is supported") } From 98a5f52ef0658f1e1ad823bfad91dd5bbc261a75 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 14:48:47 -0400 Subject: [PATCH 125/430] os: avoid error result when dir is removed out from under RemoveAll Fixes #7776. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews, r https://golang.org/cl/145860043 --- src/os/os_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ src/os/path.go | 5 ++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/os/os_test.go b/src/os/os_test.go index 0224c9b01d..7a28497414 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -18,6 +18,7 @@ import ( "runtime" "sort" "strings" + "sync" "syscall" "testing" "text/template" @@ -1403,3 +1404,44 @@ func TestNilFileMethods(t *testing.T) { } } } + +func mkdirTree(t *testing.T, root string, level, max int) { + if level >= max { + return + } + level++ + for i := 'a'; i < 'c'; i++ { + dir := filepath.Join(root, string(i)) + if err := Mkdir(dir, 0700); err != nil { + t.Fatal(err) + } + mkdirTree(t, dir, level, max) + } +} + +// Test that simultaneous RemoveAll do not report an error. +// As long as it gets removed, we should be happy. +func TestRemoveAllRace(t *testing.T) { + n := runtime.GOMAXPROCS(16) + defer runtime.GOMAXPROCS(n) + root, err := ioutil.TempDir("", "issue") + if err != nil { + t.Fatal(err) + } + mkdirTree(t, root, 1, 6) + hold := make(chan struct{}) + var wg sync.WaitGroup + for i := 0; i < 4; i++ { + wg.Add(1) + go func() { + defer wg.Done() + <-hold + err := RemoveAll(root) + if err != nil { + t.Errorf("unexpected error: %T, %q", err, err) + } + }() + } + close(hold) // let workers race to remove root + wg.Wait() +} diff --git a/src/os/path.go b/src/os/path.go index 02a77ec805..6cc69403b6 100644 --- a/src/os/path.go +++ b/src/os/path.go @@ -66,7 +66,7 @@ func MkdirAll(path string, perm FileMode) error { func RemoveAll(path string) error { // Simple case: if Remove works, we're done. err := Remove(path) - if err == nil { + if err == nil || IsNotExist(err) { return nil } @@ -116,6 +116,9 @@ func RemoveAll(path string) error { // Remove directory. err1 := Remove(path) + if err1 == nil || IsNotExist(err1) { + return nil + } if err == nil { err = err1 } From c3b5db895b11ba28bc1546f37178efcb057ab3f0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 14:49:24 -0400 Subject: [PATCH 126/430] runtime: delete panicstring; move its checks into gopanic In Go 1.3 the runtime called panicstring to report errors like divide by zero or memory faults. Now we call panic (gopanic) with pre-allocated error values. That new path is missing the checking that panicstring did, so add it there. The only call to panicstring left is in cnew, which is problematic because if it fails, probably the heap is corrupt. In that case, calling panicstring creates a new errorCString (no allocation there), but then panic tries to print it, invoking errorCString.Error, which does a string concatenation (allocating), which then dies. Replace that one panicstring with a throw: cnew is for allocating runtime data structures and should never ask for an inappropriate amount of memory. With panicstring gone, delete newErrorCString, errorCString. While we're here, delete newErrorString, not called by anyone. (It can't be: that would be C code calling Go code that might block or grow the stack.) Found while debugging a malloc corruption. This resulted in 'panic during panic' instead of a more useful message. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/138290045 --- src/runtime/error.go | 22 ---------------- src/runtime/malloc.c | 2 +- src/runtime/panic.go | 59 +++++++++++++++++++++---------------------- src/runtime/proc.c | 7 ----- src/runtime/runtime.h | 3 --- 5 files changed, 30 insertions(+), 63 deletions(-) diff --git a/src/runtime/error.go b/src/runtime/error.go index 3ea93680ce..0b40c702b0 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -71,28 +71,6 @@ func (e errorString) Error() string { return "runtime error: " + string(e) } -// For calling from C. -func newErrorString(s string, ret *interface{}) { - *ret = errorString(s) -} - -// An errorCString represents a runtime error described by a single C string. -// Not "type errorCString unsafe.Pointer" because of http://golang.org/issue/7084. -// Not uintptr because we want to avoid an allocation if interfaces can't hold -// uintptrs directly (and cstr _is_ a pointer). -type errorCString struct{ cstr unsafe.Pointer } - -func (e errorCString) RuntimeError() {} - -func (e errorCString) Error() string { - return "runtime error: " + gostringnocopy((*byte)(e.cstr)) -} - -// For calling from C. -func newErrorCString(s unsafe.Pointer, ret *interface{}) { - *ret = errorCString{s} -} - type stringer interface { String() string } diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index d5f2b9ab80..60d20a992d 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -335,7 +335,7 @@ static void* cnew(Type *typ, intgo n) { if(n < 0 || (typ->size > 0 && n > MaxMem/typ->size)) - runtime·panicstring("runtime: allocation size out of range"); + runtime·throw("runtime: allocation size out of range"); return runtime·mallocgc(typ->size*n, typ, typ->kind&KindNoPointers ? FlagNoScan : 0); } diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 927b6db44b..3cc31053e8 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -281,6 +281,35 @@ func gopanic(e interface{}) { if gp.m.curg != gp { gothrow("panic on m stack") } + + // m.softfloat is set during software floating point. + // It increments m.locks to avoid preemption. + // We moved the memory loads out, so there shouldn't be + // any reason for it to panic anymore. + if gp.m.softfloat != 0 { + gp.m.locks-- + gp.m.softfloat = 0 + gothrow("panic during softfloat") + } + if gp.m.mallocing != 0 { + print("panic: ") + printany(e) + print("\n") + gothrow("panic during malloc") + } + if gp.m.gcing != 0 { + print("panic: ") + printany(e) + print("\n") + gothrow("panic during gc") + } + if gp.m.locks != 0 { + print("panic: ") + printany(e) + print("\n") + gothrow("panic holding locks") + } + var p _panic p.arg = e p.link = gp._panic @@ -431,33 +460,3 @@ func gothrow(s string) { dopanic(0) *(*int)(nil) = 0 // not reached } - -func panicstring(s *int8) { - // m.softfloat is set during software floating point, - // which might cause a fault during a memory load. - // It increments m.locks to avoid preemption. - // If we're panicking, the software floating point frames - // will be unwound, so decrement m.locks as they would. - gp := getg() - if gp.m.softfloat != 0 { - gp.m.locks-- - gp.m.softfloat = 0 - } - - if gp.m.mallocing != 0 { - print("panic: ", s, "\n") - gothrow("panic during malloc") - } - if gp.m.gcing != 0 { - print("panic: ", s, "\n") - gothrow("panic during gc") - } - if gp.m.locks != 0 { - print("panic: ", s, "\n") - gothrow("panic holding locks") - } - - var err interface{} - newErrorCString(unsafe.Pointer(s), &err) - gopanic(err) -} diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 4282a145e1..860701ee58 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -123,7 +123,6 @@ runtime·schedinit(void) { int32 n, procs; byte *p; - Eface i; // raceinit must be the first call to race detector. // In particular, it must be done before mallocinit below calls racemapshadow. @@ -137,12 +136,6 @@ runtime·schedinit(void) runtime·mallocinit(); mcommoninit(g->m); - // Initialize the itable value for newErrorCString, - // so that the next time it gets called, possibly - // in a fault during a garbage collection, it will not - // need to allocated memory. - runtime·newErrorCString(0, &i); - runtime·goargs(); runtime·goenvs(); runtime·parsedebugvars(); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index c034f3aa97..386b09b96b 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -804,7 +804,6 @@ void runtime·goenvs(void); void runtime·goenvs_unix(void); void* runtime·getu(void); void runtime·throw(int8*); -void runtime·panicstring(int8*); bool runtime·canpanic(G*); void runtime·prints(int8*); void runtime·printf(int8*, ...); @@ -1063,8 +1062,6 @@ void runtime·panicdivide(void); */ void runtime·printany(Eface); void runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*); -void runtime·newErrorString(String, Eface*); -void runtime·newErrorCString(int8*, Eface*); void runtime·fadd64c(uint64, uint64, uint64*); void runtime·fsub64c(uint64, uint64, uint64*); void runtime·fmul64c(uint64, uint64, uint64*); From 45143aeca47da4595367e9ab0f1d0194f7847a96 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 18 Sep 2014 23:25:11 +0200 Subject: [PATCH 127/430] runtime: fix handling of GOTRACEBACK Since CL 130990043, the GOTRACEBACK variable is only used when the GODEBUG variable is set. This change restores the original behavior. LGTM=rsc R=golang-codereviews, aram, gobot, r, rsc CC=golang-codereviews https://golang.org/cl/132520043 --- src/runtime/runtime.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index ae754dc5cd..aa8dd8f7a0 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -287,18 +287,18 @@ runtime·parsedebugvars(void) intgo i, n; p = runtime·getenv("GODEBUG"); - if(p == nil) - return; - for(;;) { - for(i=0; i Date: Thu, 18 Sep 2014 15:43:06 -0700 Subject: [PATCH 128/430] go/doc: treat _ consts as exported Fixes #5397. LGTM=adg R=gri, adg CC=golang-codereviews, rsc https://golang.org/cl/144110044 --- src/go/doc/exports.go | 21 ++++++++------ src/go/doc/testdata/blank.0.golden | 37 ++++++++++++++++++++++++ src/go/doc/testdata/blank.1.golden | 46 ++++++++++++++++++++++++++++++ src/go/doc/testdata/blank.2.golden | 37 ++++++++++++++++++++++++ src/go/doc/testdata/blank.go | 38 ++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 src/go/doc/testdata/blank.0.golden create mode 100644 src/go/doc/testdata/blank.1.golden create mode 100644 src/go/doc/testdata/blank.2.golden create mode 100644 src/go/doc/testdata/blank.go diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go index ff01285d4c..9b421e7341 100644 --- a/src/go/doc/exports.go +++ b/src/go/doc/exports.go @@ -6,15 +6,18 @@ package doc -import "go/ast" +import ( + "go/ast" + "go/token" +) // filterIdentList removes unexported names from list in place // and returns the resulting list. // -func filterIdentList(list []*ast.Ident) []*ast.Ident { +func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident { j := 0 for _, x := range list { - if ast.IsExported(x.Name) { + if ast.IsExported(x.Name) || (blankOk && x.Name == "_") { list[j] = x j++ } @@ -74,7 +77,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp r.remember(ityp) } } else { - field.Names = filterIdentList(field.Names) + field.Names = filterIdentList(field.Names, false) if len(field.Names) < n { removedFields = true } @@ -136,13 +139,13 @@ func (r *reader) filterType(parent *namedType, typ ast.Expr) { } } -func (r *reader) filterSpec(spec ast.Spec) bool { +func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool { switch s := spec.(type) { case *ast.ImportSpec: // always keep imports so we can collect them return true case *ast.ValueSpec: - s.Names = filterIdentList(s.Names) + s.Names = filterIdentList(s.Names, tok == token.CONST) if len(s.Names) > 0 { r.filterType(nil, s.Type) return true @@ -159,10 +162,10 @@ func (r *reader) filterSpec(spec ast.Spec) bool { return false } -func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec { +func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec { j := 0 for _, s := range list { - if r.filterSpec(s) { + if r.filterSpec(s, tok) { list[j] = s j++ } @@ -173,7 +176,7 @@ func (r *reader) filterSpecList(list []ast.Spec) []ast.Spec { func (r *reader) filterDecl(decl ast.Decl) bool { switch d := decl.(type) { case *ast.GenDecl: - d.Specs = r.filterSpecList(d.Specs) + d.Specs = r.filterSpecList(d.Specs, d.Tok) return len(d.Specs) > 0 case *ast.FuncDecl: // ok to filter these methods early because any diff --git a/src/go/doc/testdata/blank.0.golden b/src/go/doc/testdata/blank.0.golden new file mode 100644 index 0000000000..dae3ab2aff --- /dev/null +++ b/src/go/doc/testdata/blank.0.golden @@ -0,0 +1,37 @@ +// Package blank is a go/doc test for the handling of _. See issue ... +PACKAGE blank + +IMPORTPATH + testdata/blank + +FILENAMES + testdata/blank.go + +CONSTANTS + // Package constants. + const ( + _ int = iota + I1 + I2 + ) + + +TYPES + // S has a padding field. + type S struct { + H uint32 + + A uint8 + // contains filtered or unexported fields + } + + // + type T int + + // T constants. + const ( + _ T = iota + T1 + T2 + ) + diff --git a/src/go/doc/testdata/blank.1.golden b/src/go/doc/testdata/blank.1.golden new file mode 100644 index 0000000000..333d7e5b04 --- /dev/null +++ b/src/go/doc/testdata/blank.1.golden @@ -0,0 +1,46 @@ +// Package blank is a go/doc test for the handling of _. See issue ... +PACKAGE blank + +IMPORTPATH + testdata/blank + +FILENAMES + testdata/blank.go + +CONSTANTS + // Package constants. + const ( + _ int = iota + I1 + I2 + ) + + +VARIABLES + // + var _ = T(55) + + +FUNCTIONS + // + func _() + + +TYPES + // S has a padding field. + type S struct { + H uint32 + _ uint8 + A uint8 + } + + // + type T int + + // T constants. + const ( + _ T = iota + T1 + T2 + ) + diff --git a/src/go/doc/testdata/blank.2.golden b/src/go/doc/testdata/blank.2.golden new file mode 100644 index 0000000000..dae3ab2aff --- /dev/null +++ b/src/go/doc/testdata/blank.2.golden @@ -0,0 +1,37 @@ +// Package blank is a go/doc test for the handling of _. See issue ... +PACKAGE blank + +IMPORTPATH + testdata/blank + +FILENAMES + testdata/blank.go + +CONSTANTS + // Package constants. + const ( + _ int = iota + I1 + I2 + ) + + +TYPES + // S has a padding field. + type S struct { + H uint32 + + A uint8 + // contains filtered or unexported fields + } + + // + type T int + + // T constants. + const ( + _ T = iota + T1 + T2 + ) + diff --git a/src/go/doc/testdata/blank.go b/src/go/doc/testdata/blank.go new file mode 100644 index 0000000000..f812c77b77 --- /dev/null +++ b/src/go/doc/testdata/blank.go @@ -0,0 +1,38 @@ +// 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 blank is a go/doc test for the handling of _. +// See issue 5397. +package blank + +type T int + +// T constants. +const ( + _ T = iota + T1 + T2 +) + +// Package constants. +const ( + _ int = iota + I1 + I2 +) + +// Blanks not in doc output: + +// S has a padding field. +type S struct { + H uint32 + _ uint8 + A uint8 +} + +func _() {} + +type _ T + +var _ = T(55) From ab76638cdc1705ec4f22cb6f757c1b542b388692 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 19:40:06 -0400 Subject: [PATCH 129/430] syscall: fix infinite recursion in itoa Fixes #8332. LGTM=dvyukov R=golang-codereviews, dvyukov CC=golang-codereviews https://golang.org/cl/138650044 --- src/syscall/export_test.go | 7 +++++++ src/syscall/str.go | 6 +++++- src/syscall/syscall_test.go | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/syscall/export_test.go diff --git a/src/syscall/export_test.go b/src/syscall/export_test.go new file mode 100644 index 0000000000..c9774622c8 --- /dev/null +++ b/src/syscall/export_test.go @@ -0,0 +1,7 @@ +// 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 syscall + +var Itoa = itoa diff --git a/src/syscall/str.go b/src/syscall/str.go index 0fce842e8c..2ddf04b227 100644 --- a/src/syscall/str.go +++ b/src/syscall/str.go @@ -6,8 +6,12 @@ package syscall func itoa(val int) string { // do it here rather than with fmt to avoid dependency if val < 0 { - return "-" + itoa(-val) + return "-" + uitoa(uint(-val)) } + return uitoa(uint(val)) +} + +func uitoa(val uint) string { var buf [32]byte // big enough for int64 i := len(buf) - 1 for val >= 10 { diff --git a/src/syscall/syscall_test.go b/src/syscall/syscall_test.go index 2a39b54f1b..846c4873d2 100644 --- a/src/syscall/syscall_test.go +++ b/src/syscall/syscall_test.go @@ -5,6 +5,7 @@ package syscall_test import ( + "fmt" "syscall" "testing" ) @@ -28,3 +29,19 @@ func TestEnv(t *testing.T) { // make sure TESTENV gets set to "", not deleted testSetGetenv(t, "TESTENV", "") } + +func TestItoa(t *testing.T) { + // Make most negative integer: 0x8000... + i := 1 + for i<<1 != 0 { + i <<= 1 + } + if i >= 0 { + t.Fatal("bad math") + } + s := syscall.Itoa(i) + f := fmt.Sprint(i) + if s != f { + t.Fatalf("itoa(%d) = %s, want %s", i, s, f) + } +} From e9ec8e7a2693b322287a96100750c6f00cf574ef Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 19:40:31 -0400 Subject: [PATCH 130/430] bytes, strings: document that FieldsFunc f must not be stateful Fixes #8738. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/143260045 --- src/bytes/bytes.go | 2 ++ src/strings/strings.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 34c22bbfb1..7634707b3c 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -267,6 +267,8 @@ func Fields(s []byte) [][]byte { // It splits the slice s at each run of code points c satisfying f(c) and // returns a slice of subslices of s. If all code points in s satisfy f(c), or // len(s) == 0, an empty slice is returned. +// FieldsFunc makes no guarantees about the order in which it calls f(c). +// If f does not return consistent results for a given c, FieldsFunc may crash. func FieldsFunc(s []byte, f func(rune) bool) [][]byte { n := 0 inField := false diff --git a/src/strings/strings.go b/src/strings/strings.go index 761f32a068..1b9df2e757 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -347,6 +347,8 @@ func Fields(s string) []string { // FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c) // and returns an array of slices of s. If all code points in s satisfy f(c) or the // string is empty, an empty slice is returned. +// FieldsFunc makes no guarantees about the order in which it calls f(c). +// If f does not return consistent results for a given c, FieldsFunc may crash. func FieldsFunc(s string, f func(rune) bool) []string { // First count the fields. n := 0 From e4fa1e40354dfd1e16c2b1f912bfbbdc8c0dfa9f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 18 Sep 2014 16:53:35 -0700 Subject: [PATCH 131/430] go/doc: document rationale for recent change LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/143290043 --- src/go/doc/exports.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go index 9b421e7341..1d3b466d8c 100644 --- a/src/go/doc/exports.go +++ b/src/go/doc/exports.go @@ -12,7 +12,8 @@ import ( ) // filterIdentList removes unexported names from list in place -// and returns the resulting list. +// and returns the resulting list. If blankOk is set, blank +// identifiers are considered exported names. // func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident { j := 0 @@ -145,6 +146,8 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool { // always keep imports so we can collect them return true case *ast.ValueSpec: + // special case: consider blank constants as exported + // (work-around for issue 5397) s.Names = filterIdentList(s.Names, tok == token.CONST) if len(s.Names) > 0 { r.filterType(nil, s.Type) From 84f9c42bbbfb67c2ef78d4a4e19417329d7f8f5a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 20:13:07 -0400 Subject: [PATCH 132/430] os: skip TestRemoveAllRace on Windows It's just fundamentally incompatible with Windows' pickiness about removing things that are in use. TBR=brainman CC=golang-codereviews https://golang.org/cl/142270043 --- src/os/os_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/os/os_test.go b/src/os/os_test.go index 7a28497414..973cc3a7bf 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1422,6 +1422,14 @@ func mkdirTree(t *testing.T, root string, level, max int) { // Test that simultaneous RemoveAll do not report an error. // As long as it gets removed, we should be happy. func TestRemoveAllRace(t *testing.T) { + if runtime.GOOS == "windows" { + // Windows has very strict rules about things like + // removing directories while someone else has + // them open. The racing doesn't work out nicely + // like it does on Unix. + t.Skip("skipping on windows") + } + n := runtime.GOMAXPROCS(16) defer runtime.GOMAXPROCS(n) root, err := ioutil.TempDir("", "issue") From 5a40b568d023922e735ddc21f3b4a30d52197b7a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 18 Sep 2014 17:27:26 -0700 Subject: [PATCH 133/430] lib9, cmd/ld: fixes for cross-linking on a Windows host This fixes a couple of problems that occur when the linker removes its temporary directory on Windows. The linker only creates and removes a temporary directory when doing external linking. Windows does not yet support external linking. Therefore, these problems are only seen when using a cross-compiler hosted on Windows. In lib9, FindFirstFileW returns just the file name, not the full path name. Don't assume that we will find a slash. Changed the code to work either way just in case. In ld, Windows requires that files be closed before they are removed, so close the output file before we might try to remove it. Fixes #8723. LGTM=alex.brainman R=golang-codereviews, alex.brainman CC=golang-codereviews https://golang.org/cl/141690043 --- src/cmd/ld/lib.c | 4 ++++ src/lib9/tempdir_windows.c | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 651705a2e6..36f0f99de2 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -144,6 +144,10 @@ libinit(void) void errorexit(void) { + if(cout >= 0) { + // For rmtemp run at atexit time on Windows. + close(cout); + } if(nerrors) { if(cout >= 0) mayberemoveoutfile(); diff --git a/src/lib9/tempdir_windows.c b/src/lib9/tempdir_windows.c index 1a530059ae..4c3df7cf11 100644 --- a/src/lib9/tempdir_windows.c +++ b/src/lib9/tempdir_windows.c @@ -70,7 +70,7 @@ removeall(char *p) { WinRune *r, *r1; DWORD attr; - char *q, *elem; + char *q, *qt, *elem; HANDLE h; WIN32_FIND_DATAW data; @@ -91,15 +91,18 @@ removeall(char *p) do{ q = toutf(data.cFileName); elem = strrchr(q, '\\'); - if(elem != nil) { + if(elem != nil) elem++; - if(strcmp(elem, ".") == 0 || strcmp(elem, "..") == 0) { - free(q); - continue; - } + else + elem = q; + if(strcmp(elem, ".") == 0 || strcmp(elem, "..") == 0) { + free(q); + continue; } - removeall(q); - free(q); + qt = smprint("%s\\%s", p, q); + free(q); + removeall(qt); + free(qt); }while(FindNextFileW(h, &data)); FindClose(h); From 54245cba1f5f3971c82be6d2b3e658f968f08e7b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 20:35:36 -0400 Subject: [PATCH 134/430] runtime: show frames for exported runtime functions The current Windows build failure happens because by default runtime frames are excluded from stack traces. Apparently the Windows breakpoint path dies with an ordinary panic, while the Unix path dies with a throw. Breakpoint is a strange function and I don't mind that it's a little different on the two operating systems. The panic squelches runtime frames but the throw shows them, because throw is considered something that shouldn't have happened at all, so as much detail as possible is wanted. The runtime exclusion is meant to prevents printing too much noise about internal runtime details. But exported functions are not internal details, so show exported functions. If the program dies because you called runtime.Breakpoint, it's okay to see that frame. This makes the Breakpoint test show Breakpoint in the stack trace no matter how it is handled. Should fix Windows build. Tested on Unix by changing Breakpoint to fault instead of doing a breakpoint. TBR=brainman CC=golang-codereviews https://golang.org/cl/143300043 --- src/runtime/traceback.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 9e95fa33d5..a93c42186b 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -499,7 +499,14 @@ func showframe(f *_func, gp *g) bool { return true } - return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.") + return traceback > 1 || f != nil && contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name)) +} + +// isExportedRuntime reports whether name is an exported runtime function. +// It is only for runtime functions, so ASCII A-Z is fine. +func isExportedRuntime(name string) bool { + const n = len("runtime.") + return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' } var gStatusStrings = [...]string{ From 048692e5de12c89b80761a9532c86eff526af640 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 20:41:00 -0400 Subject: [PATCH 135/430] runtime: fix Windows SysUsed Same fix as for SysUnused. Fixes #8038. LGTM=iant, alex.brainman R=golang-codereviews, iant, alex.brainman CC=golang-codereviews https://golang.org/cl/147820043 --- src/runtime/mem_windows.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/runtime/mem_windows.c b/src/runtime/mem_windows.c index 7bc028bf3a..6ea992020c 100644 --- a/src/runtime/mem_windows.c +++ b/src/runtime/mem_windows.c @@ -68,10 +68,22 @@ void runtime·SysUsed(void *v, uintptr n) { void *r; + uintptr small; r = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE); if(r != v) runtime·throw("runtime: failed to commit pages"); + + // Commit failed. See SysUnused. + while(n > 0) { + small = n; + while(small >= 4096 && runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, small, MEM_COMMIT, PAGE_READWRITE) == nil) + small = (small / 2) & ~(4096-1); + if(small < 4096) + runtime·throw("runtime: failed to decommit pages"); + v = (byte*)v + small; + n -= small; + } } void From f8474fa01d6995b9e442abff3f7b01a9119a22cc Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 19 Sep 2014 11:14:51 +1000 Subject: [PATCH 136/430] runtime: remove useless code around of EXCEPTION_BREAKPOINT This is to simplify VEH handler before making changes to fix issue 8006. Update #8006 LGTM=adg, rsc R=golang-codereviews, adg, rsc CC=golang-codereviews https://golang.org/cl/138630043 --- src/runtime/defs_windows.go | 1 - src/runtime/defs_windows_386.h | 1 - src/runtime/defs_windows_amd64.h | 1 - src/runtime/os_windows_386.c | 13 ------------- src/runtime/os_windows_amd64.c | 10 ---------- 5 files changed, 26 deletions(-) diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go index 01aea92dee..cb0f54d8ab 100644 --- a/src/runtime/defs_windows.go +++ b/src/runtime/defs_windows.go @@ -49,7 +49,6 @@ const ( CONTEXT_FULL = C.CONTEXT_FULL EXCEPTION_ACCESS_VIOLATION = C.STATUS_ACCESS_VIOLATION - EXCEPTION_BREAKPOINT = C.STATUS_BREAKPOINT EXCEPTION_FLT_DENORMAL_OPERAND = C.STATUS_FLOAT_DENORMAL_OPERAND EXCEPTION_FLT_DIVIDE_BY_ZERO = C.STATUS_FLOAT_DIVIDE_BY_ZERO EXCEPTION_FLT_INEXACT_RESULT = C.STATUS_FLOAT_INEXACT_RESULT diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h index db3629a1d2..295e422c6b 100644 --- a/src/runtime/defs_windows_386.h +++ b/src/runtime/defs_windows_386.h @@ -22,7 +22,6 @@ enum { CONTEXT_FULL = 0x10007, EXCEPTION_ACCESS_VIOLATION = 0xc0000005, - EXCEPTION_BREAKPOINT = 0x80000003, EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d, EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e, EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f, diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h index fe26f5a84a..2516c84128 100644 --- a/src/runtime/defs_windows_amd64.h +++ b/src/runtime/defs_windows_amd64.h @@ -22,7 +22,6 @@ enum { CONTEXT_FULL = 0x10000b, EXCEPTION_ACCESS_VIOLATION = 0xc0000005, - EXCEPTION_BREAKPOINT = 0x80000003, EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d, EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e, EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f, diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c index 15a5ea5d1f..028b09bbc8 100644 --- a/src/runtime/os_windows_386.c +++ b/src/runtime/os_windows_386.c @@ -54,19 +54,6 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) return 0; - switch(info->ExceptionCode) { - case EXCEPTION_BREAKPOINT: - // It is unclear whether this is needed, unclear whether it - // would work, and unclear how to test it. Leave out for now. - // This only handles breakpoint instructions written in the - // assembly sources, not breakpoints set by a debugger, and - // there are very few of the former. - // - // r->Eip--; // because 8l generates 2 bytes for INT3 - // return 0; - break; - } - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c index 9a69d73c07..d7b45c5b1d 100644 --- a/src/runtime/os_windows_amd64.c +++ b/src/runtime/os_windows_amd64.c @@ -62,16 +62,6 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) return 0; - switch(info->ExceptionCode) { - case EXCEPTION_BREAKPOINT: - // It is unclear whether this is needed, unclear whether it - // would work, and unclear how to test it. Leave out for now. - // This only handles breakpoint instructions written in the - // assembly sources, not breakpoints set by a debugger, and - // there are very few of the former. - break; - } - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { // Make it look like a call to the signal func. // Have to pass arguments out of band since From 2debfeb93666dcde759b7cc3a3e001a82307a84c Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 18 Sep 2014 21:16:01 -0400 Subject: [PATCH 137/430] os: handle 'has been removed' error as IsNotExist on Plan 9 It fixes the TestRemoveAllRace test introduced in CL 145860043. LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/147820044 --- src/os/error_plan9.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/error_plan9.go b/src/os/error_plan9.go index 62d4e420e4..45cd747923 100644 --- a/src/os/error_plan9.go +++ b/src/os/error_plan9.go @@ -25,7 +25,7 @@ func isNotExist(err error) bool { case *LinkError: err = pe.Err } - return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") + return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || contains(err.Error(), "has been removed") } func isPermission(err error) bool { From dd8f29e3feb91f3c7ec0681ef23694578e4d9228 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 21:19:18 -0400 Subject: [PATCH 138/430] reflect: adjust Value.String to give correct answer for methods Fixes #7859. LGTM=r R=adonovan, r CC=golang-codereviews https://golang.org/cl/136710043 --- src/reflect/all_test.go | 16 ++++++++++++++++ src/reflect/value.go | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 4be0e353df..b72c4b176d 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -3923,3 +3923,19 @@ func useStack(n int) { var b [1024]byte // makes frame about 1KB useStack(n - 1 + int(b[99])) } + +type Impl struct{} + +func (Impl) f() {} + +func TestValueString(t *testing.T) { + rv := ValueOf(Impl{}) + if rv.String() != "" { + t.Errorf("ValueOf(Impl{}).String() = %q, want %q", rv.String(), "") + } + + method := rv.Method(0) + if method.String() != "" { + t.Errorf("ValueOf(Impl{}).Method(0).String() = %q, want %q", method.String(), "") + } +} diff --git a/src/reflect/value.go b/src/reflect/value.go index b0dfe840b6..12d423f3c3 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -1771,7 +1771,7 @@ func (v Value) String() string { } // If you call String on a reflect.Value of other type, it's better to // print something than to panic. Useful in debugging. - return "<" + v.typ.String() + " Value>" + return "<" + v.Type().String() + " Value>" } // TryRecv attempts to receive a value from the channel v but will not block. From 2ed209eaf59c3b7372258419c5fa1f5b0abc507e Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 19 Sep 2014 11:38:48 +1000 Subject: [PATCH 139/430] runtime: allow OutputDebugString to be sent to debugger We mark DBG_PRINTEXCEPTION_C messages in VEH handler as handled, thus preventing debugger from seeing them. I don't see reason for doing that. The comment warns of crashes, but I added test and don't see any crashes. This is also simplify VEH handler before making changes to fix issue 8006. Update #8006 LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/146800043 --- src/runtime/os_windows_386.c | 15 --------------- src/runtime/os_windows_amd64.c | 15 --------------- src/runtime/syscall_windows_test.go | 6 ++++++ 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c index 028b09bbc8..e2ae8db277 100644 --- a/src/runtime/os_windows_386.c +++ b/src/runtime/os_windows_386.c @@ -24,8 +24,6 @@ runtime·dumpregs(Context *r) runtime·printf("gs %x\n", r->SegGs); } -#define DBG_PRINTEXCEPTION_C 0x40010006 - // Called by sigtramp from Windows VEH handler. // Return value signals whether the exception has been handled (-1) // or should be made available to other handlers in the chain (0). @@ -36,19 +34,6 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) uintptr *sp; extern byte runtime·text[], runtime·etext[]; - if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) { - // This exception is intended to be caught by debuggers. - // There is a not-very-informational message like - // "Invalid parameter passed to C runtime function" - // sitting at info->ExceptionInformation[0] (a wchar_t*), - // with length info->ExceptionInformation[1]. - // The default behavior is to ignore this exception, - // but somehow returning 0 here (meaning keep going) - // makes the program crash instead. Maybe Windows has no - // other handler registered? In any event, ignore it. - return -1; - } - // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c index d7b45c5b1d..261880d450 100644 --- a/src/runtime/os_windows_amd64.c +++ b/src/runtime/os_windows_amd64.c @@ -32,8 +32,6 @@ runtime·dumpregs(Context *r) runtime·printf("gs %X\n", (uint64)r->SegGs); } -#define DBG_PRINTEXCEPTION_C 0x40010006 - // Called by sigtramp from Windows VEH handler. // Return value signals whether the exception has been handled (-1) // or should be made available to other handlers in the chain (0). @@ -44,19 +42,6 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) uintptr *sp; extern byte runtime·text[], runtime·etext[]; - if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) { - // This exception is intended to be caught by debuggers. - // There is a not-very-informational message like - // "Invalid parameter passed to C runtime function" - // sitting at info->ExceptionInformation[0] (a wchar_t*), - // with length info->ExceptionInformation[1]. - // The default behavior is to ignore this exception, - // but somehow returning 0 here (meaning keep going) - // makes the program crash instead. Maybe Windows has no - // other handler registered? In any event, ignore it. - return -1; - } - // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index a828512188..9ed016ccc8 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -488,3 +488,9 @@ func TestRegisterClass(t *testing.T) { t.Fatalf("UnregisterClass failed: %v", err) } } + +func TestOutputDebugString(t *testing.T) { + d := GetDLL(t, "kernel32.dll") + p := syscall.StringToUTF16Ptr("testing OutputDebugString") + d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p))) +} From 5fdea3430aed2224a88efa764034ef2ee2b4ccb1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 21:43:09 -0400 Subject: [PATCH 140/430] runtime: revise TestSetPanicOnFault We can't assume all those addresses are unmapped. But at least one should be. What we're really testing is that the program doesn't crash. Fixes #8542. LGTM=iant R=golang-codereviews, iant, minux CC=golang-codereviews https://golang.org/cl/144120043 --- src/runtime/runtime_test.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go index cffc9f7d35..3c4075842b 100644 --- a/src/runtime/runtime_test.go +++ b/src/runtime/runtime_test.go @@ -157,8 +157,8 @@ var faultAddrs = []uint64{ // or else malformed. 0xffffffffffffffff, 0xfffffffffffff001, - // no 0xffffffffffff0001; 0xffff0001 is mapped for 32-bit user space on OS X - // no 0xfffffffffff00001; 0xfff00001 is mapped for 32-bit user space sometimes on Linux + 0xffffffffffff0001, + 0xfffffffffff00001, 0xffffffffff000001, 0xfffffffff0000001, 0xffffffff00000001, @@ -182,26 +182,33 @@ func TestSetPanicOnFault(t *testing.T) { old := debug.SetPanicOnFault(true) defer debug.SetPanicOnFault(old) + nfault := 0 for _, addr := range faultAddrs { - testSetPanicOnFault(t, uintptr(addr)) + testSetPanicOnFault(t, uintptr(addr), &nfault) + } + if nfault == 0 { + t.Fatalf("none of the addresses faulted") } } -func testSetPanicOnFault(t *testing.T, addr uintptr) { +func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) { if GOOS == "nacl" { t.Skip("nacl doesn't seem to fault on high addresses") } defer func() { - if err := recover(); err == nil { - t.Fatalf("did not find error in recover") + if err := recover(); err != nil { + *nfault++ } }() + // The read should fault, except that sometimes we hit + // addresses that have had C or kernel pages mapped there + // readable by user code. So just log the content. + // If no addresses fault, we'll fail the test. var p *int p = (*int)(unsafe.Pointer(addr)) - println(*p) - t.Fatalf("still here - should have faulted on address %#x", addr) + t.Logf("addr %#x: %#x\n", addr, *p) } func eqstring_generic(s1, s2 string) bool { From 54b63f06478d390d69fc826a16ab19dc6b5d5503 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 21:50:22 -0400 Subject: [PATCH 141/430] path/filepath: document that Glob ignores i/o errors Fixes #8008. LGTM=adg R=golang-codereviews, nightlyone, adg CC=golang-codereviews https://golang.org/cl/138630045 --- src/path/filepath/match.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go index a9bcc103c5..ecc07aa5da 100644 --- a/src/path/filepath/match.go +++ b/src/path/filepath/match.go @@ -228,6 +228,9 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { // as in Match. The pattern may describe hierarchical names such as // /usr/*/bin/ed (assuming the Separator is '/'). // +// Glob ignores file system errors such as I/O errors reading directories. +// The only possible returned error is ErrBadPattern, when pattern +// is malformed. func Glob(pattern string) (matches []string, err error) { if !hasMeta(pattern) { if _, err = os.Lstat(pattern); err != nil { @@ -283,10 +286,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) { } defer d.Close() - names, err := d.Readdirnames(-1) - if err != nil { - return - } + names, _ := d.Readdirnames(-1) sort.Strings(names) for _, n := range names { From 66795e8ba101fc20916196db6d343b0d927e7dd5 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 19 Sep 2014 02:02:21 +0000 Subject: [PATCH 142/430] runtime: fix GOARM<7 build Update #8690 If liblink determines that the host doesn't support TLS it replaces the MRC call with a BL runtime.tls_read_fallback. The problem is save_g doesn't expect anyone to make any BL calls and hasn't setup its own link register properly so when runtime.tls_read_fallback returns the LR points to save_g, not save_g's caller so the RET at the end of the function turns into an infinite loop. This fix is only a proof of concept, I think the real fix should go into liblink as its MRC substitution is not as transparent as expected. LGTM=rsc R=rsc, minux CC=golang-codereviews https://golang.org/cl/143050043 --- src/runtime/tls_arm.s | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s index 7a247ab195..039b013833 100644 --- a/src/runtime/tls_arm.s +++ b/src/runtime/tls_arm.s @@ -29,7 +29,13 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4 MOVW g, R0 // preserve R0 across call to setg<> RET #endif + // If the host does not support MRC the linker will replace it with + // a call to runtime.read_tls_fallback which jumps to __kuser_get_tls. + // Both functions are written to only disturb R0 so it should be safe to + // use R11 here to temporarily store LR. + MOVW LR, R11 MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer + MOVW R11, LR // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g. @@ -51,7 +57,10 @@ TEXT runtime·load_g(SB),NOSPLIT,$0 // nothing to do as nacl/arm does not use TLS at all. RET #endif + // See comment in save_g. + MOVW LR, R11 MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer + MOVW R11, LR // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g. From 88d53ddb17d985693b2b5f065286d2647e4cb72d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 22:33:49 -0400 Subject: [PATCH 143/430] runtime: release Windows thread handle in unminit Fixes #8517. LGTM=dvyukov, alex.brainman R=golang-codereviews, dvyukov, alex.brainman CC=golang-codereviews https://golang.org/cl/145890044 --- src/runtime/os_windows.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 6c8f137ee5..62d94b65a0 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -278,6 +278,8 @@ runtime·minit(void) void runtime·unminit(void) { + runtime·stdcall1(runtime·CloseHandle, (uintptr)g->m->thread); + g->m->thread = nil; } // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ From a07a57b00ec9fdd8f6b02360d39454859709d08a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 23:07:36 -0400 Subject: [PATCH 144/430] syscall: mark ECONNRESET, ECONNABORTED as temporary network errors Fixes #6163. LGTM=adg R=golang-codereviews, adg, dvyukov CC=golang-codereviews https://golang.org/cl/141600043 --- src/syscall/syscall_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index f18dfca5e6..a06bd7dd08 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -109,7 +109,7 @@ func (e Errno) Error() string { } func (e Errno) Temporary() bool { - return e == EINTR || e == EMFILE || e.Timeout() + return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout() } func (e Errno) Timeout() bool { From c7f6bd795acf002d60f712f0f4e2701051e74e4a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 18 Sep 2014 23:51:22 -0400 Subject: [PATCH 145/430] runtime: rename SchedType to SchedT CL 144940043 renamed it from Sched to SchedType to avoid a lowercasing conflict in the Go code with the variable named sched. We've been using just T resolve those conflicts, not Type. The FooType pattern is already taken for the kind-specific variants of the runtime Type structure: ChanType, MapType, and so on. SchedType isn't a Type. LGTM=bradfitz, khr R=khr, bradfitz CC=golang-codereviews https://golang.org/cl/145180043 --- src/runtime/proc.c | 2 +- src/runtime/runtime.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 860701ee58..3f4179d473 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -31,7 +31,7 @@ enum GoidCacheBatch = 16, }; -SchedType runtime·sched; +SchedT runtime·sched; int32 runtime·gomaxprocs; uint32 runtime·needextram; bool runtime·iscgo; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 386b09b96b..7fefbc2997 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -60,7 +60,7 @@ typedef struct SudoG SudoG; typedef struct Mutex Mutex; typedef struct M M; typedef struct P P; -typedef struct SchedType SchedType; +typedef struct SchedT SchedT; typedef struct Note Note; typedef struct Slice Slice; typedef struct String String; @@ -434,7 +434,7 @@ enum { MaxGomaxprocs = 1<<8, }; -struct SchedType +struct SchedT { Mutex lock; @@ -753,7 +753,7 @@ extern DebugVars runtime·debug; extern uintptr runtime·maxstacksize; extern Note runtime·signote; extern ForceGCState runtime·forcegc; -extern SchedType runtime·sched; +extern SchedT runtime·sched; extern int32 runtime·newprocs; /* From 0c47bd1e61ab09e04572170f839297cb8ce97a5c Mon Sep 17 00:00:00 2001 From: John Tuley Date: Fri, 19 Sep 2014 11:28:38 -0400 Subject: [PATCH 146/430] net/http: ensured that proxy errors are returned by Transport.RoundTrip. Fixes #8755. LGTM=bradfitz R=bradfitz CC=golang-codereviews, jtuley https://golang.org/cl/136710044 --- src/net/http/transport.go | 2 +- src/net/http/transport_test.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 527ed8bdd1..f1aab8587c 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -316,7 +316,7 @@ func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectM if t.Proxy != nil { cm.proxyURL, err = t.Proxy(treq.Request) } - return cm, nil + return cm, err } // proxyAuth returns the Proxy-Authorization header to set diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 3460d690e3..bdfeba3626 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2136,6 +2136,24 @@ func TestTransportDialTLS(t *testing.T) { } } +// Test for issue 8755 +// Ensure that if a proxy returns an error, it is exposed by RoundTrip +func TestRoundTripReturnsProxyError(t *testing.T) { + badProxy := func(*http.Request) (*url.URL, error) { + return nil, errors.New("errorMessage") + } + + tr := &Transport{Proxy: badProxy} + + req, _ := http.NewRequest("GET", "http://example.com", nil) + + _, err := tr.RoundTrip(req) + + if err == nil { + t.Error("Expected proxy error to be returned by RoundTrip") + } +} + func wantBody(res *http.Response, err error, want string) error { if err != nil { return err From 182d1316dd975f426451cee34ba2e3e0953e084f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Sep 2014 13:51:06 -0400 Subject: [PATCH 147/430] cmd/go, testing: add TestMain support Fixes #8202. LGTM=r, bradfitz R=r, josharian, bradfitz CC=golang-codereviews https://golang.org/cl/148770043 --- doc/go1.4.txt | 1 + src/cmd/go/test.go | 46 ++++++++++++++++++++++++++++-- src/testing/testing.go | 56 +++++++++++++++++++++++++++++++++---- src/testing/testing_test.go | 18 ++++++++++++ 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 src/testing/testing_test.go diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 6180bc5b92..f46ef48f5d 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -32,6 +32,7 @@ sync/atomic: add Value (CL 136710045) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) syscall: now frozen (CL 129820043) testing: add Coverage (CL 98150043) +testing: add TestMain support (CL 148770043) text/scanner: add IsIdentRune field of Scanner. (CL 108030044) time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046) encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045). diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index a602469e44..e990b17bfa 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -6,6 +6,7 @@ package main import ( "bytes" + "errors" "fmt" "go/ast" "go/build" @@ -291,6 +292,7 @@ var testMainDeps = map[string]bool{ // Dependencies for testmain. "testing": true, "regexp": true, + "os": true, } func runTest(cmd *Command, args []string) { @@ -687,7 +689,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, omitDWARF: !testC && !testNeedBinary, } - // The generated main also imports testing and regexp. + // The generated main also imports testing, regexp, and os. stk.push("testmain") for dep := range testMainDeps { if dep == ptest.ImportPath { @@ -1057,6 +1059,31 @@ func (b *builder) notest(a *action) error { return nil } +// isTestMain tells whether fn is a TestMain(m *testing.Main) function. +func isTestMain(fn *ast.FuncDecl) bool { + if fn.Name.String() != "TestMain" || + fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || + fn.Type.Params == nil || + len(fn.Type.Params.List) != 1 || + len(fn.Type.Params.List[0].Names) > 1 { + return false + } + ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr) + if !ok { + return false + } + // We can't easily check that the type is *testing.M + // because we don't know how testing has been imported, + // but at least check that it's *M or *something.M. + if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" { + return true + } + if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" { + return true + } + return false +} + // isTest tells whether name looks like a test (or benchmark, according to prefix). // It is a Test (say) if there is a character after Test that is not a lower-case letter. // We don't want TesticularCancer. @@ -1113,6 +1140,7 @@ type testFuncs struct { Tests []testFunc Benchmarks []testFunc Examples []testFunc + TestMain *testFunc Package *Package ImportTest bool NeedTest bool @@ -1168,6 +1196,12 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { } name := n.Name.String() switch { + case isTestMain(n): + if t.TestMain != nil { + return errors.New("multiple definitions of TestMain") + } + t.TestMain = &testFunc{pkg, name, ""} + *doImport, *seen = true, true case isTest(name, "Test"): t.Tests = append(t.Tests, testFunc{pkg, name, ""}) *doImport, *seen = true, true @@ -1200,6 +1234,9 @@ var testmainTmpl = template.Must(template.New("main").Parse(` package main import ( +{{if not .TestMain}} + "os" +{{end}} "regexp" "testing" @@ -1294,7 +1331,12 @@ func main() { CoveredPackages: {{printf "%q" .Covered}}, }) {{end}} - testing.Main(matchString, tests, benchmarks, examples) + m := testing.MainStart(matchString, tests, benchmarks, examples) +{{with .TestMain}} + {{.Package}}.{{.Name}}(m) +{{else}} + os.Exit(m.Run()) +{{end}} } `)) diff --git a/src/testing/testing.go b/src/testing/testing.go index 731762cb1d..21460b0ed4 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -117,6 +117,26 @@ // The entire test file is presented as the example when it contains a single // example function, at least one other function, type, variable, or constant // declaration, and no test or benchmark functions. +// +// Main +// +// It is sometimes necessary for a test program to do extra setup or teardown +// before or after testing. It is also sometimes necessary for a test to control +// which code runs on the main thread. To support these and other cases, +// if a test file contains a function: +// +// func TestMain(m *testing.M) +// +// then the generated test will call TestMain(m) instead of running the tests +// directly. TestMain runs in the main goroutine and can do whatever setup +// and teardown is necessary around a call to m.Run. It should then call +// os.Exit with the result of m.Run. +// +// The minimal implementation of TestMain is: +// +// func TestMain(m *testing.M) { os.Exit(m.Run()) } +// +// In effect, that is the implementation used when no TestMain is explicitly defined. package testing import ( @@ -431,23 +451,49 @@ func tRunner(t *T, test *InternalTest) { // An internal function but exported because it is cross-package; part of the implementation // of the "go test" command. func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) { + os.Exit(MainStart(matchString, tests, benchmarks, examples).Run()) +} + +// M is a type passed to a TestMain function to run the actual tests. +type M struct { + matchString func(pat, str string) (bool, error) + tests []InternalTest + benchmarks []InternalBenchmark + examples []InternalExample +} + +// MainStart is meant for use by tests generated by 'go test'. +// It is not meant to be called directly and is not subject to the Go 1 compatibility document. +// It may change signature from release to release. +func MainStart(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M { + return &M{ + matchString: matchString, + tests: tests, + benchmarks: benchmarks, + examples: examples, + } +} + +// Run runs the tests. It returns an exit code to pass to os.Exit. +func (m *M) Run() int { flag.Parse() parseCpuList() before() startAlarm() - haveExamples = len(examples) > 0 - testOk := RunTests(matchString, tests) - exampleOk := RunExamples(matchString, examples) + haveExamples = len(m.examples) > 0 + testOk := RunTests(m.matchString, m.tests) + exampleOk := RunExamples(m.matchString, m.examples) stopAlarm() if !testOk || !exampleOk { fmt.Println("FAIL") after() - os.Exit(1) + return 1 } fmt.Println("PASS") - RunBenchmarks(matchString, benchmarks) + RunBenchmarks(m.matchString, m.benchmarks) after() + return 0 } func (t *T) report() { diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go new file mode 100644 index 0000000000..87a5c16d6e --- /dev/null +++ b/src/testing/testing_test.go @@ -0,0 +1,18 @@ +// 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 testing_test + +import ( + "os" + "testing" +) + +// This is exactly what a test would do without a TestMain. +// It's here only so that there is at least one package in the +// standard library with a TestMain, so that code is executed. + +func TestMain(m *testing.M) { + os.Exit(m.Run()) +} From 5c795632d658003bdc193b0441137385950bca54 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Sep 2014 13:51:23 -0400 Subject: [PATCH 148/430] =?UTF-8?q?runtime:=20add=20runtime=C2=B7=20prefix?= =?UTF-8?q?=20to=20some=20static=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure renaming. This will make an upcoming CL have smaller diffs. LGTM=dvyukov, iant R=iant, dvyukov CC=golang-codereviews https://golang.org/cl/142280043 --- src/runtime/mcache.c | 10 ++-- src/runtime/mgc0.c | 112 +++++++++++++++++++++---------------------- src/runtime/stack.c | 30 ++++++------ 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/runtime/mcache.c b/src/runtime/mcache.c index bb1fc54032..17ea5d2e26 100644 --- a/src/runtime/mcache.c +++ b/src/runtime/mcache.c @@ -13,7 +13,7 @@ extern volatile intgo runtime·MemProfileRate; // dummy MSpan that contains no free objects. -static MSpan emptymspan; +static MSpan runtime·emptymspan; MCache* runtime·allocmcache(void) @@ -27,7 +27,7 @@ runtime·allocmcache(void) runtime·unlock(&runtime·mheap.lock); runtime·memclr((byte*)c, sizeof(*c)); for(i = 0; i < NumSizeClasses; i++) - c->alloc[i] = &emptymspan; + c->alloc[i] = &runtime·emptymspan; // Set first allocation sample size. rate = runtime·MemProfileRate; @@ -83,7 +83,7 @@ runtime·MCache_Refill(MCache *c, int32 sizeclass) s = c->alloc[sizeclass]; if(s->freelist != nil) runtime·throw("refill on a nonempty span"); - if(s != &emptymspan) + if(s != &runtime·emptymspan) s->incache = false; // Get a new cached span from the central lists. @@ -107,9 +107,9 @@ runtime·MCache_ReleaseAll(MCache *c) for(i=0; ialloc[i]; - if(s != &emptymspan) { + if(s != &runtime·emptymspan) { runtime·MCentral_UncacheSpan(&runtime·mheap.central[i].mcentral, s); - c->alloc[i] = &emptymspan; + c->alloc[i] = &runtime·emptymspan; } } } diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 88c8d0f3c9..03ca288496 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -120,7 +120,7 @@ FinBlock* runtime·finc; // cache of free blocks static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte]; bool runtime·fingwait; bool runtime·fingwake; -static FinBlock *allfin; // list of all blocks +static FinBlock *runtime·allfin; // list of all blocks BitVector runtime·gcdatamask; BitVector runtime·gcbssmask; @@ -154,7 +154,7 @@ static struct { // Copy of mheap.allspans for marker or sweeper. MSpan** spans; uint32 nspan; -} work; +} runtime·work; // scanblock scans a block of n bytes starting at pointer b for references // to other objects, scanning any it finds recursively until there are no @@ -225,7 +225,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) } // If another proc wants a pointer, give it some. - if(work.nwait > 0 && nobj > 4 && work.full == 0) { + if(runtime·work.nwait > 0 && nobj > 4 && runtime·work.full == 0) { wbuf->nobj = nobj; wbuf = handoff(wbuf); nobj = wbuf->nobj; @@ -369,7 +369,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) // quadruple is already marked. Otherwise we resort to CAS // loop for marking. if((xbits&(bitMask|(bitMask<alllink) + for(fb=runtime·allfin; fb; fb=fb->alllink) scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), finptrmask); break; case RootSpans: // mark MSpan.specials sg = runtime·mheap.sweepgen; - for(spanidx=0; spanidxstate != MSpanInUse) continue; if(s->sweepgen != sg) { @@ -479,7 +479,7 @@ markroot(ParFor *desc, uint32 i) // needed only to output in traceback status = runtime·readgstatus(gp); if((status == Gwaiting || status == Gsyscall) && gp->waitsince == 0) - gp->waitsince = work.tstart; + gp->waitsince = runtime·work.tstart; // Shrink a stack if not much of it is being used. runtime·shrinkstack(gp); if(runtime·readgstatus(gp) == Gdead) @@ -502,7 +502,7 @@ getempty(Workbuf *b) MCache *c; if(b != nil) - runtime·lfstackpush(&work.full, &b->node); + runtime·lfstackpush(&runtime·work.full, &b->node); b = nil; c = g->m->mcache; if(c->gcworkbuf != nil) { @@ -510,7 +510,7 @@ getempty(Workbuf *b) c->gcworkbuf = nil; } if(b == nil) - b = (Workbuf*)runtime·lfstackpop(&work.empty); + b = (Workbuf*)runtime·lfstackpop(&runtime·work.empty); if(b == nil) b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys); b->nobj = 0; @@ -527,7 +527,7 @@ putempty(Workbuf *b) c->gcworkbuf = b; return; } - runtime·lfstackpush(&work.empty, &b->node); + runtime·lfstackpush(&runtime·work.empty, &b->node); } void @@ -544,21 +544,21 @@ getfull(Workbuf *b) int32 i; if(b != nil) - runtime·lfstackpush(&work.empty, &b->node); - b = (Workbuf*)runtime·lfstackpop(&work.full); - if(b != nil || work.nproc == 1) + runtime·lfstackpush(&runtime·work.empty, &b->node); + b = (Workbuf*)runtime·lfstackpop(&runtime·work.full); + if(b != nil || runtime·work.nproc == 1) return b; - runtime·xadd(&work.nwait, +1); + runtime·xadd(&runtime·work.nwait, +1); for(i=0;; i++) { - if(work.full != 0) { - runtime·xadd(&work.nwait, -1); - b = (Workbuf*)runtime·lfstackpop(&work.full); + if(runtime·work.full != 0) { + runtime·xadd(&runtime·work.nwait, -1); + b = (Workbuf*)runtime·lfstackpop(&runtime·work.full); if(b != nil) return b; - runtime·xadd(&work.nwait, +1); + runtime·xadd(&runtime·work.nwait, +1); } - if(work.nwait == work.nproc) + if(runtime·work.nwait == runtime·work.nproc) return nil; if(i < 10) { g->m->gcstats.nprocyield++; @@ -589,7 +589,7 @@ handoff(Workbuf *b) g->m->gcstats.nhandoffcnt += n; // Put b on full list - let first half of b get stolen. - runtime·lfstackpush(&work.full, &b->node); + runtime·lfstackpush(&runtime·work.full, &b->node); return b1; } @@ -773,8 +773,8 @@ runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType if(runtime·finc == nil) { runtime·finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys); runtime·finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1; - runtime·finc->alllink = allfin; - allfin = runtime·finc; + runtime·finc->alllink = runtime·allfin; + runtime·allfin = runtime·finc; if(finptrmask[0] == 0) { // Build pointer mask for Finalizer array in block. // Check assumptions made in finalizer1 array above. @@ -814,7 +814,7 @@ runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType* Finalizer *f; uintptr i; - for(fb = allfin; fb; fb = fb->alllink) { + for(fb = runtime·allfin; fb; fb = fb->alllink) { for(i = 0; i < fb->cnt; i++) { f = &fb->fin[i]; callback(f->fn, f->arg, f->nret, f->fint, f->ot); @@ -1065,12 +1065,12 @@ runtime·sweepone(void) sg = runtime·mheap.sweepgen; for(;;) { idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1; - if(idx >= work.nspan) { + if(idx >= runtime·work.nspan) { runtime·mheap.sweepdone = true; g->m->locks--; return -1; } - s = work.spans[idx]; + s = runtime·work.spans[idx]; if(s->state != MSpanInUse) { s->sweepgen = sg; continue; @@ -1118,14 +1118,14 @@ runtime·gchelper(void) gchelperstart(); // parallel mark for over gc roots - runtime·parfordo(work.markfor); + runtime·parfordo(runtime·work.markfor); // help other threads scan secondary blocks scanblock(nil, 0, nil); - nproc = work.nproc; // work.nproc can change right after we increment work.ndone - if(runtime·xadd(&work.ndone, +1) == nproc-1) - runtime·notewakeup(&work.alldone); + nproc = runtime·work.nproc; // runtime·work.nproc can change right after we increment runtime·work.ndone + if(runtime·xadd(&runtime·work.ndone, +1) == nproc-1) + runtime·notewakeup(&runtime·work.alldone); g->m->traceback = 0; } @@ -1284,7 +1284,7 @@ runtime·gcinit(void) if(sizeof(Workbuf) != WorkbufSize) runtime·throw("runtime: size of Workbuf is suboptimal"); - work.markfor = runtime·parforalloc(MaxGcproc); + runtime·work.markfor = runtime·parforalloc(MaxGcproc); runtime·gcpercent = runtime·readgogc(); runtime·gcdatamask = unrollglobgcprog(runtime·gcdata, runtime·edata - runtime·data); runtime·gcbssmask = unrollglobgcprog(runtime·gcbss, runtime·ebss - runtime·bss); @@ -1319,7 +1319,7 @@ gc(struct gc_args *args) g->m->traceback = 2; t0 = args->start_time; - work.tstart = args->start_time; + runtime·work.tstart = args->start_time; t1 = 0; if(runtime·debug.gctrace) @@ -1339,21 +1339,21 @@ gc(struct gc_args *args) // Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap. runtime·lock(&runtime·mheap.lock); // Free the old cached sweep array if necessary. - if(work.spans != nil && work.spans != runtime·mheap.allspans) - runtime·SysFree(work.spans, work.nspan*sizeof(work.spans[0]), &mstats.other_sys); + if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans) + runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys); // Cache the current array for marking. runtime·mheap.gcspans = runtime·mheap.allspans; - work.spans = runtime·mheap.allspans; - work.nspan = runtime·mheap.nspan; + runtime·work.spans = runtime·mheap.allspans; + runtime·work.nspan = runtime·mheap.nspan; runtime·unlock(&runtime·mheap.lock); - work.nwait = 0; - work.ndone = 0; - work.nproc = runtime·gcprocs(); - runtime·parforsetup(work.markfor, work.nproc, RootCount + runtime·allglen, nil, false, markroot); - if(work.nproc > 1) { - runtime·noteclear(&work.alldone); - runtime·helpgc(work.nproc); + runtime·work.nwait = 0; + runtime·work.ndone = 0; + runtime·work.nproc = runtime·gcprocs(); + runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + runtime·allglen, nil, false, markroot); + if(runtime·work.nproc > 1) { + runtime·noteclear(&runtime·work.alldone); + runtime·helpgc(runtime·work.nproc); } t2 = 0; @@ -1361,15 +1361,15 @@ gc(struct gc_args *args) t2 = runtime·nanotime(); gchelperstart(); - runtime·parfordo(work.markfor); + runtime·parfordo(runtime·work.markfor); scanblock(nil, 0, nil); t3 = 0; if(runtime·debug.gctrace) t3 = runtime·nanotime(); - if(work.nproc > 1) - runtime·notesleep(&work.alldone); + if(runtime·work.nproc > 1) + runtime·notesleep(&runtime·work.alldone); cachestats(); // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap @@ -1396,21 +1396,21 @@ gc(struct gc_args *args) } obj = mstats.nmalloc - mstats.nfree; - stats.nprocyield += work.markfor->nprocyield; - stats.nosyield += work.markfor->nosyield; - stats.nsleep += work.markfor->nsleep; + stats.nprocyield += runtime·work.markfor->nprocyield; + stats.nosyield += runtime·work.markfor->nosyield; + stats.nsleep += runtime·work.markfor->nsleep; runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects," " %d goroutines," " %d/%d/%d sweeps," " %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n", - mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000, + mstats.numgc, runtime·work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000, heap0>>20, heap1>>20, obj, mstats.nmalloc, mstats.nfree, runtime·gcount(), - work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep, + runtime·work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep, stats.nhandoff, stats.nhandoffcnt, - work.markfor->nsteal, work.markfor->nstealcnt, + runtime·work.markfor->nsteal, runtime·work.markfor->nstealcnt, stats.nprocyield, stats.nosyield, stats.nsleep); runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0; } @@ -1419,14 +1419,14 @@ gc(struct gc_args *args) // Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap. runtime·lock(&runtime·mheap.lock); // Free the old cached mark array if necessary. - if(work.spans != nil && work.spans != runtime·mheap.allspans) - runtime·SysFree(work.spans, work.nspan*sizeof(work.spans[0]), &mstats.other_sys); + if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans) + runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys); // Cache the current array for sweeping. runtime·mheap.gcspans = runtime·mheap.allspans; runtime·mheap.sweepgen += 2; runtime·mheap.sweepdone = false; - work.spans = runtime·mheap.allspans; - work.nspan = runtime·mheap.nspan; + runtime·work.spans = runtime·mheap.allspans; + runtime·work.nspan = runtime·mheap.nspan; runtime·sweep.spanidx = 0; runtime·unlock(&runtime·mheap.lock); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 95a5a123d9..6fbab8fb6e 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -32,8 +32,8 @@ enum // Stacks are assigned an order according to size. // order = log_2(size/FixedStack) // There is a free list for each order. -static MSpan stackpool[NumStackOrders]; -static Mutex stackpoolmu; +static MSpan runtime·stackpool[NumStackOrders]; +static Mutex runtime·stackpoolmu; // TODO: one lock per order? void @@ -45,7 +45,7 @@ runtime·stackinit(void) runtime·throw("cache size must be a multiple of page size"); for(i = 0; i < NumStackOrders; i++) - runtime·MSpanList_Init(&stackpool[i]); + runtime·MSpanList_Init(&runtime·stackpool[i]); } // Allocates a stack from the free pool. Must be called with @@ -58,7 +58,7 @@ poolalloc(uint8 order) MLink *x; uintptr i; - list = &stackpool[order]; + list = &runtime·stackpool[order]; s = list->next; if(s == list) { // no free stacks. Allocate another span worth. @@ -99,7 +99,7 @@ poolfree(MLink *x, uint8 order) runtime·throw("freeing stack not in a stack span"); if(s->freelist == nil) { // s will now have a free stack - runtime·MSpanList_Insert(&stackpool[order], s); + runtime·MSpanList_Insert(&runtime·stackpool[order], s); } x->next = s->freelist; s->freelist = x; @@ -127,14 +127,14 @@ stackcacherefill(MCache *c, uint8 order) // Grab half of the allowed capacity (to prevent thrashing). list = nil; size = 0; - runtime·lock(&stackpoolmu); + runtime·lock(&runtime·stackpoolmu); while(size < StackCacheSize/2) { x = poolalloc(order); x->next = list; list = x; size += FixedStack << order; } - runtime·unlock(&stackpoolmu); + runtime·unlock(&runtime·stackpoolmu); c->stackcache[order].list = list; c->stackcache[order].size = size; @@ -150,14 +150,14 @@ stackcacherelease(MCache *c, uint8 order) runtime·printf("stackcacherelease order=%d\n", order); x = c->stackcache[order].list; size = c->stackcache[order].size; - runtime·lock(&stackpoolmu); + runtime·lock(&runtime·stackpoolmu); while(size > StackCacheSize/2) { y = x->next; poolfree(x, order); x = y; size -= FixedStack << order; } - runtime·unlock(&stackpoolmu); + runtime·unlock(&runtime·stackpoolmu); c->stackcache[order].list = x; c->stackcache[order].size = size; } @@ -170,7 +170,7 @@ runtime·stackcache_clear(MCache *c) if(StackDebug >= 1) runtime·printf("stackcache clear\n"); - runtime·lock(&stackpoolmu); + runtime·lock(&runtime·stackpoolmu); for(order = 0; order < NumStackOrders; order++) { x = c->stackcache[order].list; while(x != nil) { @@ -181,7 +181,7 @@ runtime·stackcache_clear(MCache *c) c->stackcache[order].list = nil; c->stackcache[order].size = 0; } - runtime·unlock(&stackpoolmu); + runtime·unlock(&runtime·stackpoolmu); } Stack @@ -227,9 +227,9 @@ runtime·stackalloc(uint32 n) // procresize. Just get a stack from the global pool. // Also don't touch stackcache during gc // as it's flushed concurrently. - runtime·lock(&stackpoolmu); + runtime·lock(&runtime·stackpoolmu); x = poolalloc(order); - runtime·unlock(&stackpoolmu); + runtime·unlock(&runtime·stackpoolmu); } else { x = c->stackcache[order].list; if(x == nil) { @@ -289,9 +289,9 @@ runtime·stackfree(Stack stk) x = (MLink*)v; c = g->m->mcache; if(c == nil || g->m->gcing || g->m->helpgc) { - runtime·lock(&stackpoolmu); + runtime·lock(&runtime·stackpoolmu); poolfree(x, order); - runtime·unlock(&stackpoolmu); + runtime·unlock(&runtime·stackpoolmu); } else { if(c->stackcache[order].size >= StackCacheSize) stackcacherelease(c, order); From 2c15d45131bbad55c710427a2ea5a1b383e9811c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Sep 2014 13:53:33 -0400 Subject: [PATCH 149/430] net/http: document server recovering panics Fixes #8594. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/145760043 --- src/net/http/server.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/net/http/server.go b/src/net/http/server.go index 203037e9f5..8f2b777b29 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -42,6 +42,12 @@ var ( // and then return. Returning signals that the request is finished // and that the HTTP server can move on to the next request on // the connection. +// +// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes +// that the effect of the panic was isolated to the active request. +// It recovers the panic, logs a stack trace to the server error log, +// and hangs up the connection. +// type Handler interface { ServeHTTP(ResponseWriter, *Request) } From 0e1a07167b2ba0e71487feea8e2e20a2e29fdf3a Mon Sep 17 00:00:00 2001 From: Sameer Ajmani Date: Fri, 19 Sep 2014 15:59:47 -0400 Subject: [PATCH 150/430] cmd/go: fix typo LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/138700043 --- src/cmd/go/test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index e990b17bfa..c135b89c84 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -49,7 +49,7 @@ It prints a summary of the test results in the format: followed by detailed output for each failed package. 'Go test' recompiles each package along with any files with names matching -the file pattern "*_test.go". +the file pattern "*_test.go". Files whose names begin with "_" (including "_test.go") or "." are ignored. These additional files can contain test functions, benchmark functions, and example functions. See 'go help testfunc' for more. @@ -1059,7 +1059,7 @@ func (b *builder) notest(a *action) error { return nil } -// isTestMain tells whether fn is a TestMain(m *testing.Main) function. +// isTestMain tells whether fn is a TestMain(m *testing.M) function. func isTestMain(fn *ast.FuncDecl) bool { if fn.Name.String() != "TestMain" || fn.Type.Results != nil && len(fn.Type.Results.List) > 0 || From b4eb22d76457bacc1b4131a31f9ae369a5f8f177 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 19 Sep 2014 13:32:07 -0700 Subject: [PATCH 151/430] spec: clarify panic behavior when deferring nil functions Fixes #8107. LGTM=iant, rsc, r R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/145960043 --- doc/go_spec.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e8bb35f0b0..da1e2a5d24 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -5243,13 +5243,16 @@ Calls of built-in functions are restricted as for

-Each time the "defer" statement +Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual -and saved anew but the actual function body is not executed. -Instead, deferred functions are executed immediately before +and saved anew but the actual function is not invoked. +Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred. +If a deferred function value evaluates +to nil, execution panics +when the function is invoked not when the "defer" statement is executed.

From 651bb8e026f94502ed45db1b6284eeddd74570dc Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 19 Sep 2014 14:13:51 -0700 Subject: [PATCH 152/430] spec: add dropped comma The proposed text in the last CL had a comma that was missing from the submitted spec. LGTM=gri R=gri CC=golang-codereviews https://golang.org/cl/150720043 --- doc/go_spec.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index da1e2a5d24..7d86ca863a 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -5252,7 +5252,7 @@ the surrounding function returns, in the reverse order they were deferred. If a deferred function value evaluates to nil, execution panics -when the function is invoked not when the "defer" statement is executed. +when the function is invoked, not when the "defer" statement is executed.

From 0306478fe57767530164b43c12969ca91496db47 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 19 Sep 2014 16:33:14 -0700 Subject: [PATCH 153/430] runtime: Fix interaction between Goexit and defers When running defers, we must check whether the defer has already been marked as started so we don't run it twice. Fixes #8774. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/142280044 --- src/runtime/crash_test.go | 88 +++++++++++++++++++++++++++++++++++++++ src/runtime/panic.go | 18 +++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index d1577fb5fe..783b4c48f5 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -412,3 +412,91 @@ func main() { runtime.Breakpoint() } ` + +func TestGoexitInPanic(t *testing.T) { + // see issue 8774: this code used to trigger an infinite recursion + output := executeTest(t, goexitInPanicSource, nil) + want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +const goexitInPanicSource = ` +package main +import "runtime" +func main() { + go func() { + defer func() { + runtime.Goexit() + }() + panic("hello") + }() + runtime.Goexit() +} +` + +func TestPanicAfterGoexit(t *testing.T) { + // an uncaught panic should still work after goexit + output := executeTest(t, panicAfterGoexitSource, nil) + want := "panic: hello" + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +const panicAfterGoexitSource = ` +package main +import "runtime" +func main() { + defer func() { + panic("hello") + }() + runtime.Goexit() +} +` + +func TestRecoveredPanicAfterGoexit(t *testing.T) { + output := executeTest(t, recoveredPanicAfterGoexitSource, nil) + want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!" + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +const recoveredPanicAfterGoexitSource = ` +package main +import "runtime" +func main() { + defer func() { + defer func() { + r := recover() + if r == nil { + panic("bad recover") + } + }() + panic("hello") + }() + runtime.Goexit() +} +` + +func TestRecoverBeforePanicAfterGoexit(t *testing.T) { + // 1. defer a function that recovers + // 2. defer a function that panics + // 3. call goexit + // Goexit should run the #2 defer. Its panic + // should be caught by the #1 defer, and execution + // should resume in the caller. Like the Goexit + // never happened! + defer func() { + r := recover() + if r == nil { + panic("bad recover") + } + }() + defer func() { + panic("hello") + }() + runtime.Goexit() +} diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 3cc31053e8..7eb2d6055a 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -247,11 +247,27 @@ func deferreturn(arg0 uintptr) { // If all other goroutines exit, the program crashes. func Goexit() { // Run all deferred functions for the current goroutine. + // This code is similar to gopanic, see that implementation + // for detailed comments. gp := getg() - for gp._defer != nil { + for { d := gp._defer + if d == nil { + break + } + if d.started { + if d._panic != nil { + d._panic.aborted = true + } + gp._defer = d.link + freedefer(d) + continue + } d.started = true reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) + if gp._defer != d { + gothrow("bad defer entry in Goexit") + } gp._defer = d.link freedefer(d) // Note: we ignore recovers here because Goexit isn't a panic From 3b2577ced39194fdd2f1359136c7e176d8de5576 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 20 Sep 2014 23:31:11 -0700 Subject: [PATCH 154/430] runtime: be very careful with bad pointer tests Saw this on a test: runtime: bad pointer in frame runtime_test.testSetPanicOnFault at 0xc20801c6b0: 0xfff fatal error: bad pointer! runtime stack: ... copystack(0xc2081bf7a0, 0x1000) /root/work/solaris-amd64-smartos-2dde8b453d26/go/src/runtime/stack.c:621 +0x173 fp=0xfffffd7ffd5ffee0 sp=0xfffffd7ffd5ffe20 runtime.newstack() /root/work/solaris-amd64-smartos-2dde8b453d26/go/src/runtime/stack.c:774 +0x552 fp=0xfffffd7ffd5fff90 sp=0xfffffd7ffd5ffee0 runtime.morestack() /root/work/solaris-amd64-smartos-2dde8b453d26/go/src/runtime/asm_amd64.s:324 +0x90 fp=0xfffffd7ffd5fff98 sp=0xfffffd7ffd5fff90 goroutine 163354 [stack growth]: ... runtime.convT2E(0x587000, 0xc20807bea8, 0x0, 0x0) /root/work/solaris-amd64-smartos-2dde8b453d26/go/src/runtime/iface.go:141 +0xd2 fp=0xc20801c678 sp=0xc20801c640 runtime_test.testSetPanicOnFault(0xc20822c510, 0xfff, 0xc20801c748) /root/work/solaris-amd64-smartos-2dde8b453d26/go/src/runtime/runtime_test.go:211 +0xc6 fp=0xc20801c718 sp=0xc20801c678 ... This test is testing bad pointers. It loads the bad pointer into a pointer variable, but before it gets a chance to dereference it, calls convT2E. That call causes a stack copy, which exposes that live but bad pointer variable. LGTM=dvyukov R=golang-codereviews, dvyukov CC=golang-codereviews https://golang.org/cl/146880043 --- src/runtime/runtime_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go index 3c4075842b..1688364a8e 100644 --- a/src/runtime/runtime_test.go +++ b/src/runtime/runtime_test.go @@ -206,9 +206,8 @@ func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) { // addresses that have had C or kernel pages mapped there // readable by user code. So just log the content. // If no addresses fault, we'll fail the test. - var p *int - p = (*int)(unsafe.Pointer(addr)) - t.Logf("addr %#x: %#x\n", addr, *p) + v := *(*byte)(unsafe.Pointer(addr)) + t.Logf("addr %#x: %#x\n", addr, v) } func eqstring_generic(s1, s2 string) bool { From 0be3176a8bc394f5234a2665843b5490e9095f46 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Mon, 22 Sep 2014 14:29:45 +1000 Subject: [PATCH 155/430] image/gif: don't let the per-frame transparent index modify the global palette. Fixes #7993. LGTM=r R=r CC=golang-codereviews, james.jdunne https://golang.org/cl/138600043 --- src/image/gif/reader.go | 7 +++- src/image/gif/reader_test.go | 64 +++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go index 926710a456..5a863e204f 100644 --- a/src/image/gif/reader.go +++ b/src/image/gif/reader.go @@ -171,7 +171,8 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { if err != nil { return err } - if d.imageFields&fColorMapFollows != 0 { + useLocalColorMap := d.imageFields&fColorMapFollows != 0 + if useLocalColorMap { m.Palette, err = d.readColorMap() if err != nil { return err @@ -180,6 +181,10 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { m.Palette = d.globalColorMap } if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) { + if !useLocalColorMap { + // Clone the global color map. + m.Palette = append(color.Palette(nil), d.globalColorMap...) + } m.Palette[d.transparentIndex] = color.RGBA{} } litWidth, err := d.r.ReadByte() diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go index fc2041e997..7b6f504367 100644 --- a/src/image/gif/reader_test.go +++ b/src/image/gif/reader_test.go @@ -22,16 +22,16 @@ const ( trailerStr = "\x3b" ) -func TestDecode(t *testing.T) { - // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. - lzwEncode := func(n int) []byte { - b := &bytes.Buffer{} - w := lzw.NewWriter(b, lzw.LSB, 2) - w.Write(make([]byte, n)) - w.Close() - return b.Bytes() - } +// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. +func lzwEncode(n int) []byte { + b := &bytes.Buffer{} + w := lzw.NewWriter(b, lzw.LSB, 2) + w.Write(make([]byte, n)) + w.Close() + return b.Bytes() +} +func TestDecode(t *testing.T) { testCases := []struct { nPix int // The number of pixels in the image data. extra bool // Whether to write an extra block after the LZW-encoded data. @@ -90,6 +90,52 @@ func TestDecode(t *testing.T) { } } +func TestTransparentIndex(t *testing.T) { + b := &bytes.Buffer{} + b.WriteString(headerStr) + b.WriteString(paletteStr) + for transparentIndex := 0; transparentIndex < 3; transparentIndex++ { + if transparentIndex < 2 { + // Write the graphic control for the transparent index. + b.WriteString("\x21\xf9\x00\x01\x00\x00") + b.WriteByte(byte(transparentIndex)) + b.WriteByte(0) + } + // Write an image with bounds 2x1, as per TestDecode. + b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") + enc := lzwEncode(2) + if len(enc) > 0xff { + t.Fatalf("compressed length %d is too large", len(enc)) + } + b.WriteByte(byte(len(enc))) + b.Write(enc) + b.WriteByte(0x00) + } + b.WriteString(trailerStr) + + g, err := DecodeAll(b) + if err != nil { + t.Fatalf("DecodeAll: %v", err) + } + c0 := color.RGBA{paletteStr[0], paletteStr[1], paletteStr[2], 0xff} + c1 := color.RGBA{paletteStr[3], paletteStr[4], paletteStr[5], 0xff} + cz := color.RGBA{} + wants := []color.Palette{ + {cz, c1}, + {c0, cz}, + {c0, c1}, + } + if len(g.Image) != len(wants) { + t.Fatalf("got %d images, want %d", len(g.Image), len(wants)) + } + for i, want := range wants { + got := g.Image[i].Palette + if !reflect.DeepEqual(got, want) { + t.Errorf("palette #%d:\ngot %v\nwant %v", i, got, want) + } + } +} + // testGIF is a simple GIF that we can modify to test different scenarios. var testGIF = []byte{ 'G', 'I', 'F', '8', '9', 'a', From 93e5cc224e3e5c6dfaad4fc835cc89e33fb957c6 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 22 Sep 2014 09:13:09 -0400 Subject: [PATCH 156/430] net/http: replace z_last_test hack with testing.Main LGTM=adg R=rsc, adg CC=golang-codereviews https://golang.org/cl/144240043 --- src/net/http/{z_last_test.go => main_test.go} | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) rename src/net/http/{z_last_test.go => main_test.go} (81%) diff --git a/src/net/http/z_last_test.go b/src/net/http/main_test.go similarity index 81% rename from src/net/http/z_last_test.go rename to src/net/http/main_test.go index 5a0cc11984..9f1dfc3727 100644 --- a/src/net/http/z_last_test.go +++ b/src/net/http/main_test.go @@ -5,7 +5,9 @@ package http_test import ( + "fmt" "net/http" + "os" "runtime" "sort" "strings" @@ -13,6 +15,14 @@ import ( "time" ) +func TestMain(m *testing.M) { + v := m.Run() + if v == 0 && goroutineLeaked() { + os.Exit(1) + } + os.Exit(v) +} + func interestingGoroutines() (gs []string) { buf := make([]byte, 2<<20) buf = buf[:runtime.Stack(buf, true)] @@ -30,6 +40,7 @@ func interestingGoroutines() (gs []string) { // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) strings.Contains(stack, "runtime.goexit") || strings.Contains(stack, "created by runtime.gc") || + strings.Contains(stack, "net/http_test.interestingGoroutines") || strings.Contains(stack, "runtime.MHeap_Scavenger") { continue } @@ -40,10 +51,10 @@ func interestingGoroutines() (gs []string) { } // Verify the other tests didn't leave any goroutines running. -// This is in a file named z_last_test.go so it sorts at the end. -func TestGoroutinesRunning(t *testing.T) { +func goroutineLeaked() bool { if testing.Short() { - t.Skip("not counting goroutines for leakage in -short mode") + // not counting goroutines for leakage in -short mode + return false } gs := interestingGoroutines() @@ -54,13 +65,14 @@ func TestGoroutinesRunning(t *testing.T) { n++ } - t.Logf("num goroutines = %d", n) - if n > 0 { - t.Error("Too many goroutines.") - for stack, count := range stackCount { - t.Logf("%d instances of:\n%s", count, stack) - } + if n == 0 { + return false } + fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") + for stack, count := range stackCount { + fmt.Fprintf(os.Stderr, "%d instances of:\n%s", count, stack) + } + return true } func afterTest(t *testing.T) { From 5f739d9dcd01730e10d829968755c7b1a7b5f2b7 Mon Sep 17 00:00:00 2001 From: Marko Tiikkaja Date: Mon, 22 Sep 2014 09:19:27 -0400 Subject: [PATCH 157/430] database/sql: Close per-tx prepared statements when the associated tx ends LGTM=bradfitz R=golang-codereviews, bradfitz, mattn.jp CC=golang-codereviews https://golang.org/cl/131650043 --- src/database/sql/sql.go | 41 +++++++++++++++++++++++++++++++----- src/database/sql/sql_test.go | 31 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 90f813d823..731b7a7f79 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -1043,6 +1043,13 @@ type Tx struct { // or Rollback. once done, all operations fail with // ErrTxDone. done bool + + // All Stmts prepared for this transaction. These will be closed after the + // transaction has been committed or rolled back. + stmts struct { + sync.Mutex + v []*Stmt + } } var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back") @@ -1064,6 +1071,15 @@ func (tx *Tx) grabConn() (*driverConn, error) { return tx.dc, nil } +// Closes all Stmts prepared for this transaction. +func (tx *Tx) closePrepared() { + tx.stmts.Lock() + for _, stmt := range tx.stmts.v { + stmt.Close() + } + tx.stmts.Unlock() +} + // Commit commits the transaction. func (tx *Tx) Commit() error { if tx.done { @@ -1071,8 +1087,12 @@ func (tx *Tx) Commit() error { } defer tx.close() tx.dc.Lock() - defer tx.dc.Unlock() - return tx.txi.Commit() + err := tx.txi.Commit() + tx.dc.Unlock() + if err != driver.ErrBadConn { + tx.closePrepared() + } + return err } // Rollback aborts the transaction. @@ -1082,8 +1102,12 @@ func (tx *Tx) Rollback() error { } defer tx.close() tx.dc.Lock() - defer tx.dc.Unlock() - return tx.txi.Rollback() + err := tx.txi.Rollback() + tx.dc.Unlock() + if err != driver.ErrBadConn { + tx.closePrepared() + } + return err } // Prepare creates a prepared statement for use within a transaction. @@ -1127,6 +1151,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { }, query: query, } + tx.stmts.Lock() + tx.stmts.v = append(tx.stmts.v, stmt) + tx.stmts.Unlock() return stmt, nil } @@ -1155,7 +1182,7 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt { dc.Lock() si, err := dc.ci.Prepare(stmt.query) dc.Unlock() - return &Stmt{ + txs := &Stmt{ db: tx.db, tx: tx, txsi: &driverStmt{ @@ -1165,6 +1192,10 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt { query: stmt.query, stickyErr: err, } + tx.stmts.Lock() + tx.stmts.v = append(tx.stmts.v, txs) + tx.stmts.Unlock() + return txs } // Exec executes a query that doesn't return rows. diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go index 12e5a6fd6f..34efdf254c 100644 --- a/src/database/sql/sql_test.go +++ b/src/database/sql/sql_test.go @@ -441,6 +441,33 @@ func TestExec(t *testing.T) { } } +func TestTxPrepare(t *testing.T) { + db := newTestDB(t, "") + defer closeDB(t, db) + exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") + tx, err := db.Begin() + if err != nil { + t.Fatalf("Begin = %v", err) + } + stmt, err := tx.Prepare("INSERT|t1|name=?,age=?") + if err != nil { + t.Fatalf("Stmt, err = %v, %v", stmt, err) + } + defer stmt.Close() + _, err = stmt.Exec("Bobby", 7) + if err != nil { + t.Fatalf("Exec = %v", err) + } + err = tx.Commit() + if err != nil { + t.Fatalf("Commit = %v", err) + } + // Commit() should have closed the statement + if !stmt.closed { + t.Fatal("Stmt not closed after Commit") + } +} + func TestTxStmt(t *testing.T) { db := newTestDB(t, "") defer closeDB(t, db) @@ -464,6 +491,10 @@ func TestTxStmt(t *testing.T) { if err != nil { t.Fatalf("Commit = %v", err) } + // Commit() should have closed the statement + if !txs.closed { + t.Fatal("Stmt not closed after Commit") + } } // Issue: http://golang.org/issue/2784 From db56d4d5eb14454e0d4b5c46d0dc89af11fbbf9d Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 11:46:02 -0700 Subject: [PATCH 158/430] text/template: allow comparison functions to work between any integers Previously, signed and unsigned integers could not be compared, but this has problems with things like comparing 'x' with a byte in a string. Since signed and unsigned integers have a well-defined ordering, even though their types are different, and since we already allow comparison regardless of the size of the integers, why not allow it regardless of the sign? Integers only, a fine place to draw the line. Fixes #7489. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/149780043 --- src/text/template/doc.go | 9 ++-- src/text/template/exec_test.go | 66 +++++++++++++++++++------- src/text/template/funcs.go | 86 ++++++++++++++++++++-------------- 3 files changed, 105 insertions(+), 56 deletions(-) diff --git a/src/text/template/doc.go b/src/text/template/doc.go index 7c6efd59cd..223c595c25 100644 --- a/src/text/template/doc.go +++ b/src/text/template/doc.go @@ -338,10 +338,11 @@ arguments will be evaluated.) The comparison functions work on basic types only (or named basic types, such as "type Celsius float32"). They implement the Go rules for comparison of values, except that size and exact type are -ignored, so any integer value may be compared with any other integer -value, any unsigned integer value may be compared with any other -unsigned integer value, and so on. However, as usual, one may not -compare an int with a float32 and so on. +ignored, so any integer value, signed or unsigned, may be compared +with any other integer value. (The arithmetic value is compared, +not the bit pattern, so all negative integers are less than all +unsigned integers.) However, as usual, one may not compare an int +with a float32 and so on. Associated templates diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 663aaf3af8..3bffcc1599 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -902,8 +902,8 @@ var cmpTests = []cmpTest{ {"eq 1 2", "false", true}, {"eq `xy` `xy`", "true", true}, {"eq `xy` `xyz`", "false", true}, - {"eq .Xuint .Xuint", "true", true}, - {"eq .Xuint .Yuint", "false", true}, + {"eq .Uthree .Uthree", "true", true}, + {"eq .Uthree .Ufour", "false", true}, {"eq 3 4 5 6 3", "true", true}, {"eq 3 4 5 6 7", "false", true}, {"ne true true", "false", true}, @@ -916,16 +916,16 @@ var cmpTests = []cmpTest{ {"ne 1 2", "true", true}, {"ne `xy` `xy`", "false", true}, {"ne `xy` `xyz`", "true", true}, - {"ne .Xuint .Xuint", "false", true}, - {"ne .Xuint .Yuint", "true", true}, + {"ne .Uthree .Uthree", "false", true}, + {"ne .Uthree .Ufour", "true", true}, {"lt 1.5 1.5", "false", true}, {"lt 1.5 2.5", "true", true}, {"lt 1 1", "false", true}, {"lt 1 2", "true", true}, {"lt `xy` `xy`", "false", true}, {"lt `xy` `xyz`", "true", true}, - {"lt .Xuint .Xuint", "false", true}, - {"lt .Xuint .Yuint", "true", true}, + {"lt .Uthree .Uthree", "false", true}, + {"lt .Uthree .Ufour", "true", true}, {"le 1.5 1.5", "true", true}, {"le 1.5 2.5", "true", true}, {"le 2.5 1.5", "false", true}, @@ -935,9 +935,9 @@ var cmpTests = []cmpTest{ {"le `xy` `xy`", "true", true}, {"le `xy` `xyz`", "true", true}, {"le `xyz` `xy`", "false", true}, - {"le .Xuint .Xuint", "true", true}, - {"le .Xuint .Yuint", "true", true}, - {"le .Yuint .Xuint", "false", true}, + {"le .Uthree .Uthree", "true", true}, + {"le .Uthree .Ufour", "true", true}, + {"le .Ufour .Uthree", "false", true}, {"gt 1.5 1.5", "false", true}, {"gt 1.5 2.5", "false", true}, {"gt 1 1", "false", true}, @@ -945,9 +945,9 @@ var cmpTests = []cmpTest{ {"gt 1 2", "false", true}, {"gt `xy` `xy`", "false", true}, {"gt `xy` `xyz`", "false", true}, - {"gt .Xuint .Xuint", "false", true}, - {"gt .Xuint .Yuint", "false", true}, - {"gt .Yuint .Xuint", "true", true}, + {"gt .Uthree .Uthree", "false", true}, + {"gt .Uthree .Ufour", "false", true}, + {"gt .Ufour .Uthree", "true", true}, {"ge 1.5 1.5", "true", true}, {"ge 1.5 2.5", "false", true}, {"ge 2.5 1.5", "true", true}, @@ -957,11 +957,40 @@ var cmpTests = []cmpTest{ {"ge `xy` `xy`", "true", true}, {"ge `xy` `xyz`", "false", true}, {"ge `xyz` `xy`", "true", true}, - {"ge .Xuint .Xuint", "true", true}, - {"ge .Xuint .Yuint", "false", true}, - {"ge .Yuint .Xuint", "true", true}, + {"ge .Uthree .Uthree", "true", true}, + {"ge .Uthree .Ufour", "false", true}, + {"ge .Ufour .Uthree", "true", true}, + // Mixing signed and unsigned integers. + {"eq .Uthree .Three", "true", true}, + {"eq .Three .Uthree", "true", true}, + {"le .Uthree .Three", "true", true}, + {"le .Three .Uthree", "true", true}, + {"ge .Uthree .Three", "true", true}, + {"ge .Three .Uthree", "true", true}, + {"lt .Uthree .Three", "false", true}, + {"lt .Three .Uthree", "false", true}, + {"gt .Uthree .Three", "false", true}, + {"gt .Three .Uthree", "false", true}, + {"eq .Ufour .Three", "false", true}, + {"lt .Ufour .Three", "false", true}, + {"gt .Ufour .Three", "true", true}, + {"eq .NegOne .Uthree", "false", true}, + {"eq .Uthree .NegOne", "false", true}, + {"ne .NegOne .Uthree", "true", true}, + {"ne .Uthree .NegOne", "true", true}, + {"lt .NegOne .Uthree", "true", true}, + {"lt .Uthree .NegOne", "false", true}, + {"le .NegOne .Uthree", "true", true}, + {"le .Uthree .NegOne", "false", true}, + {"gt .NegOne .Uthree", "false", true}, + {"gt .Uthree .NegOne", "true", true}, + {"ge .NegOne .Uthree", "false", true}, + {"ge .Uthree .NegOne", "true", true}, + {"eq (index `x` 0) 'x'", "true", true}, // The example that triggered this rule. + {"eq (index `x` 0) 'y'", "false", true}, // Errors {"eq `xy` 1", "", false}, // Different types. + {"eq 2 2.0", "", false}, // Different types. {"lt true true", "", false}, // Unordered types. {"lt 1+0i 1+0i", "", false}, // Unordered types. } @@ -969,13 +998,14 @@ var cmpTests = []cmpTest{ func TestComparison(t *testing.T) { b := new(bytes.Buffer) var cmpStruct = struct { - Xuint, Yuint uint - }{3, 4} + Uthree, Ufour uint + NegOne, Three int + }{3, 4, -1, 3} for _, test := range cmpTests { text := fmt.Sprintf("{{if %s}}true{{else}}false{{end}}", test.expr) tmpl, err := New("empty").Parse(text) if err != nil { - t.Fatal(err) + t.Fatalf("%q: %s", test.expr, err) } b.Reset() err = tmpl.Execute(b, &cmpStruct) diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index e854122624..39ee5ed68f 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -314,25 +314,34 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) { if err != nil { return false, err } - if k1 != k2 { - return false, errBadComparison - } truth := false - switch k1 { - case boolKind: - truth = v1.Bool() == v2.Bool() - case complexKind: - truth = v1.Complex() == v2.Complex() - case floatKind: - truth = v1.Float() == v2.Float() - case intKind: - truth = v1.Int() == v2.Int() - case stringKind: - truth = v1.String() == v2.String() - case uintKind: - truth = v1.Uint() == v2.Uint() - default: - panic("invalid kind") + if k1 != k2 { + // Special case: Can compare integer values regardless of type's sign. + switch { + case k1 == intKind && k2 == uintKind: + truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint() + case k1 == uintKind && k2 == intKind: + truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int()) + default: + return false, errBadComparison + } + } else { + switch k1 { + case boolKind: + truth = v1.Bool() == v2.Bool() + case complexKind: + truth = v1.Complex() == v2.Complex() + case floatKind: + truth = v1.Float() == v2.Float() + case intKind: + truth = v1.Int() == v2.Int() + case stringKind: + truth = v1.String() == v2.String() + case uintKind: + truth = v1.Uint() == v2.Uint() + default: + panic("invalid kind") + } } if truth { return true, nil @@ -360,23 +369,32 @@ func lt(arg1, arg2 interface{}) (bool, error) { if err != nil { return false, err } - if k1 != k2 { - return false, errBadComparison - } truth := false - switch k1 { - case boolKind, complexKind: - return false, errBadComparisonType - case floatKind: - truth = v1.Float() < v2.Float() - case intKind: - truth = v1.Int() < v2.Int() - case stringKind: - truth = v1.String() < v2.String() - case uintKind: - truth = v1.Uint() < v2.Uint() - default: - panic("invalid kind") + if k1 != k2 { + // Special case: Can compare integer values regardless of type's sign. + switch { + case k1 == intKind && k2 == uintKind: + truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() + case k1 == uintKind && k2 == intKind: + truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int()) + default: + return false, errBadComparison + } + } else { + switch k1 { + case boolKind, complexKind: + return false, errBadComparisonType + case floatKind: + truth = v1.Float() < v2.Float() + case intKind: + truth = v1.Int() < v2.Int() + case stringKind: + truth = v1.String() < v2.String() + case uintKind: + truth = v1.Uint() < v2.Uint() + default: + panic("invalid kind") + } } return truth, nil } From 78b5321e823d6dbb7a009ec73775f7b5e8dc95e7 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 11:58:15 -0700 Subject: [PATCH 159/430] fmt: make printing of ints 25-35% faster Inspired by a remark by Leonard Holz, use constants for division BenchmarkSprintfEmpty 130 132 +1.54% BenchmarkSprintfString 438 437 -0.23% BenchmarkSprintfInt 417 414 -0.72% BenchmarkSprintfIntInt 663 691 +4.22% BenchmarkSprintfPrefixedInt 791 774 -2.15% BenchmarkSprintfFloat 701 686 -2.14% BenchmarkManyArgs 2584 2469 -4.45% BenchmarkFprintInt 488 357 -26.84% BenchmarkFprintIntNoAlloc 402 265 -34.08% BenchmarkScanInts 1244346 1267574 +1.87% BenchmarkScanRecursiveInt 1748741 1724138 -1.41% Update #3463 LGTM=josharian, rsc R=golang-codereviews, josharian, rsc CC=golang-codereviews https://golang.org/cl/144250043 --- src/fmt/fmt_test.go | 17 +++++++++++++++++ src/fmt/format.go | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index a212c9f702..cca0a495ff 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -854,6 +854,23 @@ func BenchmarkManyArgs(b *testing.B) { }) } +func BenchmarkFprintInt(b *testing.B) { + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + buf.Reset() + Fprint(&buf, 123456) + } +} + +func BenchmarkFprintIntNoAlloc(b *testing.B) { + var x interface{} = 123456 + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + buf.Reset() + Fprint(&buf, x) + } +} + var mallocBuf bytes.Buffer var mallocPointer *int // A pointer so we know the interface value won't allocate. diff --git a/src/fmt/format.go b/src/fmt/format.go index 8aeffd7b2b..255167c8f5 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -199,10 +199,36 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { // block but it's not worth the duplication, so ua has 64 bits. i := len(buf) ua := uint64(a) - for ua >= base { - i-- - buf[i] = digits[ua%base] - ua /= base + // use constants for the division and modulo for more efficient code. + // switch cases ordered by popularity. + switch base { + case 10: + for ua >= 10 { + i-- + next := ua / 10 + buf[i] = byte('0' + ua - next*10) + ua = next + } + case 16: + for ua >= 16 { + i-- + buf[i] = digits[ua&0xF] + ua >>= 4 + } + case 8: + for ua >= 8 { + i-- + buf[i] = byte('0' + ua&7) + ua >>= 3 + } + case 2: + for ua >= 2 { + i-- + buf[i] = byte('0' + ua&1) + ua >>= 1 + } + default: + panic("fmt: unknown base; can't happen") } i-- buf[i] = digits[ua] From 1392276bfb7b6100b2def909ef9d19e477970f6b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 12:00:37 -0700 Subject: [PATCH 160/430] doc/go1.4.txt: text/template comparison functions allow int==uint CC=golang-codereviews https://golang.org/cl/142450043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index f46ef48f5d..f69b7fa5f0 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -34,6 +34,7 @@ syscall: now frozen (CL 129820043) testing: add Coverage (CL 98150043) testing: add TestMain support (CL 148770043) text/scanner: add IsIdentRune field of Scanner. (CL 108030044) +text/template: allow comparison of signed and unsigned integers (CL 149780043) time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046) encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045). From 892b5074f521ae812b880808e0bd79ee2a02b1a1 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 15:35:25 -0700 Subject: [PATCH 161/430] fmt: document that self-recursive data structures can be fatal Fixes #8241. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/144420043 --- src/fmt/doc.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index 5af8d3e717..b7eaedc11e 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -147,6 +147,10 @@ func (x X) String() string { return Sprintf("<%s>", x) } convert the value before recurring: func (x X) String() string { return Sprintf("<%s>", string(x)) } + Infinite recursion can also be triggered by self-referential data + structures, such as a slice that contains itself as an element, if + that type has a String method. Such pathologies are rare, however, + and the package does not protect against them. Explicit argument indexes: From 5d5e73b14a46178a636b20f45ed8f8fae0177dee Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 17:48:13 -0700 Subject: [PATCH 162/430] text/template: type-check chained node as argument Was just a missing case (literally) in the type checker. Fixes #8473. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/142460043 --- src/text/template/exec.go | 2 ++ src/text/template/exec_test.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 8e155d478e..f6eed662b7 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -636,6 +636,8 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle return s.validateType(s.evalPipeline(dot, arg), typ) case *parse.IdentifierNode: return s.evalFunction(dot, arg, arg, nil, zero) + case *parse.ChainNode: + return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ) } switch typ.Kind() { case reflect.Bool: diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 3bffcc1599..e2cf2d3705 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -176,6 +176,12 @@ func (t *T) Method3(v interface{}) string { return fmt.Sprintf("Method3: %v", v) } +func (t *T) Copy() *T { + n := new(T) + *n = *t + return n +} + func (t *T) MAdd(a int, b []int) []int { v := make([]int, len(b)) for i, x := range b { @@ -519,6 +525,8 @@ var execTests = []execTest{ {"bug12xE", "{{printf `%T` 0xEE}}", "int", T{}, true}, {"bug12Xe", "{{printf `%T` 0Xef}}", "int", T{}, true}, {"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true}, + // Chained nodes did not work as arguments. Issue 8473. + {"bug13", "{{print (.Copy).I}}", "17", tVal, true}, } func zeroArgs() string { From dcb594ec30f428b4b116682a7536ed694526f0e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Mon, 22 Sep 2014 19:51:53 -0700 Subject: [PATCH 163/430] runtime: remove unused function declaration LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/145970043 --- src/runtime/mgc0.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 03ca288496..54728d5ada 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1263,7 +1263,6 @@ struct gc_args }; static void gc(struct gc_args *args); -static void mgc(G *gp); int32 runtime·readgogc(void) From c486d4130d01f1034901d65c764b8e8ae329a01b Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Tue, 23 Sep 2014 15:34:38 +1000 Subject: [PATCH 164/430] runtime: fix runtime.Breakpoint on ARMv5 Fixes #8775. Use the illegal instruction suggested by Ian in https://golang.org/cl/144180043/#msg4 on all arm arches. LGTM=minux R=golang-codereviews, gobot, rsc CC=golang-codereviews, iant, minux https://golang.org/cl/146130043 --- src/runtime/asm_arm.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index f67f94939b..38d97b78f3 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -96,7 +96,7 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 #ifdef GOOS_nacl WORD $0xe125be7f // BKPT 0x5bef, NACL_INSTR_ARM_BREAKPOINT #else - WORD $0xe1200071 // BKPT 0x0001 + WORD $0xe7f001f0 // undefined instruction that gdb understands is a software breakpoint #endif RET From 82ddcc05f44a510118a1fc8bb8e3552a92d8f441 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 23 Sep 2014 14:26:20 -0700 Subject: [PATCH 165/430] os: fix another case where RemoveAll should return nil This hopefully fixes issue 8793. Fixes #8793 LGTM=iant R=rsc, iant CC=golang-codereviews https://golang.org/cl/150860046 --- src/os/path.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/os/path.go b/src/os/path.go index 6cc69403b6..b1a90b3e52 100644 --- a/src/os/path.go +++ b/src/os/path.go @@ -86,6 +86,9 @@ func RemoveAll(path string) error { // Directory. fd, err := Open(path) if err != nil { + if IsNotExist(err) { + return nil + } return err } From db492b8df41cd90ebecaf69a73bf4cc5e0db5f20 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 23 Sep 2014 14:55:19 -0700 Subject: [PATCH 166/430] os: add a comment inside RemoveAll LGTM=r R=r CC=golang-codereviews https://golang.org/cl/149950043 --- src/os/path.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/os/path.go b/src/os/path.go index b1a90b3e52..24a3415b46 100644 --- a/src/os/path.go +++ b/src/os/path.go @@ -87,6 +87,8 @@ func RemoveAll(path string) error { fd, err := Open(path) if err != nil { if IsNotExist(err) { + // Race. It was deleted between the Lstat and Open. + // Return nil per RemoveAll's docs. return nil } return err From 1193993c1db83ee8c0a8e86e6d41db1dd1982002 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 23 Sep 2014 18:24:35 -0700 Subject: [PATCH 167/430] cmd/pack: fix c command for existing file There were at least two bugs: 1) It would overwrite a non-archive. 2) It would truncate a non-archive and then fail. In general the file handling was too clever to be correct. Make it more straightforward, doing the creation separately from archive management. Fixes #8369. LGTM=adg, iant R=golang-codereviews, adg, iant CC=golang-codereviews https://golang.org/cl/147010046 --- src/cmd/pack/doc.go | 4 ++++ src/cmd/pack/pack.go | 50 +++++++++++++++++++++++++++------------ src/cmd/pack/pack_test.go | 23 ++++++++++++++---- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/cmd/pack/doc.go b/src/cmd/pack/doc.go index 1529e07e90..a702594e23 100644 --- a/src/cmd/pack/doc.go +++ b/src/cmd/pack/doc.go @@ -20,6 +20,10 @@ The operation op is given by one of these letters: t list files from the archive x extract files from the archive +The archive argument to the c command must be non-existent or a +valid archive file, which will be cleared before adding new entries. It +is an error if the file exists but is not an archive. + For the p, t, and x commands, listing no names on the command line causes the operation to apply to all files in the archive. diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go index 594433712d..ffb2d617ae 100644 --- a/src/cmd/pack/pack.go +++ b/src/cmd/pack/pack.go @@ -142,16 +142,19 @@ type Archive struct { matchAll bool // match all files in archive } -// archive opens (or if necessary creates) the named archive. +// archive opens (and if necessary creates) the named archive. func archive(name string, mode int, files []string) *Archive { - fd, err := os.OpenFile(name, mode, 0) - if err != nil && mode&^os.O_TRUNC == os.O_RDWR && os.IsNotExist(err) { - fd, err = create(name) + // If the file exists, it must be an archive. If it doesn't exist, or if + // we're doing the c command, indicated by O_TRUNC, truncate the archive. + if !existingArchive(name) || mode&os.O_TRUNC != 0 { + create(name) + mode &^= os.O_TRUNC } + fd, err := os.OpenFile(name, mode, 0) if err != nil { log.Fatal(err) } - mustBeArchive(fd) + checkHeader(fd) return &Archive{ fd: fd, files: files, @@ -160,23 +163,40 @@ func archive(name string, mode int, files []string) *Archive { } // create creates and initializes an archive that does not exist. -func create(name string) (*os.File, error) { - fd, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) +func create(name string) { + fd, err := os.Create(name) if err != nil { - return nil, err + log.Fatal(err) } - fmt.Fprint(fd, arHeader) - fd.Seek(0, 0) - return fd, nil + _, err = fmt.Fprint(fd, arHeader) + if err != nil { + log.Fatal(err) + } + fd.Close() } -// mustBeArchive verifies the header of the file. It assumes the file offset -// is 0 coming in, and leaves it positioned immediately after the header. -func mustBeArchive(fd *os.File) { +// existingArchive reports whether the file exists and is a valid archive. +// If it exists but is not an archive, existingArchive will exit. +func existingArchive(name string) bool { + fd, err := os.Open(name) + if err != nil { + if os.IsNotExist(err) { + return false + } + log.Fatal("cannot open file: %s", err) + } + checkHeader(fd) + fd.Close() + return true +} + +// checkHeader verifies the header of the file. It assumes the file +// is positioned at 0 and leaves it positioned at the end of the header. +func checkHeader(fd *os.File) { buf := make([]byte, len(arHeader)) _, err := io.ReadFull(fd, buf) if err != nil || string(buf) != arHeader { - log.Fatal("file is not an archive: bad header") + log.Fatal("%s is not an archive: bad header", fd.Name()) } } diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go index e41cf3ce42..cf6121fcc1 100644 --- a/src/cmd/pack/pack_test.go +++ b/src/cmd/pack/pack_test.go @@ -56,11 +56,8 @@ func tmpDir(t *testing.T) string { return name } -// Test that we can create an archive, write to it, and get the same contents back. -// Tests the rv and then the pv command on a new archive. -func TestCreate(t *testing.T) { - dir := tmpDir(t) - defer os.RemoveAll(dir) +// testCreate creates an archive in the specified directory. +func testCreate(t *testing.T, dir string) { name := filepath.Join(dir, "pack.a") ar := archive(name, os.O_RDWR, nil) // Add an entry by hand. @@ -85,6 +82,22 @@ func TestCreate(t *testing.T) { } } +// Test that we can create an archive, write to it, and get the same contents back. +// Tests the rv and then the pv command on a new archive. +func TestCreate(t *testing.T) { + dir := tmpDir(t) + defer os.RemoveAll(dir) + testCreate(t, dir) +} + +// Test that we can create an archive twice with the same name (Issue 8369). +func TestCreateTwice(t *testing.T) { + dir := tmpDir(t) + defer os.RemoveAll(dir) + testCreate(t, dir) + testCreate(t, dir) +} + // Test that we can create an archive, put some files in it, and get back a correct listing. // Tests the tv command. func TestTableOfContents(t *testing.T) { From a69e504a34bb965850cbab6fdc1b4bc687cdd0c5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 13:12:15 -0400 Subject: [PATCH 168/430] A+C: Hector Martin Cantero (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/147080043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 5d7b870459..8673dce968 100644 --- a/AUTHORS +++ b/AUTHORS @@ -183,6 +183,7 @@ Gustavo Niemeyer Gwenael Treguier Harley Laue Hector Chu +Hector Martin Cantero Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 09fec9f7ae..560faf4274 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -258,6 +258,7 @@ Gwenael Treguier Han-Wen Nienhuys Harley Laue Hector Chu +Hector Martin Cantero Henning Schmiedehausen Henrik Edwards Herbert Georg Fischer From 7283e08cbf06bcd32a391183e26080cff301e7f9 Mon Sep 17 00:00:00 2001 From: Hector Martin Cantero Date: Wed, 24 Sep 2014 13:20:25 -0400 Subject: [PATCH 169/430] runtime: keep g->syscallsp consistent after cgo->Go callbacks Normally, the caller to runtime.entersyscall() must not return before calling runtime.exitsyscall(), lest g->syscallsp become a dangling pointer. runtime.cgocallbackg() violates this constraint. To work around this, save g->syscallsp and g->syscallpc around cgo->Go callbacks, then restore them after calling runtime.entersyscall(), which restores the syscall stack frame pointer saved by cgocall. This allows the GC to correctly trace a goroutine that is currently returning from a Go->cgo->Go chain. This also adds a check to proc.c that panics if g->syscallsp is clearly invalid. It is not 100% foolproof, as it will not catch a case where the stack was popped then pushed back beyond g->syscallsp, but it does catch the present cgo issue and makes existing tests fail without the bugfix. Fixes #7978. LGTM=dvyukov, rsc R=golang-codereviews, dvyukov, minux, bradfitz, iant, gobot, rsc CC=golang-codereviews, rsc https://golang.org/cl/131910043 --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue7978.go | 99 ++++++++++++++++++++++++++++++++++++++ src/run.bash | 2 + src/run.bat | 7 +++ src/runtime/cgocall.go | 12 ++++- src/runtime/proc.c | 39 ++++++++++----- src/runtime/runtime.h | 1 + src/runtime/stubs.go | 1 + 8 files changed, 149 insertions(+), 13 deletions(-) create mode 100644 misc/cgo/test/issue7978.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 3783af061c..1899d46053 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -56,5 +56,6 @@ func TestNaming(t *testing.T) { testNaming(t) } func Test7560(t *testing.T) { test7560(t) } func Test5242(t *testing.T) { test5242(t) } func Test8092(t *testing.T) { test8092(t) } +func Test7978(t *testing.T) { test7978(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go new file mode 100644 index 0000000000..39864476ce --- /dev/null +++ b/misc/cgo/test/issue7978.go @@ -0,0 +1,99 @@ +// 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. + +// Issue 7978. Stack tracing didn't work during cgo code after calling a Go +// callback. Make sure GC works and the stack trace is correct. + +package cgotest + +/* +#include + +void issue7978cb(void); + +// use ugly atomic variable sync since that doesn't require calling back into +// Go code or OS dependencies +static void issue7978c(uint32_t *sync) { + while(__sync_fetch_and_add(sync, 0) != 0) + ; + __sync_fetch_and_add(sync, 1); + while(__sync_fetch_and_add(sync, 0) != 2) + ; + issue7978cb(); + __sync_fetch_and_add(sync, 1); + while(__sync_fetch_and_add(sync, 0) != 6) + ; +} +*/ +import "C" + +import ( + "runtime" + "strings" + "sync/atomic" + "testing" +) + +var issue7978sync uint32 + +func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) { + runtime.GC() + buf := make([]byte, 65536) + trace := string(buf[:runtime.Stack(buf, true)]) + for _, goroutine := range strings.Split(trace, "\n\n") { + if strings.Contains(goroutine, "test.issue7978go") { + trace := strings.Split(goroutine, "\n") + // look for the expected function in the stack + for i := 0; i < depth; i++ { + if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) { + t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine) + return + } + if strings.Contains(trace[1+2*i], wantFunc) { + return + } + } + t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine) + return + } + } + t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace) +} + +func issue7978wait(store uint32, wait uint32) { + if store != 0 { + atomic.StoreUint32(&issue7978sync, store) + } + for atomic.LoadUint32(&issue7978sync) != wait { + runtime.Gosched() + } +} + +//export issue7978cb +func issue7978cb() { + issue7978wait(3, 4) +} + +func issue7978go() { + C.issue7978c((*C.uint32_t)(&issue7978sync)) + issue7978wait(7, 8) +} + +func test7978(t *testing.T) { + issue7978sync = 0 + go issue7978go() + // test in c code, before callback + issue7978wait(0, 1) + issue7978check(t, "runtime.cgocall_errno(", "", 1) + // test in go code, during callback + issue7978wait(2, 3) + issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3) + // test in c code, after callback + issue7978wait(4, 5) + issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1) + // test in go code, after return from cgo + issue7978wait(6, 7) + issue7978check(t, "test.issue7978go(", "", 3) + atomic.StoreUint32(&issue7978sync, 8) +} diff --git a/src/run.bash b/src/run.bash index b5f061d885..d6e53304d8 100755 --- a/src/run.bash +++ b/src/run.bash @@ -119,6 +119,8 @@ go run $GOROOT/test/run.go - . || exit 1 [ "$CGO_ENABLED" != 1 ] || (xcd ../misc/cgo/test +# cgo tests inspect the traceback for runtime functions +export GOTRACEBACK=2 go test -ldflags '-linkmode=auto' || exit 1 # linkmode=internal fails on dragonfly since errno is a TLS relocation. [ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1 diff --git a/src/run.bat b/src/run.bat index 62692acaf2..309e06d507 100644 --- a/src/run.bat +++ b/src/run.bat @@ -90,11 +90,18 @@ go run "%GOROOT%\test\run.go" - ..\misc\cgo\stdio if errorlevel 1 goto fail echo. +# cgo tests inspect the traceback for runtime functions +set OLDGOTRACEBACK=%GOTRACEBACK% +set GOTRACEBACK=2 + echo # ..\misc\cgo\test go test ..\misc\cgo\test if errorlevel 1 goto fail echo. +set GOTRACEBACK=%OLDGOTRACEBACK% +set OLDGOTRACEBACK= + echo # ..\misc\cgo\testso cd ..\misc\cgo\testso set FAIL=0 diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index a21474b01f..7fd91469eb 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -177,14 +177,22 @@ func cfree(p unsafe.Pointer) { // Call from C back to Go. //go:nosplit func cgocallbackg() { - if gp := getg(); gp != gp.m.curg { + gp := getg() + if gp != gp.m.curg { println("runtime: bad g in cgocallback") exit(2) } + // entersyscall saves the caller's SP to allow the GC to trace the Go + // stack. However, since we're returning to an earlier stack frame and + // need to pair with the entersyscall() call made by cgocall, we must + // save syscall* and let reentersyscall restore them. + savedsp := unsafe.Pointer(gp.syscallsp) + savedpc := gp.syscallpc exitsyscall() // coming out of cgo call cgocallbackg1() - entersyscall() // going back to cgo call + // going back to cgo call + reentersyscall(savedpc, savedsp) } func cgocallbackg1() { diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 3f4179d473..564798be7b 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -1700,9 +1700,9 @@ goexit0(G *gp) #pragma textflag NOSPLIT static void -save(void *pc, uintptr sp) +save(uintptr pc, uintptr sp) { - g->sched.pc = (uintptr)pc; + g->sched.pc = pc; g->sched.sp = sp; g->sched.lr = 0; g->sched.ret = 0; @@ -1730,9 +1730,15 @@ static void entersyscall_gcwait(void); // In practice, this means that we make the fast path run through // entersyscall doing no-split things, and the slow path has to use onM // to run bigger things on the m stack. +// +// reentersyscall is the entry point used by cgo callbacks, where explicitly +// saved SP and PC are restored. This is needed when exitsyscall will be called +// from a function further up in the call stack than the parent, as g->syscallsp +// must always point to a valid stack frame. entersyscall below is the normal +// entry point for syscalls, which obtains the SP and PC from the caller. #pragma textflag NOSPLIT void -·entersyscall(int32 dummy) +runtime·reentersyscall(uintptr pc, uintptr sp) { void (*fn)(void); @@ -1748,9 +1754,9 @@ void g->throwsplit = 1; // Leave SP around for GC and traceback. - save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); - g->syscallsp = g->sched.sp; - g->syscallpc = g->sched.pc; + save(pc, sp); + g->syscallsp = sp; + g->syscallpc = pc; runtime·casgstatus(g, Grunning, Gsyscall); if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) { fn = entersyscall_bad; @@ -1760,7 +1766,7 @@ void if(runtime·atomicload(&runtime·sched.sysmonwait)) { // TODO: fast atomic fn = entersyscall_sysmon; runtime·onM(&fn); - save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); + save(pc, sp); } g->m->mcache = nil; @@ -1769,7 +1775,7 @@ void if(runtime·sched.gcwaiting) { fn = entersyscall_gcwait; runtime·onM(&fn); - save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); + save(pc, sp); } // Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched). @@ -1779,6 +1785,14 @@ void g->m->locks--; } +// Standard syscall entry used by the go syscall library and normal cgo calls. +#pragma textflag NOSPLIT +void +·entersyscall(int32 dummy) +{ + runtime·reentersyscall((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); +} + static void entersyscall_bad(void) { @@ -1826,7 +1840,7 @@ void g->stackguard0 = StackPreempt; // see comment in entersyscall // Leave SP around for GC and traceback. - save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); + save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); g->syscallsp = g->sched.sp; g->syscallpc = g->sched.pc; runtime·casgstatus(g, Grunning, Gsyscall); @@ -1839,7 +1853,7 @@ void runtime·onM(&fn); // Resave for traceback during blocked call. - save(runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); + save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy)); g->m->locks--; } @@ -1856,12 +1870,15 @@ entersyscallblock_handoff(void) // from the low-level system calls used by the runtime. #pragma textflag NOSPLIT void -runtime·exitsyscall(void) +·exitsyscall(int32 dummy) { void (*fn)(G*); g->m->locks++; // see comment in entersyscall + if(runtime·getcallersp(&dummy) > g->syscallsp) + runtime·throw("exitsyscall: syscall frame is no longer valid"); + g->waitsince = 0; if(exitsyscallfast()) { // There's a cpu for us, so we can run. diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 7fefbc2997..3a6d3e3262 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -901,6 +901,7 @@ void runtime·goexit(void); void runtime·asmcgocall(void (*fn)(void*), void*); int32 runtime·asmcgocall_errno(void (*fn)(void*), void*); void runtime·entersyscall(void); +void runtime·reentersyscall(uintptr, uintptr); void runtime·entersyscallblock(void); void runtime·exitsyscall(void); G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*); diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 2e6aadca7a..1381c7efdb 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -164,6 +164,7 @@ func noescape(p unsafe.Pointer) unsafe.Pointer { } func entersyscall() +func reentersyscall(pc uintptr, sp unsafe.Pointer) func entersyscallblock() func exitsyscall() From 6f219e8b847c731a6c0d3695b74f312a1ea705a5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 14:18:25 -0400 Subject: [PATCH 170/430] runtime: fix LastGC comment I have no idea what "absolute time" means. LGTM=dvyukov, r R=r, dvyukov CC=golang-codereviews https://golang.org/cl/144320043 --- src/runtime/mem.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/mem.go b/src/runtime/mem.go index b3c216f18e..438f22ec09 100644 --- a/src/runtime/mem.go +++ b/src/runtime/mem.go @@ -41,8 +41,8 @@ type MemStats struct { OtherSys uint64 // other system allocations // Garbage collector statistics. - NextGC uint64 // next run in HeapAlloc time (bytes) - LastGC uint64 // last run in absolute time (ns) + NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount + LastGC uint64 // end time of last collection (nanoseconds since 1970) PauseTotalNs uint64 PauseNs [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256] NumGC uint32 From a0785a53add4253db84349d58abbe2ba8be130d9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 15:10:38 -0400 Subject: [PATCH 171/430] cmd/go: prohibit C sources files unless using cgo Those C files would have been compiled with 6c. It's close to impossible to use C correctly anymore, and the C compilers are going away eventually. Make them unavailable now. go1.4.txt change in CL 145890046 LGTM=iant R=iant CC=golang-codereviews, r https://golang.org/cl/149720043 --- misc/cgo/test/backdoor/backdoor.go | 3 +-- misc/cgo/test/backdoor/backdoor_gccgo.go | 11 --------- misc/cgo/test/backdoor/runtime.c | 18 -------------- misc/cgo/test/issue7695_test.go | 30 ------------------------ src/cmd/go/pkg.go | 10 ++++++++ src/cmd/go/test.bash | 14 +++++++++++ src/cmd/go/testdata/src/badc/x.c | 1 + src/cmd/go/testdata/src/badc/x.go | 1 + src/net/{empty.c => empty.s} | 0 src/runtime/debug/{debug.c => debug.s} | 0 10 files changed, 27 insertions(+), 61 deletions(-) delete mode 100644 misc/cgo/test/backdoor/backdoor_gccgo.go delete mode 100644 misc/cgo/test/backdoor/runtime.c delete mode 100644 misc/cgo/test/issue7695_test.go create mode 100644 src/cmd/go/testdata/src/badc/x.c create mode 100644 src/cmd/go/testdata/src/badc/x.go rename src/net/{empty.c => empty.s} (100%) rename src/runtime/debug/{debug.c => debug.s} (100%) diff --git a/misc/cgo/test/backdoor/backdoor.go b/misc/cgo/test/backdoor/backdoor.go index 7398772bd2..3a973494bc 100644 --- a/misc/cgo/test/backdoor/backdoor.go +++ b/misc/cgo/test/backdoor/backdoor.go @@ -4,5 +4,4 @@ package backdoor -func LockedOSThread() bool // in runtime.c -func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) +func LockedOSThread() bool // in thunk.s diff --git a/misc/cgo/test/backdoor/backdoor_gccgo.go b/misc/cgo/test/backdoor/backdoor_gccgo.go deleted file mode 100644 index 514f76ec5e..0000000000 --- a/misc/cgo/test/backdoor/backdoor_gccgo.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -// This is the gccgo version of the stub in runtime.c. - -// +build gccgo - -package backdoor - -func Issue7695(x1, x2, x3, x4, x5, x6, x7, x8 uintptr) {} diff --git a/misc/cgo/test/backdoor/runtime.c b/misc/cgo/test/backdoor/runtime.c deleted file mode 100644 index 87ee44eb6f..0000000000 --- a/misc/cgo/test/backdoor/runtime.c +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2011 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. - -// Expose some runtime functions for testing. -// Must be in a non-cgo-using package so that -// the go command compiles this file with 6c, not gcc. - -// +build gc - -typedef char bool; - -// This is what a cgo-compiled stub declaration looks like. -void -·Issue7695(struct{void *y[8*sizeof(void*)];}p) -{ - USED(p); -} diff --git a/misc/cgo/test/issue7695_test.go b/misc/cgo/test/issue7695_test.go deleted file mode 100644 index de2fc03d42..0000000000 --- a/misc/cgo/test/issue7695_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// 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. - -// +build ignore -// This test depends on running C code on Go stacks. Not allowed anymore. - -// Demo of deferred C function with untrue prototype -// breaking stack copying. See golang.org/issue/7695. - -package cgotest - -import ( - "testing" - - "./backdoor" -) - -func TestIssue7695(t *testing.T) { - defer backdoor.Issue7695(1, 0, 2, 0, 0, 3, 0, 4) - recurse(100) -} - -func recurse(n int) { - var x [128]int - n += x[0] - if n > 0 { - recurse(n - 1) - } -} diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 63875aed5a..4bbcc2b971 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -614,6 +614,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } p.Target = p.target + // Check for C code compiled with Plan 9 C compiler. + // No longer allowed except in runtime and runtime/cgo, for now. + if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") { + p.Error = &PackageError{ + ImportStack: stk.copy(), + Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")), + } + return p + } + // In the absence of errors lower in the dependency tree, // check for case-insensitive collisions of import paths. if len(p.DepsErrors) == 0 { diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 13886e158b..9ae17e1054 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -157,6 +157,20 @@ fi rm -f ./testdata/err unset GOPATH +export GOPATH=$(pwd)/testdata/src +TEST disallowed C source files +export GOPATH=$(pwd)/testdata +if ./testgo build badc 2>testdata/err; then + echo 'go build badc succeeded' + ok=false +elif ! grep 'C source files not allowed' testdata/err >/dev/null; then + echo 'go test did not say C source files not allowed:' + cat testdata/err + ok=false +fi +rm -f ./testdata/err +unset GOPATH + TEST error message for syntax error in test go file says FAIL export GOPATH=$(pwd)/testdata if ./testgo test syntaxerror 2>testdata/err; then diff --git a/src/cmd/go/testdata/src/badc/x.c b/src/cmd/go/testdata/src/badc/x.c new file mode 100644 index 0000000000..f6cbf6924d --- /dev/null +++ b/src/cmd/go/testdata/src/badc/x.c @@ -0,0 +1 @@ +// C code! diff --git a/src/cmd/go/testdata/src/badc/x.go b/src/cmd/go/testdata/src/badc/x.go new file mode 100644 index 0000000000..bfa1de28bd --- /dev/null +++ b/src/cmd/go/testdata/src/badc/x.go @@ -0,0 +1 @@ +package badc diff --git a/src/net/empty.c b/src/net/empty.s similarity index 100% rename from src/net/empty.c rename to src/net/empty.s diff --git a/src/runtime/debug/debug.c b/src/runtime/debug/debug.s similarity index 100% rename from src/runtime/debug/debug.c rename to src/runtime/debug/debug.s From 50c9d6345915dfacf6d09bf40d21161e77be987a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 15:10:54 -0400 Subject: [PATCH 172/430] doc/go1.4.txt: document that C sources in non-cgo packages are no longer allowed CC=golang-codereviews https://golang.org/cl/145890046 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index f69b7fa5f0..d09a154a3d 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -13,6 +13,7 @@ cmd/6l, liblink: use pc-relative addressing for all memory references, so that l cmd/go: import comments (CL 124940043) cmd/go: implement "internal" (CL 120600043) cmd/go: implement "generate" (CL 125580044) +cmd/go: disallow C sources except when using cgo (CL 149720043) asm: make textflag.h available outside of cmd/ld (CL 128050043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) From 00d2f916adf2fb025406f0558ab8cac122fdf060 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 15:20:03 -0400 Subject: [PATCH 173/430] cmd/gc: run escape analysis always (even in -N mode) Fixes #8585. Removes some little-used code paths. LGTM=josharian R=golang-codereviews, minux, josharian CC=golang-codereviews, iant, r https://golang.org/cl/132970043 --- src/cmd/gc/gen.c | 6 +- src/cmd/gc/lex.c | 8 +- src/cmd/gc/typecheck.c | 6 - test/escape2.go | 2 + test/escape2n.go | 1494 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1503 insertions(+), 13 deletions(-) create mode 100644 test/escape2n.go diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 83c46c6504..eb9eacca8f 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -54,9 +54,6 @@ addrescapes(Node *n) if(n->class == PAUTO && n->esc == EscNever) break; - if(debug['N'] && n->esc != EscUnknown) - fatal("without escape analysis, only PAUTO's should have esc: %N", n); - switch(n->class) { case PPARAMREF: addrescapes(n->defn); @@ -91,8 +88,7 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->orig->sym = n->heapaddr->sym; - if(!debug['N']) - n->esc = EscHeap; + n->esc = EscHeap; if(debug['m']) print("%L: moved to heap: %N\n", n->lineno, n); curfn = oldfn; diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 6d83177477..2303b442cd 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -481,8 +481,12 @@ main(int argc, char *argv[]) } // Phase 5: Escape analysis. - if(!debug['N']) - escapes(xtop); + // Required for moving heap allocations onto stack, + // which in turn is required by the closure implementation, + // which stores the addresses of stack variables into the closure. + // If the closure does not escape, it needs to be on the stack + // or else the stack copier will not update it. + escapes(xtop); // Escape analysis moved escaped values off stack. // Move large values off stack too. diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 18d20cdd16..298920bfec 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -736,10 +736,6 @@ reswitch: l = n->left; if((t = l->type) == T) goto error; - // top&Eindir means this is &x in *&x. (or the arg to built-in print) - // n->etype means code generator flagged it as non-escaping. - if(debug['N'] && !(top & Eindir) && !n->etype) - addrescapes(n->left); n->type = ptrto(t); goto ret; @@ -2119,8 +2115,6 @@ lookdot(Node *n, Type *t, int dostrcmp) if(!eqtype(rcvr, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { checklvalue(n->left, "call pointer method on"); - if(debug['N']) - addrescapes(n->left); n->left = nod(OADDR, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); diff --git a/test/escape2.go b/test/escape2.go index 28251aa98b..6a46ce86ab 100644 --- a/test/escape2.go +++ b/test/escape2.go @@ -7,6 +7,8 @@ // Test, using compiler diagnostic flags, that the escape analysis is working. // Compiles but does not run. Inlining is disabled. +// escape2n.go contains all the same tests but compiles with -N. + package foo import ( diff --git a/test/escape2n.go b/test/escape2n.go new file mode 100644 index 0000000000..002a78ea50 --- /dev/null +++ b/test/escape2n.go @@ -0,0 +1,1494 @@ +// errorcheck -0 -N -m -l + +// Copyright 2010 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. + +// Test, using compiler diagnostic flags, that the escape analysis is working. +// Compiles but does not run. Inlining is disabled. +// Registerization is disabled too (-N), which should +// have no effect on escape analysis. + +package foo + +import ( + "fmt" + "unsafe" +) + +var gxx *int + +func foo1(x int) { // ERROR "moved to heap: x" + gxx = &x // ERROR "&x escapes to heap" +} + +func foo2(yy *int) { // ERROR "leaking param: yy" + gxx = yy +} + +func foo3(x int) *int { // ERROR "moved to heap: x" + return &x // ERROR "&x escapes to heap" +} + +type T *T + +func foo3b(t T) { // ERROR "leaking param: t" + *t = t +} + +// xx isn't going anywhere, so use of yy is ok +func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape" + xx = yy +} + +// xx isn't going anywhere, so taking address of yy is ok +func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape" + xx = &yy // ERROR "&yy does not escape" +} + +func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy" + *xx = yy +} + +func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape" + **xx = *yy +} + +func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape" + xx = yy + return *xx +} + +func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy" + xx = yy + return xx +} + +func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape" + *xx = *yy +} + +func foo11() int { + x, y := 0, 42 + xx := &x // ERROR "&x does not escape" + yy := &y // ERROR "&y does not escape" + *xx = *yy + return x +} + +var xxx **int + +func foo12(yyy **int) { // ERROR "leaking param: yyy" + xxx = yyy +} + +// Must treat yyy as leaking because *yyy leaks, and the escape analysis +// summaries in exported metadata do not distinguish these two cases. +func foo13(yyy **int) { // ERROR "leaking param: yyy" + *xxx = *yyy +} + +func foo14(yyy **int) { // ERROR "yyy does not escape" + **xxx = **yyy +} + +func foo15(yy *int) { // ERROR "moved to heap: yy" + xxx = &yy // ERROR "&yy escapes to heap" +} + +func foo16(yy *int) { // ERROR "leaking param: yy" + *xxx = yy +} + +func foo17(yy *int) { // ERROR "yy does not escape" + **xxx = *yy +} + +func foo18(y int) { // ERROR "moved to heap: "y" + *xxx = &y // ERROR "&y escapes to heap" +} + +func foo19(y int) { + **xxx = y +} + +type Bar struct { + i int + ii *int +} + +func NewBar() *Bar { + return &Bar{42, nil} // ERROR "&Bar literal escapes to heap" +} + +func NewBarp(x *int) *Bar { // ERROR "leaking param: x" + return &Bar{42, x} // ERROR "&Bar literal escapes to heap" +} + +func NewBarp2(x *int) *Bar { // ERROR "x does not escape" + return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap" +} + +func (b *Bar) NoLeak() int { // ERROR "b does not escape" + return *(b.ii) +} + +func (b *Bar) Leak() *int { // ERROR "leaking param: b" + return &b.i // ERROR "&b.i escapes to heap" +} + +func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0" + return b.ii +} + +func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b" + return b.ii +} + +func (b Bar) LeaksToo() *int { // ERROR "leaking param: b" + v := 0 // ERROR "moved to heap: v" + b.ii = &v // ERROR "&v escapes" + return b.ii +} + +func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0" + v := 0 // ERROR "moved to heap: v" + b.ii = &v // ERROR "&v escapes" + return b.ii +} + +func (b Bar) StillNoLeak() int { // ERROR "b does not escape" + v := 0 + b.ii = &v // ERROR "&v does not escape" + return b.i +} + +func goLeak(b *Bar) { // ERROR "leaking param: b" + go b.NoLeak() +} + +type Bar2 struct { + i [12]int + ii []int +} + +func NewBar2() *Bar2 { + return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap" +} + +func (b *Bar2) NoLeak() int { // ERROR "b does not escape" + return b.i[0] +} + +func (b *Bar2) Leak() []int { // ERROR "leaking param: b" + return b.i[:] // ERROR "b.i escapes to heap" +} + +func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0" + return b.ii[0:1] +} + +func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape" + return b.i +} + +func (b *Bar2) LeakSelf() { // ERROR "leaking param: b" + b.ii = b.i[0:4] // ERROR "b.i escapes to heap" +} + +func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b" + var buf []int + buf = b.i[0:] // ERROR "b.i escapes to heap" + b.ii = buf +} + +func foo21() func() int { + x := 42 // ERROR "moved to heap: x" + return func() int { // ERROR "func literal escapes to heap" + return x // ERROR "&x escapes to heap" + } +} + +func foo22() int { + x := 42 + return func() int { // ERROR "func literal does not escape" + return x + }() +} + +func foo23(x int) func() int { // ERROR "moved to heap: x" + return func() int { // ERROR "func literal escapes to heap" + return x // ERROR "&x escapes to heap" + } +} + +func foo23a(x int) func() int { // ERROR "moved to heap: x" + f := func() int { // ERROR "func literal escapes to heap" + return x // ERROR "&x escapes to heap" + } + return f +} + +func foo23b(x int) *(func() int) { // ERROR "moved to heap: x" + f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap" + return &f // ERROR "&f escapes to heap" +} + +func foo24(x int) int { + return func() int { // ERROR "func literal does not escape" + return x + }() +} + +var x *int + +func fooleak(xx *int) int { // ERROR "leaking param: xx" + x = xx + return *x +} + +func foonoleak(xx *int) int { // ERROR "xx does not escape" + return *x + *xx +} + +func foo31(x int) int { // ERROR "moved to heap: x" + return fooleak(&x) // ERROR "&x escapes to heap" +} + +func foo32(x int) int { + return foonoleak(&x) // ERROR "&x does not escape" +} + +type Foo struct { + xx *int + x int +} + +var F Foo +var pf *Foo + +func (f *Foo) fooleak() { // ERROR "leaking param: f" + pf = f +} + +func (f *Foo) foonoleak() { // ERROR "f does not escape" + F.x = f.x +} + +func (f *Foo) Leak() { // ERROR "leaking param: f" + f.fooleak() +} + +func (f *Foo) NoLeak() { // ERROR "f does not escape" + f.foonoleak() +} + +func foo41(x int) { // ERROR "moved to heap: x" + F.xx = &x // ERROR "&x escapes to heap" +} + +func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x" + f.xx = &x // ERROR "&x escapes to heap" +} + +func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x" + f.xx = &x // ERROR "&x escapes to heap" +} + +func foo44(yy *int) { // ERROR "leaking param: yy" + F.xx = yy +} + +func (f *Foo) foo45() { // ERROR "f does not escape" + F.x = f.x +} + +// See foo13 above for explanation of why f leaks. +func (f *Foo) foo46() { // ERROR "leaking param: f" + F.xx = f.xx +} + +func (f *Foo) foo47() { // ERROR "leaking param: f" + f.xx = &f.x // ERROR "&f.x escapes to heap" +} + +var ptrSlice []*int + +func foo50(i *int) { // ERROR "leaking param: i" + ptrSlice[0] = i +} + +var ptrMap map[*int]*int + +func foo51(i *int) { // ERROR "leaking param: i" + ptrMap[i] = i +} + +func indaddr1(x int) *int { // ERROR "moved to heap: x" + return &x // ERROR "&x escapes to heap" +} + +func indaddr2(x *int) *int { // ERROR "leaking param: x" + return *&x // ERROR "&x does not escape" +} + +func indaddr3(x *int32) *int { // ERROR "leaking param: x" + return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape" +} + +// From package math: + +func Float32bits(f float32) uint32 { + return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape" +} + +func Float32frombits(b uint32) float32 { + return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape" +} + +func Float64bits(f float64) uint64 { + return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape" +} + +func Float64frombits(b uint64) float64 { + return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape" +} + +// contrast with +func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f" + return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap" +} + +func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f" + return (*uint64)(unsafe.Pointer(f)) +} + +func typesw(i interface{}) *int { // ERROR "leaking param: i" + switch val := i.(type) { + case *int: + return val + case *int8: + v := int(*val) // ERROR "moved to heap: v" + return &v // ERROR "&v escapes to heap" + } + return nil +} + +func exprsw(i *int) *int { // ERROR "leaking param: i" + switch j := i; *j + 110 { + case 12: + return j + case 42: + return nil + } + return nil + +} + +// assigning to an array element is like assigning to the array +func foo60(i *int) *int { // ERROR "leaking param: i" + var a [12]*int + a[0] = i + return a[1] +} + +func foo60a(i *int) *int { // ERROR "i does not escape" + var a [12]*int + a[0] = i + return nil +} + +// assigning to a struct field is like assigning to the struct +func foo61(i *int) *int { // ERROR "leaking param: i" + type S struct { + a, b *int + } + var s S + s.a = i + return s.b +} + +func foo61a(i *int) *int { // ERROR "i does not escape" + type S struct { + a, b *int + } + var s S + s.a = i + return nil +} + +// assigning to a struct field is like assigning to the struct but +// here this subtlety is lost, since s.a counts as an assignment to a +// track-losing dereference. +func foo62(i *int) *int { // ERROR "leaking param: i" + type S struct { + a, b *int + } + s := new(S) // ERROR "new[(]S[)] does not escape" + s.a = i + return nil // s.b +} + +type M interface { + M() +} + +func foo63(m M) { // ERROR "m does not escape" +} + +func foo64(m M) { // ERROR "leaking param: m" + m.M() +} + +func foo64b(m M) { // ERROR "leaking param: m" + defer m.M() +} + +type MV int + +func (MV) M() {} + +func foo65() { + var mv MV + foo63(&mv) // ERROR "&mv does not escape" +} + +func foo66() { + var mv MV // ERROR "moved to heap: mv" + foo64(&mv) // ERROR "&mv escapes to heap" +} + +func foo67() { + var mv MV + foo63(mv) +} + +func foo68() { + var mv MV + foo64(mv) // escapes but it's an int so irrelevant +} + +func foo69(m M) { // ERROR "leaking param: m" + foo64(m) +} + +func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m" + m = mv1 + foo64(m) +} + +func foo71(x *int) []*int { // ERROR "leaking param: x" + var y []*int + y = append(y, x) + return y +} + +func foo71a(x int) []*int { // ERROR "moved to heap: x" + var y []*int + y = append(y, &x) // ERROR "&x escapes to heap" + return y +} + +func foo72() { + var x int + var y [1]*int + y[0] = &x // ERROR "&x does not escape" +} + +func foo72aa() [10]*int { + var x int // ERROR "moved to heap: x" + var y [10]*int + y[0] = &x // ERROR "&x escapes to heap" + return y +} + +func foo72a() { + var y [10]*int + for i := 0; i < 10; i++ { + // escapes its scope + x := i // ERROR "moved to heap: x" + y[i] = &x // ERROR "&x escapes to heap" + } + return +} + +func foo72b() [10]*int { + var y [10]*int + for i := 0; i < 10; i++ { + x := i // ERROR "moved to heap: x" + y[i] = &x // ERROR "&x escapes to heap" + } + return y +} + +// issue 2145 +func foo73() { + s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape" + for _, v := range s { + vv := v // ERROR "moved to heap: vv" + // actually just escapes its scope + defer func() { // ERROR "func literal escapes to heap" + println(vv) // ERROR "&vv escapes to heap" + }() + } +} + +func foo74() { + s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape" + for _, v := range s { + vv := v // ERROR "moved to heap: vv" + // actually just escapes its scope + fn := func() { // ERROR "func literal escapes to heap" + println(vv) // ERROR "&vv escapes to heap" + } + defer fn() + } +} + +// issue 3975 +func foo74b() { + var array [3]func() + s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape" + for i, v := range s { + vv := v // ERROR "moved to heap: vv" + // actually just escapes its scope + array[i] = func() { // ERROR "func literal escapes to heap" + println(vv) // ERROR "&vv escapes to heap" + } + } +} + +func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y" + return y +} + +func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x" + return &x[0] // ERROR "&x.0. escapes to heap" +} + +func foo75(z *int) { // ERROR "z does not escape" + myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo75a(z *int) { // ERROR "z does not escape" + myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo75esc(z *int) { // ERROR "leaking param: z" + gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo75aesc(z *int) { // ERROR "z does not escape" + var ppi **interface{} // assignments to pointer dereferences lose track + *ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" +} + +func foo76(z *int) { // ERROR "leaking param: z" + myprint(nil, z) // ERROR "[.][.][.] argument does not escape" +} + +func foo76a(z *int) { // ERROR "leaking param: z" + myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" +} + +func foo76b() { + myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo76c() { + myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo76d() { + defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo76e() { + defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" +} + +func foo76f() { + for { + // TODO: This one really only escapes its scope, but we don't distinguish yet. + defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" + } +} + +func foo76g() { + for { + defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" + } +} + +func foo77(z []interface{}) { // ERROR "z does not escape" + myprint(nil, z...) // z does not escape +} + +func foo77a(z []interface{}) { // ERROR "z does not escape" + myprint1(nil, z...) +} + +func foo77b(z []interface{}) { // ERROR "leaking param: z" + var ppi **interface{} + *ppi = myprint1(nil, z...) +} + +func foo78(z int) *int { // ERROR "moved to heap: z" + return &z // ERROR "&z escapes to heap" +} + +func foo78a(z int) *int { // ERROR "moved to heap: z" + y := &z // ERROR "&z escapes to heap" + x := &y // ERROR "&y does not escape" + return *x // really return y +} + +func foo79() *int { + return new(int) // ERROR "new[(]int[)] escapes to heap" +} + +func foo80() *int { + var z *int + for { + // Really just escapes its scope but we don't distinguish + z = new(int) // ERROR "new[(]int[)] escapes to heap" + } + _ = z + return nil +} + +func foo81() *int { + for { + z := new(int) // ERROR "new[(]int[)] does not escape" + _ = z + } + return nil +} + +func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param" + +func noop(x, y *int) {} // ERROR "does not escape" + +func foo82() { + var x, y, z int // ERROR "moved to heap" + go noop(tee(&z)) // ERROR "&z escapes to heap" + go noop(&x, &y) // ERROR "escapes to heap" + for { + var u, v, w int // ERROR "moved to heap" + defer noop(tee(&u)) // ERROR "&u escapes to heap" + defer noop(&v, &w) // ERROR "escapes to heap" + } +} + +type Fooer interface { + Foo() +} + +type LimitedFooer struct { + Fooer + N int64 +} + +func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r" + return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap" +} + +func foo90(x *int) map[*int]*int { // ERROR "leaking param: x" + return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap" +} + +func foo91(x *int) map[*int]*int { // ERROR "leaking param: x" + return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap" +} + +func foo92(x *int) [2]*int { // ERROR "leaking param: x" + return [2]*int{x, nil} +} + +// does not leak c +func foo93(c chan *int) *int { // ERROR "c does not escape" + for v := range c { + return v + } + return nil +} + +// does not leak m +func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape" + for k, v := range m { + if b { + return k + } + return v + } + return nil +} + +// does leak x +func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x" + m[x] = x +} + +// does not leak m +func foo96(m []*int) *int { // ERROR "m does not escape" + return m[0] +} + +// does leak m +func foo97(m [1]*int) *int { // ERROR "leaking param: m" + return m[0] +} + +// does not leak m +func foo98(m map[int]*int) *int { // ERROR "m does not escape" + return m[0] +} + +// does leak m +func foo99(m *[1]*int) []*int { // ERROR "leaking param: m" + return m[:] +} + +// does not leak m +func foo100(m []*int) *int { // ERROR "m does not escape" + for _, v := range m { + return v + } + return nil +} + +// does leak m +func foo101(m [1]*int) *int { // ERROR "leaking param: m" + for _, v := range m { + return v + } + return nil +} + +// does not leak m +func foo101a(m [1]*int) *int { // ERROR "m does not escape" + for i := range m { // ERROR "moved to heap: i" + return &i // ERROR "&i escapes to heap" + } + return nil +} + +// does leak x +func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x" + m[0] = x +} + +// does not leak x +func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape" + m[0] = x +} + +var y []*int + +// does not leak x +func foo104(x []*int) { // ERROR "x does not escape" + copy(y, x) +} + +// does not leak x +func foo105(x []*int) { // ERROR "x does not escape" + _ = append(y, x...) +} + +// does leak x +func foo106(x *int) { // ERROR "leaking param: x" + _ = append(y, x) +} + +func foo107(x *int) map[*int]*int { // ERROR "leaking param: x" + return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap" +} + +func foo108(x *int) map[*int]*int { // ERROR "leaking param: x" + return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap" +} + +func foo109(x *int) *int { // ERROR "leaking param: x" + m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape" + for k, _ := range m { + return k + } + return nil +} + +func foo110(x *int) *int { // ERROR "leaking param: x" + m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape" + return m[nil] +} + +func foo111(x *int) *int { // ERROR "leaking param: x" + m := []*int{x} // ERROR "\[\]\*int literal does not escape" + return m[0] +} + +func foo112(x *int) *int { // ERROR "leaking param: x" + m := [1]*int{x} + return m[0] +} + +func foo113(x *int) *int { // ERROR "leaking param: x" + m := Bar{ii: x} + return m.ii +} + +func foo114(x *int) *int { // ERROR "leaking param: x" + m := &Bar{ii: x} // ERROR "&Bar literal does not escape" + return m.ii +} + +func foo115(x *int) *int { // ERROR "leaking param: x" + return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1)) +} + +func foo116(b bool) *int { + if b { + x := 1 // ERROR "moved to heap: x" + return &x // ERROR "&x escapes to heap" + } else { + y := 1 // ERROR "moved to heap: y" + return &y // ERROR "&y escapes to heap" + } + return nil +} + +func foo117(unknown func(interface{})) { // ERROR "unknown does not escape" + x := 1 // ERROR "moved to heap: x" + unknown(&x) // ERROR "&x escapes to heap" +} + +func foo118(unknown func(*int)) { // ERROR "unknown does not escape" + x := 1 // ERROR "moved to heap: x" + unknown(&x) // ERROR "&x escapes to heap" +} + +func external(*int) + +func foo119(x *int) { // ERROR "leaking param: x" + external(x) +} + +func foo120() { + // formerly exponential time analysis +L1: +L2: +L3: +L4: +L5: +L6: +L7: +L8: +L9: +L10: +L11: +L12: +L13: +L14: +L15: +L16: +L17: +L18: +L19: +L20: +L21: +L22: +L23: +L24: +L25: +L26: +L27: +L28: +L29: +L30: +L31: +L32: +L33: +L34: +L35: +L36: +L37: +L38: +L39: +L40: +L41: +L42: +L43: +L44: +L45: +L46: +L47: +L48: +L49: +L50: +L51: +L52: +L53: +L54: +L55: +L56: +L57: +L58: +L59: +L60: +L61: +L62: +L63: +L64: +L65: +L66: +L67: +L68: +L69: +L70: +L71: +L72: +L73: +L74: +L75: +L76: +L77: +L78: +L79: +L80: +L81: +L82: +L83: +L84: +L85: +L86: +L87: +L88: +L89: +L90: +L91: +L92: +L93: +L94: +L95: +L96: +L97: +L98: +L99: +L100: + // use the labels to silence compiler errors + goto L1 + goto L2 + goto L3 + goto L4 + goto L5 + goto L6 + goto L7 + goto L8 + goto L9 + goto L10 + goto L11 + goto L12 + goto L13 + goto L14 + goto L15 + goto L16 + goto L17 + goto L18 + goto L19 + goto L20 + goto L21 + goto L22 + goto L23 + goto L24 + goto L25 + goto L26 + goto L27 + goto L28 + goto L29 + goto L30 + goto L31 + goto L32 + goto L33 + goto L34 + goto L35 + goto L36 + goto L37 + goto L38 + goto L39 + goto L40 + goto L41 + goto L42 + goto L43 + goto L44 + goto L45 + goto L46 + goto L47 + goto L48 + goto L49 + goto L50 + goto L51 + goto L52 + goto L53 + goto L54 + goto L55 + goto L56 + goto L57 + goto L58 + goto L59 + goto L60 + goto L61 + goto L62 + goto L63 + goto L64 + goto L65 + goto L66 + goto L67 + goto L68 + goto L69 + goto L70 + goto L71 + goto L72 + goto L73 + goto L74 + goto L75 + goto L76 + goto L77 + goto L78 + goto L79 + goto L80 + goto L81 + goto L82 + goto L83 + goto L84 + goto L85 + goto L86 + goto L87 + goto L88 + goto L89 + goto L90 + goto L91 + goto L92 + goto L93 + goto L94 + goto L95 + goto L96 + goto L97 + goto L98 + goto L99 + goto L100 +} + +func foo121() { + for i := 0; i < 10; i++ { + defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" + go myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" + } +} + +// same as foo121 but check across import +func foo121b() { + for i := 0; i < 10; i++ { + defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" + go fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" + } +} + +// a harmless forward jump +func foo122() { + var i *int + + goto L1 +L1: + i = new(int) // ERROR "new.int. does not escape" + _ = i +} + +// a backward jump, increases loopdepth +func foo123() { + var i *int + +L1: + i = new(int) // ERROR "new.int. escapes to heap" + + goto L1 + _ = i +} + +func foo124(x **int) { // ERROR "x does not escape" + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes" + func() { // ERROR "func literal does not escape" + *x = p // ERROR "leaking closure reference p" + }() +} + +func foo125(ch chan *int) { // ERROR "does not escape" + var i int // ERROR "moved to heap" + p := &i // ERROR "&i escapes to heap" + func() { // ERROR "func literal does not escape" + ch <- p // ERROR "leaking closure reference p" + }() +} + +func foo126() { + var px *int // loopdepth 0 + for { + // loopdepth 1 + var i int // ERROR "moved to heap" + func() { // ERROR "func literal does not escape" + px = &i // ERROR "&i escapes" + }() + } + _ = px +} + +var px *int + +func foo127() { + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes to heap" + q := p + px = q +} + +func foo128() { + var i int + p := &i // ERROR "&i does not escape" + q := p + _ = q +} + +func foo129() { + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes to heap" + func() { // ERROR "func literal does not escape" + q := p // ERROR "leaking closure reference p" + func() { // ERROR "func literal does not escape" + r := q // ERROR "leaking closure reference q" + px = r + }() + }() +} + +func foo130() { + for { + var i int // ERROR "moved to heap" + func() { // ERROR "func literal does not escape" + px = &i // ERROR "&i escapes" "leaking closure reference i" + }() + } +} + +func foo131() { + var i int // ERROR "moved to heap" + func() { // ERROR "func literal does not escape" + px = &i // ERROR "&i escapes" "leaking closure reference i" + }() +} + +func foo132() { + var i int // ERROR "moved to heap" + go func() { // ERROR "func literal escapes to heap" + px = &i // ERROR "&i escapes" "leaking closure reference i" + }() +} + +func foo133() { + var i int // ERROR "moved to heap" + defer func() { // ERROR "func literal does not escape" + px = &i // ERROR "&i escapes" "leaking closure reference i" + }() +} + +func foo134() { + var i int + p := &i // ERROR "&i does not escape" + func() { // ERROR "func literal does not escape" + q := p + func() { // ERROR "func literal does not escape" + r := q + _ = r + }() + }() +} + +func foo135() { + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes to heap" "moved to heap: p" + go func() { // ERROR "func literal escapes to heap" + q := p // ERROR "&p escapes to heap" + func() { // ERROR "func literal does not escape" + r := q + _ = r + }() + }() +} + +func foo136() { + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes to heap" "moved to heap: p" + go func() { // ERROR "func literal escapes to heap" + q := p // ERROR "&p escapes to heap" "leaking closure reference p" + func() { // ERROR "func literal does not escape" + r := q // ERROR "leaking closure reference q" + px = r + }() + }() +} + +func foo137() { + var i int // ERROR "moved to heap: i" + p := &i // ERROR "&i escapes to heap" + func() { // ERROR "func literal does not escape" + q := p // ERROR "leaking closure reference p" "moved to heap: q" + go func() { // ERROR "func literal escapes to heap" + r := q // ERROR "&q escapes to heap" + _ = r + }() + }() +} + +func foo138() *byte { + type T struct { + x [1]byte + } + t := new(T) // ERROR "new.T. escapes to heap" + return &t.x[0] // ERROR "&t.x.0. escapes to heap" +} + +func foo139() *byte { + type T struct { + x struct { + y byte + } + } + t := new(T) // ERROR "new.T. escapes to heap" + return &t.x.y // ERROR "&t.x.y escapes to heap" +} + +// issue 4751 +func foo140() interface{} { + type T struct { + X string + } + type U struct { + X string + T *T + } + t := &T{} // ERROR "&T literal escapes to heap" + return U{ + X: t.X, + T: t, + } +} + +//go:noescape + +func F1([]byte) + +func F2([]byte) + +//go:noescape + +func F3(x []byte) // ERROR "F3 x does not escape" + +func F4(x []byte) + +func G() { + var buf1 [10]byte + F1(buf1[:]) // ERROR "buf1 does not escape" + + var buf2 [10]byte // ERROR "moved to heap: buf2" + F2(buf2[:]) // ERROR "buf2 escapes to heap" + + var buf3 [10]byte + F3(buf3[:]) // ERROR "buf3 does not escape" + + var buf4 [10]byte // ERROR "moved to heap: buf4" + F4(buf4[:]) // ERROR "buf4 escapes to heap" +} + +type Tm struct { + x int +} + +func (t *Tm) M() { // ERROR "t does not escape" +} + +func foo141() { + var f func() + + t := new(Tm) // ERROR "escapes to heap" + f = t.M // ERROR "t.M does not escape" + _ = f +} + +var gf func() + +func foo142() { + t := new(Tm) // ERROR "escapes to heap" + gf = t.M // ERROR "t.M escapes to heap" +} + +// issue 3888. +func foo143() { + for i := 0; i < 1000; i++ { + func() { // ERROR "func literal does not escape" + for i := 0; i < 1; i++ { + var t Tm + t.M() // ERROR "t does not escape" + } + }() + } +} + +// issue 5773 +// Check that annotations take effect regardless of whether they +// are before or after the use in the source code. + +//go:noescape + +func foo144a(*int) + +func foo144() { + var x int + foo144a(&x) // ERROR "&x does not escape" + var y int + foo144b(&y) // ERROR "&y does not escape" +} + +//go:noescape + +func foo144b(*int) + +// issue 7313: for loop init should not be treated as "in loop" + +type List struct { + Next *List +} + +func foo145(l List) { // ERROR "l does not escape" + var p *List + for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape" + } +} + +func foo146(l List) { // ERROR "l does not escape" + var p *List + p = &l // ERROR "&l does not escape" + for ; p.Next != nil; p = p.Next { + } +} + +func foo147(l List) { // ERROR "l does not escape" + var p *List + p = &l // ERROR "&l does not escape" + for p.Next != nil { + p = p.Next + } +} + +func foo148(l List) { // ERROR " l does not escape" + for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape" + } +} + +// related: address of variable should have depth of variable, not of loop + +func foo149(l List) { // ERROR " l does not escape" + var p *List + for { + for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape" + } + } +} + +// issue 7934: missed ... if element type had no pointers + +var save150 []byte + +func foo150(x ...byte) { // ERROR "leaking param: x" + save150 = x +} + +func bar150() { + foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" +} + +// issue 7931: bad handling of slice of array + +var save151 *int + +func foo151(x *int) { // ERROR "leaking param: x" + save151 = x +} + +func bar151() { + var a [64]int // ERROR "moved to heap: a" + a[4] = 101 + foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap" +} + +func bar151b() { + var a [10]int // ERROR "moved to heap: a" + b := a[:] // ERROR "a escapes to heap" + foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap" +} + +func bar151c() { + var a [64]int // ERROR "moved to heap: a" + a[4] = 101 + foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap" +} + +func bar151d() { + var a [10]int // ERROR "moved to heap: a" + b := a[:] // ERROR "a escapes to heap" + foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap" +} + +// issue 8120 + +type U struct { + s *string +} + +func (u *U) String() *string { // ERROR "leaking param u content to result ~r0" + return u.s +} + +type V struct { + s *string +} + +func NewV(u U) *V { // ERROR "leaking param: u" + return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape" +} + +func foo152() { + a := "a" // ERROR "moved to heap: a" + u := U{&a} // ERROR "&a escapes to heap" + v := NewV(u) + println(v) +} + +// issue 8176 - &x in type switch body not marked as escaping + +func foo153(v interface{}) *int { // ERROR "leaking param: v" + switch x := v.(type) { + case int: // ERROR "moved to heap: x" + return &x // ERROR "&x escapes to heap" + } + panic(0) +} + +// issue 8185 - &result escaping into result + +func f() (x int, y *int) { // ERROR "moved to heap: x" + y = &x // ERROR "&x escapes to heap" + return +} + +func g() (x interface{}) { // ERROR "moved to heap: x" + x = &x // ERROR "&x escapes to heap" + return +} From fb4e185a99f3e93bc1bbe08a09ebfd5419409d48 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 24 Sep 2014 12:42:47 -0700 Subject: [PATCH 174/430] src: pass GO_GCFLAGS down to go test std Update #8725 LGTM=rsc, josharian R=rsc, josharian CC=golang-codereviews https://golang.org/cl/149000043 --- src/run.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/run.bash b/src/run.bash index d6e53304d8..4966cf1aa6 100755 --- a/src/run.bash +++ b/src/run.bash @@ -52,7 +52,7 @@ timeout_scale=1 [ "$GOARCH" == "arm" ] && timeout_scale=3 echo '# Testing packages.' -time go test std -short -timeout=$(expr 120 \* $timeout_scale)s +time go test std -short -timeout=$(expr 120 \* $timeout_scale)s -gcflags "$GO_GCFLAGS" echo # We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code, From 43c4287b25da53b2e8cb0de64d40689c56eb42bd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 16:53:34 -0400 Subject: [PATCH 175/430] cmd/gc: fix import of package with var func returning _ Fixes #8280. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/146240043 --- src/cmd/gc/fmt.c | 15 +++++---------- test/fixedbugs/issue8280.dir/a.go | 3 +++ test/fixedbugs/issue8280.dir/b.go | 5 +++++ test/fixedbugs/issue8280.go | 9 +++++++++ 4 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 test/fixedbugs/issue8280.dir/a.go create mode 100644 test/fixedbugs/issue8280.dir/b.go create mode 100644 test/fixedbugs/issue8280.go diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index 98556a658f..f67757449b 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -1108,16 +1108,11 @@ exprfmt(Fmt *f, Node *n, int prec) case ONAME: // Special case: name used as local variable in export. - switch(n->class&~PHEAP){ - case PAUTO: - case PPARAM: - case PPARAMOUT: - // _ becomes ~b%d internally; print as _ for export - if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') - return fmtprint(f, "_"); - if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) - return fmtprint(f, "%S·%d", n->sym, n->vargen); - } + // _ becomes ~b%d internally; print as _ for export + if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') + return fmtprint(f, "_"); + if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) + return fmtprint(f, "%S·%d", n->sym, n->vargen); // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, // but for export, this should be rendered as (*pkg.T).meth. diff --git a/test/fixedbugs/issue8280.dir/a.go b/test/fixedbugs/issue8280.dir/a.go new file mode 100644 index 0000000000..588536e79a --- /dev/null +++ b/test/fixedbugs/issue8280.dir/a.go @@ -0,0 +1,3 @@ +package a + +var Bar = func() (_ int) { return 0 } diff --git a/test/fixedbugs/issue8280.dir/b.go b/test/fixedbugs/issue8280.dir/b.go new file mode 100644 index 0000000000..c46c554588 --- /dev/null +++ b/test/fixedbugs/issue8280.dir/b.go @@ -0,0 +1,5 @@ +package b + +import "./a" + +var foo = a.Bar diff --git a/test/fixedbugs/issue8280.go b/test/fixedbugs/issue8280.go new file mode 100644 index 0000000000..91256c852d --- /dev/null +++ b/test/fixedbugs/issue8280.go @@ -0,0 +1,9 @@ +// compiledir + +// 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. + +// Issue 8280: cannot import package exporting a func var returning a result named _ + +package ignored From 5917692b98695b606744f638224a82a2472bfeaa Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 16:53:47 -0400 Subject: [PATCH 176/430] debug/dwarf: correct name for clang-generated complex type Fixes #8694. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/143570043 --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue8694.go | 32 ++++++++++++++++++++++++++++++++ src/debug/dwarf/type.go | 11 +++++++++++ 3 files changed, 44 insertions(+) create mode 100644 misc/cgo/test/issue8694.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 1899d46053..1d1abf7291 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -57,5 +57,6 @@ func Test7560(t *testing.T) { test7560(t) } func Test5242(t *testing.T) { test5242(t) } func Test8092(t *testing.T) { test8092(t) } func Test7978(t *testing.T) { test7978(t) } +func Test8694(t *testing.T) { test8694(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/misc/cgo/test/issue8694.go b/misc/cgo/test/issue8694.go new file mode 100644 index 0000000000..643b284f6a --- /dev/null +++ b/misc/cgo/test/issue8694.go @@ -0,0 +1,32 @@ +// 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 cgotest + +/* +#include + +complex float complexFloatSquared(complex float a) { return a*a; } +complex double complexDoubleSquared(complex double a) { return a*a; } +*/ +import "C" + +import "testing" + +func test8694(t *testing.T) { + // Really just testing that this compiles, but check answer anyway. + x := complex64(2 + 3i) + x2 := x * x + cx2 := C.complexFloatSquared(x) + if cx2 != x2 { + t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2) + } + + y := complex128(2 + 3i) + y2 := y * y + cy2 := C.complexDoubleSquared(y) + if cy2 != y2 { + t.Errorf("C.complexDoubleSquared(%v) = %v, want %v", y, cy2, y2) + } +} diff --git a/src/debug/dwarf/type.go b/src/debug/dwarf/type.go index fa40b2bef1..6986b19e72 100644 --- a/src/debug/dwarf/type.go +++ b/src/debug/dwarf/type.go @@ -431,6 +431,17 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off typ = new(BoolType) case encComplexFloat: typ = new(ComplexType) + if name == "complex" { + // clang writes out 'complex' instead of 'complex float' or 'complex double'. + // clang also writes out a byte size that we can use to distinguish. + // See issue 8694. + switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { + case 8: + name = "complex float" + case 16: + name = "complex double" + } + } case encFloat: typ = new(FloatType) case encSigned: From 193daab9889708f7a20ff46efe0fa4b2bf0468d3 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 16:55:26 -0400 Subject: [PATCH 177/430] cmd/cc, cmd/ld, runtime: disallow conservative data/bss objects In linker, refuse to write conservative (array of pointers) as the garbage collection type for any variable in the data/bss GC program. In the linker, attach the Go type to an already-read C declaration during dedup. This gives us Go types for C globals for free as long as the cmd/dist-generated Go code contains the declaration. (Most runtime C declarations have a corresponding Go declaration. Both are bss declarations and so the linker dedups them.) In cmd/dist, add a few more C files to the auto-Go-declaration list in order to get Go type information for the C declarations into the linker. In C compiler, mark all non-pointer-containing global declarations and all string data as NOPTR. This allows them to exist in C files without any corresponding Go declaration. Count C function pointers as "non-pointer-containing", since we have no heap-allocated C functions. In runtime, add NOPTR to the remaining pointer-containing declarations, none of which refer to Go heap objects. In runtime, also move os.Args and syscall.envs data into runtime-owned variables. Otherwise, in programs that do not import os or syscall, the runtime variables named os.Args and syscall.envs will be missing type information. I believe that this CL eliminates the final source of conservative GC scanning in non-SWIG Go programs, and therefore... Fixes #909. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/149770043 --- src/cmd/cc/dcl.c | 9 ++++++--- src/cmd/cc/lex.c | 2 ++ src/cmd/cgo/out.go | 13 +++++++++++++ src/cmd/dist/buildruntime.c | 2 ++ src/cmd/ld/data.c | 1 + src/liblink/objfile.c | 6 ++++-- src/os/proc.go | 6 ++++++ src/runtime/asm_386.s | 2 -- src/runtime/asm_amd64.s | 2 -- src/runtime/asm_amd64p32.s | 2 -- src/runtime/heapdump.c | 3 +++ src/runtime/malloc.c | 23 ----------------------- src/runtime/malloc.h | 2 -- src/runtime/mcache.c | 2 +- src/runtime/mgc0.c | 5 ++--- src/runtime/os_windows.c | 6 +++--- src/runtime/proc.c | 30 +++++++++--------------------- src/runtime/proc.go | 8 ++++++++ src/runtime/runtime.c | 25 ++++++++++++++++--------- src/runtime/runtime.go | 11 +++++++++++ src/runtime/signals_darwin.h | 3 +++ src/runtime/signals_dragonfly.h | 3 +++ src/runtime/signals_freebsd.h | 3 +++ src/runtime/signals_linux.h | 3 +++ src/runtime/signals_nacl.h | 3 +++ src/runtime/signals_netbsd.h | 3 +++ src/runtime/signals_openbsd.h | 3 +++ src/runtime/signals_plan9.h | 3 +++ src/runtime/signals_solaris.h | 3 +++ src/runtime/stack.c | 4 ++-- src/runtime/thunk.s | 8 +++++++- src/syscall/env_unix.go | 4 +++- 32 files changed, 126 insertions(+), 77 deletions(-) diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index 292717d688..117508fd6d 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -30,6 +30,9 @@ #include #include "cc.h" +#include "../ld/textflag.h" + +static int haspointers(Type*); Node* dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) @@ -123,7 +126,8 @@ loop: if(dataflag) { s->dataflag = dataflag; dataflag = 0; - } + } else if(s->type != T && !haspointers(s->type)) + s->dataflag = NOPTR; firstbit = 0; n->sym = s; n->type = s->type; @@ -568,9 +572,8 @@ haspointers(Type *t) return 0; case TARRAY: return haspointers(t->link); - case TFUNC: case TIND: - return 1; + return t->link->etype != TFUNC; default: return 0; } diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c index 55fc36b1e0..7c9f718c09 100644 --- a/src/cmd/cc/lex.c +++ b/src/cmd/cc/lex.c @@ -31,6 +31,7 @@ #include #include "cc.h" #include "y.tab.h" +#include "../ld/textflag.h" #ifndef CPP #define CPP "cpp" @@ -1317,6 +1318,7 @@ cinit(void) t->width = 0; symstring = slookup(".string"); symstring->class = CSTATIC; + symstring->dataflag = NOPTR; symstring->type = t; t = typ(TARRAY, types[TCHAR]); diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 6586531ada..2d14f766fc 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -129,6 +129,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C) } else { + fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n") fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C) } fmt.Fprintf(fc, "\n") @@ -397,6 +398,7 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { // C wrapper calls into gcc, passing a pointer to the argument frame. fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname) fmt.Fprintf(fc, "void %s(void*);\n", cname) + fmt.Fprintf(fc, "#pragma dataflag NOPTR\n") fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname) nret := 0 @@ -1151,20 +1153,31 @@ void *_CMalloc(size_t); const cProlog = ` #include "runtime.h" #include "cgocall.h" +#include "textflag.h" +#pragma dataflag NOPTR static void *cgocall_errno = runtime·cgocall_errno; +#pragma dataflag NOPTR void *·_cgo_runtime_cgocall_errno = &cgocall_errno; +#pragma dataflag NOPTR static void *runtime_gostring = runtime·gostring; +#pragma dataflag NOPTR void *·_cgo_runtime_gostring = &runtime_gostring; +#pragma dataflag NOPTR static void *runtime_gostringn = runtime·gostringn; +#pragma dataflag NOPTR void *·_cgo_runtime_gostringn = &runtime_gostringn; +#pragma dataflag NOPTR static void *runtime_gobytes = runtime·gobytes; +#pragma dataflag NOPTR void *·_cgo_runtime_gobytes = &runtime_gobytes; +#pragma dataflag NOPTR static void *runtime_cmalloc = runtime·cmalloc; +#pragma dataflag NOPTR void *·_cgo_runtime_cmalloc = &runtime_cmalloc; void ·_Cerrno(void*, int32); diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c index 1257d5b811..bb774e05fc 100644 --- a/src/cmd/dist/buildruntime.c +++ b/src/cmd/dist/buildruntime.c @@ -330,9 +330,11 @@ mkzsys(char *dir, char *file) static char *runtimedefs[] = { "defs.c", "malloc.c", + "mcache.c", "mgc0.c", "proc.c", "parfor.c", + "stack.c", }; // mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h, diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 71624c3304..9d224d9eb9 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -818,6 +818,7 @@ proggenaddsym(ProgGen *g, LSym *s) if(s->gotype == nil && s->size >= PtrSize) { // conservative scan + diag("missing Go type information for global symbol: %s", s->name); if((s->size%PtrSize) || (g->pos%PtrSize)) diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", s->name, s->size, g->pos); diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index 9b1e1b7a8f..15d602df92 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -550,7 +550,7 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) static int ndup; char *name; Reloc *r; - LSym *s, *dup; + LSym *s, *dup, *typ; Pcln *pc; Auto *a; @@ -586,7 +586,9 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) s->type = t; if(s->size < size) s->size = size; - s->gotype = rdsym(ctxt, f, pkg); + typ = rdsym(ctxt, f, pkg); + if(typ != nil) // if bss sym defined multiple times, take type from any one def + s->gotype = typ; rddata(f, &s->p, &s->np); s->maxp = s->np; n = rdint(f); diff --git a/src/os/proc.go b/src/os/proc.go index 38c436ec54..b63c85ad90 100644 --- a/src/os/proc.go +++ b/src/os/proc.go @@ -11,6 +11,12 @@ import "syscall" // Args hold the command-line arguments, starting with the program name. var Args []string +func init() { + Args = runtime_args() +} + +func runtime_args() []string // in package runtime + // Getuid returns the numeric user id of the caller. func Getuid() int { return syscall.Getuid() } diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 2961f10f2a..846a214d55 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -903,8 +903,6 @@ TEXT runtime·emptyfunc(SB),0,$0-0 TEXT runtime·abort(SB),NOSPLIT,$0-0 INT $0x3 -GLOBL runtime·tls0(SB), $32 - // hash function using AES hardware instructions TEXT runtime·aeshash(SB),NOSPLIT,$0-16 MOVL p+0(FP), AX // ptr to data diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 44159bb57e..7304d79a2f 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -871,8 +871,6 @@ TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 MOVQ AX, ret+0(FP) RET -GLOBL runtime·tls0(SB), $64 - // hash function using AES hardware instructions TEXT runtime·aeshash(SB),NOSPLIT,$0-32 MOVQ p+0(FP), AX // ptr to data diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index bbbd886a53..13a1642568 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -674,8 +674,6 @@ TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 MOVQ AX, ret+0(FP) RET -GLOBL runtime·tls0(SB), $64 - // hash function using AES hardware instructions // For now, our one amd64p32 system (NaCl) does not // support using AES instructions, so have not bothered to diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index 75897c3d35..54b9666b55 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -59,6 +59,8 @@ static BitVector makeheapobjbv(byte *p, uintptr size); // fd to write the dump to. static uintptr dumpfd; + +#pragma dataflag NOPTR /* tmpbuf not a heap pointer at least */ static byte *tmpbuf; static uintptr tmpbufsize; @@ -109,6 +111,7 @@ typedef struct TypeCacheBucket TypeCacheBucket; struct TypeCacheBucket { Type *t[TypeCacheAssoc]; }; +#pragma dataflag NOPTR /* only initialized and used while world is stopped */ static TypeCacheBucket typecache[TypeCacheBuckets]; // dump a uint64 in a varint format parseable by encoding/binary diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index 60d20a992d..b79c30b720 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -329,29 +329,6 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n) return p; } -// Runtime stubs. - -static void* -cnew(Type *typ, intgo n) -{ - if(n < 0 || (typ->size > 0 && n > MaxMem/typ->size)) - runtime·throw("runtime: allocation size out of range"); - return runtime·mallocgc(typ->size*n, typ, typ->kind&KindNoPointers ? FlagNoScan : 0); -} - -// same as runtime·new, but callable from C -void* -runtime·cnew(Type *typ) -{ - return cnew(typ, 1); -} - -void* -runtime·cnewarray(Type *typ, intgo n) -{ - return cnew(typ, n); -} - void runtime·setFinalizer_m(void) { diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index 410a007173..b90f1baf29 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -526,8 +526,6 @@ uintptr runtime·sweepone(void); void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover); void runtime·unmarkspan(void *v, uintptr size); void runtime·purgecachedstats(MCache*); -void* runtime·cnew(Type*); -void* runtime·cnewarray(Type*, intgo); void runtime·tracealloc(void*, uintptr, Type*); void runtime·tracefree(void*, uintptr); void runtime·tracegc(void); diff --git a/src/runtime/mcache.c b/src/runtime/mcache.c index 17ea5d2e26..5fdbe32667 100644 --- a/src/runtime/mcache.c +++ b/src/runtime/mcache.c @@ -13,7 +13,7 @@ extern volatile intgo runtime·MemProfileRate; // dummy MSpan that contains no free objects. -static MSpan runtime·emptymspan; +MSpan runtime·emptymspan; MCache* runtime·allocmcache(void) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 54728d5ada..c92fa1db73 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -120,7 +120,7 @@ FinBlock* runtime·finc; // cache of free blocks static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte]; bool runtime·fingwait; bool runtime·fingwake; -static FinBlock *runtime·allfin; // list of all blocks +FinBlock *runtime·allfin; // list of all blocks BitVector runtime·gcdatamask; BitVector runtime·gcbssmask; @@ -140,7 +140,7 @@ static BitVector unrollglobgcprog(byte *prog, uintptr size); void runtime·bgsweep(void); static FuncVal bgsweepv = {runtime·bgsweep}; -static struct { +struct { uint64 full; // lock-free list of full blocks uint64 empty; // lock-free list of empty blocks byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait @@ -1038,7 +1038,6 @@ runtime·MSpan_Sweep(MSpan *s, bool preserve) // State of background runtime·sweep. // Protected by runtime·gclock. -// Must match mgc0.go. struct { G* g; diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 62d94b65a0..6546d51d33 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -147,7 +147,7 @@ runtime·get_random_data(byte **rnd, int32 *rnd_len) void runtime·goenvs(void) { - extern Slice syscall·envs; + extern Slice runtime·envs; uint16 *env; String *s; @@ -160,8 +160,8 @@ runtime·goenvs(void) for(p=env; *p; n++) p += runtime·findnullw(p)+1; - syscall·envs = runtime·makeStringSlice(n); - s = (String*)syscall·envs.array; + runtime·envs = runtime·makeStringSlice(n); + s = (String*)runtime·envs.array; p = env; for(i=0; im->locks++; // disable GC because it can be called from sysmon if(g->m->p == nil) acquirep(p); // temporarily borrow p for mallocs in this function - if(mtype == nil) { - Eface e; - runtime·gc_m_ptr(&e); - mtype = ((PtrType*)e.type)->elem; - } - - mp = runtime·cnew(mtype); + mp = runtime·newM(); mcommoninit(mp); // In case of cgo or Solaris, pthread_create will make us a stack. @@ -889,19 +884,12 @@ runtime·allocm(P *p) return mp; } +G *runtime·newG(void); // in proc.go + static G* allocg(void) { - G *gp; - static Type *gtype; - - if(gtype == nil) { - Eface e; - runtime·gc_g_ptr(&e); - gtype = ((PtrType*)e.type)->elem; - } - gp = runtime·cnew(gtype); - return gp; + return runtime·newG(); } static M* lockextra(bool nilokay); diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 9b95868594..4bb661b54b 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -202,6 +202,14 @@ func newP() *p { return new(p) } +func newM() *m { + return new(m) +} + +func newG() *g { + return new(g) +} + func allgadd(gp *g) { if readgstatus(gp) == _Gidle { gothrow("allgadd: bad status Gidle") diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index aa8dd8f7a0..b3503fb909 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -62,10 +62,12 @@ runtime·mchr(byte *p, byte c, byte *ep) } static int32 argc; + +#pragma dataflag NOPTR /* argv not a heap pointer */ static uint8** argv; -Slice os·Args; -Slice syscall·envs; +extern Slice runtime·argslice; +extern Slice runtime·envs; void (*runtime·sysargs)(int32, uint8**); @@ -97,8 +99,8 @@ runtime·goargs(void) if(Windows) return; - os·Args = runtime·makeStringSlice(argc); - s = (String*)os·Args.array; + runtime·argslice = runtime·makeStringSlice(argc); + s = (String*)runtime·argslice.array; for(i=0; i Date: Wed, 24 Sep 2014 14:33:30 -0700 Subject: [PATCH 178/430] fmt: document and fix the handling of precision for strings and byte slices Previous behavior was undocumented and inconsistent. Now it is documented and consistent and measures the input size, since that makes more sense when talking about %q and %x. For %s the change has no effect. Fixes #8151. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/144540044 --- src/fmt/doc.go | 20 ++++++++++++-------- src/fmt/fmt_test.go | 7 +++++++ src/fmt/format.go | 6 ++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index b7eaedc11e..00dd8d01cd 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -63,16 +63,20 @@ %9.2f width 9, precision 2 %9.f width 9, precision 0 - Width and precision are measured in units of Unicode code points. - (This differs from C's printf where the units are numbers - of bytes.) Either or both of the flags may be replaced with the - character '*', causing their values to be obtained from the next - operand, which must be of type int. + Width and precision are measured in units of Unicode code points, + that is, runes. (This differs from C's printf where the + units are always measured in bytes.) Either or both of the flags + may be replaced with the character '*', causing their values to be + obtained from the next operand, which must be of type int. - For most values, width is the minimum number of characters to output, + For most values, width is the minimum number of runes to output, padding the formatted form with spaces if necessary. - For strings, precision is the maximum number of characters to output, - truncating if necessary. + + For strings, byte slices and byte arrays, however, precision + limits the length of the input to be formatted (not the size of + the output), truncating if necessary. Normally it is measured in + runes, but for these types when formatted with the %x or %X format + it is measured in bytes. For floating-point values, width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index cca0a495ff..4586fcf933 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -194,8 +194,15 @@ var fmtTests = []struct { {"%.5s", "日本語日本語", "日本語日本"}, {"%.5s", []byte("日本語日本語"), "日本語日本"}, {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`}, + {"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`}, + {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`}, + {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`}, {"%.3q", "日本語日本語", `"日本語"`}, {"%.3q", []byte("日本語日本語"), `"日本語"`}, + {"%.1q", "日本語", `"日"`}, + {"%.1q", []byte("日本語"), `"日"`}, + {"%.1x", "日本語", `e6`}, + {"%.1X", []byte("日本語"), `E6`}, {"%10.1q", "日本語日本語", ` "日"`}, {"%3c", '⌘', " ⌘"}, {"%5q", '\u2026', ` '…'`}, diff --git a/src/fmt/format.go b/src/fmt/format.go index 255167c8f5..a92f3c2f86 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -340,11 +340,17 @@ func (f *fmt) fmt_sbx(s string, b []byte, digits string) { // fmt_sx formats a string as a hexadecimal encoding of its bytes. func (f *fmt) fmt_sx(s, digits string) { + if f.precPresent && f.prec < len(s) { + s = s[:f.prec] + } f.fmt_sbx(s, nil, digits) } // fmt_bx formats a byte slice as a hexadecimal encoding of its bytes. func (f *fmt) fmt_bx(b []byte, digits string) { + if f.precPresent && f.prec < len(b) { + b = b[:f.prec] + } f.fmt_sbx("", b, digits) } From 117a6973cb17d45c0c14cd8fb576f5a06b0d7234 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 14:45:11 -0700 Subject: [PATCH 179/430] build: fix elf builds Corrections due to new strict type rules for data+bss. Also disable misc/cgo/cdefstest since you can't compile C code anymore. TBR=iant CC=golang-codereviews https://golang.org/cl/148050044 --- include/link.h | 2 +- src/cmd/ld/data.c | 13 ++++++++++--- src/cmd/ld/lib.c | 4 +++- src/run.bash | 11 +++++++---- src/runtime/vdso_linux_amd64.c | 9 +++++++-- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/include/link.h b/include/link.h index 292b077394..845f9338d9 100644 --- a/include/link.h +++ b/include/link.h @@ -204,10 +204,10 @@ enum SELFSECT, SMACHO, /* Mach-O __nl_symbol_ptr */ SMACHOGOT, + SWINDOWS, SNOPTRDATA, SINITARR, SDATA, - SWINDOWS, SBSS, SNOPTRBSS, STLSBSS, diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 9d224d9eb9..89226bfe28 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -625,6 +625,7 @@ addstrdata(char *name, char *value) sp = linklookup(ctxt, p, 0); free(p); addstring(sp, value); + sp->type = SRODATA; s = linklookup(ctxt, name, 0); s->size = 0; @@ -816,9 +817,15 @@ proggenaddsym(ProgGen *g, LSym *s) proggenskip(g, g->pos, s->value - g->pos); g->pos += s->value - g->pos; - if(s->gotype == nil && s->size >= PtrSize) { + // The test for names beginning with . here is meant + // to keep .dynamic and .dynsym from turning up as + // conservative symbols. They should be marked SELFSECT + // and not SDATA, but sometimes that doesn't happen. + // Leave debugging the SDATA issue for the Go rewrite. + + if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') { // conservative scan - diag("missing Go type information for global symbol: %s", s->name); + diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size); if((s->size%PtrSize) || (g->pos%PtrSize)) diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld", s->name, s->size, g->pos); @@ -834,7 +841,7 @@ proggenaddsym(ProgGen *g, LSym *s) proggenarrayend(g); } g->pos = s->value + size; - } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize) { + } else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') { // no scan if(s->size < 32*PtrSize) { // Emit small symbols as data. diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 36f0f99de2..3edf7253d4 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -221,8 +221,10 @@ loadlib(void) // Provided by the code that imports the package. // Since we are simulating the import, we have to provide this string. cgostrsym = "go.string.\"runtime/cgo\""; - if(linkrlookup(ctxt, cgostrsym, 0) == nil) + if(linkrlookup(ctxt, cgostrsym, 0) == nil) { addstrdata(cgostrsym, "runtime/cgo"); + linklookup(ctxt, cgostrsym, 0)->type = SRODATA; + } } if(linkmode == LinkAuto) { diff --git a/src/run.bash b/src/run.bash index 4966cf1aa6..3c9430c87e 100755 --- a/src/run.bash +++ b/src/run.bash @@ -167,10 +167,13 @@ esac # This tests cgo -cdefs. That mode is not supported, # so it's okay if it doesn't work on some systems. # In particular, it works badly with clang on OS X. -[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || -(xcd ../misc/cgo/testcdefs -./test.bash || exit 1 -) || exit $? +# It doesn't work at all now that we disallow C code +# outside runtime. Once runtime has no C code it won't +# even be necessary. +# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || +# (xcd ../misc/cgo/testcdefs +# ./test.bash || exit 1 +# ) || exit $? [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] || (xcd ../misc/cgo/testgodefs diff --git a/src/runtime/vdso_linux_amd64.c b/src/runtime/vdso_linux_amd64.c index 38e1152438..41a41fdd6a 100644 --- a/src/runtime/vdso_linux_amd64.c +++ b/src/runtime/vdso_linux_amd64.c @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "textflag.h" // Look up symbols in the Linux vDSO. @@ -171,14 +172,18 @@ struct vdso_info { Elf64_Verdef *verdef; }; +#pragma dataflag NOPTR static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 }; // initialize with vsyscall fallbacks +#pragma dataflag NOPTR void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL; +#pragma dataflag NOPTR void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL; +#pragma dataflag NOPTR void* runtime·__vdso_clock_gettime_sym = (void*)0; -#define SYM_KEYS_COUNT 3 +#pragma dataflag NOPTR static symbol_key sym_keys[] = { { (byte*)"__vdso_time", 0xa33c485, &runtime·__vdso_time_sym }, { (byte*)"__vdso_gettimeofday", 0x315ca59, &runtime·__vdso_gettimeofday_sym }, @@ -301,7 +306,7 @@ vdso_parse_symbols(struct vdso_info *vdso_info, int32 version) if(vdso_info->valid == false) return; - for(i=0; ibucket[sym_keys[i].sym_hash % vdso_info->nbucket]; chain != 0; chain = vdso_info->chain[chain]) { From 39cd39b0238b079227460448f298bdd097562e7e Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 25 Sep 2014 01:49:04 +0400 Subject: [PATCH 180/430] cmd/go: strip -fsanitize= flags when building cgo object Fixes #8788. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/142470043 --- src/cmd/go/build.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 2e52731529..27bd307378 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -2228,6 +2228,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi strings.HasSuffix(f, ".so"), strings.HasSuffix(f, ".dll"): continue + // Remove any -fsanitize=foo flags. + // Otherwise the compiler driver thinks that we are doing final link + // and links sanitizer runtime into the object file. But we are not doing + // the final link, we will link the resulting object file again. And + // so the program ends up with two copies of sanitizer runtime. + // See issue 8788 for details. + case strings.HasPrefix(f, "-fsanitize="): + continue default: bareLDFLAGS = append(bareLDFLAGS, f) } From 75cca0526dc00ffeacc2aecfa6a0263a5f276e8b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 17:50:44 -0400 Subject: [PATCH 181/430] runtime: more NOPTR Fixes (or makes better) various builds. TBR=iant CC=golang-codereviews https://golang.org/cl/146280043 --- src/runtime/cgo/dragonfly.c | 4 ++++ src/runtime/cgo/freebsd.c | 4 ++++ src/runtime/cgo/netbsd.c | 4 ++++ src/runtime/cgo/openbsd.c | 4 ++++ src/runtime/os_windows.c | 4 ++++ src/runtime/rt0_windows_386.s | 2 +- src/runtime/rt0_windows_amd64.s | 2 +- 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/runtime/cgo/dragonfly.c b/src/runtime/cgo/dragonfly.c index acf53e2655..3c95ff354e 100644 --- a/src/runtime/cgo/dragonfly.c +++ b/src/runtime/cgo/dragonfly.c @@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "textflag.h" + // Supply environ and __progname, because we don't // link against the standard DragonFly crt0.o and the // libc dynamic library needs them. +#pragma dataflag NOPTR char *environ[1]; +#pragma dataflag NOPTR char *__progname; #pragma dynexport environ environ diff --git a/src/runtime/cgo/freebsd.c b/src/runtime/cgo/freebsd.c index dfcfa3a213..aefc481e64 100644 --- a/src/runtime/cgo/freebsd.c +++ b/src/runtime/cgo/freebsd.c @@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "textflag.h" + // Supply environ and __progname, because we don't // link against the standard FreeBSD crt0.o and the // libc dynamic library needs them. +#pragma dataflag NOPTR char *environ[1]; +#pragma dataflag NOPTR char *__progname; #pragma dynexport environ environ diff --git a/src/runtime/cgo/netbsd.c b/src/runtime/cgo/netbsd.c index b6403f686c..de38bb7707 100644 --- a/src/runtime/cgo/netbsd.c +++ b/src/runtime/cgo/netbsd.c @@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "textflag.h" + // Supply environ and __progname, because we don't // link against the standard NetBSD crt0.o and the // libc dynamic library needs them. +#pragma dataflag NOPTR char *environ[1]; +#pragma dataflag NOPTR char *__progname; #pragma dynexport environ environ diff --git a/src/runtime/cgo/openbsd.c b/src/runtime/cgo/openbsd.c index 84e9f9efff..7c2b6c1737 100644 --- a/src/runtime/cgo/openbsd.c +++ b/src/runtime/cgo/openbsd.c @@ -2,11 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "textflag.h" + // Supply environ, __progname and __guard_local, because // we don't link against the standard OpenBSD crt0.o and // the libc dynamic library needs them. +#pragma dataflag NOPTR char *environ[1]; +#pragma dataflag NOPTR char *__progname; long __guard_local; diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 6546d51d33..77f99062cf 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -72,6 +72,7 @@ extern void *runtime·WaitForSingleObject; extern void *runtime·WriteFile; extern void *runtime·timeBeginPeriod; +#pragma dataflag NOPTR void *runtime·GetQueuedCompletionStatusEx; extern uintptr runtime·externalthreadhandlerp; @@ -289,7 +290,9 @@ typedef struct KSYSTEM_TIME { int32 High2Time; } KSYSTEM_TIME; +#pragma dataflag NOPTR const KSYSTEM_TIME* INTERRUPT_TIME = (KSYSTEM_TIME*)0x7ffe0008; +#pragma dataflag NOPTR const KSYSTEM_TIME* SYSTEM_TIME = (KSYSTEM_TIME*)0x7ffe0014; static void badsystime(void); @@ -500,6 +503,7 @@ runtime·ctrlhandler1(uint32 type) extern void runtime·dosigprof(Context *r, G *gp, M *mp); extern void runtime·profileloop(void); +#pragma dataflag NOPTR static void *profiletimer; static void diff --git a/src/runtime/rt0_windows_386.s b/src/runtime/rt0_windows_386.s index 00604372f1..3c2deda903 100644 --- a/src/runtime/rt0_windows_386.s +++ b/src/runtime/rt0_windows_386.s @@ -17,4 +17,4 @@ TEXT main(SB),NOSPLIT,$0 DATA runtime·iswindows(SB)/4, $1 -GLOBL runtime·iswindows(SB), $4 +GLOBL runtime·iswindows(SB), NOPTR, $4 diff --git a/src/runtime/rt0_windows_amd64.s b/src/runtime/rt0_windows_amd64.s index 890a570d1d..197f52e113 100644 --- a/src/runtime/rt0_windows_amd64.s +++ b/src/runtime/rt0_windows_amd64.s @@ -16,4 +16,4 @@ TEXT main(SB),NOSPLIT,$-8 JMP AX DATA runtime·iswindows(SB)/4, $1 -GLOBL runtime·iswindows(SB), $4 +GLOBL runtime·iswindows(SB), NOPTR, $4 From 665a4166650d088c067130eb41f8f95efb9c12ed Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 24 Sep 2014 18:50:54 -0400 Subject: [PATCH 182/430] os: fix Args setup on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should fix the Windows build. Untested. on Windows, args are made by src/os/exec_windows.go, not package runtime. runtime·goargs has if(Windows) return; The two init funcs in pkg os were conflicting, with the second overwriting Args back to an empty slice. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/143540044 --- src/os/proc.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/os/proc.go b/src/os/proc.go index b63c85ad90..774f09900e 100644 --- a/src/os/proc.go +++ b/src/os/proc.go @@ -6,12 +6,19 @@ package os -import "syscall" +import ( + "runtime" + "syscall" +) // Args hold the command-line arguments, starting with the program name. var Args []string func init() { + if runtime.GOOS == "windows" { + // Initialized in exec_windows.go. + return + } Args = runtime_args() } From 3c94b1d305967d260b31ec3fdda51b705db752cd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 19:04:06 -0400 Subject: [PATCH 183/430] runtime: more NOPTR Fixes linux builds (_vdso); may fix others. I can at least cross-compile cmd/go for every implemented system now. TBR=iant CC=golang-codereviews https://golang.org/cl/142630043 --- src/runtime/mem_plan9.c | 1 + src/runtime/rt0_linux_386.s | 2 +- src/runtime/rt0_linux_arm.s | 2 +- src/runtime/rt0_plan9_386.s | 8 ++++---- src/runtime/rt0_plan9_amd64.s | 8 ++++---- src/runtime/rt0_solaris_amd64.s | 2 +- src/runtime/sys_dragonfly_386.s | 2 +- src/runtime/sys_freebsd_386.s | 2 +- src/runtime/sys_netbsd_386.s | 2 +- src/runtime/sys_openbsd_386.s | 2 +- src/runtime/sys_windows_386.s | 2 +- src/runtime/sys_windows_amd64.s | 2 +- src/sync/atomic/asm_arm.s | 2 +- src/sync/atomic/asm_linux_arm.s | 2 +- 14 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c index 402869f393..d673d6f830 100644 --- a/src/runtime/mem_plan9.c +++ b/src/runtime/mem_plan9.c @@ -10,6 +10,7 @@ #include "textflag.h" extern byte runtime·end[]; +#pragma dataflag NOPTR static byte *bloc = { runtime·end }; static Mutex memlock; diff --git a/src/runtime/rt0_linux_386.s b/src/runtime/rt0_linux_386.s index 74ddc94da9..352e594d53 100644 --- a/src/runtime/rt0_linux_386.s +++ b/src/runtime/rt0_linux_386.s @@ -21,5 +21,5 @@ TEXT _fallback_vdso(SB),NOSPLIT,$0 RET DATA runtime·_vdso(SB)/4, $_fallback_vdso(SB) -GLOBL runtime·_vdso(SB), $4 +GLOBL runtime·_vdso(SB), NOPTR, $4 diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s index 8af3d3505e..5f521d24ba 100644 --- a/src/runtime/rt0_linux_arm.s +++ b/src/runtime/rt0_linux_arm.s @@ -77,7 +77,7 @@ DATA bad_abi_msg+0x18(SB)/8, $" run on " DATA bad_abi_msg+0x20(SB)/8, $"EABI ker" DATA bad_abi_msg+0x28(SB)/4, $"nels" DATA bad_abi_msg+0x2c(SB)/1, $0xa -GLOBL bad_abi_msg(SB), $45 +GLOBL bad_abi_msg(SB), RODATA, $45 TEXT oabi_syscall<>(SB),NOSPLIT,$-4 ADD $1, PC, R4 diff --git a/src/runtime/rt0_plan9_386.s b/src/runtime/rt0_plan9_386.s index 7e2887b857..c451299eec 100644 --- a/src/runtime/rt0_plan9_386.s +++ b/src/runtime/rt0_plan9_386.s @@ -17,7 +17,7 @@ TEXT _rt0_386_plan9(SB),NOSPLIT,$12 CALL runtime·rt0_go(SB) DATA runtime·isplan9(SB)/4, $1 -GLOBL runtime·isplan9(SB), $4 -GLOBL _tos(SB), $4 -GLOBL _privates(SB), $4 -GLOBL _nprivates(SB), $4 +GLOBL runtime·isplan9(SB), NOPTR, $4 +GLOBL _tos(SB), NOPTR, $4 +GLOBL _privates(SB), NOPTR, $4 +GLOBL _nprivates(SB), NOPTR, $4 diff --git a/src/runtime/rt0_plan9_amd64.s b/src/runtime/rt0_plan9_amd64.s index a372a0ba8b..ec2d9ec827 100644 --- a/src/runtime/rt0_plan9_amd64.s +++ b/src/runtime/rt0_plan9_amd64.s @@ -15,7 +15,7 @@ TEXT _rt0_amd64_plan9(SB),NOSPLIT,$24 JMP AX DATA runtime·isplan9(SB)/4, $1 -GLOBL runtime·isplan9(SB), $4 -GLOBL _tos(SB), $8 -GLOBL _privates(SB), $8 -GLOBL _nprivates(SB), $4 +GLOBL runtime·isplan9(SB), NOPTR, $4 +GLOBL _tos(SB), NOPTR, $8 +GLOBL _privates(SB), NOPTR, $8 +GLOBL _nprivates(SB), NOPTR, $4 diff --git a/src/runtime/rt0_solaris_amd64.s b/src/runtime/rt0_solaris_amd64.s index 92a9fc2952..5997cbf8e3 100644 --- a/src/runtime/rt0_solaris_amd64.s +++ b/src/runtime/rt0_solaris_amd64.s @@ -15,4 +15,4 @@ TEXT main(SB),NOSPLIT,$-8 JMP AX DATA runtime·issolaris(SB)/4, $1 -GLOBL runtime·issolaris(SB), $4 +GLOBL runtime·issolaris(SB), NOPTR, $4 diff --git a/src/runtime/sys_dragonfly_386.s b/src/runtime/sys_dragonfly_386.s index dd0e27e26a..161eaec19d 100644 --- a/src/runtime/sys_dragonfly_386.s +++ b/src/runtime/sys_dragonfly_386.s @@ -378,4 +378,4 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$32 NEGL AX RET -GLOBL runtime·tlsoffset(SB),$4 +GLOBL runtime·tlsoffset(SB),NOPTR,$4 diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s index ffc28560ec..2c40fc433b 100644 --- a/src/runtime/sys_freebsd_386.s +++ b/src/runtime/sys_freebsd_386.s @@ -388,4 +388,4 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$32 NEGL AX RET -GLOBL runtime·tlsoffset(SB),$4 +GLOBL runtime·tlsoffset(SB),NOPTR,$4 diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s index 83a76cb343..23f2f6bd14 100644 --- a/src/runtime/sys_netbsd_386.s +++ b/src/runtime/sys_netbsd_386.s @@ -350,7 +350,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$28 MOVL $0, AX RET -GLOBL runtime·tlsoffset(SB),$4 +GLOBL runtime·tlsoffset(SB),NOPTR,$4 // int32 runtime·kqueue(void) TEXT runtime·kqueue(SB),NOSPLIT,$0 diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s index 12d9c5c6b4..5cda7768ae 100644 --- a/src/runtime/sys_openbsd_386.s +++ b/src/runtime/sys_openbsd_386.s @@ -395,4 +395,4 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$32 NEGL AX RET -GLOBL runtime·tlsoffset(SB),$4 +GLOBL runtime·tlsoffset(SB),NOPTR,$4 diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 9b1fc7a205..1bf4d062ac 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -212,7 +212,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 POPL BP RET -GLOBL runtime·cbctxts(SB), $4 +GLOBL runtime·cbctxts(SB), NOPTR, $4 TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0 MOVL 0(SP), AX // will use to find our callback context diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index f701d157ed..05750398ea 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -249,7 +249,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0 POPQ BP RET -GLOBL runtime·cbctxts(SB), $8 +GLOBL runtime·cbctxts(SB), NOPTR, $8 TEXT runtime·callbackasm1(SB),NOSPLIT,$0 // Construct args vector for cgocallback(). diff --git a/src/sync/atomic/asm_arm.s b/src/sync/atomic/asm_arm.s index 47639a80ea..8a85273da2 100644 --- a/src/sync/atomic/asm_arm.s +++ b/src/sync/atomic/asm_arm.s @@ -194,4 +194,4 @@ TEXT slowCheck64<>(SB),NOSPLIT,$0-0 MOVW R0, ok64<>(SB) RET -GLOBL ok64<>(SB), $4 +GLOBL ok64<>(SB), NOPTR, $4 diff --git a/src/sync/atomic/asm_linux_arm.s b/src/sync/atomic/asm_linux_arm.s index 63f1f9e38e..944758441a 100644 --- a/src/sync/atomic/asm_linux_arm.s +++ b/src/sync/atomic/asm_linux_arm.s @@ -124,7 +124,7 @@ TEXT kernelCAS64<>(SB),NOSPLIT,$0-21 TEXT ·generalCAS64(SB),NOSPLIT,$0-21 B runtime·cas64(SB) -GLOBL armCAS64(SB), $4 +GLOBL armCAS64(SB), NOPTR, $4 TEXT setupAndCallCAS64<>(SB),NOSPLIT,$-4-21 MOVW $0xffff0ffc, R0 // __kuser_helper_version From d2b84dd941456751cd09363a1027746683818f09 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 19:09:43 -0400 Subject: [PATCH 184/430] net: only "build" empty.s in non-cgo mode In cgo mode it gets passed to gcc, and on ARM it appears that gcc does not support // comments. TBR=iant CC=golang-codereviews https://golang.org/cl/142640043 --- src/net/empty.s | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/net/empty.s b/src/net/empty.s index a515c2fe29..f0b255a0cf 100644 --- a/src/net/empty.s +++ b/src/net/empty.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !cgo + // This file is required to prevent compiler errors // when the package built with CGO_ENABLED=0. // Otherwise the compiler says: From 6077f0fc32a401f9a7b9540b6d1b00e855018c9a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 24 Sep 2014 19:18:01 -0400 Subject: [PATCH 185/430] cmd/go: fix bytes and net the right way Not sure why they used empty.s and all these other packages were special cased in cmd/go instead. Add them to the list. This avoids problems with net .s files being compiled with gcc in cgo mode and gcc not supporting // comments on ARM. Not a problem with bytes, but be consistent. The last change fixed the ARM build but broke the Windows build. Maybe *this* will make everyone happy. Sigh. TBR=iant CC=golang-codereviews https://golang.org/cl/144530046 --- src/bytes/bytes.s | 5 ----- src/cmd/go/build.go | 2 +- src/net/empty.s | 10 ---------- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 src/bytes/bytes.s delete mode 100644 src/net/empty.s diff --git a/src/bytes/bytes.s b/src/bytes/bytes.s deleted file mode 100644 index 55103bae05..0000000000 --- a/src/bytes/bytes.s +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2013 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. - -// This file is here just to make the go tool happy. diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 27bd307378..fcc6b699be 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1630,7 +1630,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles) if p.Standard { switch p.ImportPath { - case "os", "runtime/pprof", "sync", "time": + case "bytes", "net", "os", "runtime/pprof", "sync", "time": extFiles++ } } diff --git a/src/net/empty.s b/src/net/empty.s deleted file mode 100644 index f0b255a0cf..0000000000 --- a/src/net/empty.s +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2013 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. - -// +build !cgo - -// This file is required to prevent compiler errors -// when the package built with CGO_ENABLED=0. -// Otherwise the compiler says: -// pkg/net/fd_poll_runtime.go:15: missing function body From e6f21be3f48802f18013a7e95bb3850882ab96e3 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 24 Sep 2014 16:55:39 -0700 Subject: [PATCH 186/430] net/http: support https_proxy in ProxyFromEnvironment Fixes #6181 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/148980043 --- src/net/http/export_test.go | 1 + src/net/http/transport.go | 11 ++++++++++- src/net/http/transport_test.go | 33 ++++++++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index 2c87353554..f8cc835b25 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -66,6 +66,7 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { func ResetCachedEnvironment() { httpProxyEnv.reset() + httpsProxyEnv.reset() noProxyEnv.reset() } diff --git a/src/net/http/transport.go b/src/net/http/transport.go index f1aab8587c..6be341faa9 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -124,7 +124,13 @@ type Transport struct { // As a special case, if req.URL.Host is "localhost" (with or without // a port number), then a nil URL and nil error will be returned. func ProxyFromEnvironment(req *Request) (*url.URL, error) { - proxy := httpProxyEnv.Get() + var proxy string + if req.URL.Scheme == "https" { + proxy = httpsProxyEnv.Get() + } + if proxy == "" { + proxy = httpProxyEnv.Get() + } if proxy == "" { return nil, nil } @@ -276,6 +282,9 @@ var ( httpProxyEnv = &envOnce{ names: []string{"HTTP_PROXY", "http_proxy"}, } + httpsProxyEnv = &envOnce{ + names: []string{"HTTPS_PROXY", "https_proxy"}, + } noProxyEnv = &envOnce{ names: []string{"NO_PROXY", "no_proxy"}, } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index bdfeba3626..2ffd359794 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -1701,26 +1701,40 @@ Content-Length: %d } type proxyFromEnvTest struct { - req string // URL to fetch; blank means "http://example.com" - env string - noenv string + req string // URL to fetch; blank means "http://example.com" + + env string // HTTP_PROXY + httpsenv string // HTTPS_PROXY + noenv string // NO_RPXY + want string wanterr error } func (t proxyFromEnvTest) String() string { var buf bytes.Buffer + space := func() { + if buf.Len() > 0 { + buf.WriteByte(' ') + } + } if t.env != "" { fmt.Fprintf(&buf, "http_proxy=%q", t.env) } + if t.httpsenv != "" { + space() + fmt.Fprintf(&buf, "https_proxy=%q", t.httpsenv) + } if t.noenv != "" { - fmt.Fprintf(&buf, " no_proxy=%q", t.noenv) + space() + fmt.Fprintf(&buf, "no_proxy=%q", t.noenv) } req := "http://example.com" if t.req != "" { req = t.req } - fmt.Fprintf(&buf, " req=%q", req) + space() + fmt.Fprintf(&buf, "req=%q", req) return strings.TrimSpace(buf.String()) } @@ -1731,7 +1745,15 @@ var proxyFromEnvTests = []proxyFromEnvTest{ {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"}, {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"}, {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"}, + + // Don't use secure for http + {req: "http://insecure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://http.proxy.tld"}, + // Use secure for https. + {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"}, + {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"}, + {want: ""}, + {noenv: "example.com", req: "http://example.com/", env: "proxy", want: ""}, {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: ""}, {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"}, @@ -1743,6 +1765,7 @@ func TestProxyFromEnvironment(t *testing.T) { ResetProxyEnv() for _, tt := range proxyFromEnvTests { os.Setenv("HTTP_PROXY", tt.env) + os.Setenv("HTTPS_PROXY", tt.httpsenv) os.Setenv("NO_PROXY", tt.noenv) ResetCachedEnvironment() reqURL := tt.req From 446524269ee152b8053d44117887bc3cc8d5ef9d Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 24 Sep 2014 17:01:54 -0700 Subject: [PATCH 187/430] net/http: check for CloseWrite interface, not TCPConn implementation Fixes #8724 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/148040043 --- src/net/http/export_test.go | 4 ++++ src/net/http/serve_test.go | 23 +++++++++++++++++++++++ src/net/http/server.go | 10 ++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index f8cc835b25..e5bc02afa2 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -77,3 +77,7 @@ var DefaultUserAgent = defaultUserAgent func SetPendingDialHooks(before, after func()) { prePendingDial, postPendingDial = before, after } + +var ExportServerNewConn = (*Server).newConn + +var ExportCloseWriteAndWait = (*conn).closeWriteAndWait diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index ee4f204995..a690ae4699 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -2607,6 +2607,29 @@ func TestServerConnStateNew(t *testing.T) { } } +type closeWriteTestConn struct { + rwTestConn + didCloseWrite bool +} + +func (c *closeWriteTestConn) CloseWrite() error { + c.didCloseWrite = true + return nil +} + +func TestCloseWrite(t *testing.T) { + var srv Server + var testConn closeWriteTestConn + c, err := ExportServerNewConn(&srv, &testConn) + if err != nil { + t.Fatal(err) + } + ExportCloseWriteAndWait(c) + if !testConn.didCloseWrite { + t.Error("didn't see CloseWrite call") + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() diff --git a/src/net/http/server.go b/src/net/http/server.go index 8f2b777b29..7ad0bcbc20 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1064,15 +1064,21 @@ func (c *conn) close() { // This timeout is somewhat arbitrary (~latency around the planet). const rstAvoidanceDelay = 500 * time.Millisecond +type closeWriter interface { + CloseWrite() error +} + +var _ closeWriter = (*net.TCPConn)(nil) + // closeWrite flushes any outstanding data and sends a FIN packet (if // client is connected via TCP), signalling that we're done. We then -// pause for a bit, hoping the client processes it before `any +// pause for a bit, hoping the client processes it before any // subsequent RST. // // See http://golang.org/issue/3595 func (c *conn) closeWriteAndWait() { c.finalFlush() - if tcp, ok := c.rwc.(*net.TCPConn); ok { + if tcp, ok := c.rwc.(closeWriter); ok { tcp.CloseWrite() } time.Sleep(rstAvoidanceDelay) From e59ad69a44df7f00c5afab3716374f80d1bb47c7 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Thu, 25 Sep 2014 10:21:52 +1000 Subject: [PATCH 188/430] net/http: allow double-quotes only on cookie values, not cookie attribute values, a la RFC 6265 section 4.1.1 "Syntax". Fixes #7751. LGTM=dr.volker.dobler R=dr.volker.dobler CC=bradfitz, golang-codereviews https://golang.org/cl/148890043 --- src/net/http/cookie.go | 10 +++++----- src/net/http/cookie_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go index dc60ba87f5..a0d0fdbbd0 100644 --- a/src/net/http/cookie.go +++ b/src/net/http/cookie.go @@ -56,7 +56,7 @@ func readSetCookies(h Header) []*Cookie { if !isCookieNameValid(name) { continue } - value, success := parseCookieValue(value) + value, success := parseCookieValue(value, true) if !success { continue } @@ -76,7 +76,7 @@ func readSetCookies(h Header) []*Cookie { attr, val = attr[:j], attr[j+1:] } lowerAttr := strings.ToLower(attr) - val, success = parseCookieValue(val) + val, success = parseCookieValue(val, false) if !success { c.Unparsed = append(c.Unparsed, parts[i]) continue @@ -205,7 +205,7 @@ func readCookies(h Header, filter string) []*Cookie { if filter != "" && filter != name { continue } - val, success := parseCookieValue(val) + val, success := parseCookieValue(val, true) if !success { continue } @@ -345,9 +345,9 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string { return string(buf) } -func parseCookieValue(raw string) (string, bool) { +func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { // Strip the quotes, if present. - if len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { + if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { raw = raw[1 : len(raw)-1] } for i := 0; i < len(raw); i++ { diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go index f78f37299f..98dc2fade0 100644 --- a/src/net/http/cookie_test.go +++ b/src/net/http/cookie_test.go @@ -313,6 +313,14 @@ var readCookiesTests = []struct { {Name: "c2", Value: "v2"}, }, }, + { + Header{"Cookie": {`Cookie-1="v$1"; c2="v2"`}}, + "", + []*Cookie{ + {Name: "Cookie-1", Value: "v$1"}, + {Name: "c2", Value: "v2"}, + }, + }, } func TestReadCookies(t *testing.T) { @@ -327,6 +335,30 @@ func TestReadCookies(t *testing.T) { } } +func TestSetCookieDoubleQuotes(t *testing.T) { + res := &Response{Header: Header{}} + res.Header.Add("Set-Cookie", `quoted0=none; max-age=30`) + res.Header.Add("Set-Cookie", `quoted1="cookieValue"; max-age=31`) + res.Header.Add("Set-Cookie", `quoted2=cookieAV; max-age="32"`) + res.Header.Add("Set-Cookie", `quoted3="both"; max-age="33"`) + got := res.Cookies() + want := []*Cookie{ + {Name: "quoted0", Value: "none", MaxAge: 30}, + {Name: "quoted1", Value: "cookieValue", MaxAge: 31}, + {Name: "quoted2", Value: "cookieAV"}, + {Name: "quoted3", Value: "both"}, + } + if len(got) != len(want) { + t.Fatal("got %d cookies, want %d", len(got), len(want)) + } + for i, w := range want { + g := got[i] + if g.Name != w.Name || g.Value != w.Value || g.MaxAge != w.MaxAge { + t.Errorf("cookie #%d:\ngot %v\nwant %v", i, g, w) + } + } +} + func TestCookieSanitizeValue(t *testing.T) { defer log.SetOutput(os.Stderr) var logbuf bytes.Buffer From dfaf1f71e67de2807e07c880060b457d32a66b8b Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 24 Sep 2014 17:39:00 -0700 Subject: [PATCH 189/430] net/http: update ProxyFromEnvironment docs for HTTPS_PROXY addition LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/142650043 --- src/net/http/transport.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 6be341faa9..f1a6837527 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -116,10 +116,17 @@ type Transport struct { // ProxyFromEnvironment returns the URL of the proxy to use for a // given request, as indicated by the environment variables -// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy). -// An error is returned if the proxy environment is invalid. +// HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions +// thereof). HTTPS_PROXY takes precedence over HTTP_PROXY for https +// requests. +// +// The environment values may be either a complete URL or a +// "host[:port]", in which case the "http" scheme is assumed. +// An error is returned if the value is a different form. +// // A nil URL and nil error are returned if no proxy is defined in the -// environment, or a proxy should not be used for the given request. +// environment, or a proxy should not be used for the given request, +// as defined by NO_PROXY. // // As a special case, if req.URL.Host is "localhost" (with or without // a port number), then a nil URL and nil error will be returned. From 1b6807bb069c528447270c3d6c66c5c7597f388f Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 25 Sep 2014 07:59:01 -0700 Subject: [PATCH 190/430] cgo: adjust return value location to account for stack copies. During a cgo call, the stack can be copied. This copy invalidates the pointer that cgo has into the return value area. To fix this problem, pass the address of the location containing the stack top value (which is in the G struct). For cgo functions which return values, read the stktop before and after the cgo call to compute the adjustment necessary to write the return value. Fixes #8771 LGTM=iant, rsc R=iant, rsc, khr CC=golang-codereviews https://golang.org/cl/144130043 --- misc/cgo/test/callback.go | 45 +++++++++++++++++ misc/cgo/test/callback_c.c | 16 ++++++ misc/cgo/test/cgo_test.go | 98 +++++++++++++++++++------------------ src/cmd/cgo/out.go | 16 +++++- src/runtime/asm_386.s | 10 ++++ src/runtime/asm_amd64.s | 11 +++++ src/runtime/asm_arm.s | 8 +++ src/runtime/cgo/callbacks.c | 3 ++ src/runtime/stack.c | 4 +- 9 files changed, 161 insertions(+), 50 deletions(-) diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go index a7f1a3ecd6..44167e6e9e 100644 --- a/misc/cgo/test/callback.go +++ b/misc/cgo/test/callback.go @@ -10,6 +10,9 @@ void callGoFoo(void); void callGoStackCheck(void); void callPanic(void); void callCgoAllocate(void); +int callGoReturnVal(void); +int returnAfterGrow(void); +int returnAfterGrowFromGo(void); */ import "C" @@ -212,6 +215,48 @@ func testAllocateFromC(t *testing.T) { C.callCgoAllocate() // crashes or exits on failure } +// Test that C code can return a value if it calls a Go function that +// causes a stack copy. +func testReturnAfterGrow(t *testing.T) { + // Use a new goroutine so that we get a small stack. + c := make(chan int) + go func() { + c <- int(C.returnAfterGrow()) + }() + if got, want := <-c, 123456; got != want { + t.Errorf("got %d want %d", got, want) + } +} + +// Test that we can return a value from Go->C->Go if the Go code +// causes a stack copy. +func testReturnAfterGrowFromGo(t *testing.T) { + // Use a new goroutine so that we get a small stack. + c := make(chan int) + go func() { + c <- int(C.returnAfterGrowFromGo()) + }() + if got, want := <-c, 129*128/2; got != want { + t.Errorf("got %d want %d", got, want) + } +} + +//export goReturnVal +func goReturnVal() (r C.int) { + // Force a stack copy. + var f func(int) int + f = func(i int) int { + var buf [256]byte + use(buf[:]) + if i == 0 { + return 0 + } + return i + f(i-1) + } + r = C.int(f(128)) + return +} + func testCallbackStack(t *testing.T) { // Make cgo call and callback with different amount of stack stack available. // We do not do any explicit checks, just ensure that it does not crash. diff --git a/misc/cgo/test/callback_c.c b/misc/cgo/test/callback_c.c index dcd4ddd4ee..5bb6425340 100644 --- a/misc/cgo/test/callback_c.c +++ b/misc/cgo/test/callback_c.c @@ -64,3 +64,19 @@ callGoStackCheck(void) extern void goStackCheck(void); goStackCheck(); } + +int +returnAfterGrow(void) +{ + extern int goReturnVal(void); + goReturnVal(); + return 123456; +} + +int +returnAfterGrowFromGo(void) +{ + extern int goReturnVal(void); + return goReturnVal(); +} + diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 1d1abf7291..fcfad83049 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -10,53 +10,55 @@ import "testing" // so that they can use cgo (import "C"). // These wrappers are here for gotest to find. -func TestAlign(t *testing.T) { testAlign(t) } -func TestConst(t *testing.T) { testConst(t) } -func TestEnum(t *testing.T) { testEnum(t) } -func TestAtol(t *testing.T) { testAtol(t) } -func TestErrno(t *testing.T) { testErrno(t) } -func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) } -func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) } -func TestCallback(t *testing.T) { testCallback(t) } -func TestCallbackGC(t *testing.T) { testCallbackGC(t) } -func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) } -func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) } -func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) } -func TestPanicFromC(t *testing.T) { testPanicFromC(t) } -func TestAllocateFromC(t *testing.T) { testAllocateFromC(t) } -func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } -func TestBlocking(t *testing.T) { testBlocking(t) } -func Test1328(t *testing.T) { test1328(t) } -func TestParallelSleep(t *testing.T) { testParallelSleep(t) } -func TestSetEnv(t *testing.T) { testSetEnv(t) } -func TestHelpers(t *testing.T) { testHelpers(t) } -func TestLibgcc(t *testing.T) { testLibgcc(t) } -func Test1635(t *testing.T) { test1635(t) } -func TestPrintf(t *testing.T) { testPrintf(t) } -func Test4029(t *testing.T) { test4029(t) } -func TestBoolAlign(t *testing.T) { testBoolAlign(t) } -func Test3729(t *testing.T) { test3729(t) } -func Test3775(t *testing.T) { test3775(t) } -func TestCthread(t *testing.T) { testCthread(t) } -func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) } -func Test5227(t *testing.T) { test5227(t) } -func TestCflags(t *testing.T) { testCflags(t) } -func Test5337(t *testing.T) { test5337(t) } -func Test5548(t *testing.T) { test5548(t) } -func Test5603(t *testing.T) { test5603(t) } -func Test6833(t *testing.T) { test6833(t) } -func Test3250(t *testing.T) { test3250(t) } -func TestCallbackStack(t *testing.T) { testCallbackStack(t) } -func TestFpVar(t *testing.T) { testFpVar(t) } -func Test4339(t *testing.T) { test4339(t) } -func Test6390(t *testing.T) { test6390(t) } -func Test5986(t *testing.T) { test5986(t) } -func Test7665(t *testing.T) { test7665(t) } -func TestNaming(t *testing.T) { testNaming(t) } -func Test7560(t *testing.T) { test7560(t) } -func Test5242(t *testing.T) { test5242(t) } -func Test8092(t *testing.T) { test8092(t) } -func Test7978(t *testing.T) { test7978(t) } -func Test8694(t *testing.T) { test8694(t) } +func TestAlign(t *testing.T) { testAlign(t) } +func TestConst(t *testing.T) { testConst(t) } +func TestEnum(t *testing.T) { testEnum(t) } +func TestAtol(t *testing.T) { testAtol(t) } +func TestErrno(t *testing.T) { testErrno(t) } +func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) } +func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) } +func TestCallback(t *testing.T) { testCallback(t) } +func TestCallbackGC(t *testing.T) { testCallbackGC(t) } +func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) } +func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) } +func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) } +func TestPanicFromC(t *testing.T) { testPanicFromC(t) } +func TestAllocateFromC(t *testing.T) { testAllocateFromC(t) } +func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } +func TestBlocking(t *testing.T) { testBlocking(t) } +func Test1328(t *testing.T) { test1328(t) } +func TestParallelSleep(t *testing.T) { testParallelSleep(t) } +func TestSetEnv(t *testing.T) { testSetEnv(t) } +func TestHelpers(t *testing.T) { testHelpers(t) } +func TestLibgcc(t *testing.T) { testLibgcc(t) } +func Test1635(t *testing.T) { test1635(t) } +func TestPrintf(t *testing.T) { testPrintf(t) } +func Test4029(t *testing.T) { test4029(t) } +func TestBoolAlign(t *testing.T) { testBoolAlign(t) } +func Test3729(t *testing.T) { test3729(t) } +func Test3775(t *testing.T) { test3775(t) } +func TestCthread(t *testing.T) { testCthread(t) } +func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) } +func Test5227(t *testing.T) { test5227(t) } +func TestCflags(t *testing.T) { testCflags(t) } +func Test5337(t *testing.T) { test5337(t) } +func Test5548(t *testing.T) { test5548(t) } +func Test5603(t *testing.T) { test5603(t) } +func Test6833(t *testing.T) { test6833(t) } +func Test3250(t *testing.T) { test3250(t) } +func TestCallbackStack(t *testing.T) { testCallbackStack(t) } +func TestFpVar(t *testing.T) { testFpVar(t) } +func Test4339(t *testing.T) { test4339(t) } +func Test6390(t *testing.T) { test6390(t) } +func Test5986(t *testing.T) { test5986(t) } +func Test7665(t *testing.T) { test7665(t) } +func TestNaming(t *testing.T) { testNaming(t) } +func Test7560(t *testing.T) { test7560(t) } +func Test5242(t *testing.T) { test5242(t) } +func Test8092(t *testing.T) { test8092(t) } +func Test7978(t *testing.T) { test7978(t) } +func Test8694(t *testing.T) { test8694(t) } +func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) } +func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 2d14f766fc..4e5b3a2454 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -44,6 +44,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "int main() { return 0; }\n") if *importRuntimeCgo { fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") + fmt.Fprintf(fm, "char* cgo_topofstack(void) { return (char*)0; }\n") } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, // which provides crosscall2. We just need a prototype. @@ -519,9 +520,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // Use packed attribute to force no padding in this struct in case // gcc has different packing requirements. fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) + if n.FuncType.Result != nil { + // Save the stack top for use below. + fmt.Fprintf(fgcc, "\tchar *stktop = cgo_topofstack();\n") + } fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { - fmt.Fprintf(fgcc, "a->r = ") + fmt.Fprintf(fgcc, "__typeof__(a->r) r = ") if c := t.C.String(); c[len(c)-1] == '*' { fmt.Fprint(fgcc, "(__typeof__(a->r)) ") } @@ -544,6 +549,13 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "a->p%d", i) } fmt.Fprintf(fgcc, ");\n") + if n.FuncType.Result != nil { + // The cgo call may have caused a stack copy (via a callback). + // Adjust the return value pointer appropriately. + fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (cgo_topofstack() - stktop));\n") + // Save the return value. + fmt.Fprintf(fgcc, "\ta->r = r;\n") + } if n.AddError { fmt.Fprintf(fgcc, "\treturn errno;\n") } @@ -1131,6 +1143,8 @@ __cgo_size_assert(__cgo_long_long, 8) __cgo_size_assert(float, 4) __cgo_size_assert(double, 8) +extern char* cgo_topofstack(void); + #include #include ` diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 846a214d55..f1b3346e83 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -2275,3 +2275,13 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 TEXT runtime·return0(SB), NOSPLIT, $0 MOVL $0, AX RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT cgo_topofstack(SB),NOSPLIT,$0 + get_tls(CX) + MOVL g(CX), AX + MOVL g_m(AX), AX + MOVL m_curg(AX), AX + MOVL (g_stack+stack_hi)(AX), AX + RET diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 7304d79a2f..b4c6c6bdca 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -2220,3 +2220,14 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4 TEXT runtime·return0(SB), NOSPLIT, $0 MOVL $0, AX RET + + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT cgo_topofstack(SB),NOSPLIT,$0 + get_tls(CX) + MOVQ g(CX), AX + MOVQ g_m(AX), AX + MOVQ m_curg(AX), AX + MOVQ (g_stack+stack_hi)(AX), AX + RET diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 38d97b78f3..2c5de8afb1 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -1300,3 +1300,11 @@ yieldloop: RET SUB $1, R1 B yieldloop + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +TEXT cgo_topofstack(SB),NOSPLIT,$0 + MOVW g_m(g), R0 + MOVW m_curg(R0), R0 + MOVW (g_stack+stack_hi)(R0), R0 + RET diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c index 16614d03db..cea9b1667f 100644 --- a/src/runtime/cgo/callbacks.c +++ b/src/runtime/cgo/callbacks.c @@ -78,3 +78,6 @@ void (*_cgo_free)(void*) = x_cgo_free; #pragma cgo_import_static x_cgo_thread_start extern void x_cgo_thread_start(void*); void (*_cgo_thread_start)(void*) = x_cgo_thread_start; + +#pragma cgo_export_static cgo_topofstack +#pragma cgo_export_dynamic cgo_topofstack diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 0d8814731c..2d23c717bd 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -827,7 +827,9 @@ runtime·shrinkstack(G *gp) if(used >= oldsize / 4) return; // still using at least 1/4 of the segment. - if(gp->syscallsp != 0) // TODO: can we handle this case? + // We can't copy the stack if we're in a syscall. + // The syscall might have pointers into the stack. + if(gp->syscallsp != 0) return; #ifdef GOOS_windows From 1aa65fe8d4c0ebdd754480d281f378fcd1c42cea Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 25 Sep 2014 08:37:04 -0700 Subject: [PATCH 191/430] runtime: add load_g call in arm callback. Need to restore the g register. Somehow this line vaporized from CL 144130043. Also cgo_topofstack -> _cgo_topofstack, that vaporized also. TBR=rsc CC=golang-codereviews https://golang.org/cl/150940044 --- src/cmd/cgo/out.go | 8 ++++---- src/runtime/asm_386.s | 2 +- src/runtime/asm_amd64.s | 2 +- src/runtime/asm_arm.s | 3 ++- src/runtime/cgo/callbacks.c | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 4e5b3a2454..d92bed9bf0 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -44,7 +44,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "int main() { return 0; }\n") if *importRuntimeCgo { fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") - fmt.Fprintf(fm, "char* cgo_topofstack(void) { return (char*)0; }\n") + fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n") } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, // which provides crosscall2. We just need a prototype. @@ -522,7 +522,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) if n.FuncType.Result != nil { // Save the stack top for use below. - fmt.Fprintf(fgcc, "\tchar *stktop = cgo_topofstack();\n") + fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n") } fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { @@ -552,7 +552,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { if n.FuncType.Result != nil { // The cgo call may have caused a stack copy (via a callback). // Adjust the return value pointer appropriately. - fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (cgo_topofstack() - stktop));\n") + fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n") // Save the return value. fmt.Fprintf(fgcc, "\ta->r = r;\n") } @@ -1143,7 +1143,7 @@ __cgo_size_assert(__cgo_long_long, 8) __cgo_size_assert(float, 4) __cgo_size_assert(double, 8) -extern char* cgo_topofstack(void); +extern char* _cgo_topofstack(void); #include #include diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index f1b3346e83..1495246a25 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -2278,7 +2278,7 @@ TEXT runtime·return0(SB), NOSPLIT, $0 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. // Must obey the gcc calling convention. -TEXT cgo_topofstack(SB),NOSPLIT,$0 +TEXT _cgo_topofstack(SB),NOSPLIT,$0 get_tls(CX) MOVL g(CX), AX MOVL g_m(AX), AX diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index b4c6c6bdca..3f7f608410 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -2224,7 +2224,7 @@ TEXT runtime·return0(SB), NOSPLIT, $0 // Called from cgo wrappers, this function returns g->m->curg.stack.hi. // Must obey the gcc calling convention. -TEXT cgo_topofstack(SB),NOSPLIT,$0 +TEXT _cgo_topofstack(SB),NOSPLIT,$0 get_tls(CX) MOVQ g(CX), AX MOVQ g_m(AX), AX diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 2c5de8afb1..06bd0751db 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -1303,7 +1303,8 @@ yieldloop: // Called from cgo wrappers, this function returns g->m->curg.stack.hi. // Must obey the gcc calling convention. -TEXT cgo_topofstack(SB),NOSPLIT,$0 +TEXT _cgo_topofstack(SB),NOSPLIT,$0 + BL runtime·load_g(SB) MOVW g_m(g), R0 MOVW m_curg(R0), R0 MOVW (g_stack+stack_hi)(R0), R0 diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c index cea9b1667f..282beeea88 100644 --- a/src/runtime/cgo/callbacks.c +++ b/src/runtime/cgo/callbacks.c @@ -79,5 +79,5 @@ void (*_cgo_free)(void*) = x_cgo_free; extern void x_cgo_thread_start(void*); void (*_cgo_thread_start)(void*) = x_cgo_thread_start; -#pragma cgo_export_static cgo_topofstack -#pragma cgo_export_dynamic cgo_topofstack +#pragma cgo_export_static _cgo_topofstack +#pragma cgo_export_dynamic _cgo_topofstack From 53c66543e022b1a96a599fee0819f6b16e92bead Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 25 Sep 2014 13:08:37 -0400 Subject: [PATCH 192/430] cmd/gc: avoid infinite recursion on invalid recursive type Fixes #8507. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/144560043 --- src/cmd/gc/align.c | 4 +++- src/cmd/gc/subr.c | 3 ++- test/fixedbugs/issue8507.go | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/fixedbugs/issue8507.go diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index b809640e42..6e5d149c75 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -119,8 +119,10 @@ dowidth(Type *t) if(t->width == -2) { lno = lineno; lineno = t->lineno; - if(!t->broke) + if(!t->broke) { + t->broke = 1; yyerror("invalid recursive type %T", t); + } t->width = 0; lineno = lno; return; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 666be96679..c3bc5af3b8 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -529,7 +529,8 @@ algtype1(Type *t, Type **bad) if(bad) *bad = T; - + if(t->broke) + return AMEM; if(t->noalg) return ANOEQ; diff --git a/test/fixedbugs/issue8507.go b/test/fixedbugs/issue8507.go new file mode 100644 index 0000000000..00a14aa88f --- /dev/null +++ b/test/fixedbugs/issue8507.go @@ -0,0 +1,16 @@ +// errorcheck + +// 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. + +// issue 8507 +// used to call algtype on invalid recursive type and get into infinite recursion + +package p + +type T struct{ T } // ERROR "invalid recursive type T" + +func f() { + println(T{} == T{}) +} From 52e9bcafe1b5bdae3354ddf82879751dfe6eb25b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 25 Sep 2014 13:13:02 -0400 Subject: [PATCH 193/430] cmd/gc: print x++ (not x += 1) in errors about x++ Fixes #8311. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/146270043 --- src/cmd/gc/fmt.c | 7 + src/cmd/gc/go.y | 2 + src/cmd/gc/typecheck.c | 4 + src/cmd/gc/y.tab.c | 526 ++++++++++++++++++------------------ test/fixedbugs/issue8311.go | 16 ++ 5 files changed, 293 insertions(+), 262 deletions(-) create mode 100644 test/fixedbugs/issue8311.go diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index f67757449b..89d2a14046 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -810,6 +810,13 @@ stmtfmt(Fmt *f, Node *n) break; case OASOP: + if(n->implicit) { + if(n->etype == OADD) + fmtprint(f, "%N++", n->left); + else + fmtprint(f, "%N--", n->left); + break; + } fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right); break; diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index b16f64b5d6..68fccc1ad1 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -460,11 +460,13 @@ simple_stmt: | expr LINC { $$ = nod(OASOP, $1, nodintconst(1)); + $$->implicit = 1; $$->etype = OADD; } | expr LDEC { $$ = nod(OASOP, $1, nodintconst(1)); + $$->implicit = 1; $$->etype = OSUB; } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 298920bfec..9440526060 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -600,6 +600,10 @@ reswitch: } if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { defaultlit2(&l, &r, 1); + if(n->op == OASOP && n->implicit) { + yyerror("invalid operation: %N (non-numeric type %T)", n, l->type); + goto error; + } yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); goto error; } diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c index 47beae03b6..f464126ac9 100644 --- a/src/cmd/gc/y.tab.c +++ b/src/cmd/gc/y.tab.c @@ -663,37 +663,37 @@ static const yytype_uint16 yyrline[] = 263, 264, 271, 271, 284, 288, 289, 293, 298, 304, 308, 312, 316, 322, 328, 334, 339, 343, 347, 353, 359, 363, 367, 373, 377, 383, 384, 388, 394, 403, - 409, 427, 432, 444, 460, 465, 472, 492, 510, 519, - 538, 537, 552, 551, 583, 586, 593, 592, 603, 609, - 616, 623, 634, 640, 643, 651, 650, 661, 667, 679, - 683, 688, 678, 709, 708, 721, 724, 730, 733, 745, - 749, 744, 767, 766, 782, 783, 787, 791, 795, 799, - 803, 807, 811, 815, 819, 823, 827, 831, 835, 839, - 843, 847, 851, 855, 860, 866, 867, 871, 882, 886, - 890, 894, 899, 903, 913, 917, 922, 930, 934, 935, - 946, 950, 954, 958, 962, 970, 971, 977, 984, 990, - 997, 1000, 1007, 1013, 1030, 1037, 1038, 1045, 1046, 1065, - 1066, 1069, 1072, 1076, 1087, 1096, 1102, 1105, 1108, 1115, - 1116, 1122, 1135, 1150, 1158, 1170, 1175, 1181, 1182, 1183, - 1184, 1185, 1186, 1192, 1193, 1194, 1195, 1201, 1202, 1203, - 1204, 1205, 1211, 1212, 1215, 1218, 1219, 1220, 1221, 1222, - 1225, 1226, 1239, 1243, 1248, 1253, 1258, 1262, 1263, 1266, - 1272, 1279, 1285, 1292, 1298, 1309, 1324, 1353, 1391, 1416, - 1434, 1443, 1446, 1454, 1458, 1462, 1469, 1475, 1480, 1492, - 1495, 1506, 1507, 1513, 1514, 1520, 1524, 1530, 1531, 1537, - 1541, 1547, 1570, 1575, 1581, 1587, 1594, 1603, 1612, 1627, - 1633, 1638, 1642, 1649, 1662, 1663, 1669, 1675, 1678, 1682, - 1688, 1691, 1700, 1703, 1704, 1708, 1709, 1715, 1716, 1717, - 1718, 1719, 1721, 1720, 1735, 1741, 1745, 1749, 1753, 1757, - 1762, 1781, 1787, 1795, 1799, 1805, 1809, 1815, 1819, 1825, - 1829, 1838, 1842, 1846, 1850, 1856, 1859, 1867, 1868, 1870, - 1871, 1874, 1877, 1880, 1883, 1886, 1889, 1892, 1895, 1898, - 1901, 1904, 1907, 1910, 1913, 1919, 1923, 1927, 1931, 1935, - 1939, 1959, 1966, 1977, 1978, 1979, 1982, 1983, 1986, 1990, - 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2030, 2036, 2044, - 2052, 2058, 2065, 2081, 2103, 2107, 2113, 2116, 2119, 2123, - 2133, 2137, 2156, 2164, 2165, 2177, 2178, 2181, 2185, 2191, - 2195, 2201, 2205 + 409, 427, 432, 444, 460, 466, 474, 494, 512, 521, + 540, 539, 554, 553, 585, 588, 595, 594, 605, 611, + 618, 625, 636, 642, 645, 653, 652, 663, 669, 681, + 685, 690, 680, 711, 710, 723, 726, 732, 735, 747, + 751, 746, 769, 768, 784, 785, 789, 793, 797, 801, + 805, 809, 813, 817, 821, 825, 829, 833, 837, 841, + 845, 849, 853, 857, 862, 868, 869, 873, 884, 888, + 892, 896, 901, 905, 915, 919, 924, 932, 936, 937, + 948, 952, 956, 960, 964, 972, 973, 979, 986, 992, + 999, 1002, 1009, 1015, 1032, 1039, 1040, 1047, 1048, 1067, + 1068, 1071, 1074, 1078, 1089, 1098, 1104, 1107, 1110, 1117, + 1118, 1124, 1137, 1152, 1160, 1172, 1177, 1183, 1184, 1185, + 1186, 1187, 1188, 1194, 1195, 1196, 1197, 1203, 1204, 1205, + 1206, 1207, 1213, 1214, 1217, 1220, 1221, 1222, 1223, 1224, + 1227, 1228, 1241, 1245, 1250, 1255, 1260, 1264, 1265, 1268, + 1274, 1281, 1287, 1294, 1300, 1311, 1326, 1355, 1393, 1418, + 1436, 1445, 1448, 1456, 1460, 1464, 1471, 1477, 1482, 1494, + 1497, 1508, 1509, 1515, 1516, 1522, 1526, 1532, 1533, 1539, + 1543, 1549, 1572, 1577, 1583, 1589, 1596, 1605, 1614, 1629, + 1635, 1640, 1644, 1651, 1664, 1665, 1671, 1677, 1680, 1684, + 1690, 1693, 1702, 1705, 1706, 1710, 1711, 1717, 1718, 1719, + 1720, 1721, 1723, 1722, 1737, 1743, 1747, 1751, 1755, 1759, + 1764, 1783, 1789, 1797, 1801, 1807, 1811, 1817, 1821, 1827, + 1831, 1840, 1844, 1848, 1852, 1858, 1861, 1869, 1870, 1872, + 1873, 1876, 1879, 1882, 1885, 1888, 1891, 1894, 1897, 1900, + 1903, 1906, 1909, 1912, 1915, 1921, 1925, 1929, 1933, 1937, + 1941, 1961, 1968, 1979, 1980, 1981, 1984, 1985, 1988, 1992, + 2002, 2006, 2010, 2014, 2018, 2022, 2026, 2032, 2038, 2046, + 2054, 2060, 2067, 2083, 2105, 2109, 2115, 2118, 2121, 2125, + 2135, 2139, 2158, 2166, 2167, 2179, 2180, 2183, 2187, 2193, + 2197, 2203, 2207 }; #endif @@ -2781,20 +2781,22 @@ yyreduce: #line 461 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->implicit = 1; (yyval.node)->etype = OADD; } break; case 55: -#line 466 "go.y" +#line 467 "go.y" { (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->implicit = 1; (yyval.node)->etype = OSUB; } break; case 56: -#line 473 "go.y" +#line 475 "go.y" { Node *n, *nn; @@ -2817,7 +2819,7 @@ yyreduce: break; case 57: -#line 493 "go.y" +#line 495 "go.y" { Node *n; @@ -2838,7 +2840,7 @@ yyreduce: break; case 58: -#line 511 "go.y" +#line 513 "go.y" { // will be converted to OCASE // right will point to next case @@ -2850,7 +2852,7 @@ yyreduce: break; case 59: -#line 520 "go.y" +#line 522 "go.y" { Node *n, *nn; @@ -2869,14 +2871,14 @@ yyreduce: break; case 60: -#line 538 "go.y" +#line 540 "go.y" { markdcl(); } break; case 61: -#line 542 "go.y" +#line 544 "go.y" { if((yyvsp[(3) - (4)].list) == nil) (yyval.node) = nod(OEMPTY, N, N); @@ -2887,7 +2889,7 @@ yyreduce: break; case 62: -#line 552 "go.y" +#line 554 "go.y" { // If the last token read by the lexer was consumed // as part of the case, clear it (parser has cleared yychar). @@ -2901,7 +2903,7 @@ yyreduce: break; case 63: -#line 563 "go.y" +#line 565 "go.y" { int last; @@ -2923,28 +2925,28 @@ yyreduce: break; case 64: -#line 583 "go.y" +#line 585 "go.y" { (yyval.list) = nil; } break; case 65: -#line 587 "go.y" +#line 589 "go.y" { (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); } break; case 66: -#line 593 "go.y" +#line 595 "go.y" { markdcl(); } break; case 67: -#line 597 "go.y" +#line 599 "go.y" { (yyval.list) = (yyvsp[(3) - (4)].list); popdcl(); @@ -2952,7 +2954,7 @@ yyreduce: break; case 68: -#line 604 "go.y" +#line 606 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -2961,7 +2963,7 @@ yyreduce: break; case 69: -#line 610 "go.y" +#line 612 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); (yyval.node)->list = (yyvsp[(1) - (4)].list); @@ -2971,7 +2973,7 @@ yyreduce: break; case 70: -#line 617 "go.y" +#line 619 "go.y" { (yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node)); (yyval.node)->etype = 0; // := flag @@ -2979,7 +2981,7 @@ yyreduce: break; case 71: -#line 624 "go.y" +#line 626 "go.y" { // init ; test ; incr if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0) @@ -2993,7 +2995,7 @@ yyreduce: break; case 72: -#line 635 "go.y" +#line 637 "go.y" { // normal test (yyval.node) = nod(OFOR, N, N); @@ -3002,7 +3004,7 @@ yyreduce: break; case 74: -#line 644 "go.y" +#line 646 "go.y" { (yyval.node) = (yyvsp[(1) - (2)].node); (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list)); @@ -3010,14 +3012,14 @@ yyreduce: break; case 75: -#line 651 "go.y" +#line 653 "go.y" { markdcl(); } break; case 76: -#line 655 "go.y" +#line 657 "go.y" { (yyval.node) = (yyvsp[(3) - (3)].node); popdcl(); @@ -3025,7 +3027,7 @@ yyreduce: break; case 77: -#line 662 "go.y" +#line 664 "go.y" { // test (yyval.node) = nod(OIF, N, N); @@ -3034,7 +3036,7 @@ yyreduce: break; case 78: -#line 668 "go.y" +#line 670 "go.y" { // init ; test (yyval.node) = nod(OIF, N, N); @@ -3045,14 +3047,14 @@ yyreduce: break; case 79: -#line 679 "go.y" +#line 681 "go.y" { markdcl(); } break; case 80: -#line 683 "go.y" +#line 685 "go.y" { if((yyvsp[(3) - (3)].node)->ntest == N) yyerror("missing condition in if statement"); @@ -3060,14 +3062,14 @@ yyreduce: break; case 81: -#line 688 "go.y" +#line 690 "go.y" { (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); } break; case 82: -#line 692 "go.y" +#line 694 "go.y" { Node *n; NodeList *nn; @@ -3085,14 +3087,14 @@ yyreduce: break; case 83: -#line 709 "go.y" +#line 711 "go.y" { markdcl(); } break; case 84: -#line 713 "go.y" +#line 715 "go.y" { if((yyvsp[(4) - (5)].node)->ntest == N) yyerror("missing condition in if statement"); @@ -3102,28 +3104,28 @@ yyreduce: break; case 85: -#line 721 "go.y" +#line 723 "go.y" { (yyval.list) = nil; } break; case 86: -#line 725 "go.y" +#line 727 "go.y" { (yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); } break; case 87: -#line 730 "go.y" +#line 732 "go.y" { (yyval.list) = nil; } break; case 88: -#line 734 "go.y" +#line 736 "go.y" { NodeList *node; @@ -3135,14 +3137,14 @@ yyreduce: break; case 89: -#line 745 "go.y" +#line 747 "go.y" { markdcl(); } break; case 90: -#line 749 "go.y" +#line 751 "go.y" { Node *n; n = (yyvsp[(3) - (3)].node)->ntest; @@ -3153,7 +3155,7 @@ yyreduce: break; case 91: -#line 757 "go.y" +#line 759 "go.y" { (yyval.node) = (yyvsp[(3) - (7)].node); (yyval.node)->op = OSWITCH; @@ -3164,14 +3166,14 @@ yyreduce: break; case 92: -#line 767 "go.y" +#line 769 "go.y" { typesw = nod(OXXX, typesw, N); } break; case 93: -#line 771 "go.y" +#line 773 "go.y" { (yyval.node) = nod(OSELECT, N, N); (yyval.node)->lineno = typesw->lineno; @@ -3181,154 +3183,154 @@ yyreduce: break; case 95: -#line 784 "go.y" +#line 786 "go.y" { (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 96: -#line 788 "go.y" +#line 790 "go.y" { (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 97: -#line 792 "go.y" +#line 794 "go.y" { (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 98: -#line 796 "go.y" +#line 798 "go.y" { (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 99: -#line 800 "go.y" +#line 802 "go.y" { (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 100: -#line 804 "go.y" +#line 806 "go.y" { (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 101: -#line 808 "go.y" +#line 810 "go.y" { (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 102: -#line 812 "go.y" +#line 814 "go.y" { (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 103: -#line 816 "go.y" +#line 818 "go.y" { (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 104: -#line 820 "go.y" +#line 822 "go.y" { (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 105: -#line 824 "go.y" +#line 826 "go.y" { (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 106: -#line 828 "go.y" +#line 830 "go.y" { (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 107: -#line 832 "go.y" +#line 834 "go.y" { (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 108: -#line 836 "go.y" +#line 838 "go.y" { (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 109: -#line 840 "go.y" +#line 842 "go.y" { (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 110: -#line 844 "go.y" +#line 846 "go.y" { (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 111: -#line 848 "go.y" +#line 850 "go.y" { (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 112: -#line 852 "go.y" +#line 854 "go.y" { (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 113: -#line 856 "go.y" +#line 858 "go.y" { (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 114: -#line 861 "go.y" +#line 863 "go.y" { (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 116: -#line 868 "go.y" +#line 870 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 117: -#line 872 "go.y" +#line 874 "go.y" { if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) { // Special case for &T{...}: turn into (*T){...}. @@ -3342,28 +3344,28 @@ yyreduce: break; case 118: -#line 883 "go.y" +#line 885 "go.y" { (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N); } break; case 119: -#line 887 "go.y" +#line 889 "go.y" { (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N); } break; case 120: -#line 891 "go.y" +#line 893 "go.y" { (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N); } break; case 121: -#line 895 "go.y" +#line 897 "go.y" { yyerror("the bitwise complement operator is ^"); (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); @@ -3371,28 +3373,28 @@ yyreduce: break; case 122: -#line 900 "go.y" +#line 902 "go.y" { (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); } break; case 123: -#line 904 "go.y" +#line 906 "go.y" { (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N); } break; case 124: -#line 914 "go.y" +#line 916 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N); } break; case 125: -#line 918 "go.y" +#line 920 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3400,7 +3402,7 @@ yyreduce: break; case 126: -#line 923 "go.y" +#line 925 "go.y" { (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N); (yyval.node)->list = (yyvsp[(3) - (6)].list); @@ -3409,14 +3411,14 @@ yyreduce: break; case 127: -#line 931 "go.y" +#line 933 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; case 129: -#line 936 "go.y" +#line 938 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -3430,35 +3432,35 @@ yyreduce: break; case 130: -#line 947 "go.y" +#line 949 "go.y" { (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node)); } break; case 131: -#line 951 "go.y" +#line 953 "go.y" { (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node)); } break; case 132: -#line 955 "go.y" +#line 957 "go.y" { (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); } break; case 133: -#line 959 "go.y" +#line 961 "go.y" { (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node))); } break; case 134: -#line 963 "go.y" +#line 965 "go.y" { if((yyvsp[(5) - (8)].node) == N) yyerror("middle index required in 3-index slice"); @@ -3469,7 +3471,7 @@ yyreduce: break; case 136: -#line 972 "go.y" +#line 974 "go.y" { // conversion (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); @@ -3478,7 +3480,7 @@ yyreduce: break; case 137: -#line 978 "go.y" +#line 980 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3488,7 +3490,7 @@ yyreduce: break; case 138: -#line 985 "go.y" +#line 987 "go.y" { (yyval.node) = (yyvsp[(3) - (5)].node); (yyval.node)->right = (yyvsp[(1) - (5)].node); @@ -3497,7 +3499,7 @@ yyreduce: break; case 139: -#line 991 "go.y" +#line 993 "go.y" { yyerror("cannot parenthesize type in composite literal"); (yyval.node) = (yyvsp[(5) - (7)].node); @@ -3507,7 +3509,7 @@ yyreduce: break; case 141: -#line 1000 "go.y" +#line 1002 "go.y" { // composite expression. // make node early so we get the right line number. @@ -3516,14 +3518,14 @@ yyreduce: break; case 142: -#line 1008 "go.y" +#line 1010 "go.y" { (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); } break; case 143: -#line 1014 "go.y" +#line 1016 "go.y" { // These nodes do not carry line numbers. // Since a composite literal commonly spans several lines, @@ -3543,7 +3545,7 @@ yyreduce: break; case 144: -#line 1031 "go.y" +#line 1033 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); @@ -3551,7 +3553,7 @@ yyreduce: break; case 146: -#line 1039 "go.y" +#line 1041 "go.y" { (yyval.node) = (yyvsp[(2) - (4)].node); (yyval.node)->list = (yyvsp[(3) - (4)].list); @@ -3559,7 +3561,7 @@ yyreduce: break; case 148: -#line 1047 "go.y" +#line 1049 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -3579,21 +3581,21 @@ yyreduce: break; case 152: -#line 1073 "go.y" +#line 1075 "go.y" { (yyval.i) = LBODY; } break; case 153: -#line 1077 "go.y" +#line 1079 "go.y" { (yyval.i) = '{'; } break; case 154: -#line 1088 "go.y" +#line 1090 "go.y" { if((yyvsp[(1) - (1)].sym) == S) (yyval.node) = N; @@ -3603,21 +3605,21 @@ yyreduce: break; case 155: -#line 1097 "go.y" +#line 1099 "go.y" { (yyval.node) = dclname((yyvsp[(1) - (1)].sym)); } break; case 156: -#line 1102 "go.y" +#line 1104 "go.y" { (yyval.node) = N; } break; case 158: -#line 1109 "go.y" +#line 1111 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); // during imports, unqualified non-exported identifiers are from builtinpkg @@ -3627,14 +3629,14 @@ yyreduce: break; case 160: -#line 1117 "go.y" +#line 1119 "go.y" { (yyval.sym) = S; } break; case 161: -#line 1123 "go.y" +#line 1125 "go.y" { Pkg *p; @@ -3650,7 +3652,7 @@ yyreduce: break; case 162: -#line 1136 "go.y" +#line 1138 "go.y" { Pkg *p; @@ -3666,7 +3668,7 @@ yyreduce: break; case 163: -#line 1151 "go.y" +#line 1153 "go.y" { (yyval.node) = oldname((yyvsp[(1) - (1)].sym)); if((yyval.node)->pack != N) @@ -3675,7 +3677,7 @@ yyreduce: break; case 165: -#line 1171 "go.y" +#line 1173 "go.y" { yyerror("final argument in variadic function missing type"); (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N); @@ -3683,35 +3685,35 @@ yyreduce: break; case 166: -#line 1176 "go.y" +#line 1178 "go.y" { (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N); } break; case 172: -#line 1187 "go.y" +#line 1189 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); } break; case 176: -#line 1196 "go.y" +#line 1198 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 181: -#line 1206 "go.y" +#line 1208 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); } break; case 191: -#line 1227 "go.y" +#line 1229 "go.y" { if((yyvsp[(1) - (3)].node)->op == OPACK) { Sym *s; @@ -3725,14 +3727,14 @@ yyreduce: break; case 192: -#line 1240 "go.y" +#line 1242 "go.y" { (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node)); } break; case 193: -#line 1244 "go.y" +#line 1246 "go.y" { // array literal of nelem (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node)); @@ -3740,7 +3742,7 @@ yyreduce: break; case 194: -#line 1249 "go.y" +#line 1251 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N); (yyval.node)->etype = Cboth; @@ -3748,7 +3750,7 @@ yyreduce: break; case 195: -#line 1254 "go.y" +#line 1256 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Csend; @@ -3756,21 +3758,21 @@ yyreduce: break; case 196: -#line 1259 "go.y" +#line 1261 "go.y" { (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); } break; case 199: -#line 1267 "go.y" +#line 1269 "go.y" { (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); } break; case 200: -#line 1273 "go.y" +#line 1275 "go.y" { (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); (yyval.node)->etype = Crecv; @@ -3778,7 +3780,7 @@ yyreduce: break; case 201: -#line 1280 "go.y" +#line 1282 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3787,7 +3789,7 @@ yyreduce: break; case 202: -#line 1286 "go.y" +#line 1288 "go.y" { (yyval.node) = nod(OTSTRUCT, N, N); fixlbrace((yyvsp[(2) - (3)].i)); @@ -3795,7 +3797,7 @@ yyreduce: break; case 203: -#line 1293 "go.y" +#line 1295 "go.y" { (yyval.node) = nod(OTINTER, N, N); (yyval.node)->list = (yyvsp[(3) - (5)].list); @@ -3804,7 +3806,7 @@ yyreduce: break; case 204: -#line 1299 "go.y" +#line 1301 "go.y" { (yyval.node) = nod(OTINTER, N, N); fixlbrace((yyvsp[(2) - (3)].i)); @@ -3812,7 +3814,7 @@ yyreduce: break; case 205: -#line 1310 "go.y" +#line 1312 "go.y" { (yyval.node) = (yyvsp[(2) - (3)].node); if((yyval.node) == N) @@ -3828,7 +3830,7 @@ yyreduce: break; case 206: -#line 1325 "go.y" +#line 1327 "go.y" { Node *t; @@ -3860,7 +3862,7 @@ yyreduce: break; case 207: -#line 1354 "go.y" +#line 1356 "go.y" { Node *rcvr, *t; @@ -3899,7 +3901,7 @@ yyreduce: break; case 208: -#line 1392 "go.y" +#line 1394 "go.y" { Sym *s; Type *t; @@ -3927,7 +3929,7 @@ yyreduce: break; case 209: -#line 1417 "go.y" +#line 1419 "go.y" { (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); @@ -3946,7 +3948,7 @@ yyreduce: break; case 210: -#line 1435 "go.y" +#line 1437 "go.y" { (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); (yyval.node) = nod(OTFUNC, N, N); @@ -3956,14 +3958,14 @@ yyreduce: break; case 211: -#line 1443 "go.y" +#line 1445 "go.y" { (yyval.list) = nil; } break; case 212: -#line 1447 "go.y" +#line 1449 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); if((yyval.list) == nil) @@ -3972,21 +3974,21 @@ yyreduce: break; case 213: -#line 1455 "go.y" +#line 1457 "go.y" { (yyval.list) = nil; } break; case 214: -#line 1459 "go.y" +#line 1461 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); } break; case 215: -#line 1463 "go.y" +#line 1465 "go.y" { (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); (yyval.list) = (yyvsp[(2) - (3)].list); @@ -3994,14 +3996,14 @@ yyreduce: break; case 216: -#line 1470 "go.y" +#line 1472 "go.y" { closurehdr((yyvsp[(1) - (1)].node)); } break; case 217: -#line 1476 "go.y" +#line 1478 "go.y" { (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); fixlbrace((yyvsp[(2) - (4)].i)); @@ -4009,21 +4011,21 @@ yyreduce: break; case 218: -#line 1481 "go.y" +#line 1483 "go.y" { (yyval.node) = closurebody(nil); } break; case 219: -#line 1492 "go.y" +#line 1494 "go.y" { (yyval.list) = nil; } break; case 220: -#line 1496 "go.y" +#line 1498 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); if(nsyntaxerrors == 0) @@ -4035,56 +4037,56 @@ yyreduce: break; case 222: -#line 1508 "go.y" +#line 1510 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 224: -#line 1515 "go.y" +#line 1517 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 225: -#line 1521 "go.y" +#line 1523 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 226: -#line 1525 "go.y" +#line 1527 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 228: -#line 1532 "go.y" +#line 1534 "go.y" { (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); } break; case 229: -#line 1538 "go.y" +#line 1540 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 230: -#line 1542 "go.y" +#line 1544 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 231: -#line 1548 "go.y" +#line 1550 "go.y" { NodeList *l; @@ -4110,7 +4112,7 @@ yyreduce: break; case 232: -#line 1571 "go.y" +#line 1573 "go.y" { (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); (yyval.list) = list1((yyvsp[(1) - (2)].node)); @@ -4118,7 +4120,7 @@ yyreduce: break; case 233: -#line 1576 "go.y" +#line 1578 "go.y" { (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); (yyval.list) = list1((yyvsp[(2) - (4)].node)); @@ -4127,7 +4129,7 @@ yyreduce: break; case 234: -#line 1582 "go.y" +#line 1584 "go.y" { (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); @@ -4136,7 +4138,7 @@ yyreduce: break; case 235: -#line 1588 "go.y" +#line 1590 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4146,7 +4148,7 @@ yyreduce: break; case 236: -#line 1595 "go.y" +#line 1597 "go.y" { (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); @@ -4156,7 +4158,7 @@ yyreduce: break; case 237: -#line 1604 "go.y" +#line 1606 "go.y" { Node *n; @@ -4168,7 +4170,7 @@ yyreduce: break; case 238: -#line 1613 "go.y" +#line 1615 "go.y" { Pkg *pkg; @@ -4184,14 +4186,14 @@ yyreduce: break; case 239: -#line 1628 "go.y" +#line 1630 "go.y" { (yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg); } break; case 240: -#line 1634 "go.y" +#line 1636 "go.y" { (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); ifacedcl((yyval.node)); @@ -4199,14 +4201,14 @@ yyreduce: break; case 241: -#line 1639 "go.y" +#line 1641 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); } break; case 242: -#line 1643 "go.y" +#line 1645 "go.y" { (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); yyerror("cannot parenthesize embedded type"); @@ -4214,7 +4216,7 @@ yyreduce: break; case 243: -#line 1650 "go.y" +#line 1652 "go.y" { // without func keyword (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); @@ -4225,7 +4227,7 @@ yyreduce: break; case 245: -#line 1664 "go.y" +#line 1666 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4234,7 +4236,7 @@ yyreduce: break; case 246: -#line 1670 "go.y" +#line 1672 "go.y" { (yyval.node) = nod(ONONAME, N, N); (yyval.node)->sym = (yyvsp[(1) - (2)].sym); @@ -4243,56 +4245,56 @@ yyreduce: break; case 248: -#line 1679 "go.y" +#line 1681 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 249: -#line 1683 "go.y" +#line 1685 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 250: -#line 1688 "go.y" +#line 1690 "go.y" { (yyval.list) = nil; } break; case 251: -#line 1692 "go.y" +#line 1694 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 252: -#line 1700 "go.y" +#line 1702 "go.y" { (yyval.node) = N; } break; case 254: -#line 1705 "go.y" +#line 1707 "go.y" { (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); } break; case 256: -#line 1710 "go.y" +#line 1712 "go.y" { (yyval.node) = N; } break; case 262: -#line 1721 "go.y" +#line 1723 "go.y" { (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions @@ -4300,7 +4302,7 @@ yyreduce: break; case 263: -#line 1726 "go.y" +#line 1728 "go.y" { NodeList *l; @@ -4313,7 +4315,7 @@ yyreduce: break; case 264: -#line 1736 "go.y" +#line 1738 "go.y" { // will be converted to OFALL (yyval.node) = nod(OXFALL, N, N); @@ -4322,35 +4324,35 @@ yyreduce: break; case 265: -#line 1742 "go.y" +#line 1744 "go.y" { (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); } break; case 266: -#line 1746 "go.y" +#line 1748 "go.y" { (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); } break; case 267: -#line 1750 "go.y" +#line 1752 "go.y" { (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); } break; case 268: -#line 1754 "go.y" +#line 1756 "go.y" { (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); } break; case 269: -#line 1758 "go.y" +#line 1760 "go.y" { (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); (yyval.node)->sym = dclstack; // context, for goto restrictions @@ -4358,7 +4360,7 @@ yyreduce: break; case 270: -#line 1763 "go.y" +#line 1765 "go.y" { (yyval.node) = nod(ORETURN, N, N); (yyval.node)->list = (yyvsp[(2) - (2)].list); @@ -4378,7 +4380,7 @@ yyreduce: break; case 271: -#line 1782 "go.y" +#line 1784 "go.y" { (yyval.list) = nil; if((yyvsp[(1) - (1)].node) != N) @@ -4387,7 +4389,7 @@ yyreduce: break; case 272: -#line 1788 "go.y" +#line 1790 "go.y" { (yyval.list) = (yyvsp[(1) - (3)].list); if((yyvsp[(3) - (3)].node) != N) @@ -4396,189 +4398,189 @@ yyreduce: break; case 273: -#line 1796 "go.y" +#line 1798 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 274: -#line 1800 "go.y" +#line 1802 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 275: -#line 1806 "go.y" +#line 1808 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 276: -#line 1810 "go.y" +#line 1812 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 277: -#line 1816 "go.y" +#line 1818 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 278: -#line 1820 "go.y" +#line 1822 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 279: -#line 1826 "go.y" +#line 1828 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 280: -#line 1830 "go.y" +#line 1832 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 281: -#line 1839 "go.y" +#line 1841 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 282: -#line 1843 "go.y" +#line 1845 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 283: -#line 1847 "go.y" +#line 1849 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 284: -#line 1851 "go.y" +#line 1853 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 285: -#line 1856 "go.y" +#line 1858 "go.y" { (yyval.list) = nil; } break; case 286: -#line 1860 "go.y" +#line 1862 "go.y" { (yyval.list) = (yyvsp[(1) - (2)].list); } break; case 291: -#line 1874 "go.y" +#line 1876 "go.y" { (yyval.node) = N; } break; case 293: -#line 1880 "go.y" +#line 1882 "go.y" { (yyval.list) = nil; } break; case 295: -#line 1886 "go.y" +#line 1888 "go.y" { (yyval.node) = N; } break; case 297: -#line 1892 "go.y" +#line 1894 "go.y" { (yyval.list) = nil; } break; case 299: -#line 1898 "go.y" +#line 1900 "go.y" { (yyval.list) = nil; } break; case 301: -#line 1904 "go.y" +#line 1906 "go.y" { (yyval.list) = nil; } break; case 303: -#line 1910 "go.y" +#line 1912 "go.y" { (yyval.val).ctype = CTxxx; } break; case 305: -#line 1920 "go.y" +#line 1922 "go.y" { importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); } break; case 306: -#line 1924 "go.y" +#line 1926 "go.y" { importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); } break; case 307: -#line 1928 "go.y" +#line 1930 "go.y" { importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); } break; case 308: -#line 1932 "go.y" +#line 1934 "go.y" { importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); } break; case 309: -#line 1936 "go.y" +#line 1938 "go.y" { importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); } break; case 310: -#line 1940 "go.y" +#line 1942 "go.y" { if((yyvsp[(2) - (4)].node) == N) { dclcontext = PEXTERN; // since we skip the funcbody below @@ -4599,7 +4601,7 @@ yyreduce: break; case 311: -#line 1960 "go.y" +#line 1962 "go.y" { (yyval.sym) = (yyvsp[(1) - (1)].sym); structpkg = (yyval.sym)->pkg; @@ -4607,7 +4609,7 @@ yyreduce: break; case 312: -#line 1967 "go.y" +#line 1969 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); importsym((yyvsp[(1) - (1)].sym), OTYPE); @@ -4615,14 +4617,14 @@ yyreduce: break; case 318: -#line 1987 "go.y" +#line 1989 "go.y" { (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); } break; case 319: -#line 1991 "go.y" +#line 1993 "go.y" { // predefined name like uint8 (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); @@ -4635,49 +4637,49 @@ yyreduce: break; case 320: -#line 2001 "go.y" +#line 2003 "go.y" { (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); } break; case 321: -#line 2005 "go.y" +#line 2007 "go.y" { (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); } break; case 322: -#line 2009 "go.y" +#line 2011 "go.y" { (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); } break; case 323: -#line 2013 "go.y" +#line 2015 "go.y" { (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); } break; case 324: -#line 2017 "go.y" +#line 2019 "go.y" { (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); } break; case 325: -#line 2021 "go.y" +#line 2023 "go.y" { (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); } break; case 326: -#line 2025 "go.y" +#line 2027 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(2) - (2)].type); @@ -4686,7 +4688,7 @@ yyreduce: break; case 327: -#line 2031 "go.y" +#line 2033 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (4)].type); @@ -4695,7 +4697,7 @@ yyreduce: break; case 328: -#line 2037 "go.y" +#line 2039 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4704,7 +4706,7 @@ yyreduce: break; case 329: -#line 2045 "go.y" +#line 2047 "go.y" { (yyval.type) = typ(TCHAN); (yyval.type)->type = (yyvsp[(3) - (3)].type); @@ -4713,14 +4715,14 @@ yyreduce: break; case 330: -#line 2053 "go.y" +#line 2055 "go.y" { (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); } break; case 331: -#line 2059 "go.y" +#line 2061 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); if((yyvsp[(1) - (3)].sym)) @@ -4730,7 +4732,7 @@ yyreduce: break; case 332: -#line 2066 "go.y" +#line 2068 "go.y" { Type *t; @@ -4747,7 +4749,7 @@ yyreduce: break; case 333: -#line 2082 "go.y" +#line 2084 "go.y" { Sym *s; Pkg *p; @@ -4770,49 +4772,49 @@ yyreduce: break; case 334: -#line 2104 "go.y" +#line 2106 "go.y" { (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); } break; case 335: -#line 2108 "go.y" +#line 2110 "go.y" { (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); } break; case 336: -#line 2113 "go.y" +#line 2115 "go.y" { (yyval.list) = nil; } break; case 338: -#line 2120 "go.y" +#line 2122 "go.y" { (yyval.list) = (yyvsp[(2) - (3)].list); } break; case 339: -#line 2124 "go.y" +#line 2126 "go.y" { (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); } break; case 340: -#line 2134 "go.y" +#line 2136 "go.y" { (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); } break; case 341: -#line 2138 "go.y" +#line 2140 "go.y" { (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); switch((yyval.node)->val.ctype){ @@ -4834,7 +4836,7 @@ yyreduce: break; case 342: -#line 2157 "go.y" +#line 2159 "go.y" { (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); if((yyval.node)->op != OLITERAL) @@ -4843,7 +4845,7 @@ yyreduce: break; case 344: -#line 2166 "go.y" +#line 2168 "go.y" { if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { (yyval.node) = (yyvsp[(2) - (5)].node); @@ -4857,42 +4859,42 @@ yyreduce: break; case 347: -#line 2182 "go.y" +#line 2184 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 348: -#line 2186 "go.y" +#line 2188 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 349: -#line 2192 "go.y" +#line 2194 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 350: -#line 2196 "go.y" +#line 2198 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } break; case 351: -#line 2202 "go.y" +#line 2204 "go.y" { (yyval.list) = list1((yyvsp[(1) - (1)].node)); } break; case 352: -#line 2206 "go.y" +#line 2208 "go.y" { (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); } @@ -4900,7 +4902,7 @@ yyreduce: /* Line 1267 of yacc.c. */ -#line 4905 "y.tab.c" +#line 4907 "y.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -5114,7 +5116,7 @@ yyreturn: } -#line 2210 "go.y" +#line 2212 "go.y" static void diff --git a/test/fixedbugs/issue8311.go b/test/fixedbugs/issue8311.go new file mode 100644 index 0000000000..dd928566d6 --- /dev/null +++ b/test/fixedbugs/issue8311.go @@ -0,0 +1,16 @@ +// errorcheck + +// 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. + +// issue 8311. +// error for x++ should say x++ not x += 1 + +package p + +func f() { + var x []byte + x++ // ERROR "invalid operation: x[+][+]" + +} From 870f4e190ccbc70900bd0ba724d4f4c1e14e3070 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 25 Sep 2014 13:24:43 -0400 Subject: [PATCH 194/430] cmd/gc: emit error for out-of-bounds slice of constant string Fixes #7200. LGTM=gri, iant R=golang-codereviews, gri, iant CC=golang-codereviews, r https://golang.org/cl/150020044 --- src/cmd/gc/typecheck.c | 25 +++++++++++++++---------- test/fixedbugs/issue4232.go | 29 ++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 9440526060..ff49fe6f92 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -33,7 +33,7 @@ static void stringtoarraylit(Node**); static Node* resolve(Node*); static void checkdefergo(Node*); static int checkmake(Type*, char*, Node*); -static int checksliceindex(Node*, Type*); +static int checksliceindex(Node*, Node*, Type*); static int checksliceconst(Node*, Node*); static NodeList* typecheckdefstack; @@ -311,6 +311,7 @@ typecheck1(Node **np, int top) Type *t, *tp, *missing, *have, *badtype; Val v; char *why, *desc, descbuf[64]; + vlong x; n = *np; @@ -895,11 +896,12 @@ reswitch: break; } if(isconst(n->right, CTINT)) { - if(mpgetfix(n->right->val.u.xval) < 0) + x = mpgetfix(n->right->val.u.xval); + if(x < 0) yyerror("invalid %s index %N (index must be non-negative)", why, n->right); - else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound) + else if(isfixedarray(t) && t->bound > 0 && x >= t->bound) yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound); - else if(isconst(n->left, CTSTR) && mpgetfix(n->right->val.u.xval) >= n->left->val.u.sval->len) + else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len) yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len); else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0) yyerror("invalid %s index %N (index too large)", why, n->right); @@ -999,9 +1001,9 @@ reswitch: yyerror("cannot slice %N (type %T)", l, t); goto error; } - if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0) + if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) goto error; - if((hi = n->right->right) != N && checksliceindex(hi, tp) < 0) + if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0) goto error; if(checksliceconst(lo, hi) < 0) goto error; @@ -1048,11 +1050,11 @@ reswitch: yyerror("cannot slice %N (type %T)", l, t); goto error; } - if((lo = n->right->left) != N && checksliceindex(lo, tp) < 0) + if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) goto error; - if((mid = n->right->right->left) != N && checksliceindex(mid, tp) < 0) + if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0) goto error; - if((hi = n->right->right->right) != N && checksliceindex(hi, tp) < 0) + if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0) goto error; if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0) goto error; @@ -1822,7 +1824,7 @@ out: } static int -checksliceindex(Node *r, Type *tp) +checksliceindex(Node *l, Node *r, Type *tp) { Type *t; @@ -1839,6 +1841,9 @@ checksliceindex(Node *r, Type *tp) } else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) { yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound); return -1; + } else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) { + yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len); + return -1; } else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) { yyerror("invalid slice index %N (index too large)", r); return -1; diff --git a/test/fixedbugs/issue4232.go b/test/fixedbugs/issue4232.go index e5daa65623..755b1b1de0 100644 --- a/test/fixedbugs/issue4232.go +++ b/test/fixedbugs/issue4232.go @@ -4,6 +4,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// issue 4232 +// issue 7200 + package p func f() { @@ -12,22 +15,42 @@ func f() { _ = a[-1:] // ERROR "invalid slice index -1|index out of bounds" _ = a[:-1] // ERROR "invalid slice index -1|index out of bounds" _ = a[10] // ERROR "invalid array index 10|index out of bounds" + _ = a[9:10] + _ = a[10:10] + _ = a[9:12] // ERROR "invalid slice index 12|index out of bounds" + _ = a[11:12] // ERROR "invalid slice index 11|index out of bounds" + _ = a[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" var s []int _ = s[-1] // ERROR "invalid slice index -1|index out of bounds" _ = s[-1:] // ERROR "invalid slice index -1|index out of bounds" _ = s[:-1] // ERROR "invalid slice index -1|index out of bounds" _ = s[10] + _ = s[9:10] + _ = s[10:10] + _ = s[9:12] + _ = s[11:12] + _ = s[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" - const c = "foo" + const c = "foofoofoof" _ = c[-1] // ERROR "invalid string index -1|index out of bounds" _ = c[-1:] // ERROR "invalid slice index -1|index out of bounds" _ = c[:-1] // ERROR "invalid slice index -1|index out of bounds" - _ = c[3] // ERROR "invalid string index 3|index out of bounds" + _ = c[10] // ERROR "invalid string index 10|index out of bounds" + _ = c[9:10] + _ = c[10:10] + _ = c[9:12] // ERROR "invalid slice index 12|index out of bounds" + _ = c[11:12] // ERROR "invalid slice index 11|index out of bounds" + _ = c[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" var t string _ = t[-1] // ERROR "invalid string index -1|index out of bounds" _ = t[-1:] // ERROR "invalid slice index -1|index out of bounds" _ = t[:-1] // ERROR "invalid slice index -1|index out of bounds" - _ = t[3] + _ = t[10] + _ = t[9:10] + _ = t[10:10] + _ = t[9:12] + _ = t[11:12] + _ = t[1<<100 : 1<<110] // ERROR "overflows int" "invalid slice index 1 << 100|index out of bounds" } From cfae41ff36d833719b073d1eec5f0fd535ca9e61 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 25 Sep 2014 10:52:02 -0700 Subject: [PATCH 195/430] time: make it clear that time.Time values do not compare with == LGTM=bradfitz, josharian, adg, rsc R=golang-codereviews, bradfitz, josharian, rsc, adg CC=golang-codereviews https://golang.org/cl/141340043 --- src/time/time.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/time/time.go b/src/time/time.go index 4f76d79ee5..0300e846a4 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -31,6 +31,11 @@ import "errors" // change the instant in time being denoted and therefore does not affect the // computations described in earlier paragraphs. // +// Note that the Go == operator compares not just the time instant but also the +// Location. Therefore, Time values should not be used as map or database keys +// without first guaranteeing that the identical Location has been set for all +// values, which can be achieved through use of the UTC or Local method. +// type Time struct { // sec gives the number of seconds elapsed since // January 1, year 1 00:00:00 UTC. From 74c0de8fb6ef26deece0541a7bf9337ce30c1878 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 25 Sep 2014 12:45:21 -0700 Subject: [PATCH 196/430] bufio: fix handling of empty tokens at end of line/file Fixes #8672. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/145390043 --- src/bufio/scan.go | 4 +++- src/bufio/scan_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/bufio/scan.go b/src/bufio/scan.go index c5714f331e..a41451524d 100644 --- a/src/bufio/scan.go +++ b/src/bufio/scan.go @@ -112,7 +112,9 @@ func (s *Scanner) Scan() bool { // Loop until we have a token. for { // See if we can get a token with what we already have. - if s.end > s.start { + // If we've run out of data but have an error, give the split function + // a chance to recover any remaining, possibly empty token. + if s.end > s.start || s.err != nil { advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil) if err != nil { s.setErr(err) diff --git a/src/bufio/scan_test.go b/src/bufio/scan_test.go index 3ddb25acf9..1454a8113c 100644 --- a/src/bufio/scan_test.go +++ b/src/bufio/scan_test.go @@ -419,3 +419,39 @@ func TestScanWordsExcessiveWhiteSpace(t *testing.T) { t.Fatalf("unexpected token: %v", token) } } + +// Test that empty tokens, including at end of line or end of file, are found by the scanner. +// Issue 8672: Could miss final empty token. + +func commaSplit(data []byte, atEOF bool) (advance int, token []byte, err error) { + for i := 0; i < len(data); i++ { + if data[i] == ',' { + return i + 1, data[:i], nil + } + } + if !atEOF { + return 0, nil, nil + } + return 0, data, nil +} + +func TestEmptyTokens(t *testing.T) { + s := NewScanner(strings.NewReader("1,2,3,")) + values := []string{"1", "2", "3", ""} + s.Split(commaSplit) + var i int + for i = 0; i < len(values); i++ { + if !s.Scan() { + break + } + if s.Text() != values[i] { + t.Errorf("%d: expected %q got %q", i, values[i], s.Text()) + } + } + if i != len(values) { + t.Errorf("got %d fields, expected %d", i, len(values)) + } + if err := s.Err(); err != nil { + t.Fatal(err) + } +} From bb29c5a1ed872b770ff5203d8a0109a49e6d1dba Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 25 Sep 2014 12:49:42 -0700 Subject: [PATCH 197/430] spec: clarify embedding of interfaces Fixes #7886. LGTM=iant, r, rsc R=r, iant, rsc, ken CC=golang-codereviews https://golang.org/cl/149010043 --- doc/go_spec.html | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 7d86ca863a..e0ed7e7b74 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -1154,11 +1154,11 @@ interface{}

Similarly, consider this interface specification, which appears within a type declaration -to define an interface called Lock: +to define an interface called Locker:

-type Lock interface {
+type Locker interface {
 	Lock()
 	Unlock()
 }
@@ -1174,28 +1174,35 @@ func (p T) Unlock() { … }
 

-they implement the Lock interface as well +they implement the Locker interface as well as the File interface.

+

-An interface may use an interface type name T -in place of a method specification. -The effect, called embedding an interface, -is equivalent to enumerating the methods of T explicitly -in the interface. +An interface T may use a (possibly qualified) interface type +name E in place of a method specification. This is called +embedding interface E in T; it adds +all (exported and non-exported) methods of E to the interface +T.

-type ReadWrite interface {
+type ReadWriter interface {
 	Read(b Buffer) bool
 	Write(b Buffer) bool
 }
 
 type File interface {
-	ReadWrite  // same as enumerating the methods in ReadWrite
-	Lock       // same as enumerating the methods in Lock
+	ReadWriter  // same as adding the methods of ReadWriter
+	Locker      // same as adding the methods of Locker
 	Close()
 }
+
+type LockedFile interface {
+	Locker
+	File        // illegal: Lock, Unlock not unique
+	Lock()      // illegal: Lock not unique
+}
 

From 2fa3e43fae867f5b8757780eb2bbf7444b56f5d5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 25 Sep 2014 12:52:05 -0700 Subject: [PATCH 198/430] spec: clarify scope and re-use of iteration variables Fixes #7834. LGTM=iant, rsc, r R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/148940044 --- doc/go_spec.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e0ed7e7b74..583517269c 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -4682,6 +4682,7 @@ additionally it may specify an init and a post statement, such as an assignment, an increment or decrement statement. The init statement may be a short variable declaration, but the post statement must not. +Variables declared by the init statement are re-used in each iteration.

@@ -4808,7 +4809,7 @@ The iteration variables may be declared by the "range" clause using a form of
 short variable declaration
 (:=).
 In this case their types are set to the types of the respective iteration values
-and their scope ends at the end of the "for"
+and their scope is the block of the "for"
 statement; they are re-used in each iteration.
 If the iteration variables are declared outside the "for" statement,
 after execution their values will be those of the last iteration.

From dd84cf4ea0aefe7758dea21a6d123f8283941bf9 Mon Sep 17 00:00:00 2001
From: Russ Cox 
Date: Thu, 25 Sep 2014 15:57:52 -0400
Subject: [PATCH 199/430] cmd/go: install dependencies for 'go build -i' on a
 command

Fixes #8242.

LGTM=r
R=golang-codereviews, r
CC=golang-codereviews, iant
https://golang.org/cl/147150043
---
 src/cmd/go/build.go  |  11 +++--
 src/cmd/go/test.bash | 114 +++++++++++++++++++++++++++----------------
 2 files changed, 78 insertions(+), 47 deletions(-)

diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index fcc6b699be..c72631ae9e 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -284,6 +284,11 @@ func runBuild(cmd *Command, args []string) {
 		}
 	}
 
+	depMode := modeBuild
+	if buildI {
+		depMode = modeInstall
+	}
+
 	if *buildO != "" {
 		if len(pkgs) > 1 {
 			fatalf("go build: cannot use -o with multiple packages")
@@ -292,17 +297,13 @@ func runBuild(cmd *Command, args []string) {
 		}
 		p := pkgs[0]
 		p.target = "" // must build - not up to date
-		a := b.action(modeInstall, modeBuild, p)
+		a := b.action(modeInstall, depMode, p)
 		a.target = *buildO
 		b.do(a)
 		return
 	}
 
 	a := &action{}
-	depMode := modeBuild
-	if buildI {
-		depMode = modeInstall
-	}
 	for _, p := range packages(args) {
 		a.deps = append(a.deps, b.action(modeBuild, depMode, p))
 	}
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 9ae17e1054..8bd01ea21b 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -11,11 +11,15 @@ go() {
 }
 
 started=false
+testdesc=""
+nl="
+"
 TEST() {
 	if $started; then
 		stop
 	fi
 	echo TEST: "$@"
+	testdesc="$@"
 	started=true
 	ok=true
 }
@@ -29,6 +33,7 @@ stop() {
 		echo PASS
 	else
 		echo FAIL
+		testfail="$testfail	$testdesc$nl"
 		allok=false
 	fi
 }
@@ -59,8 +64,8 @@ rm -r $d
 testlocal() {
 	local="$1"
 	TEST local imports $2 '(easy)'
-	./testgo build -o hello "testdata/$local/easy.go"
-	./hello >hello.out
+	./testgo build -o hello "testdata/$local/easy.go" || ok=false
+	./hello >hello.out || ok=false
 	if ! grep -q '^easysub\.Hello' hello.out; then
 		echo "testdata/$local/easy.go did not generate expected output"
 		cat hello.out
@@ -68,8 +73,8 @@ testlocal() {
 	fi
 	
 	TEST local imports $2 '(easysub)'
-	./testgo build -o hello "testdata/$local/easysub/main.go"
-	./hello >hello.out
+	./testgo build -o hello "testdata/$local/easysub/main.go" || ok=false
+	./hello >hello.out || ok=false
 	if ! grep -q '^easysub\.Hello' hello.out; then
 		echo "testdata/$local/easysub/main.go did not generate expected output"
 		cat hello.out
@@ -77,8 +82,8 @@ testlocal() {
 	fi
 	
 	TEST local imports $2 '(hard)'
-	./testgo build -o hello "testdata/$local/hard.go"
-	./hello >hello.out
+	./testgo build -o hello "testdata/$local/hard.go" || ok=false
+	./hello >hello.out || ok=false
 	if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
 		echo "testdata/$local/hard.go did not generate expected output"
 		cat hello.out
@@ -317,20 +322,20 @@ TEST godoc installs into GOBIN
 d=$(mktemp -d -t testgoXXX)
 export GOPATH=$d
 mkdir $d/gobin
-GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc
+GOBIN=$d/gobin ./testgo get code.google.com/p/go.tools/cmd/godoc || ok=false
 if [ ! -x $d/gobin/godoc ]; then
 	echo did not install godoc to '$GOBIN'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc || true
 	ok=false
 fi
 
 TEST godoc installs into GOROOT
 GOROOT=$(./testgo env GOROOT)
 rm -f $GOROOT/bin/godoc
-./testgo install code.google.com/p/go.tools/cmd/godoc
+./testgo install code.google.com/p/go.tools/cmd/godoc || ok=false
 if [ ! -x $GOROOT/bin/godoc ]; then
 	echo did not install godoc to '$GOROOT/bin'
-	./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc
+	./testgo list -f 'Target: {{.Target}}' code.google.com/p/go.tools/cmd/godoc || true
 	ok=false
 fi
 
@@ -338,36 +343,36 @@ TEST cmd/fix installs into tool
 GOOS=$(./testgo env GOOS)
 GOARCH=$(./testgo env GOARCH)
 rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
-./testgo install cmd/fix
+./testgo install cmd/fix || ok=false
 if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
 	echo 'did not install cmd/fix to $GOROOT/pkg/tool'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
 	ok=false
 fi
 rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
-GOBIN=$d/gobin ./testgo install cmd/fix
+GOBIN=$d/gobin ./testgo install cmd/fix || ok=false
 if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
 	echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
 	ok=false
 fi
 
 TEST gopath program installs into GOBIN
 mkdir $d/src/progname
 echo 'package main; func main() {}' >$d/src/progname/p.go
-GOBIN=$d/gobin ./testgo install progname
+GOBIN=$d/gobin ./testgo install progname || ok=false
 if [ ! -x $d/gobin/progname ]; then
 	echo 'did not install progname to $GOBIN/progname'
-	./testgo list -f 'Target: {{.Target}}' cmd/api
+	./testgo list -f 'Target: {{.Target}}' cmd/api || true
 	ok=false
 fi
 rm -f $d/gobin/progname $d/bin/progname
 
 TEST gopath program installs into GOPATH/bin
-./testgo install progname
+./testgo install progname || ok=false
 if [ ! -x $d/bin/progname ]; then
 	echo 'did not install progname to $GOPATH/bin/progname'
-	./testgo list -f 'Target: {{.Target}}' progname
+	./testgo list -f 'Target: {{.Target}}' progname || true
 	ok=false
 fi
 
@@ -396,7 +401,7 @@ fi
 
 # ensure that output of 'go list' is consistent between runs
 TEST go list is consistent
-./testgo list std > test_std.list
+./testgo list std > test_std.list || ok=false
 if ! ./testgo list std | cmp -s test_std.list - ; then
 	echo "go list std ordering is inconsistent"
 	ok=false
@@ -470,7 +475,7 @@ func main() {
 	println(extern)
 }
 EOF
-./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out
+./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out || ok=false
 if ! grep -q '^hello world' hello.out; then
 	echo "ldflags -X main.extern 'hello world' failed. Output:"
 	cat hello.out
@@ -608,28 +613,36 @@ TEST shadowing logic
 export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
 
 # The math in root1 is not "math" because the standard math is.
+set +e
 cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
+set -e
 if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/math)" ]; then
 	echo shadowed math is not shadowed: "$cdir"
 	ok=false
 fi
 
 # The foo in root1 is "foo".
+set +e
 cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
+set -e
 if [ "$cdir" != "(foo) ()" ]; then
 	echo unshadowed foo is shadowed: "$cdir"
 	ok=false
 fi
 
 # The foo in root2 is not "foo" because the foo in root1 got there first.
+set +e
 cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
+set -e
 if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
 	echo shadowed foo is not shadowed: "$cdir"
 	ok=false
 fi
 
 # The error for go install should mention the conflicting directory.
-err=$(! ./testgo install ./testdata/shadow/root2/src/foo 2>&1)
+set +e
+err=$(./testgo install ./testdata/shadow/root2/src/foo 2>&1)
+set -e
 if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
 	echo wrong shadowed install error: "$err"
 	ok=false
@@ -818,30 +831,46 @@ echo '
 package foo
 func F() {}
 ' >$d/src/x/y/foo/foo.go
+checkbar() {
+	desc="$1"
+	sleep 1
+	touch $d/src/x/y/foo/foo.go
+	if ! ./testgo build -v -i x/y/bar &> $d/err; then
+		echo build -i "$1" failed
+		cat $d/err
+		ok=false
+	elif ! grep x/y/foo $d/err >/dev/null; then
+		echo first build -i "$1" did not build x/y/foo
+		cat $d/err
+		ok=false
+	fi
+	if ! ./testgo build -v -i x/y/bar &> $d/err; then
+		echo second build -i "$1" failed
+		cat $d/err
+		ok=false
+	elif grep x/y/foo $d/err >/dev/null; then
+		echo second build -i "$1" built x/y/foo
+		cat $d/err
+		ok=false
+	fi
+}
+
 echo '
 package bar
 import "x/y/foo"
 func F() { foo.F() }
 ' >$d/src/x/y/bar/bar.go
-if ! ./testgo build -v -i x/y/bar &> $d/err; then
-	echo build -i failed
-	cat $d/err
-	ok=false
-elif ! grep x/y/foo $d/err >/dev/null; then
-	echo first build -i did not build x/y/foo
-	cat $d/err
-	ok=false
-fi
-if ! ./testgo build -v -i x/y/bar &> $d/err; then
-	echo second build -i failed
-	cat $d/err
-	ok=false
-elif grep x/y/foo $d/err >/dev/null; then
-	echo second build -i built x/y/foo
-	cat $d/err
-	ok=false
-fi
-rm -rf $d
+checkbar pkg
+
+TEST build -i installs dependencies for command
+echo '
+package main
+import "x/y/foo"
+func main() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+checkbar cmd
+
+rm -rf $d bar
 unset GOPATH
 
 TEST 'go build in test-only directory fails with a good error'
@@ -876,7 +905,7 @@ fi
 
 TEST 'go test xtestonly works'
 export GOPATH=$(pwd)/testdata
-./testgo clean -i xtestonly
+./testgo clean -i xtestonly || ok=false
 if ! ./testgo test xtestonly >/dev/null; then
 	echo "go test xtestonly failed"
 	ok=false
@@ -927,6 +956,7 @@ rm -f testgo
 if $allok; then
 	echo PASS
 else
-	echo FAIL
+	echo FAIL:
+	echo "$testfail"
 	exit 1
 fi

From dff461f935523035d2f64dc80b1626a0644ab344 Mon Sep 17 00:00:00 2001
From: Rob Pike 
Date: Thu, 25 Sep 2014 14:10:56 -0700
Subject: [PATCH 200/430] doc/gopher: add biplane.jpg

LGTM=0intro
R=golang-codereviews, 0intro
CC=golang-codereviews
https://golang.org/cl/150960043
---
 doc/gopher/biplane.jpg | Bin 0 -> 203420 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 doc/gopher/biplane.jpg

diff --git a/doc/gopher/biplane.jpg b/doc/gopher/biplane.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..d5e666f963281db3fa1f05df6c24bdf375e1c2f0
GIT binary patch
literal 203420
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%0A&GM4#
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%0D+$6`aq&>-we##O
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�Wnbj
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
 
 

-The library sources are in go/src. +The library sources are in the src directory of the repository. If you want to make a significant change, please discuss on the mailing list before embarking.

@@ -1590,30 +1595,40 @@ and uses a variant of the Plan 9 loader to generate ELF/Mach-O/PE binaries.

-We considered writing gc, the original Go compiler, in Go itself but -elected not to do so because of the difficulties of bootstrapping and -especially of open source distribution—you'd need a Go compiler to -set up a Go environment. Gccgo, which came later, makes it possible to -consider writing a compiler in Go, which might well happen. -(Go would be a -fine language in which to implement a compiler; a native lexer and -parser are already available in the go package -and a type checker is in the works.) +We considered using LLVM for gc but we felt it was too large and +slow to meet our performance goals.

-We also considered using LLVM for gc but we felt it was too large and -slow to meet our performance goals. +We also considered writing gc, the original Go compiler, in Go itself but +elected not to do so because of the difficulties of bootstrapping and +especially of open source distribution—you'd need a Go compiler to +set up a Go environment. Gccgo, which came later, makes it possible to +consider writing a compiler in Go. +A plan to do that by machine translation of the existing compiler is under development. +A separate document +explains the reason for this approach. +

+ +

+That plan aside, +Go is a +fine language in which to implement a self-hosting compiler: a native lexer and +parser are already available in the go package +and a separate type checking +package +has also been written.

How is the run-time support implemented?

-Again due to bootstrapping issues, the run-time code is mostly in C (with a -tiny bit of assembler) although Go is capable of implementing most of -it now. Gccgo's run-time support uses glibc. -Gc uses a custom library to keep the footprint under +Again due to bootstrapping issues, the run-time code was originally written mostly in C (with a +tiny bit of assembler) although much of it has been translated to Go since then +and one day all of it might be (except for the assembler bits). +Gccgo's run-time support uses glibc. +Gc uses a custom C library to keep the footprint under control; it is compiled with a version of the Plan 9 C compiler that supports resizable stacks for goroutines. @@ -1637,8 +1652,8 @@ A simple C "hello, world" program compiled and linked statically using gcc on Linux is around 750 kB, including an implementation of printf. An equivalent Go program using fmt.Printf -is around 1.2 MB, but -that includes more powerful run-time support. +is around 1.9 MB, but +that includes more powerful run-time support and type information.

@@ -1695,6 +1710,14 @@ func main() { }

jC{F7$gqChsob#!t`Z&6V9s4C=gG%M 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 Fe*)y~KlK0r literal 0 HcmV?d00001 From 9c3fc838ba982571e704c1674e9f97678f8a6e93 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 25 Sep 2014 15:18:25 -0700 Subject: [PATCH 201/430] encoding/gob: error rather than panic when decoding enormous slices Fixes #8084. LGTM=ruiu R=golang-codereviews, ruiu CC=golang-codereviews https://golang.org/cl/142710043 --- src/encoding/gob/decode.go | 12 +++++++++++- src/encoding/gob/decoder.go | 9 ++++++--- src/encoding/gob/encoder_test.go | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index 2367650c8b..502209a8a8 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -312,6 +312,9 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) { if n > state.b.Len() { errorf("%s data too long for buffer: %d", value.Type(), n) } + if n > tooBig { + errorf("byte slice too big: %d", n) + } if value.Cap() < n { value.Set(reflect.MakeSlice(value.Type(), n, n)) } else { @@ -539,8 +542,15 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp // of interfaces, there will be buffer reloads. errorf("length of %s is negative (%d bytes)", value.Type(), u) } + typ := value.Type() + size := uint64(typ.Elem().Size()) + // Take care with overflow in this calculation. + nBytes := u * size + if nBytes > tooBig || (size > 0 && nBytes/size != u) { + errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), n, size) + } if value.Cap() < n { - value.Set(reflect.MakeSlice(value.Type(), n, n)) + value.Set(reflect.MakeSlice(typ, n, n)) } else { value.Set(value.Slice(0, n)) } diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index 3a769ec125..dcad7a0e48 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -13,6 +13,11 @@ import ( "sync" ) +// tooBig provides a sanity check for sizes; used in several places. +// Upper limit of 1GB, allowing room to grow a little without overflow. +// TODO: make this adjustable? +const tooBig = 1 << 30 + // A Decoder manages the receipt of type and data information read from the // remote side of a connection. type Decoder struct { @@ -75,9 +80,7 @@ func (dec *Decoder) recvMessage() bool { dec.err = err return false } - // Upper limit of 1GB, allowing room to grow a little without overflow. - // TODO: We might want more control over this limit. - if nbytes >= 1<<30 { + if nbytes >= tooBig { dec.err = errBadCount return false } diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index 376df82f15..0ea4c0ec8e 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -932,3 +932,25 @@ func Test29ElementSlice(t *testing.T) { return } } + +// Don't crash, just give error when allocating a huge slice. +// Issue 8084. +func TestErrorForHugeSlice(t *testing.T) { + // Encode an int slice. + buf := new(bytes.Buffer) + slice := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + err := NewEncoder(buf).Encode(slice) + if err != nil { + t.Fatal("encode:", err) + } + // Reach into the buffer and smash the count to make the encoded slice very long. + buf.Bytes()[buf.Len()-len(slice)-1] = 0xfa + // Decode and see error. + err = NewDecoder(buf).Decode(&slice) + if err == nil { + t.Fatal("decode: no error") + } + if !strings.Contains(err.Error(), "slice too big") { + t.Fatal("decode: expected slice too big error, got %s", err.Error()) + } +} From 868948badf4a033678c7d9510543b747c2157b11 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 25 Sep 2014 17:16:27 -0700 Subject: [PATCH 202/430] encoding/gob: fix 386 build LGTM=ruiu R=golang-codereviews, ruiu CC=golang-codereviews https://golang.org/cl/146320043 --- src/encoding/gob/decode.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index 502209a8a8..6a9213fb3c 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -536,18 +536,15 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { // Slices are encoded as an unsigned length followed by the elements. func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error) { u := state.decodeUint() - n := int(u) - if n < 0 || uint64(n) != u { - // We don't check n against buffer length here because if it's a slice - // of interfaces, there will be buffer reloads. - errorf("length of %s is negative (%d bytes)", value.Type(), u) - } typ := value.Type() size := uint64(typ.Elem().Size()) - // Take care with overflow in this calculation. nBytes := u * size - if nBytes > tooBig || (size > 0 && nBytes/size != u) { - errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), n, size) + n := int(u) + // Take care with overflow in this calculation. + if n < 0 || uint64(n) != u || nBytes > tooBig || (size > 0 && nBytes/size != u) { + // We don't check n against buffer length here because if it's a slice + // of interfaces, there will be buffer reloads. + errorf("%s slice too big: %d elements of %d bytes", typ.Elem(), u, size) } if value.Cap() < n { value.Set(reflect.MakeSlice(typ, n, n)) From 0211771f2b3a36626646d08b6b8db3d1ad1ebd7a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 25 Sep 2014 17:30:12 -0700 Subject: [PATCH 203/430] .hgignore: delete some dregs I'd rather delete the file but I doubt that will be popular. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/150100043 --- .hgignore | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.hgignore b/.hgignore index c89b2d9ad0..0071161139 100644 --- a/.hgignore +++ b/.hgignore @@ -23,16 +23,12 @@ _test _testmain.go build.out test.out -doc/tmpltohtml doc/articles/wiki/*.bin include/plan9/libc_plan9.h misc/cgo/life/run.out misc/cgo/stdio/run.out misc/cgo/testso/main misc/dashboard/builder/builder -misc/goplay/goplay -misc/osx/*.pkg -misc/osx/*.dmg src/cmd/?a/y.output src/liblink/anames?.c src/cmd/cc/y.output @@ -43,7 +39,6 @@ src/cmd/gc/opnames.h src/cmd/gc/y.output src/cmd/go/zdefaultcc.go src/go/doc/headscan -src/runtime/goc2c src/runtime/mkversion src/runtime/z* src/unicode/maketables From a326d1d00c5dcba06dc591f6a5f7b7774f9d7410 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 26 Sep 2014 10:53:09 +1000 Subject: [PATCH 204/430] tag go1.3.2 LGTM=r R=r, rsc CC=golang-codereviews https://golang.org/cl/150100044 --- .hgtags | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.hgtags b/.hgtags index 51569d518f..a018693891 100644 --- a/.hgtags +++ b/.hgtags @@ -132,4 +132,5 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1 3f66a43d5180052e2e1e38d979d1aa5ad05b21f9 go1.3rc2 9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3 073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1 -073fc578434bf3e1e22749b559d273c8da728ebb release +85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2 +85518b1d6f8d6e16133b9ed2c9db6807522d37de release From 706efdb12c2c176b441e4c479ccc4d98b909c293 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 26 Sep 2014 11:00:49 +1000 Subject: [PATCH 205/430] doc: document Go 1.3.2 LGTM=r R=r, rsc, iant, agl https://golang.org/cl/142650045 --- doc/devel/release.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/devel/release.html b/doc/devel/release.html index a8f5963ca7..f8ffaf716e 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -27,6 +27,11 @@ go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the r See the change history for details.

+

+go1.3.2 (released 2014/09/25) includes bug fixes to cgo and the crypto/tls packages. +See the change history for details. +

+

go1.2 (released 2013/12/01)

From 64df53ed7f46db4a404812e2ef347521dc95a039 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Fri, 26 Sep 2014 11:02:09 +1000 Subject: [PATCH 206/430] crypto/tls: ensure that we don't resume when tickets are disabled. LGTM=r R=r, adg, rsc https://golang.org/cl/148080043 --- src/crypto/tls/handshake_server.go | 4 + src/crypto/tls/handshake_server_test.go | 26 ++++++ .../Server-TLSv12-IssueTicketPreDisable | 87 +++++++++++++++++++ .../tls/testdata/Server-TLSv12-ResumeDisabled | 87 +++++++++++++++++++ src/crypto/tls/ticket.go | 3 +- 5 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable create mode 100644 src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 684ab288f0..520675dfb5 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -231,6 +231,10 @@ Curves: func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c + if c.config.SessionTicketsDisabled { + return false + } + var ok bool if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok { return false diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 36c79a9b0c..580fbc0bfb 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -676,6 +676,32 @@ func TestResumption(t *testing.T) { runServerTestTLS12(t, test) } +func TestResumptionDisabled(t *testing.T) { + sessionFilePath := tempFile("") + defer os.Remove(sessionFilePath) + + config := *testConfig + + test := &serverTest{ + name: "IssueTicketPreDisable", + command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath}, + config: &config, + } + runServerTestTLS12(t, test) + + config.SessionTicketsDisabled = true + + test = &serverTest{ + name: "ResumeDisabled", + command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath}, + config: &config, + } + runServerTestTLS12(t, test) + + // One needs to manually confirm that the handshake in the golden data + // file for ResumeDisabled does not include a resumption handshake. +} + // cert.pem and key.pem were generated with generate_cert.go // Thus, they have no ExtKeyUsage fields and trigger an error // when verification is turned on. diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable new file mode 100644 index 0000000000..30f0026815 --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable @@ -0,0 +1,87 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 60 01 00 00 5c 03 03 54 23 54 02 17 |....`...\..T#T..| +00000010 f3 53 13 3d 48 88 c3 19 b9 d1 3d 33 7f f5 99 56 |.S.=H.....=3...V| +00000020 04 71 1b d9 d5 64 8a 0d 4a 54 00 00 00 04 00 05 |.q...d..JT......| +00000030 00 ff 01 00 00 2f 00 23 00 00 00 0d 00 22 00 20 |...../.#.....". | +00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| +00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................| +00000060 00 0f 00 01 01 |.....| +>>> Flow 2 (server to client) +00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............| +00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..| +00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................| +00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........| +00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1| +00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S| +00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I| +000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits | +000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042| +000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424| +000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U| +000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...| +000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..| +00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W| +00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.| +00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........| +00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...| +00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..| +00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#| +00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.| +00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..| +00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq| +00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...| +000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......| +000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....| +000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....| +000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..| +000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l| +000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.| +00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.| +00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| +00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| +00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| +00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| +00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...| +00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.| +00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE| +00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z| +00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O| +000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z| +000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..| +000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..| +000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _| +000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m| +000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......| +00000300 00 04 0e 00 00 00 |......| +>>> Flow 3 (client to server) +00000000 16 03 03 00 86 10 00 00 82 00 80 27 e9 a4 f7 e7 |...........'....| +00000010 df 25 de 84 8c 1f d6 e6 c3 11 28 55 9a c1 91 37 |.%........(U...7| +00000020 84 f5 ba f8 80 0d ca 50 cb 1e 72 f7 97 6f c2 b2 |.......P..r..o..| +00000030 04 4d 13 7c e0 6e a0 1f 91 e1 38 1b a2 c0 55 16 |.M.|.n....8...U.| +00000040 7f 29 fc ed 1c 1a cf 72 14 c3 00 c1 dd 36 36 af |.).....r.....66.| +00000050 a6 e4 a8 be ba ec 13 d0 1e d0 1d fd e1 5b 27 fd |.............['.| +00000060 9a da 2e 12 c8 b0 b9 c2 b9 76 ec 7f 3c 98 b6 63 |.........v..<..c| +00000070 bc da f0 07 7a 3d e7 61 f4 2f 12 80 3b f9 3b cc |....z=.a./..;.;.| +00000080 05 c8 2f 7e 28 b2 73 bf 97 61 29 14 03 03 00 01 |../~(.s..a).....| +00000090 01 16 03 03 00 24 17 59 a9 45 53 46 33 96 50 dd |.....$.Y.ESF3.P.| +000000a0 3e 23 aa 91 38 f8 56 4a 2f 1a f2 b1 44 9b ce 17 |>#..8.VJ/...D...| +000000b0 6b 8a 89 76 bc 67 b8 8b ba 90 |k..v.g....| +>>> Flow 4 (server to client) +00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e| +00000020 ea 4b d1 ef ba 2d db 0c ba 9a d4 20 76 57 c8 ec |.K...-..... vW..| +00000030 dc 2d 77 fb fb 3b 93 5f 53 e0 14 4f 90 fb d6 55 |.-w..;._S..O...U| +00000040 57 8c 8d 0d 25 ea 5d 0d f2 91 e5 12 22 12 ec 7b |W...%.]....."..{| +00000050 5f b6 6e fd 07 59 23 24 fc b1 97 ca ea 56 a5 c2 |_.n..Y#$.....V..| +00000060 a0 e4 9e 99 64 f2 64 d0 75 7a 46 63 e3 dc 21 ed |....d.d.uzFc..!.| +00000070 78 56 e9 e1 ab 66 80 14 03 03 00 01 01 16 03 03 |xV...f..........| +00000080 00 24 fc 14 68 07 17 1f df b7 84 cb fd c1 e0 e4 |.$..h...........| +00000090 f2 1a ea 34 b5 00 7f 70 be c8 1c 0a d6 55 e3 57 |...4...p.....U.W| +000000a0 50 4e 6d 7d 8a 5d 17 03 03 00 21 24 27 50 40 c1 |PNm}.]....!$'P@.| +000000b0 c5 bd c7 9f 95 d9 ba 2e 7b 0e db ea a7 31 81 05 |........{....1..| +000000c0 75 43 b1 63 cf b8 55 92 ef 76 98 a9 15 03 03 00 |uC.c..U..v......| +000000d0 16 d7 ea 3c 79 e7 a6 2f 61 39 ec 4e 95 86 48 5e |...>> Flow 1 (client to server) +00000000 16 03 01 00 e8 01 00 00 e4 03 03 54 23 54 02 a5 |...........T#T..| +00000010 10 11 0f 6d e5 2d 2f e8 bb 52 b1 38 3f 65 01 43 |...m.-/..R.8?e.C| +00000020 36 cc 48 f6 09 22 a1 85 20 28 3c 20 35 8b fe 7a |6.H..".. (< 5..z| +00000030 41 3b 59 3a 5d b9 b3 21 f0 62 e9 0d 7b af f5 5d |A;Y:]..!.b..{..]| +00000040 fa 65 1a 40 c8 ca cd 74 8c ef d2 fb 00 04 00 05 |.e.@...t........| +00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......| +00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...| +00000070 2d db 0c ba 9a d4 20 76 57 c8 ec dc 2d 77 fb fb |-..... vW...-w..| +00000080 3b 93 5f 53 e0 14 4f 90 fb d6 55 57 8c 8d 0d 25 |;._S..O...UW...%| +00000090 ea 5d 0d f2 91 e5 12 22 12 ec 7b 5f b6 6e fd 07 |.]....."..{_.n..| +000000a0 59 23 24 fc b1 97 ca ea 56 a5 c2 a0 e4 9e 99 64 |Y#$.....V......d| +000000b0 f2 64 d0 75 7a 46 63 e3 dc 21 ed 78 56 e9 e1 ab |.d.uzFc..!.xV...| +000000c0 66 80 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |f....". ........| +000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| +000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............| +>>> Flow 2 (server to client) +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| +00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| +00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| +00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| +00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| +00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| +00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| +00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| +000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | +000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| +000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| +000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| +000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| +000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| +00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| +00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| +00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| +00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| +00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| +00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| +00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| +00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| +00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| +00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| +000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| +000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| +000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| +000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| +000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| +000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| +00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| +00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| +00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| +00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| +00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| +00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| +00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| +00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| +00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| +00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| +000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| +000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| +000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| +000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| +000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| +000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........| +00000300 00 00 |..| +>>> Flow 3 (client to server) +00000000 16 03 03 00 86 10 00 00 82 00 80 ae 02 dd 1f 1a |................| +00000010 86 83 f5 2f 82 46 4b 29 58 aa a1 b3 56 8b 4e 40 |.../.FK)X...V.N@| +00000020 ef 23 65 67 ad 48 e5 e1 fd ae dd bf 68 fd bd a6 |.#eg.H......h...| +00000030 13 a0 7e 05 ab f7 20 e1 6a 4e d1 37 93 08 1d c9 |..~... .jN.7....| +00000040 37 e0 b5 34 28 bf 20 45 45 da 0f 7e 51 a7 c6 ae |7..4(. EE..~Q...| +00000050 61 6c 07 1b 73 ef da 6e 25 c4 ed be e3 3f da ae |al..s..n%....?..| +00000060 cd 3c 17 9c 2e ee fb 47 9d b3 a1 b2 c3 5d e0 83 |.<.....G.....]..| +00000070 74 20 37 2d 72 d6 d0 4d 58 0e 26 1c 50 22 95 08 |t 7-r..MX.&.P"..| +00000080 7d e0 5f 86 99 9e 2c 2e a7 a0 7f 14 03 03 00 01 |}._...,.........| +00000090 01 16 03 03 00 24 a2 ab 41 25 a5 cf 04 18 1d 98 |.....$..A%......| +000000a0 88 6c 59 21 86 33 54 f4 35 b4 21 6e a5 29 d5 6e |.lY!.3T.5.!n.).n| +000000b0 3d 08 72 b0 af 46 b5 8f 6b 86 |=.r..F..k.| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 24 59 20 4d c2 17 |..........$Y M..| +00000010 8b 3c 9b 33 d9 f9 ef fb 80 18 1f 67 a7 58 12 89 |.<.3.......g.X..| +00000020 4e 73 0f 2d 7b e6 c4 a6 79 73 01 da 22 e8 54 17 |Ns.-{...ys..".T.| +00000030 03 03 00 21 36 ca 64 0f 4a 12 a5 50 3d 97 bb 39 |...!6.d.J..P=..9| +00000040 02 fc ed d1 82 6a 9a 2e 21 79 f6 e1 b3 cc 32 db |.....j..!y....2.| +00000050 0f 5d b3 fb a5 15 03 03 00 16 51 f4 be 57 7a df |.]........Q..Wz.| +00000060 f1 f2 bd b5 51 5e 45 80 be 0b 9a 0c d1 19 3c 79 |....Q^E....... Date: Fri, 26 Sep 2014 12:09:27 -0400 Subject: [PATCH 207/430] cmd/go: fix 'go get vanity/repo/...' in clean GOPATH The pattern was only working if the checkout had already been done, but the code was trying to make it work even the first time. Test and fix. Fixes #8335. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/146310043 --- src/cmd/go/test.bash | 12 ++++++++++++ src/cmd/go/vcs.go | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 8bd01ea21b..5e4e43722a 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -948,6 +948,18 @@ elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; ok=false fi +TEST go get works with vanity wildcards +d=$(mktemp -d -t testgoXXX) +export GOPATH=$d +if ! ./testgo get -u rsc.io/pdf/...; then + ok=false +elif [ ! -x $d/bin/pdfpasswd ]; then + echo did not build rsc.io/pdf/pdfpasswd + ok=false +fi +unset GOPATH +rm -rf $d + # clean up if $started; then stop; fi rm -rf testdata/bin testdata/bin1 diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index d07948e64c..c5d246835d 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -361,7 +361,14 @@ var httpPrefixRE = regexp.MustCompile(`^https?:`) func repoRootForImportPath(importPath string) (*repoRoot, error) { rr, err := repoRootForImportPathStatic(importPath, "") if err == errUnknownSite { - rr, err = repoRootForImportDynamic(importPath) + // If there are wildcards, look up the thing before the wildcard, + // hoping it applies to the wildcarded parts too. + // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. + lookup := strings.TrimSuffix(importPath, "/...") + if i := strings.Index(lookup, "/.../"); i >= 0 { + lookup = lookup[:i] + } + rr, err = repoRootForImportDynamic(lookup) // repoRootForImportDynamic returns error detail // that is irrelevant if the user didn't intend to use a From f3a98dee27540afab414d3201aff18f30c2b163e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 12:10:13 -0400 Subject: [PATCH 208/430] cmd/go: re-resolve and check vcs roots during go get -u If you do 'go get -u rsc.io/pdf' and then rsc.io/pdf's redirect changes to point somewhere else, after this CL a later 'go get -u rsc.io/pdf' will tell you that. Fixes #8548. LGTM=iant R=golang-codereviews, iant CC=adg, golang-codereviews, n13m3y3r, r https://golang.org/cl/147170043 --- src/cmd/go/get.go | 12 +++++++ src/cmd/go/test.bash | 50 ++++++++++++++++++++++++++++ src/cmd/go/vcs.go | 79 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go index a34286f540..2640339414 100644 --- a/src/cmd/go/get.go +++ b/src/cmd/go/get.go @@ -266,6 +266,18 @@ func downloadPackage(p *Package) error { return err } repo = "" // should be unused; make distinctive + + // Double-check where it came from. + if *getU && vcs.remoteRepo != nil { + dir := filepath.Join(p.build.SrcRoot, rootPath) + if remote, err := vcs.remoteRepo(vcs, dir); err == nil { + if rr, err := repoRootForImportPath(p.ImportPath); err == nil { + if remote != rr.repo { + return fmt.Errorf("%s is from %s, should be from %s", dir, remote, rr.repo) + } + } + } + } } else { // Analyze the import path to determine the version control system, // repository, and the import path for the root of the repository. diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 5e4e43722a..243467ba9d 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -126,6 +126,56 @@ if ! ./testgo build -v ./testdata/testinternal2; then ok=false fi +# Test that 'go get -u' reports moved packages. +testmove() { + vcs=$1 + url=$2 + base=$3 + config=$4 + + TEST go get -u notices $vcs package that moved + d=$(mktemp -d -t testgoXXX) + mkdir -p $d/src + if ! GOPATH=$d ./testgo get -d $url; then + echo 'go get -d $url failed' + ok=false + elif ! GOPATH=$d ./testgo get -d -u $url; then + echo 'go get -d -u $url failed' + ok=false + else + set +e + case "$vcs" in + svn) + # SVN doesn't believe in text files so we can't just edit the config. + # Check out a different repo into the wrong place. + rm -rf $d/src/code.google.com/p/rsc-svn + GOPATH=$d ./testgo get -d -u code.google.com/p/rsc-svn2/trunk + mv $d/src/code.google.com/p/rsc-svn2 $d/src/code.google.com/p/rsc-svn + ;; + *) + echo '1,$s;'"$base"';'"$base"'XXX; +w +q' | ed $d/src/$config >/dev/null 2>&1 + esac + set -e + + if GOPATH=$d ./testgo get -d -u $url 2>$d/err; then + echo "go get -d -u $url succeeded with wrong remote repo" + cat $d/err + ok=false + elif ! grep 'should be from' $d/err >/dev/null; then + echo "go get -d -u $url failed for wrong reason" + cat $d/err + ok=false + fi + fi + rm -rf $d +} + +testmove hg rsc.io/x86/x86asm x86 rsc.io/x86/.hg/hgrc +testmove git rsc.io/pdf pdf rsc.io/pdf/.git/config +testmove svn code.google.com/p/rsc-svn/trunk - - + export GOPATH=$(pwd)/testdata/importcom TEST 'import comment - match' if ! ./testgo build ./testdata/importcom/works.go; then diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index c5d246835d..103b67b827 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -33,6 +33,8 @@ type vcsCmd struct { scheme []string pingCmd string + + remoteRepo func(v *vcsCmd, rootDir string) (remoteRepo string, err error) } // A tagCmd describes a command to list available tags @@ -81,8 +83,17 @@ var vcsHg = &vcsCmd{ tagSyncCmd: "update -r {tag}", tagSyncDefault: "update default", - scheme: []string{"https", "http", "ssh"}, - pingCmd: "identify {scheme}://{repo}", + scheme: []string{"https", "http", "ssh"}, + pingCmd: "identify {scheme}://{repo}", + remoteRepo: hgRemoteRepo, +} + +func hgRemoteRepo(vcsHg *vcsCmd, rootDir string) (remoteRepo string, err error) { + out, err := vcsHg.runOutput(rootDir, "paths default") + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil } // vcsGit describes how to use Git. @@ -104,8 +115,38 @@ var vcsGit = &vcsCmd{ tagSyncCmd: "checkout {tag}", tagSyncDefault: "checkout master", - scheme: []string{"git", "https", "http", "git+ssh"}, - pingCmd: "ls-remote {scheme}://{repo}", + scheme: []string{"git", "https", "http", "git+ssh"}, + pingCmd: "ls-remote {scheme}://{repo}", + remoteRepo: gitRemoteRepo, +} + +func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsGit.runOutput(rootDir, "remote -v") + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // origin https://github.com/rsc/pdf (fetch) + // origin https://github.com/rsc/pdf (push) + // use first line only. + + if !strings.HasPrefix(out, "origin\t") { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = strings.TrimPrefix(out, "origin\t") + i := strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = out[:i] + i = strings.LastIndex(out, " ") + if i < 0 { + return "", fmt.Errorf("unable to parse output of git remote -v") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } // vcsBzr describes how to use Bazaar. @@ -138,8 +179,34 @@ var vcsSvn = &vcsCmd{ // There is no tag command in subversion. // The branch information is all in the path names. - scheme: []string{"https", "http", "svn", "svn+ssh"}, - pingCmd: "info {scheme}://{repo}", + scheme: []string{"https", "http", "svn", "svn+ssh"}, + pingCmd: "info {scheme}://{repo}", + remoteRepo: svnRemoteRepo, +} + +func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error) { + outb, err := vcsSvn.runOutput(rootDir, "info") + if err != nil { + return "", err + } + out := string(outb) + + // Expect: + // ... + // Repository Root: + // ... + + i := strings.Index(out, "\nRepository Root: ") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[i+len("\nRepository Root: "):] + i = strings.Index(out, "\n") + if i < 0 { + return "", fmt.Errorf("unable to parse output of svn info") + } + out = out[:i] + return strings.TrimSpace(string(out)), nil } func (v *vcsCmd) String() string { From b86105e80da7fd994656f134d006a700fe037fc2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 13:47:51 -0400 Subject: [PATCH 209/430] cmd/go: make malformed import path message more precise If you say 'go get -v' you get extra information when import paths are not of the expected form. If you say 'go get -v src/rsc.io/pdf' the message says that src/rsc.io/pdf does not contain a hostname, which is incorrect. The problem is that it does not begin with a hostname. Fixes #7432. LGTM=r R=golang-codereviews, r CC=bradfitz, golang-codereviews, iant https://golang.org/cl/144650043 --- src/cmd/go/vcs.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 103b67b827..0834a7d192 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -539,11 +539,11 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { func repoRootForImportDynamic(importPath string) (*repoRoot, error) { slash := strings.Index(importPath, "/") if slash < 0 { - return nil, errors.New("import path doesn't contain a slash") + return nil, errors.New("import path does not contain a slash") } host := importPath[:slash] if !strings.Contains(host, ".") { - return nil, errors.New("import path doesn't contain a hostname") + return nil, errors.New("import path does not begin with hostname") } urlStr, body, err := httpsOrHTTP(importPath) if err != nil { From 13a2c1ca78c47a4314e32badddf6c31c4229da7f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 13:48:30 -0400 Subject: [PATCH 210/430] cmd/go: display program name when reporting crash Fix by atom (from CL 89190044), comment and test by me. Fixes #6823. LGTM=crawshaw R=golang-codereviews, crawshaw CC=0xe2.0x9a.0x9b, adg, golang-codereviews, iant, r https://golang.org/cl/148180043 --- src/cmd/go/build.go | 8 ++++++++ src/cmd/go/test.bash | 11 +++++++++++ src/cmd/ld/pobj.c | 9 +++++++++ 3 files changed, 28 insertions(+) diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index c72631ae9e..e2e17fd036 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1469,6 +1469,14 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter continue } + // err can be something like 'exit status 1'. + // Add information about what program was running. + // Note that if buf.Bytes() is non-empty, the caller usually + // shows buf.Bytes() and does not print err at all, so the + // prefix here does not make most output any more verbose. + if err != nil { + err = errors.New(cmdline[0] + ": " + err.Error()) + } return buf.Bytes(), err } } diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 243467ba9d..80af61ae0e 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -60,6 +60,17 @@ if ! grep -q "^$fn:" $d/err.out; then fi rm -r $d +TEST 'program name in crash messages' +linker=$(./testgo env GOCHAR)l +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +./testgo build -ldflags -crash_for_testing $(./testgo env GOROOT)/test/helloworld.go 2>$d/err.out || true +if ! grep -q "/tool/.*/$linker" $d/err.out; then + echo "missing linker name in error message" + cat $d/err.out + ok=false +fi +rm -r $d + # Test local (./) imports. testlocal() { local="$1" diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c index 54c5ef2472..63460df30a 100644 --- a/src/cmd/ld/pobj.c +++ b/src/cmd/ld/pobj.c @@ -45,6 +45,8 @@ char* paramspace = "FP"; void main(int argc, char *argv[]) { + int i; + linkarchinit(); ctxt = linknew(thelinkarch); ctxt->thechar = thechar; @@ -64,6 +66,13 @@ main(int argc, char *argv[]) INITENTRY = 0; linkmode = LinkAuto; + // For testing behavior of go command when tools crash. + // Undocumented, not in standard flag parser to avoid + // exposing in usage message. + for(i=1; igoarm == 5) debug['F'] = 1; From ce143f25e625ce40f4655185372dc93661545df0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 13:50:02 -0400 Subject: [PATCH 211/430] cmd/go: add test -o flag to control where test binary is written While we are here, remove undocumented, meaningless test -file flag. Fixes #7724. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/149070043 --- src/cmd/go/test.bash | 24 ++++++++++++++++++ src/cmd/go/test.go | 56 ++++++++++++++++++++++++++++-------------- src/cmd/go/testflag.go | 7 +++--- 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 80af61ae0e..bc2ce710a0 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -552,6 +552,30 @@ if [ ! -x strings.test ]; then fi rm -f strings.prof strings.test +TEST go test -cpuprofile -o controls binary location +./testgo test -cpuprofile strings.prof -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -cpuprofile -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f strings.prof mystrings.test + +TEST go test -c -o controls binary location +./testgo test -c -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -c -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f mystrings.test + +TEST go test -o writes binary +./testgo test -o mystrings.test strings || ok=false +if [ ! -x mystrings.test ]; then + echo "go test -o mystrings.test did not create mystrings.test" + ok=false +fi +rm -f mystrings.test + TEST symlinks do not confuse go list '(issue 4568)' old=$(pwd) tmp=$(cd /tmp && pwd -P) diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index c135b89c84..100ef5fa82 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -66,16 +66,23 @@ non-test installation. In addition to the build flags, the flags handled by 'go test' itself are: - -c Compile the test binary to pkg.test but do not run it. - (Where pkg is the last element of the package's import path.) + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. -i Install packages that are dependencies of the test. Do not run the test. - -exec xprog - Run the test binary using xprog. The behavior is the same as - in 'go run'. See 'go help run' for details. + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -123,6 +130,7 @@ control the execution of any test: -blockprofile block.out Write a goroutine blocking profile to the specified file when all tests are complete. + Writes test binary as -c would. -blockprofilerate n Control the detail provided in goroutine blocking profiles by @@ -154,8 +162,7 @@ control the execution of any test: Sets -cover. -coverprofile cover.out - Write a coverage profile to the specified file after all tests - have passed. + Write a coverage profile to the file after all tests have passed. Sets -cover. -cpu 1,2,4 @@ -165,10 +172,11 @@ control the execution of any test: -cpuprofile cpu.out Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. -memprofile mem.out - Write a memory profile to the specified file after all tests - have passed. + Write a memory profile to the file after all tests have passed. + Writes test binary as -c would. -memprofilerate n Enable more precise (and expensive) memory profiles by setting @@ -275,10 +283,10 @@ var ( testCoverMode string // -covermode flag testCoverPaths []string // -coverpkg flag testCoverPkgs []*Package // -coverpkg flag + testO string // -o flag testProfile bool // some profiling flag testNeedBinary bool // profile needs to keep binary around testV bool // -v flag - testFiles []string // -file flag(s) TODO: not respected testTimeout string // -timeout flag testArgs []string testBench bool @@ -310,6 +318,9 @@ func runTest(cmd *Command, args []string) { if testC && len(pkgs) != 1 { fatalf("cannot use -c flag with multiple packages") } + if testO != "" && len(pkgs) != 1 { + fatalf("cannot use -o flag with multiple packages") + } if testProfile && len(pkgs) != 1 { fatalf("cannot use test profile flag with multiple packages") } @@ -781,17 +792,24 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, a.objdir = testDir + string(filepath.Separator) a.objpkg = filepath.Join(testDir, "main.a") a.target = filepath.Join(testDir, testBinary) + exeSuffix - pmainAction := a + buildAction = a if testC || testNeedBinary { // -c or profiling flag: create action to copy binary to ./test.out. - runAction = &action{ - f: (*builder).install, - deps: []*action{pmainAction}, - p: pmain, - target: filepath.Join(cwd, testBinary+exeSuffix), + target := filepath.Join(cwd, testBinary+exeSuffix) + if testO != "" { + target = testO + if !filepath.IsAbs(target) { + target = filepath.Join(cwd, target) + } } - pmainAction = runAction // in case we are running the test + buildAction = &action{ + f: (*builder).install, + deps: []*action{buildAction}, + p: pmain, + target: target, + } + runAction = buildAction // make sure runAction != nil even if not running test } if testC { printAction = &action{p: p, deps: []*action{runAction}} // nop @@ -799,7 +817,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, // run test runAction = &action{ f: (*builder).runTest, - deps: []*action{pmainAction}, + deps: []*action{buildAction}, p: p, ignoreFail: true, } @@ -815,7 +833,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, } } - return pmainAction, runAction, printAction, nil + return buildAction, runAction, printAction, nil } func testImportStack(top string, p *Package, target string) []string { diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go index 73f311e5f6..6da74b9967 100644 --- a/src/cmd/go/testflag.go +++ b/src/cmd/go/testflag.go @@ -65,9 +65,9 @@ type testFlagSpec struct { var testFlagDefn = []*testFlagSpec{ // local. {name: "c", boolVar: &testC}, - {name: "file", multiOK: true}, {name: "cover", boolVar: &testCover}, {name: "coverpkg"}, + {name: "o"}, // build flags. {name: "a", boolVar: &buildA}, @@ -153,6 +153,9 @@ func testFlags(args []string) (packageNames, passToTest []string) { // bool flags. case "a", "c", "i", "n", "x", "v", "race", "cover", "work": setBoolFlag(f.boolVar, value) + case "o": + testO = value + testNeedBinary = true case "p": setIntFlag(&buildP, value) case "exec": @@ -184,8 +187,6 @@ func testFlags(args []string) (packageNames, passToTest []string) { buildContext.BuildTags = strings.Fields(value) case "compiler": buildCompiler{}.Set(value) - case "file": - testFiles = append(testFiles, value) case "bench": // record that we saw the flag; don't care about the value testBench = true From 6d760fb082544531bd14be27b438a1d3a1ec0016 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 13:50:39 -0400 Subject: [PATCH 212/430] cmd/go: document that testdata directories are ignored Also rebuild doc.go; was stale, so contains extra changes. Fixes #8677. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/148170043 --- src/cmd/go/doc.go | 29 +++++++++++++++++++---------- src/cmd/go/help.go | 3 ++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 0d4e263891..cffb53d995 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -524,16 +524,23 @@ non-test installation. In addition to the build flags, the flags handled by 'go test' itself are: - -c Compile the test binary to pkg.test but do not run it. - (Where pkg is the last element of the package's import path.) + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. -i Install packages that are dependencies of the test. Do not run the test. - -exec xprog - Run the test binary using xprog. The behavior is the same as - in 'go run'. See 'go help run' for details. + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + The test binary also accepts flags that control execution of the test; these flags are also accessible by 'go test'. See 'go help testflag' for details. @@ -910,7 +917,8 @@ single directory, the command is applied to a single synthesized package made up of exactly those files, ignoring any build constraints in those files and ignoring any other files in the directory. -File names that begin with "." or "_" are ignored by the go tool. +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". Description of testing flags @@ -942,6 +950,7 @@ control the execution of any test: -blockprofile block.out Write a goroutine blocking profile to the specified file when all tests are complete. + Writes test binary as -c would. -blockprofilerate n Control the detail provided in goroutine blocking profiles by @@ -973,8 +982,7 @@ control the execution of any test: Sets -cover. -coverprofile cover.out - Write a coverage profile to the specified file after all tests - have passed. + Write a coverage profile to the file after all tests have passed. Sets -cover. -cpu 1,2,4 @@ -984,10 +992,11 @@ control the execution of any test: -cpuprofile cpu.out Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. -memprofile mem.out - Write a memory profile to the specified file after all tests - have passed. + Write a memory profile to the file after all tests have passed. + Writes test binary as -c would. -memprofilerate n Enable more precise (and expensive) memory profiles by setting diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go index d6651d179b..201f0e2d79 100644 --- a/src/cmd/go/help.go +++ b/src/cmd/go/help.go @@ -81,7 +81,8 @@ single directory, the command is applied to a single synthesized package made up of exactly those files, ignoring any build constraints in those files and ignoring any other files in the directory. -File names that begin with "." or "_" are ignored by the go tool. +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". `, } From df781cc4abf83225ec2e0dbd6e16dc8dd6cab36d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 13:50:53 -0400 Subject: [PATCH 213/430] liblink: fix cmd/ld -X flag This fixes the test/linkx.go test, which does not run by default. (Issue 4139 is about fixing that.) Fixes #8806. LGTM=r R=golang-codereviews, r CC=bradfitz, golang-codereviews, iant https://golang.org/cl/145420043 --- src/liblink/objfile.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c index 15d602df92..b2478ec178 100644 --- a/src/liblink/objfile.c +++ b/src/liblink/objfile.c @@ -589,6 +589,8 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) typ = rdsym(ctxt, f, pkg); if(typ != nil) // if bss sym defined multiple times, take type from any one def s->gotype = typ; + if(dup != nil && typ != nil) + dup->gotype = typ; rddata(f, &s->p, &s->np); s->maxp = s->np; n = rdint(f); From 0b8bc7cee9cc8c2bedc030e9a59a687201210212 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 26 Sep 2014 14:36:49 -0400 Subject: [PATCH 214/430] cmd/go: handle paths like \x.go on windows Fixes #8130. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/143200043 --- src/cmd/go/build.go | 9 ++++-- src/cmd/go/go_windows_test.go | 55 +++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/cmd/go/go_windows_test.go diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index e2e17fd036..23ad765ba7 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -505,8 +505,13 @@ func goFilesPackage(gofiles []string) *Package { } ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil } - if !filepath.IsAbs(dir) { - dir = filepath.Join(cwd, dir) + var err error + if dir == "" { + dir = cwd + } + dir, err = filepath.Abs(dir) + if err != nil { + fatalf("%s", err) } bp, err := ctxt.ImportDir(dir, 0) diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go new file mode 100644 index 0000000000..53d695cccc --- /dev/null +++ b/src/cmd/go/go_windows_test.go @@ -0,0 +1,55 @@ +// 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 ( + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +func TestAbsolutePath(t *testing.T) { + tmp, err := ioutil.TempDir("", "TestAbsolutePath") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + + file := filepath.Join(tmp, "a.go") + err = ioutil.WriteFile(file, []byte{}, 0644) + if err != nil { + t.Fatal(err) + } + dir := filepath.Join(tmp, "dir") + err = os.Mkdir(dir, 0777) + if err != nil { + t.Fatal(err) + } + + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(wd) + + // Chdir so current directory and a.go reside on the same drive. + err = os.Chdir(dir) + if err != nil { + t.Fatal(err) + } + + noVolume := file[len(filepath.VolumeName(file)):] + wrongPath := filepath.Join(dir, noVolume) + output, err := exec.Command("go", "build", noVolume).CombinedOutput() + if err == nil { + t.Fatal("build should fail") + } + if strings.Contains(string(output), wrongPath) { + t.Fatalf("wrong output found: %v %v", err, string(output)) + } +} From e5afecbd0e2253fb5f1be0aa6f6cbb5c00676e42 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 14:37:38 -0400 Subject: [PATCH 215/430] doc/go1.4: add some cmd/go changes CC=golang-codereviews https://golang.org/cl/143650043 --- doc/go1.4.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index d09a154a3d..a68bca78f6 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -14,6 +14,8 @@ cmd/go: import comments (CL 124940043) cmd/go: implement "internal" (CL 120600043) cmd/go: implement "generate" (CL 125580044) cmd/go: disallow C sources except when using cgo (CL 149720043) +cmd/go: add test -o flag (CL 149070043) +cmd/go: redefine build -a to skip standard library in releases (CL 151730045) asm: make textflag.h available outside of cmd/ld (CL 128050043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) From 8c3005c4929e26cba74c80703123e150fa3fda1a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 14:41:26 -0400 Subject: [PATCH 216/430] cmd/go: make build -a skip standard packages in Go releases Today, 'go build -a my/pkg' and 'go install -a my/pkg' recompile not just my/pkg and all its dependencies that you wrote but also the standard library packages. Recompiling the standard library is problematic on some systems because the installed copy is not writable. The -a behavior means that you can't use 'go install -a all' or 'go install -a my/...' to rebuild everything after a Go release - the rebuild stops early when it cannot overwrite the installed standard library. During development work, however, you do want install -a to rebuild everything, because anything might have changed. Resolve the conflict by making the behavior of -a depend on whether we are using a released copy of Go or a devel copy. In the release copies, -a no longer applies to the standard library. In the devel copies, it still does. This is the latest in a long line of refinements to the "do I build this or not" logic. It is surely not the last. Fixes #8290. LGTM=r R=golang-codereviews, r, tracey.brendan CC=adg, golang-codereviews, iant https://golang.org/cl/151730045 --- src/cmd/go/build.go | 1 + src/cmd/go/doc.go | 1 + src/cmd/go/pkg.go | 18 +++++++++++++++++- src/cmd/go/test.bash | 28 +++++++++++++++++++++++++++- src/cmd/go/testgo.go | 21 +++++++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/cmd/go/testgo.go diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 23ad765ba7..9c7b42650a 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -57,6 +57,7 @@ and test commands: -a force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. -n print the commands but do not run them. -p n diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index cffb53d995..8e2facd044 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -76,6 +76,7 @@ and test commands: -a force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. -n print the commands but do not run them. -p n diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 4bbcc2b971..eafaa8ee67 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -14,6 +14,7 @@ import ( "os" pathpkg "path" "path/filepath" + "runtime" "sort" "strings" "time" @@ -685,6 +686,12 @@ func computeStale(pkgs ...*Package) { } } +// The runtime version string takes one of two forms: +// "go1.X[.Y]" for Go releases, and "devel +hash" at tip. +// Determine whether we are in a released copy by +// inspecting the version. +var isGoRelease = !strings.HasPrefix(runtime.Version(), "go1") + // isStale reports whether package p needs to be rebuilt. func isStale(p *Package, topRoot map[string]bool) bool { if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { @@ -705,7 +712,16 @@ func isStale(p *Package, topRoot map[string]bool) bool { return false } - if buildA || p.target == "" || p.Stale { + // If we are running a release copy of Go, do not rebuild the standard packages. + // They may not be writable anyway, but they are certainly not changing. + // This makes 'go build -a' skip the standard packages when using an official release. + // See issue 4106 and issue 8290. + pkgBuildA := buildA + if p.Standard && isGoRelease { + pkgBuildA = false + } + + if pkgBuildA || p.target == "" || p.Stale { return true } diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index bc2ce710a0..1284876193 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -4,7 +4,7 @@ # license that can be found in the LICENSE file. set -e -go build -o testgo +go build -tags testgo -o testgo go() { echo TEST ERROR: ran go, not testgo: go "$@" >&2 exit 2 @@ -71,6 +71,32 @@ if ! grep -q "/tool/.*/$linker" $d/err.out; then fi rm -r $d +TEST 'go build -a in dev branch' +./testgo install math || ok=false # should be up to date already but just in case +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then + cat $d/err.out + ok=false +elif ! grep -q runtime $d/err.out; then + echo "testgo build -a math in dev branch DID NOT build runtime, but should have" + cat $d/err.out + ok=false +fi +rm -r $d + +TEST 'go build -a in release branch' +./testgo install math || ok=false # should be up to date already but just in case +d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) +if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then + cat $d/err.out + ok=false +elif grep -q runtime $d/err.out; then + echo "testgo build -a math in dev branch DID build runtime, but should NOT have" + cat $d/err.out + ok=false +fi +rm -r $d + # Test local (./) imports. testlocal() { local="$1" diff --git a/src/cmd/go/testgo.go b/src/cmd/go/testgo.go new file mode 100644 index 0000000000..01923f74bd --- /dev/null +++ b/src/cmd/go/testgo.go @@ -0,0 +1,21 @@ +// 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. + +// This file contains extra hooks for testing the go command. +// It is compiled into the Go binary only when building the +// test copy; it does not get compiled into the standard go +// command, so these testing hooks are not present in the +// go command that everyone uses. + +// +build testgo + +package main + +import "os" + +func init() { + if v := os.Getenv("TESTGO_IS_GO_RELEASE"); v != "" { + isGoRelease = v == "1" + } +} From 1bf18b42f8475db2af1618d798285ed84a8dd521 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 15:15:48 -0400 Subject: [PATCH 217/430] cmd/go: fix -a The one line that you can't test easily was broken. This manifested as a failure of a pre-existing test in test.bash but I didn't notice it (there are a few other long-standing failures that need to be fixed). TBR=r CC=golang-codereviews https://golang.org/cl/146340044 --- src/cmd/go/pkg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index eafaa8ee67..7f7a3b04fd 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -690,7 +690,7 @@ func computeStale(pkgs ...*Package) { // "go1.X[.Y]" for Go releases, and "devel +hash" at tip. // Determine whether we are in a released copy by // inspecting the version. -var isGoRelease = !strings.HasPrefix(runtime.Version(), "go1") +var isGoRelease = strings.HasPrefix(runtime.Version(), "go1") // isStale reports whether package p needs to be rebuilt. func isStale(p *Package, topRoot map[string]bool) bool { From b2487ef6a399790cfe57127c3f50fc59341460e4 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 26 Sep 2014 12:33:05 -0700 Subject: [PATCH 218/430] flag: allow CommandLine's Usage function to be set Fixes #7779. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/147210043 --- src/flag/flag.go | 15 +++++++++------ src/flag/flag_test.go | 10 ++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/flag/flag.go b/src/flag/flag.go index de2d91f8b1..323e452a83 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -406,6 +406,7 @@ func defaultUsage(f *FlagSet) { // for how to write your own usage function. // Usage prints to standard error a usage message documenting all defined command-line flags. +// It is called when an error occurs while parsing flags. // The function is a variable that may be changed to point to a custom function. var Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) @@ -702,13 +703,15 @@ func (f *FlagSet) failf(format string, a ...interface{}) error { return err } -// usage calls the Usage method for the flag set, or the usage function if -// the flag set is CommandLine. +// usage calls the Usage method for the flag set if one is specified, +// or the appropriate default usage function otherwise. func (f *FlagSet) usage() { - if f == CommandLine { - Usage() - } else if f.Usage == nil { - defaultUsage(f) + if f.Usage == nil { + if f == CommandLine { + Usage() + } else { + defaultUsage(f) + } } else { f.Usage() } diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 2c03872697..8c88c8c274 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -251,6 +251,16 @@ func TestUserDefined(t *testing.T) { } } +func TestUserDefinedForCommandLine(t *testing.T) { + const help = "HELP" + var result string + ResetForTesting(func() { result = help }) + Usage() + if result != help { + t.Fatalf("got %q; expected %q", result, help) + } +} + // Declare a user-defined boolean flag type. type boolFlagVar struct { count int From bfebf9ea8071683af608b8bf291fc7d8365d501b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 17:03:31 -0400 Subject: [PATCH 219/430] cmd/yacc: fix parsing of character tokens From issue 7967 I learned: 1) yacc accepts either 'x' or "x" to mean token value 0x78 2) yacc also accepts 'xyz' and "XYZ" to mean token value 0x78 Use strconv.Unquote to simplify the handling of quoted strings and check that each has only one rune. Although this does clean things up, it makes 'x' and "x" treated as different internally (now they are stored as `'x'` and `"x"`; before they were both ` x`). Grammars that use both interchangeably will now die with an error similar to the one from issue 7967: yacc bug -- cannot have 2 different Ts with same value "+" and '+' The echoing of the quotes should make clear what is going on. The other semantic change caused by using strconv.Unquote is that '\"' and "\'" are no longer valid. Like in Go, they must be spelled without the backslash: '"' and "'". On the other hand, now yacc and Go agree about what character and string literals mean. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/149110043 --- src/cmd/yacc/yacc.go | 74 +++++++------------------------------------- 1 file changed, 12 insertions(+), 62 deletions(-) diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go index c53403266e..0761811cf4 100644 --- a/src/cmd/yacc/yacc.go +++ b/src/cmd/yacc/yacc.go @@ -52,9 +52,9 @@ import ( "go/format" "io/ioutil" "os" + "strconv" "strings" "unicode" - "unicode/utf8" ) // the following are adjustable @@ -756,64 +756,16 @@ func defin(nt int, s string) int { // establish value for token // single character literal - if s[0] == ' ' { - s = s[1:] - r, size := utf8.DecodeRuneInString(s) - if r == utf8.RuneError && size == 1 { - errorf("invalid UTF-8 sequence %q", s) + if s[0] == '\'' || s[0] == '"' { + q, err := strconv.Unquote(s) + if err != nil { + errorf("invalid token: %s", err) } - val = int(r) - if val == '\\' { // escape sequence - switch { - case len(s) == 2: - // single character escape sequence - switch s[1] { - case '\'': - val = '\'' - case '"': - val = '"' - case '\\': - val = '\\' - case 'a': - val = '\a' - case 'b': - val = '\b' - case 'f': - val = '\f' - case 'n': - val = '\n' - case 'r': - val = '\r' - case 't': - val = '\t' - case 'v': - val = '\v' - default: - errorf("invalid escape %s", s) - } - case s[1] == 'u' && len(s) == 2+4, // \unnnn sequence - s[1] == 'U' && len(s) == 2+8: // \Unnnnnnnn sequence - val = 0 - s = s[2:] - for s != "" { - c := int(s[0]) - switch { - case c >= '0' && c <= '9': - c -= '0' - case c >= 'a' && c <= 'f': - c -= 'a' - 10 - case c >= 'A' && c <= 'F': - c -= 'A' - 10 - default: - errorf(`illegal \u or \U construction`) - } - val = val*16 + c - s = s[1:] - } - default: - errorf("invalid escape %s", s) - } + rq := []rune(q) + if len(rq) != 1 { + errorf("character token too long: %s", s) } + val = int(rq[0]) if val == 0 { errorf("token value 0 is illegal") } @@ -896,7 +848,7 @@ func gettok() int { case '"', '\'': match = c - tokname = " " + tokname = string(c) for { c = getrune(finput) if c == '\n' || c == EOF { @@ -909,6 +861,7 @@ func gettok() int { if tokflag { fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno) } + tokname += string(c) return IDENTIFIER } tokname += string(c) @@ -1029,7 +982,7 @@ func fdtype(t int) int { } func chfind(t int, s string) int { - if s[0] == ' ' { + if s[0] == '"' || s[0] == '\'' { t = 0 } for i := 0; i <= ntokens; i++ { @@ -1516,9 +1469,6 @@ func symnam(i int) string { } else { s = tokset[i].name } - if s[0] == ' ' { - s = s[1:] - } return s } From 754cd5419ace8b1cdc615c3fe58febbcec7b61a0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 17:09:11 -0400 Subject: [PATCH 220/430] cmd/go: always build _test.go files and link into test go test's handling of _test.go files when the entire package's set of files has no Test functions has varied over the past few releases. There are a few interesting cases (all contain no Test functions): (1) x_test.go has syntax errors (2) x_test.go has type errors (3) x_test.go has runtime errors (say, a func init that panics) In Go 1.1, tests with (1) or (2) failed; (3) passed. In Go 1.2, tests with (1) or (2) failed; (3) passed. In Go 1.3, tests with (1) failed; (2) or (3) passed. After this CL, tests with (1), (2), or (3) all fail. This is clearly a corner case, but it seems to me that the behavior of the test should not change if you add or remove a line like func TestAlwaysPasses(t *testing.T) {} That implies that the _test.go files must always be built and always be imported into the test binary. Doing so means that (1), (2), and (3) must all fail. Fixes #8337. LGTM=iant R=golang-codereviews, iant CC=adg, golang-codereviews, r https://golang.org/cl/150980043 --- src/cmd/go/test.bash | 14 ++++++++++++++ src/cmd/go/test.go | 6 ++++-- src/cmd/go/testdata/src/badtest/badexec/x_test.go | 5 +++++ src/cmd/go/testdata/src/badtest/badsyntax/x.go | 1 + .../go/testdata/src/badtest/badsyntax/x_test.go | 3 +++ src/cmd/go/testdata/src/badtest/badvar/x.go | 1 + src/cmd/go/testdata/src/badtest/badvar/x_test.go | 5 +++++ 7 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/cmd/go/testdata/src/badtest/badexec/x_test.go create mode 100644 src/cmd/go/testdata/src/badtest/badsyntax/x.go create mode 100644 src/cmd/go/testdata/src/badtest/badsyntax/x_test.go create mode 100644 src/cmd/go/testdata/src/badtest/badvar/x.go create mode 100644 src/cmd/go/testdata/src/badtest/badvar/x_test.go diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 1284876193..6a72bcde07 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -71,6 +71,20 @@ if ! grep -q "/tool/.*/$linker" $d/err.out; then fi rm -r $d +TEST broken tests without Test functions all fail +d=$(mktemp -d -t testgoXXX) +./testgo test ./testdata/src/badtest/... >$d/err 2>&1 || true +if grep -q '^ok' $d/err; then + echo test passed unexpectedly: + grep '^ok' $d/err + ok=false +elif ! grep -q 'FAIL.*badtest/badexec' $d/err || ! grep -q 'FAIL.*badtest/badsyntax' $d/err || ! grep -q 'FAIL.*badtest/badvar' $d/err; then + echo test did not run everything + cat $d/err + ok=false +fi +rm -rf $d + TEST 'go build -a in dev branch' ./testgo install math || ok=false # should be up to date already but just in case d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX) diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 100ef5fa82..0962e5bb50 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -736,11 +736,13 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if err != nil { return nil, nil, nil, err } - if t.ImportTest || ptest.coverMode != "" { + if len(ptest.GoFiles) > 0 { pmain.imports = append(pmain.imports, ptest) + t.ImportTest = true } - if t.ImportXtest { + if pxtest != nil { pmain.imports = append(pmain.imports, pxtest) + t.ImportXtest = true } if ptest != p && localCover { diff --git a/src/cmd/go/testdata/src/badtest/badexec/x_test.go b/src/cmd/go/testdata/src/badtest/badexec/x_test.go new file mode 100644 index 0000000000..12f5051712 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badexec/x_test.go @@ -0,0 +1,5 @@ +package badexec + +func init() { + panic("badexec") +} diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x.go b/src/cmd/go/testdata/src/badtest/badsyntax/x.go new file mode 100644 index 0000000000..c8a5407a5a --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badsyntax/x.go @@ -0,0 +1 @@ +package badsyntax diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go b/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go new file mode 100644 index 0000000000..5be10745d9 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go @@ -0,0 +1,3 @@ +package badsyntax + +func func func func func! diff --git a/src/cmd/go/testdata/src/badtest/badvar/x.go b/src/cmd/go/testdata/src/badtest/badvar/x.go new file mode 100644 index 0000000000..fdd46c4c72 --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badvar/x.go @@ -0,0 +1 @@ +package badvar diff --git a/src/cmd/go/testdata/src/badtest/badvar/x_test.go b/src/cmd/go/testdata/src/badtest/badvar/x_test.go new file mode 100644 index 0000000000..c67df01c5c --- /dev/null +++ b/src/cmd/go/testdata/src/badtest/badvar/x_test.go @@ -0,0 +1,5 @@ +package badvar_test + +func f() { + _ = notdefined +} From 1d9c03150eead70fa350db101800df42d37ff890 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 17:09:40 -0400 Subject: [PATCH 221/430] doc/go1.4: go test builds + links all test files (CL 150980043) CC=golang-codereviews https://golang.org/cl/144660043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index a68bca78f6..7895ddd03c 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -16,6 +16,7 @@ cmd/go: implement "generate" (CL 125580044) cmd/go: disallow C sources except when using cgo (CL 149720043) cmd/go: add test -o flag (CL 149070043) cmd/go: redefine build -a to skip standard library in releases (CL 151730045) +cmd/go: compile and link all _test.go files during 'go test', even in packages where there are no Test functions (CL 150980043) asm: make textflag.h available outside of cmd/ld (CL 128050043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) From 4a8cb4a49c8bda0759dd3bc0c9fc6bdf5f6aa6b7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 26 Sep 2014 17:13:24 -0400 Subject: [PATCH 222/430] math: avoid assumption of denormalized math mode in Sincos The extra-clever code in Sincos is trying to do if v&2 == 0 { mask = 0xffffffffffffffff } else { mask = 0 } It does this by turning v&2 into a float64 X0 and then using MOVSD $0.0, X3 CMPSD X0, X3, 0 That CMPSD is defined to behave like: if X0 == X3 { X3 = 0xffffffffffffffff } else { X3 = 0 } which gives the desired mask in X3. The goal in using the CMPSD was to avoid a conditional branch. This code fails when called from a PortAudio callback. In particular, the failure behavior is exactly as if the CMPSD always chose the 'true' execution. Notice that the comparison X0 == X3 is comparing as floating point values the 64-bit pattern v&2 and the actual floating point value zero. The only possible values for v&2 are 0x0000000000000000 (floating point zero) and 0x0000000000000002 (floating point 1e-323, a denormal). If they are both comparing equal to zero, I conclude that in a PortAudio callback (whatever that means), the processor is running in "denormals are zero" mode. I confirmed this by placing the processor into that mode and running the test case in the bug; it produces the incorrect output reported in the bug. In general, if a Go program changes the floating point math modes to something other than what Go expects, the math library is not going to work exactly as intended, so we might be justified in not fixing this at all. However, it seems reasonable that the client code might have expected "denormals are zero" mode to only affect actual processing of denormals. This code has produced what is in effect a gratuitous denormal by being extra clever. There is nothing about the computation being requested that fundamentally requires a denormal. It is also easy to do this computation in integer math instead: mask = ((v&2)>>1)-1 Do that. For the record, the other math tests that fail if you put the processor in "denormals are zero" mode are the tests for Frexp, Ilogb, Ldexp, Logb, Log2, and FloatMinMax, but all fail processing denormal inputs. Sincos was the only function for which that mode causes incorrect behavior on non-denormal inputs. The existing tests check that the new assembly is correct. There is no test for behavior in "denormals are zero" mode, because I don't want to add assembly to change that. Fixes #8623. LGTM=josharian R=golang-codereviews, josharian CC=golang-codereviews, iant, r https://golang.org/cl/151750043 --- src/math/sincos_amd64.s | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/math/sincos_amd64.s b/src/math/sincos_amd64.s index dae636b248..59bf55f58c 100644 --- a/src/math/sincos_amd64.s +++ b/src/math/sincos_amd64.s @@ -15,9 +15,7 @@ // The README file says, "The software is in public domain. // You can use the software without any obligation." // -// This code is a simplified version of the original. The CMPSD -// instruction, not generated by the compiler, eliminates jumps in the -// body of the calculation. +// This code is a simplified version of the original. #define PosOne 0x3FF0000000000000 #define PosInf 0x7FF0000000000000 @@ -96,11 +94,10 @@ TEXT ·Sincos(SB),NOSPLIT,$0 // if ((q + 1) & 2) != 0 { sin, cos = cos, sin } MOVQ $1, DX ADDQ BX, DX - MOVQ $2, AX - ANDQ AX, DX - MOVQ DX, X0 - MOVSD $0.0, X3 - CMPSD X0, X3, 0 // cmpeq; x1= x, x2= z, x3 = y, x7= d, bx= q + ANDQ $2, DX + SHRQ $1, DX + SUBQ $1, DX + MOVQ DX, X3 // sin = (y & z) | (^y & x) MOVAPD X2, X0 ANDPD X3, X0 // x0= sin From 56c4d0a5c63a81de4a0d935337b226d229a44c07 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sat, 27 Sep 2014 11:56:54 -0700 Subject: [PATCH 223/430] doc/faq: update for 1.4 LGTM=iant R=golang-codereviews, bradfitz, iant CC=golang-codereviews https://golang.org/cl/150190043 --- doc/go_faq.html | 59 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/doc/go_faq.html b/doc/go_faq.html index 4e90d3907e..5813e1d047 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -889,6 +889,11 @@ type is generic; if you care about how many bits an integer holds, Go encourages you to be explicit.

+

+A blog post, title Constants, +explores this topic in more detail. +

+

Why are maps built in?

@@ -971,7 +976,7 @@ It is a handy reference for people doing code reviews for Go projects. How do I submit patches to the Go libraries?

+

+Nowadays, most Go programmers use a tool, +goimports, +which automatically rewrites a Go source file to have the correct imports, +eliminating the unused imports issue in practice. +This program is easily connected to most editors to run automatically when a Go source file is written. +

+

Performance

From f6fc14094a476d2e23722f124cfcd8204c2659b0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 28 Sep 2014 08:27:05 -0700 Subject: [PATCH 224/430] cmd/ld: don't automatically mark symbols created by -X as reachable This fixes the bug in which the linker reports "missing Go type information" when a -X option refers to a symbol that is not used. Fixes #8821. LGTM=rsc R=rsc, r CC=golang-codereviews https://golang.org/cl/151000043 --- src/cmd/ld/data.c | 9 +++++++-- src/cmd/ld/lib.c | 4 +++- test/linkx.go | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 89226bfe28..9983a9281c 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -620,6 +620,7 @@ addstrdata(char *name, char *value) { LSym *s, *sp; char *p; + uchar reachable; p = smprint("%s.str", name); sp = linklookup(ctxt, p, 0); @@ -630,13 +631,17 @@ addstrdata(char *name, char *value) s = linklookup(ctxt, name, 0); s->size = 0; s->dupok = 1; + reachable = s->reachable; addaddr(ctxt, s, sp); adduint32(ctxt, s, strlen(value)); if(PtrSize == 8) adduint32(ctxt, s, 0); // round struct to pointer width - // in case reachability has already been computed - sp->reachable = s->reachable; + // addstring, addaddr, etc., mark the symbols as reachable. + // In this case that is not necessarily true, so stick to what + // we know before entering this function. + s->reachable = reachable; + sp->reachable = reachable; } vlong diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 3edf7253d4..f889aba8a9 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -222,8 +222,10 @@ loadlib(void) // Since we are simulating the import, we have to provide this string. cgostrsym = "go.string.\"runtime/cgo\""; if(linkrlookup(ctxt, cgostrsym, 0) == nil) { + s = linklookup(ctxt, cgostrsym, 0); + s->type = SRODATA; + s->reachable = 1; addstrdata(cgostrsym, "runtime/cgo"); - linklookup(ctxt, cgostrsym, 0)->type = SRODATA; } } diff --git a/test/linkx.go b/test/linkx.go index 36d16aec9b..06888a229a 100644 --- a/test/linkx.go +++ b/test/linkx.go @@ -1,4 +1,4 @@ -// $G $D/$F.go && $L -X main.tbd hello -X main.overwrite trumped $F.$A && ./$A.out +// $G $D/$F.go && $L -X main.tbd hello -X main.overwrite trumped -X main.nosuchsymbol neverseen $F.$A && ./$A.out // NOTE: This test is not run by 'run.go' and so not run by all.bash. // To run this test you must use the ./run shell script. From e1364a6d0ecd5ba50845f416bb3c016bc54a3648 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 28 Sep 2014 23:52:08 -0700 Subject: [PATCH 225/430] runtime: fix cgo_topofstack to save clobbered registers Fixes #8816 At least, I hope it does. TBR=rsc CC=golang-codereviews https://golang.org/cl/153730043 --- src/runtime/asm_arm.s | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 06bd0751db..36fb022f95 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -1303,9 +1303,17 @@ yieldloop: // Called from cgo wrappers, this function returns g->m->curg.stack.hi. // Must obey the gcc calling convention. -TEXT _cgo_topofstack(SB),NOSPLIT,$0 +TEXT _cgo_topofstack(SB),NOSPLIT,$8 + // R11 and g register are clobbered by load_g. They are + // callee-save in the gcc calling convention, so save them here. + MOVW R11, saveR11-4(SP) + MOVW g, saveG-8(SP) + BL runtime·load_g(SB) MOVW g_m(g), R0 MOVW m_curg(R0), R0 MOVW (g_stack+stack_hi)(R0), R0 + + MOVW saveG-8(SP), g + MOVW saveR11-4(SP), R11 RET From e7e3b3ec1037669c90851670e2dc608b80d499d6 Mon Sep 17 00:00:00 2001 From: Jonathan Rudenberg Date: Mon, 29 Sep 2014 12:13:22 -0700 Subject: [PATCH 226/430] cmd/ld: close outfile before cleanup This prevents the temporary directory from being leaked when the linker is run on a FUSE filesystem. Fixes #8684. LGTM=bradfitz R=golang-codereviews, rsc, bradfitz CC=golang-codereviews https://golang.org/cl/141840043 --- src/cmd/ld/lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index f889aba8a9..910201bdbb 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -531,8 +531,9 @@ char* mktempdir(void); void removeall(char*); static void -rmtemp(void) +cleanup(void) { + close(cout); removeall(tmpdir); } @@ -547,7 +548,7 @@ hostlinksetup(void) // create temporary directory and arrange cleanup if(tmpdir == nil) { tmpdir = mktempdir(); - atexit(rmtemp); + atexit(cleanup); } // change our output to temporary object file From 192665ed9980504ca28c20624f3f9e78ba541966 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 29 Sep 2014 12:15:25 -0700 Subject: [PATCH 227/430] C: add Andres Erbsen (Google CLA) LGTM=bradfitz, minux R=bradfitz, minux CC=golang-codereviews https://golang.org/cl/119540043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 560faf4274..df1829f5fb 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -66,6 +66,7 @@ Amrut Joshi Andrea Spadaccini Andreas Jellinghaus Andrei Vieru +Andres Erbsen Andrew Balholm Andrew Bonventre Andrew Bursavich From bd72d2c650d0b7b668a8b3de58e60b8b61278956 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 29 Sep 2014 12:23:43 -0700 Subject: [PATCH 228/430] go/build: add go1.4 tag. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/138000044 --- src/go/build/build.go | 6 +++--- src/go/build/doc.go | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/go/build/build.go b/src/go/build/build.go index 69cb4b2f6b..5e11c9b9c5 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -294,10 +294,10 @@ func defaultContext() Context { // say "+build go1.x", and code that should only be built before Go 1.x // (perhaps it is the stub to use in that case) should say "+build !go1.x". // - // When we reach Go 1.4 the line will read - // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} + // When we reach Go 1.5 the line will read + // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"} // and so on. - c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"} + c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} switch os.Getenv("CGO_ENABLED") { case "1": diff --git a/src/go/build/doc.go b/src/go/build/doc.go index d78ef3f1c8..56878f2b4a 100644 --- a/src/go/build/doc.go +++ b/src/go/build/doc.go @@ -100,6 +100,7 @@ // - "go1.1", from Go version 1.1 onward // - "go1.2", from Go version 1.2 onward // - "go1.3", from Go version 1.3 onward +// - "go1.4", from Go version 1.4 onward // - any additional words listed in ctxt.BuildTags // // If a file's name, after stripping the extension and a possible _test suffix, From dca460574f28bee2c096eaafb82cbc4f88069c0b Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Sep 2014 12:24:06 -0700 Subject: [PATCH 229/430] net: fix misleading package comment example Fixes #8607 LGTM=r R=r CC=golang-codereviews https://golang.org/cl/146470043 --- src/net/net.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/net/net.go b/src/net/net.go index ca56af54fc..cb31af5e34 100644 --- a/src/net/net.go +++ b/src/net/net.go @@ -32,7 +32,6 @@ The Listen function creates servers: conn, err := ln.Accept() if err != nil { // handle error - continue } go handleConnection(conn) } From dfddd802ace3aece85985dcd4b16e2488f287477 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 29 Sep 2014 12:26:51 -0700 Subject: [PATCH 230/430] crypto/x509: accept CRLs without an expiry. RFC5280 says that the nextUpdate field is optional. Fixes #8085. R=bradfitz CC=golang-codereviews https://golang.org/cl/149770044 --- src/crypto/x509/pkix/pkix.go | 2 +- src/crypto/x509/x509_test.go | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go index 58c1e54d10..8768b78590 100644 --- a/src/crypto/x509/pkix/pkix.go +++ b/src/crypto/x509/pkix/pkix.go @@ -164,7 +164,7 @@ type TBSCertificateList struct { Signature AlgorithmIdentifier Issuer RDNSequence ThisUpdate time.Time - NextUpdate time.Time + NextUpdate time.Time `asn1:"optional"` RevokedCertificates []RevokedCertificate `asn1:"optional"` Extensions []Extension `asn1:"tag:0,optional,explicit"` } diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 56f7a98322..abe86216f9 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -707,6 +707,17 @@ func TestParseDERCRL(t *testing.T) { // Can't check the signature here without a package cycle. } +func TestCRLWithoutExpiry(t *testing.T) { + derBytes := fromBase64("MIHYMIGZMAkGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUxcNOTkwODI3MDcwMDAwWjBpMBMCAgDIFw05OTA4MjIwNzAwMDBaMBMCAgDJFw05OTA4MjIwNzAwMDBaMBMCAgDTFw05OTA4MjIwNzAwMDBaMBMCAgDSFw05OTA4MjIwNzAwMDBaMBMCAgDUFw05OTA4MjQwNzAwMDBaMAkGByqGSM44BAMDLwAwLAIUfmVSdjP+NHMX0feW+aDU2G1cfT0CFAJ6W7fVWxjBz4fvftok8yqDnDWh") + certList, err := ParseDERCRL(derBytes) + if err != nil { + t.Fatal(err) + } + if !certList.TBSCertList.NextUpdate.IsZero() { + t.Errorf("NextUpdate is not the zero value") + } +} + func TestParsePEMCRL(t *testing.T) { pemBytes := fromBase64(pemCRLBase64) certList, err := ParseCRL(pemBytes) From 259f0ffade606f121bb99884371693ed1aef2841 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 29 Sep 2014 12:44:50 -0700 Subject: [PATCH 231/430] spec: specify variable initialization order explicitly The existing spec rules on package initialization were contradictory: They specified that 1) dependent variables are initialized in dependency order, and 2) independent variables are initialized in declaration order. This 2nd rule cannot be satisfied in general. For instance, for var ( c = b + 2 a = 0 b = 1 ) because of its dependency on b, c must be initialized after b, leading to the partial order b, c. Because a is independent of b but is declared before b, we end up with the order: a, b, c. But a is also independent of c and is declared after c, so the order b, c, a should also be valid in contradiction to a, b, c. The new rules are given in form of an algorithm which outlines initialization order explicitly. gccgo and go/types already follow these rules. Fixes #8485. LGTM=iant, r, rsc R=r, rsc, iant, ken, gordon.klaus, adonovan CC=golang-codereviews https://golang.org/cl/142880043 --- doc/go_spec.html | 53 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 583517269c..de79f7ee4b 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -5927,20 +5927,42 @@ var t T

Package initialization

+

-Within a package, package-level variables are initialized according -to their dependencies: if a variable x depends on -a variable y, x will be initialized after -y. +Within a package, package-level variables are initialized in +declaration order but after any of the variables +they depend on. +

+ +

+More precisely, a package-level variable is considered ready for +initialization if it is not yet initialized and either has +no initialization expression or +its initialization expression has no dependencies on uninitialized variables. +Initialization proceeds by repeatedly initializing the next package-level +variable that is earliest in declaration order and ready for initialization, +until there are no variables ready for initialization. +

+ +

+If any variables are still uninitialized when this +process ends, those variables are part of one or more initialization cycles, +and the program is not valid. +

+ +

+The declaration order of variables declared in multiple files is determined +by the order in which the files are presented to the compiler: Variables +declared in the first file are declared before any of the variables declared +in the second file, and so on.

Dependency analysis does not rely on the actual values of the variables, only on lexical references to them in the source, -analyzed transitively. For instance, a variable x's -initialization expression -may refer to a function whose body refers to variable y; -if so, x depends on y. +analyzed transitively. For instance, if a variable x's +initialization expression refers to a function whose body refers to +variable y then x depends on y. Specifically:

@@ -5973,11 +5995,6 @@ or to a function or method that depends on y. Dependency analysis is performed per package; only references referring to variables, functions, and methods declared in the current package are considered. -It is an error if variable dependencies form a cycle -(but dependency cycles containing no variables are permitted). -If two variables are independent of each other, -they are initialized in the order they are declared -in the source, possibly in multiple files, as presented to the compiler.

@@ -6000,8 +6017,6 @@ func f() int {

the initialization order is d, b, c, a. -Since b and c are independent of each other, they are -initialized in declaration order (b before c).

@@ -6044,6 +6059,12 @@ the init functions: it will not invoke the next one until the previous one has returned.

+

+To ensure reproducible initialization behavior, build systems are encouraged +to present multiple files belonging to the same package in lexical file name +order to a compiler. +

+

Program execution

From 1cfa5958f0ab841bd00fcc0d674bfec87e2055bd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Sep 2014 13:28:08 -0700 Subject: [PATCH 232/430] undo CL 141840043 / 65e21380cb2a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unnecessary; covered by https://golang.org/cl/141690043 Verified by jonathan@titanous.com on golang-dev. ««« original CL description cmd/ld: close outfile before cleanup This prevents the temporary directory from being leaked when the linker is run on a FUSE filesystem. Fixes #8684. LGTM=bradfitz R=golang-codereviews, rsc, bradfitz CC=golang-codereviews https://golang.org/cl/141840043 »»» LGTM=jonathan, iant R=iant, jonathan CC=golang-codereviews https://golang.org/cl/150250045 --- src/cmd/ld/lib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 910201bdbb..f889aba8a9 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -531,9 +531,8 @@ char* mktempdir(void); void removeall(char*); static void -cleanup(void) +rmtemp(void) { - close(cout); removeall(tmpdir); } @@ -548,7 +547,7 @@ hostlinksetup(void) // create temporary directory and arrange cleanup if(tmpdir == nil) { tmpdir = mktempdir(); - atexit(cleanup); + atexit(rmtemp); } // change our output to temporary object file From fe2bc11e1fac672cc23e9ffd01673257a1330707 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 29 Sep 2014 13:32:14 -0700 Subject: [PATCH 233/430] cmd/yacc: fix handling of tokens that don't start with letters CL 149110043 changed yacc to no longer keep a leading space for quoted tokens. That is OK by itself but unfortunately yacc was relying on that leading space to notice which tokens it should not output as const declarations. Add a few such tokens to expr.y, although it won't make any immediate difference as we seem to have no tests for yacc. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/152720043 --- src/cmd/yacc/testdata/expr/expr.y | 2 ++ src/cmd/yacc/yacc.go | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y index 09451949ff..721b1c9172 100644 --- a/src/cmd/yacc/testdata/expr/expr.y +++ b/src/cmd/yacc/testdata/expr/expr.y @@ -32,6 +32,8 @@ import ( %type expr expr1 expr2 expr3 +%token '+' '-' '*' '/' '(' ')' + %token NUM %% diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go index 0761811cf4..4dba376fc2 100644 --- a/src/cmd/yacc/yacc.go +++ b/src/cmd/yacc/yacc.go @@ -195,8 +195,9 @@ type Item struct { } type Symb struct { - name string - value int + name string + noconst bool + value int } type Wset struct { @@ -509,8 +510,7 @@ outer: // put out non-literal terminals for i := TOKSTART; i <= ntokens; i++ { // non-literals - c := tokset[i].name[0] - if c != ' ' && c != '$' { + if !tokset[i].noconst { fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value) } } @@ -734,7 +734,7 @@ func defin(nt int, s string) int { copy(anontrst, nontrst) nontrst = anontrst } - nontrst[nnonter] = Symb{s, 0} + nontrst[nnonter] = Symb{name: s} return NTBASE + nnonter } @@ -769,9 +769,13 @@ func defin(nt int, s string) int { if val == 0 { errorf("token value 0 is illegal") } + tokset[ntokens].noconst = true } else { val = extval extval++ + if s[0] == '$' { + tokset[ntokens].noconst = true + } } tokset[ntokens].value = val From 705c1f5cd45d572ba32dea48f5fe997a9f970400 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Sep 2014 13:42:33 -0700 Subject: [PATCH 234/430] net/http: clarify Request.FormValue docs Fixes #8067 LGTM=r R=r CC=golang-codereviews https://golang.org/cl/146480043 --- src/net/http/request.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 263c26c9bd..487eebcb84 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -852,7 +852,8 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error { // POST and PUT body parameters take precedence over URL query string values. // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores // any errors returned by these functions. -// To access multiple values of the same key use ParseForm. +// To access multiple values of the same key, call ParseForm and +// then inspect Request.Form directly. func (r *Request) FormValue(key string) string { if r.Form == nil { r.ParseMultipartForm(defaultMaxMemory) From 2da734189db9a7ad7d6de259ebe9003d20f9f291 Mon Sep 17 00:00:00 2001 From: James Tucker Date: Mon, 29 Sep 2014 13:53:42 -0700 Subject: [PATCH 235/430] net/http: enable Transfer-Encoding: identity without Content-Length for HTTP 1.1. Use case is SSE recommended configuration: http://www.w3.org/TR/eventsource/#notes Removes a TODO. LGTM=bradfitz R=golang-codereviews, bradfitz, tommi.virtanen CC=golang-codereviews https://golang.org/cl/100000044 --- src/net/http/serve_test.go | 29 +++++++++++++++++++++++++++++ src/net/http/server.go | 21 ++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index a690ae4699..702bffdc13 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -778,6 +778,35 @@ func TestChunkedResponseHeaders(t *testing.T) { } } +func TestIdentityResponseHeaders(t *testing.T) { + defer afterTest(t) + log.SetOutput(ioutil.Discard) // is noisy otherwise + defer log.SetOutput(os.Stderr) + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Transfer-Encoding", "identity") + w.(Flusher).Flush() + fmt.Fprintf(w, "I am an identity response.") + })) + defer ts.Close() + + res, err := Get(ts.URL) + if err != nil { + t.Fatalf("Get error: %v", err) + } + defer res.Body.Close() + + if g, e := res.TransferEncoding, []string(nil); !reflect.DeepEqual(g, e) { + t.Errorf("expected TransferEncoding of %v; got %v", e, g) + } + if _, haveCL := res.Header["Content-Length"]; haveCL { + t.Errorf("Unexpected Content-Length") + } + if !res.Close { + t.Errorf("expected Connection: close; got %v", res.Close) + } +} + // Test304Responses verifies that 304s don't declare that they're // chunking in their response headers and aren't allowed to produce // output. diff --git a/src/net/http/server.go b/src/net/http/server.go index 7ad0bcbc20..b5959f7321 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -839,13 +839,20 @@ func (cw *chunkWriter) writeHeader(p []byte) { } else if hasCL { delHeader("Transfer-Encoding") } else if w.req.ProtoAtLeast(1, 1) { - // HTTP/1.1 or greater: use chunked transfer encoding - // to avoid closing the connection at EOF. - // TODO: this blows away any custom or stacked Transfer-Encoding they - // might have set. Deal with that as need arises once we have a valid - // use case. - cw.chunking = true - setHeader.transferEncoding = "chunked" + // HTTP/1.1 or greater: Transfer-Encoding has been set to identity, and no + // content-length has been provided. The connection must be closed after the + // reply is written, and no chunking is to be done. This is the setup + // recommended in the Server-Sent Events candidate recommendation 11, + // section 8. + if hasTE && te == "identity" { + cw.chunking = false + w.closeAfterReply = true + } else { + // HTTP/1.1 or greater: use chunked transfer encoding + // to avoid closing the connection at EOF. + cw.chunking = true + setHeader.transferEncoding = "chunked" + } } else { // HTTP version < 1.1: cannot do chunked transfer // encoding and we don't know the Content-Length so From b4380a3ba2da2515225ab45ff07082d67399757a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 29 Sep 2014 14:05:33 -0700 Subject: [PATCH 236/430] runtime: delete unused variables. We're not comparing with code addresses any more. Instead, we use nil algorithm functions to mark uncomparable types. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/151040044 --- src/runtime/stubs.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 1381c7efdb..c6a9cf9f54 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -148,10 +148,6 @@ func fastrand1() uint32 //go:noescape func memeq(a, b unsafe.Pointer, size uintptr) bool -// Code pointers for the nohash/noequal algorithms. Used for producing better error messages. -var nohashcode uintptr -var noequalcode uintptr - // noescape hides a pointer from escape analysis. noescape is // the identity function but escape analysis doesn't think the // output depends on the input. noescape is inlined and currently From 3df578012630da82c093ac995913ed5e857edb74 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Sep 2014 15:57:03 -0700 Subject: [PATCH 237/430] A+C: Tom Linford (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/149260044 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 8673dce968..9f41e5f285 100644 --- a/AUTHORS +++ b/AUTHORS @@ -418,6 +418,7 @@ Thomas Kappler Timo Savola Timo Truyts Tobias Columbus +Tom Linford Tor Andersson Travis Cline Tudor Golubenco diff --git a/CONTRIBUTORS b/CONTRIBUTORS index df1829f5fb..48465bea5c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -571,6 +571,7 @@ Timo Savola Timo Truyts Tobias Columbus Todd Wang +Tom Linford Tom Szymanski Tor Andersson Travis Cline From 5368e63b57f742495fcbbb82bb15772b761004bf Mon Sep 17 00:00:00 2001 From: Tom Linford Date: Tue, 30 Sep 2014 09:51:49 +1000 Subject: [PATCH 238/430] x509: add root certs for android. On android, root certificates appear to be stored in the folder /system/etc/security/cacerts, which has many certs in several different files. This change adds a new array of directories in which certs can be found. To test this, I simply tried making a request with the http library to an HTTPS URL on an android emulator and manually verified that it worked. LGTM=crawshaw R=golang-codereviews, gobot, crawshaw CC=golang-codereviews https://golang.org/cl/151800043 --- src/crypto/x509/root_unix.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index 11ad3c440d..10057c0c03 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -17,6 +17,13 @@ var certFiles = []string{ "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly } +// Possible directories with certificate files; stop after successfully +// reading at least one file from a directory. +var certDirectories = []string{ + "/system/etc/security/cacerts", // Android + +} + func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } @@ -32,6 +39,24 @@ func initSystemRoots() { } } + for _, directory := range certDirectories { + fis, err := ioutil.ReadDir(directory) + if err != nil { + continue + } + rootsAdded := false + for _, fi := range fis { + data, err := ioutil.ReadFile(directory + "/" + fi.Name()) + if err == nil && roots.AppendCertsFromPEM(data) { + rootsAdded = true + } + } + if rootsAdded { + systemRoots = roots + return + } + } + // All of the files failed to load. systemRoots will be nil which will // trigger a specific error at verification time. } From 0b36211cfb823f41e3a201dd18ddee7a68b4d4e3 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Tue, 30 Sep 2014 10:03:10 +1000 Subject: [PATCH 239/430] liblink: generate MRC replacement in liblink, not tls_arm Fixes #8690. This CL moves the save of LR around BL runtime.read_tls_fallback to liblink as it is not needed when MRC is not replaced. LGTM=rsc, minux R=rsc, khr, minux CC=golang-codereviews https://golang.org/cl/147310043 --- src/liblink/obj5.c | 20 ++++++++++++++++++-- src/runtime/tls_arm.s | 11 +++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c index e192b082b5..d7f2714ed8 100644 --- a/src/liblink/obj5.c +++ b/src/liblink/obj5.c @@ -119,14 +119,30 @@ progedit(Link *ctxt, Prog *p) ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno); if(ctxt->goarm < 7) { - // Replace it with BL runtime.read_tls_fallback(SB). + // Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension. if(tlsfallback == nil) tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0); - // BL runtime.read_tls_fallback(SB) + // MOVW LR, R11 + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGLINK; + p->to.type = D_REG; + p->to.reg = REGTMP; + + // BL runtime.read_tls_fallback(SB) + p = appendp(ctxt, p); p->as = ABL; p->to.type = D_BRANCH; p->to.sym = tlsfallback; p->to.offset = 0; + + // MOVW R11, LR + p = appendp(ctxt, p); + p->as = AMOVW; + p->from.type = D_REG; + p->from.reg = REGTMP; + p->to.type = D_REG; + p->to.reg = REGLINK; break; } } diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s index 039b013833..85c3940bf2 100644 --- a/src/runtime/tls_arm.s +++ b/src/runtime/tls_arm.s @@ -31,11 +31,8 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4 #endif // If the host does not support MRC the linker will replace it with // a call to runtime.read_tls_fallback which jumps to __kuser_get_tls. - // Both functions are written to only disturb R0 so it should be safe to - // use R11 here to temporarily store LR. - MOVW LR, R11 + // The replacement function saves LR in R11 over the call to read_tls_fallback. MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer - MOVW R11, LR // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g. @@ -57,10 +54,8 @@ TEXT runtime·load_g(SB),NOSPLIT,$0 // nothing to do as nacl/arm does not use TLS at all. RET #endif - // See comment in save_g. - MOVW LR, R11 - MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer - MOVW R11, LR + // See save_g + MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g. From 912ec1990bd09f8fc128c3fa6b59105085aabc03 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Mon, 29 Sep 2014 17:04:48 -0700 Subject: [PATCH 240/430] go/format, cmd/gofmt: fix issues with partial Go code with indent Fixes #5551. Fixes #4449. Adds tests for both issues. Note that the two issues occur only when formatting partial Go code with indent. The best way to understand the change is as follows: I took the code of cmd/gofmt and go/format, combined it into one unified code that does not suffer from either 4449 nor 5551, and then applied that code to both cmd/gofmt and go/format. As a result, there is now much more identical code between the two packages, making future code deduplication easier (it was not possible to do that now without adding public APIs, which I was advised not to do at this time). More specifically, I took the parse() of cmd/gofmt which correctly preserves comments (issue 5551) and modified it to fix issue where it would sometimes modify literal values (issue 4449). I ended up removing the matchSpace() function because it no longer needed to do some of its work (insert indent), and a part of its work had to be done in advance (determining the indentation of first code line), because that calculation is required for cfg.Fprint() to run. adjustIndent is used to adjust the indent of cfg.Fprint() to compensate for the body of wrapper func being indented by one level. This allows to get rid of the bytes.Replace text manipulation of inner content, which was problematic and sometimes altered raw string literals (issue 4449). This means that sometimes the value of cfg.Indent is negative, but that works as expected. So now the algorithm for formatting partial Go code is: 1. Determine and prepend leading space of original source. 2. Determine and prepend indentation of first code line. 3. Format and write partial Go code (with all of its leading & trailing space trimmed). 4. Determine and append trailing space of original source. LGTM=gri R=golang-codereviews, bradfitz, gri CC=golang-codereviews https://golang.org/cl/142360043 --- src/cmd/gofmt/gofmt.go | 163 ++++++++++--------- src/cmd/gofmt/long_test.go | 4 +- src/cmd/gofmt/testdata/stdin6.golden | 19 +++ src/cmd/gofmt/testdata/stdin6.input | 21 +++ src/cmd/gofmt/testdata/stdin7.golden | 19 +++ src/cmd/gofmt/testdata/stdin7.input | 21 +++ src/go/format/format.go | 227 ++++++++++++++++----------- src/go/format/format_test.go | 6 +- 8 files changed, 315 insertions(+), 165 deletions(-) create mode 100644 src/cmd/gofmt/testdata/stdin6.golden create mode 100644 src/cmd/gofmt/testdata/stdin6.input create mode 100644 src/cmd/gofmt/testdata/stdin7.golden create mode 100644 src/cmd/gofmt/testdata/stdin7.input diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index f322a2b0a0..8542957248 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -87,13 +87,13 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error return err } - file, adjust, err := parse(fileSet, filename, src, stdin) + file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) if err != nil { return err } if rewrite != nil { - if adjust == nil { + if sourceAdj == nil { file = rewrite(file) } else { fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n") @@ -106,15 +106,10 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error simplify(file) } - var buf bytes.Buffer - err = (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fileSet, file) + res, err := format(fileSet, file, sourceAdj, indentAdj, src) if err != nil { return err } - res := buf.Bytes() - if adjust != nil { - res = adjust(src, res) - } if !bytes.Equal(src, res) { // formatting has changed @@ -242,17 +237,19 @@ func diff(b1, b2 []byte) (data []byte, err error) { // parse parses src, which was read from filename, // as a Go source file or statement list. -func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) { +func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + err error, +) { // Try as whole source file. - file, err := parser.ParseFile(fset, filename, src, parserMode) - if err == nil { - return file, nil, nil - } - // If the error is that the source file didn't begin with a - // package line and this is standard input, fall through to + file, err = parser.ParseFile(fset, filename, src, parserMode) + // If there's no error, return. If the error is that the source file didn't begin with a + // package line and source fragments are ok, fall through to // try as a source fragment. Stop and return on any other error. - if !stdin || !strings.Contains(err.Error(), "expected 'package'") { - return nil, nil, err + if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { + return } // If this is a declaration list, make it a source file @@ -262,19 +259,19 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F psrc := append([]byte("package p;"), src...) file, err = parser.ParseFile(fset, filename, psrc, parserMode) if err == nil { - adjust := func(orig, src []byte) []byte { + sourceAdj = func(src []byte, indent int) []byte { // Remove the package clause. // Gofmt has turned the ; into a \n. - src = src[len("package p\n"):] - return matchSpace(orig, src) + src = src[indent+len("package p\n"):] + return bytes.TrimSpace(src) } - return file, adjust, nil + return } // If the error is that the source file didn't begin with a // declaration, fall through to try as a statement list. // Stop and return on any other error. if !strings.Contains(err.Error(), "expected declaration") { - return nil, nil, err + return } // If this is a statement list, make it a source file @@ -285,65 +282,89 @@ func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.F fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}') file, err = parser.ParseFile(fset, filename, fsrc, parserMode) if err == nil { - adjust := func(orig, src []byte) []byte { + sourceAdj = func(src []byte, indent int) []byte { + // Cap adjusted indent to zero. + if indent < 0 { + indent = 0 + } // Remove the wrapping. // Gofmt has turned the ; into a \n\n. - src = src[len("package p\n\nfunc _() {"):] - src = src[:len(src)-len("\n}\n")] - // Gofmt has also indented the function body one level. - // Remove that indent. - src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) - return matchSpace(orig, src) + // There will be two non-blank lines with indent, hence 2*indent. + src = src[2*indent+len("package p\n\nfunc _() {"):] + src = src[:len(src)-(indent+len("\n}\n"))] + return bytes.TrimSpace(src) } - return file, adjust, nil + // Gofmt has also indented the function body one level. + // Adjust that with indentAdj. + indentAdj = -1 } - // Failed, and out of options. - return nil, nil, err + // Succeeded, or out of options. + return } -func cutSpace(b []byte) (before, middle, after []byte) { - i := 0 - for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { - i++ +func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, indent int) []byte, indentAdj int, src []byte) ([]byte, error) { + if sourceAdj == nil { + // Complete source file. + var buf bytes.Buffer + err := (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + return buf.Bytes(), nil } - j := len(b) - for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { - j-- + + // Partial source file. + // Determine and prepend leading space. + i, j := 0, 0 + for j < len(src) && isSpace(src[j]) { + if src[j] == '\n' { + i = j + 1 // byte offset of last line in leading space + } + j++ } - if i <= j { - return b[:i], b[i:j], b[j:] + var res []byte + res = append(res, src[:i]...) + + // Determine and prepend indentation of first code line. + // Spaces are ignored unless there are no tabs, + // in which case spaces count as one tab. + indent := 0 + hasSpace := false + for _, b := range src[i:j] { + switch b { + case ' ': + hasSpace = true + case '\t': + indent++ + } } - return nil, nil, b[j:] + if indent == 0 && hasSpace { + indent = 1 + } + for i := 0; i < indent; i++ { + res = append(res, '\t') + } + + // Format the source. + // Write it without any leading and trailing space. + cfg := &printer.Config{Mode: printerMode, Tabwidth: tabWidth} + cfg.Indent = indent + indentAdj + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) + + // Determine and append trailing space. + i = len(src) + for i > 0 && isSpace(src[i-1]) { + i-- + } + return append(res, src[i:]...), nil } -// matchSpace reformats src to use the same space context as orig. -// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src. -// 2) matchSpace copies the indentation of the first non-blank line in orig -// to every non-blank line in src. -// 3) matchSpace copies the trailing space from orig and uses it in place -// of src's trailing space. -func matchSpace(orig []byte, src []byte) []byte { - before, _, after := cutSpace(orig) - i := bytes.LastIndex(before, []byte{'\n'}) - before, indent := before[:i+1], before[i+1:] - - _, src, _ = cutSpace(src) - - var b bytes.Buffer - b.Write(before) - for len(src) > 0 { - line := src - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, src = line[:i+1], line[i+1:] - } else { - src = nil - } - if len(line) > 0 && line[0] != '\n' { // not blank - b.Write(indent) - } - b.Write(line) - } - b.Write(after) - return b.Bytes() +func isSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' } diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 108278b336..237b86021b 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -32,7 +32,7 @@ var ( ) func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error { - f, _, err := parse(fset, filename, src.Bytes(), false) + f, _, _, err := parse(fset, filename, src.Bytes(), false) if err != nil { return err } @@ -60,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { // exclude files w/ syntax errors (typically test cases) fset := token.NewFileSet() - if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { + if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { if *verbose { fmt.Fprintf(os.Stderr, "ignoring %s\n", err) } diff --git a/src/cmd/gofmt/testdata/stdin6.golden b/src/cmd/gofmt/testdata/stdin6.golden new file mode 100644 index 0000000000..ffcea8011b --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin6.golden @@ -0,0 +1,19 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f := func(hat, tail string) { + + fmt.Println(hat+` +foo + + +`+tail, + "more", + "and more") + } diff --git a/src/cmd/gofmt/testdata/stdin6.input b/src/cmd/gofmt/testdata/stdin6.input new file mode 100644 index 0000000000..78330020c6 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin6.input @@ -0,0 +1,21 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f:=func( hat, tail string){ + + + + fmt. Println ( hat+ ` +foo + + +`+ tail , + "more" , + "and more" ) + } diff --git a/src/cmd/gofmt/testdata/stdin7.golden b/src/cmd/gofmt/testdata/stdin7.golden new file mode 100644 index 0000000000..bbac7133c8 --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin7.golden @@ -0,0 +1,19 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f := func(hat, tail string) { + + fmt.Println(hat+` + foo + + + `+tail, + "more", + "and more") + } diff --git a/src/cmd/gofmt/testdata/stdin7.input b/src/cmd/gofmt/testdata/stdin7.input new file mode 100644 index 0000000000..fd772a3c4e --- /dev/null +++ b/src/cmd/gofmt/testdata/stdin7.input @@ -0,0 +1,21 @@ + //gofmt -stdin + + if err != nil { + source := strings.NewReader(`line 1. +line 2. +`) + return source + } + + f:=func( hat, tail string){ + + + + fmt. Println ( hat+ ` + foo + + + `+ tail , + "more" , + "and more" ) + } diff --git a/src/go/format/format.go b/src/go/format/format.go index 3d00a645db..08a9047b99 100644 --- a/src/go/format/format.go +++ b/src/go/format/format.go @@ -18,6 +18,8 @@ import ( var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} +const parserMode = parser.ParseComments + // Node formats node in canonical gofmt style and writes the result to dst. // // The node type must be *ast.File, *printer.CommentedNode, []ast.Decl, @@ -52,7 +54,7 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { if err != nil { return err } - file, err = parser.ParseFile(fset, "", buf.Bytes(), parser.ParseComments) + file, err = parser.ParseFile(fset, "", buf.Bytes(), parserMode) if err != nil { // We should never get here. If we do, provide good diagnostic. return fmt.Errorf("format.Node internal error (%s)", err) @@ -80,66 +82,12 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { // func Source(src []byte) ([]byte, error) { fset := token.NewFileSet() - node, err := parse(fset, src) + file, sourceAdj, indentAdj, err := parse(fset, "", src, true) if err != nil { return nil, err } - var buf bytes.Buffer - if file, ok := node.(*ast.File); ok { - // Complete source file. - ast.SortImports(fset, file) - err := config.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - - } else { - // Partial source file. - // Determine and prepend leading space. - i, j := 0, 0 - for j < len(src) && isSpace(src[j]) { - if src[j] == '\n' { - i = j + 1 // index of last line in leading space - } - j++ - } - buf.Write(src[:i]) - - // Determine indentation of first code line. - // Spaces are ignored unless there are no tabs, - // in which case spaces count as one tab. - indent := 0 - hasSpace := false - for _, b := range src[i:j] { - switch b { - case ' ': - hasSpace = true - case '\t': - indent++ - } - } - if indent == 0 && hasSpace { - indent = 1 - } - - // Format the source. - cfg := config - cfg.Indent = indent - err := cfg.Fprint(&buf, fset, node) - if err != nil { - return nil, err - } - - // Determine and append trailing space. - i = len(src) - for i > 0 && isSpace(src[i-1]) { - i-- - } - buf.Write(src[i:]) - } - - return buf.Bytes(), nil + return format(fset, file, sourceAdj, indentAdj, src) } func hasUnsortedImports(file *ast.File) bool { @@ -160,40 +108,137 @@ func hasUnsortedImports(file *ast.File) bool { return false } +// parse parses src, which was read from filename, +// as a Go source file or statement list. +func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + err error, +) { + // Try as whole source file. + file, err = parser.ParseFile(fset, filename, src, parserMode) + // If there's no error, return. If the error is that the source file didn't begin with a + // package line and source fragments are ok, fall through to + // try as a source fragment. Stop and return on any other error. + if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { + return + } + + // If this is a declaration list, make it a source file + // by inserting a package clause. + // Insert using a ;, not a newline, so that the line numbers + // in psrc match the ones in src. + psrc := append([]byte("package p;"), src...) + file, err = parser.ParseFile(fset, filename, psrc, parserMode) + if err == nil { + sourceAdj = func(src []byte, indent int) []byte { + // Remove the package clause. + // Gofmt has turned the ; into a \n. + src = src[indent+len("package p\n"):] + return bytes.TrimSpace(src) + } + return + } + // If the error is that the source file didn't begin with a + // declaration, fall through to try as a statement list. + // Stop and return on any other error. + if !strings.Contains(err.Error(), "expected declaration") { + return + } + + // If this is a statement list, make it a source file + // by inserting a package clause and turning the list + // into a function body. This handles expressions too. + // Insert using a ;, not a newline, so that the line numbers + // in fsrc match the ones in src. + fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}') + file, err = parser.ParseFile(fset, filename, fsrc, parserMode) + if err == nil { + sourceAdj = func(src []byte, indent int) []byte { + // Cap adjusted indent to zero. + if indent < 0 { + indent = 0 + } + // Remove the wrapping. + // Gofmt has turned the ; into a \n\n. + // There will be two non-blank lines with indent, hence 2*indent. + src = src[2*indent+len("package p\n\nfunc _() {"):] + src = src[:len(src)-(indent+len("\n}\n"))] + return bytes.TrimSpace(src) + } + // Gofmt has also indented the function body one level. + // Adjust that with indentAdj. + indentAdj = -1 + } + + // Succeeded, or out of options. + return +} + +func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, indent int) []byte, indentAdj int, src []byte) ([]byte, error) { + if sourceAdj == nil { + // Complete source file. + ast.SortImports(fset, file) + var buf bytes.Buffer + err := config.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + return buf.Bytes(), nil + } + + // Partial source file. + // Determine and prepend leading space. + i, j := 0, 0 + for j < len(src) && isSpace(src[j]) { + if src[j] == '\n' { + i = j + 1 // byte offset of last line in leading space + } + j++ + } + var res []byte + res = append(res, src[:i]...) + + // Determine and prepend indentation of first code line. + // Spaces are ignored unless there are no tabs, + // in which case spaces count as one tab. + indent := 0 + hasSpace := false + for _, b := range src[i:j] { + switch b { + case ' ': + hasSpace = true + case '\t': + indent++ + } + } + if indent == 0 && hasSpace { + indent = 1 + } + for i := 0; i < indent; i++ { + res = append(res, '\t') + } + + // Format the source. + // Write it without any leading and trailing space. + cfg := config + cfg.Indent = indent + indentAdj + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) + + // Determine and append trailing space. + i = len(src) + for i > 0 && isSpace(src[i-1]) { + i-- + } + return append(res, src[i:]...), nil +} + func isSpace(b byte) bool { return b == ' ' || b == '\t' || b == '\n' || b == '\r' } - -func parse(fset *token.FileSet, src []byte) (interface{}, error) { - // Try as a complete source file. - file, err := parser.ParseFile(fset, "", src, parser.ParseComments) - if err == nil { - return file, nil - } - // If the source is missing a package clause, try as a source fragment; otherwise fail. - if !strings.Contains(err.Error(), "expected 'package'") { - return nil, err - } - - // Try as a declaration list by prepending a package clause in front of src. - // Use ';' not '\n' to keep line numbers intact. - psrc := append([]byte("package p;"), src...) - file, err = parser.ParseFile(fset, "", psrc, parser.ParseComments) - if err == nil { - return file.Decls, nil - } - // If the source is missing a declaration, try as a statement list; otherwise fail. - if !strings.Contains(err.Error(), "expected declaration") { - return nil, err - } - - // Try as statement list by wrapping a function around src. - fsrc := append(append([]byte("package p; func _() {"), src...), '}') - file, err = parser.ParseFile(fset, "", fsrc, parser.ParseComments) - if err == nil { - return file.Decls[0].(*ast.FuncDecl).Body.List, nil - } - - // Failed, and out of options. - return nil, err -} diff --git a/src/go/format/format_test.go b/src/go/format/format_test.go index 93f0992477..d7846bec65 100644 --- a/src/go/format/format_test.go +++ b/src/go/format/format_test.go @@ -87,7 +87,11 @@ var tests = []string{ "\tx := 0\n\tgo f()\n\n\n", "\n\t\t\n\n\tx := 0\n\tgo f()\n\n\n", "\n\t\t\n\n\t\t\tx := 0\n\t\t\tgo f()\n\n\n", - "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation inside raw strings + "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\nfoo\n`\n\n\n", // no indentation added inside raw strings + "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings + + // comments + "i := 5 /* Comment */", // Issue 5551. // erroneous programs "ERROR1 + 2 +", From f13cec9f5732dd09c51f90957c3d888aad782c27 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 29 Sep 2014 18:16:15 -0700 Subject: [PATCH 241/430] net/http: make Transport.CloseIdleConnections also close pending dials See comment 4 of https://code.google.com/p/go/issues/detail?id=8483#c4: "So if a user creates a http.Client, issues a bunch of requests and then wants to shutdown it and all opened connections; what is she intended to do? The report suggests that just waiting for all pending requests and calling CloseIdleConnections won't do, as there can be new racing connections. Obviously she can't do what you've done in the test, as it uses the unexported function. If this happens periodically, it can lead to serious resource leaks (the transport is also preserved alive). Am I missing something?" This CL tracks the user's intention to close all idle connections (CloseIdleConnections sets it true; and making a new request sets it false). If a pending dial finishes and nobody wants it, before it's retained for a future caller, the "wantIdle" bool is checked and it's closed if the user has called CloseIdleConnections without a later call to make a new request. Fixes #8483 LGTM=adg R=golang-codereviews, dvyukov, adg CC=golang-codereviews, rsc https://golang.org/cl/148970043 --- src/net/http/export_test.go | 20 +++++++++++++++++ src/net/http/transport.go | 20 ++++++++++++----- src/net/http/transport_test.go | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index e5bc02afa2..a6980b5389 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -57,6 +57,26 @@ func (t *Transport) IdleConnChMapSizeForTesting() int { return len(t.idleConnCh) } +func (t *Transport) IsIdleForTesting() bool { + t.idleMu.Lock() + defer t.idleMu.Unlock() + return t.wantIdle +} + +func (t *Transport) RequestIdleConnChForTesting() { + t.getIdleConnCh(connectMethod{nil, "http", "example.com"}) +} + +func (t *Transport) PutIdleTestConn() bool { + c, _ := net.Pipe() + return t.putIdleConn(&persistConn{ + t: t, + conn: c, // dummy + closech: make(chan struct{}), // so it can be closed + cacheKey: connectMethodKey{"", "http", "example.com"}, + }) +} + func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { f := func() <-chan time.Time { return ch diff --git a/src/net/http/transport.go b/src/net/http/transport.go index f1a6837527..70e574fc86 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -47,13 +47,16 @@ const DefaultMaxIdleConnsPerHost = 2 // HTTPS, and HTTP proxies (for either HTTP or HTTPS with CONNECT). // Transport can also cache connections for future re-use. type Transport struct { - idleMu sync.Mutex - idleConn map[connectMethodKey][]*persistConn - idleConnCh map[connectMethodKey]chan *persistConn + idleMu sync.Mutex + wantIdle bool // user has requested to close all idle conns + idleConn map[connectMethodKey][]*persistConn + idleConnCh map[connectMethodKey]chan *persistConn + reqMu sync.Mutex reqCanceler map[*Request]func() - altMu sync.RWMutex - altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper + + altMu sync.RWMutex + altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the @@ -262,6 +265,7 @@ func (t *Transport) CloseIdleConnections() { m := t.idleConn t.idleConn = nil t.idleConnCh = nil + t.wantIdle = true t.idleMu.Unlock() for _, conns := range m { for _, pconn := range conns { @@ -385,6 +389,11 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool { delete(t.idleConnCh, key) } } + if t.wantIdle { + t.idleMu.Unlock() + pconn.close() + return false + } if t.idleConn == nil { t.idleConn = make(map[connectMethodKey][]*persistConn) } @@ -413,6 +422,7 @@ func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn { key := cm.key() t.idleMu.Lock() defer t.idleMu.Unlock() + t.wantIdle = false if t.idleConnCh == nil { t.idleConnCh = make(map[connectMethodKey]chan *persistConn) } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 2ffd359794..66fcc3c7d4 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2177,6 +2177,45 @@ func TestRoundTripReturnsProxyError(t *testing.T) { } } +// tests that putting an idle conn after a call to CloseIdleConns does return it +func TestTransportCloseIdleConnsThenReturn(t *testing.T) { + tr := &Transport{} + wantIdle := func(when string, n int) bool { + got := tr.IdleConnCountForTesting("|http|example.com") // key used by PutIdleTestConn + if got == n { + return true + } + t.Errorf("%s: idle conns = %d; want %d", when, got, n) + return false + } + wantIdle("start", 0) + if !tr.PutIdleTestConn() { + t.Fatal("put failed") + } + if !tr.PutIdleTestConn() { + t.Fatal("second put failed") + } + wantIdle("after put", 2) + tr.CloseIdleConnections() + if !tr.IsIdleForTesting() { + t.Error("should be idle after CloseIdleConnections") + } + wantIdle("after close idle", 0) + if tr.PutIdleTestConn() { + t.Fatal("put didn't fail") + } + wantIdle("after second put", 0) + + tr.RequestIdleConnChForTesting() // should toggle the transport out of idle mode + if tr.IsIdleForTesting() { + t.Error("shouldn't be idle after RequestIdleConnChForTesting") + } + if !tr.PutIdleTestConn() { + t.Fatal("after re-activation") + } + wantIdle("after final put", 1) +} + func wantBody(res *http.Response, err error, want string) error { if err != nil { return err From 70b2da98ca097598326d5d01406b287bcd5eb6ee Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 29 Sep 2014 21:21:36 -0700 Subject: [PATCH 242/430] runtime: initialize traceback variables earlier Our traceback code needs to know the PC of several special functions, including goexit, mcall, etc. Make sure that these PCs are initialized before any traceback occurs. Fixes #8766 LGTM=rsc R=golang-codereviews, rsc, khr, bradfitz CC=golang-codereviews https://golang.org/cl/145570043 --- src/runtime/proc.c | 1 + src/runtime/runtime.h | 1 + src/runtime/traceback.go | 39 +++++++++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 1f0a79098b..e84dc1d048 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -131,6 +131,7 @@ runtime·schedinit(void) runtime·sched.maxmcount = 10000; + runtime·tracebackinit(); runtime·symtabinit(); runtime·stackinit(); runtime·mallocinit(); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 3a6d3e3262..aa300d7bb8 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -841,6 +841,7 @@ void runtime·mpreinit(M*); void runtime·minit(void); void runtime·unminit(void); void runtime·signalstack(byte*, int32); +void runtime·tracebackinit(void); void runtime·symtabinit(void); Func* runtime·findfunc(uintptr); int32 runtime·funcline(Func*, uintptr, String*); diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index a93c42186b..24dc3eea95 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -31,20 +31,36 @@ import "unsafe" const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386" var ( - deferprocPC = funcPC(deferproc) - goexitPC = funcPC(goexit) - jmpdeferPC = funcPC(jmpdefer) - mcallPC = funcPC(mcall) - morestackPC = funcPC(morestack) - mstartPC = funcPC(mstart) - newprocPC = funcPC(newproc) - newstackPC = funcPC(newstack) - rt0_goPC = funcPC(rt0_go) - sigpanicPC = funcPC(sigpanic) + // initialized in tracebackinit + deferprocPC uintptr + goexitPC uintptr + jmpdeferPC uintptr + mcallPC uintptr + morestackPC uintptr + mstartPC uintptr + newprocPC uintptr + rt0_goPC uintptr + sigpanicPC uintptr externalthreadhandlerp uintptr // initialized elsewhere ) +func tracebackinit() { + // Go variable initialization happens late during runtime startup. + // Instead of initializing the variables above in the declarations, + // schedinit calls this function so that the variables are + // initialized and available earlier in the startup sequence. + deferprocPC = funcPC(deferproc) + goexitPC = funcPC(goexit) + jmpdeferPC = funcPC(jmpdefer) + mcallPC = funcPC(mcall) + morestackPC = funcPC(morestack) + mstartPC = funcPC(mstart) + newprocPC = funcPC(newproc) + rt0_goPC = funcPC(rt0_go) + sigpanicPC = funcPC(sigpanic) +} + // Traceback over the deferred function calls. // Report them like calls that have been invoked but not started executing yet. func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) { @@ -81,6 +97,9 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns // collector (callback != nil). A little clunky to merge these, but avoids // duplicating the code and all its subtlety. func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, printall bool) int { + if goexitPC == 0 { + gothrow("gentraceback before goexitPC initialization") + } g := getg() gotraceback := gotraceback(nil) if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp. From 12308d5a0bb424ef3ee9a664c77192b48e3df84c Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 30 Sep 2014 19:34:33 +0400 Subject: [PATCH 243/430] runtime: fix throwsplit check Newstack runs on g0, g0->throwsplit is never set. LGTM=rsc R=rsc CC=golang-codereviews, khr https://golang.org/cl/147370043 --- src/runtime/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 2d23c717bd..8562b94076 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -695,7 +695,7 @@ runtime·newstack(void) runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g); runtime·throw("runtime: wrong goroutine in newstack"); } - if(g->throwsplit) + if(g->m->curg->throwsplit) runtime·throw("runtime: stack split at bad time"); // The goroutine must be executing in order to call newstack, From ac9218f5f06dabec3ef7682619dd98fe587d6c08 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 30 Sep 2014 08:51:02 -0700 Subject: [PATCH 244/430] runtime: fix scanning of gc work buffer GC types were not being generated for the garbage collector work buffer. The markfor object was being collected as a result. This broke amd64p32 and maybe plan9 builds. Why it didn't break every build I'm not sure... Fixes #8812 LGTM=0intro, rsc R=golang-codereviews, dave, khr, 0intro, rsc CC=golang-codereviews https://golang.org/cl/149260043 --- src/runtime/mgc0.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index c92fa1db73..9b9bc0ef13 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -140,7 +140,8 @@ static BitVector unrollglobgcprog(byte *prog, uintptr size); void runtime·bgsweep(void); static FuncVal bgsweepv = {runtime·bgsweep}; -struct { +typedef struct WorkData WorkData; +struct WorkData { uint64 full; // lock-free list of full blocks uint64 empty; // lock-free list of empty blocks byte pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait @@ -154,7 +155,8 @@ struct { // Copy of mheap.allspans for marker or sweeper. MSpan** spans; uint32 nspan; -} runtime·work; +}; +WorkData runtime·work; // scanblock scans a block of n bytes starting at pointer b for references // to other objects, scanning any it finds recursively until there are no @@ -1038,7 +1040,8 @@ runtime·MSpan_Sweep(MSpan *s, bool preserve) // State of background runtime·sweep. // Protected by runtime·gclock. -struct +typedef struct SweepData SweepData; +struct SweepData { G* g; bool parked; @@ -1047,7 +1050,8 @@ struct uint32 nbgsweep; uint32 npausesweep; -} runtime·sweep; +}; +SweepData runtime·sweep; // sweeps one span // returns number of pages returned to heap, or -1 if there is nothing to sweep From 9b2b0c8c1663330c64c6cec8feb413f4cf464348 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 30 Sep 2014 12:08:09 -0400 Subject: [PATCH 245/430] regexp/syntax: reject large repetitions created by nesting small ones Fixes #7609. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/150270043 --- src/regexp/syntax/parse.go | 34 +++++++++++++++++++++++++++++++++ src/regexp/syntax/parse_test.go | 13 +++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go index 08f8d307ae..3dc8ccf503 100644 --- a/src/regexp/syntax/parse.go +++ b/src/regexp/syntax/parse.go @@ -244,6 +244,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( if sub.Op >= opPseudo { return "", &Error{ErrMissingRepeatArgument, before[:len(before)-len(after)]} } + re := p.newRegexp(op) re.Min = min re.Max = max @@ -251,9 +252,42 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( re.Sub = re.Sub0[:1] re.Sub[0] = sub p.stack[n-1] = re + + if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { + return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} + } + return after, nil } +// repeatIsValid reports whether the repetition re is valid. +// Valid means that the combination of the top-level repetition +// and any inner repetitions does not exceed n copies of the +// innermost thing. +// This function rewalks the regexp tree and is called for every repetition, +// so we have to worry about inducing quadratic behavior in the parser. +// We avoid this by only calling repeatIsValid when min or max >= 2. +// In that case the depth of any >= 2 nesting can only get to 9 without +// triggering a parse error, so each subtree can only be rewalked 9 times. +func repeatIsValid(re *Regexp, n int) bool { + if re.Op == OpRepeat { + m := re.Max + if m < 0 { + m = re.Min + } + if m > n { + return false + } + n /= m + } + for _, sub := range re.Sub { + if !repeatIsValid(sub, n) { + return false + } + } + return true +} + // concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation. func (p *parser) concat() *Regexp { p.maybeConcat(-1, 0) diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go index f3089294c6..c4a1117ff8 100644 --- a/src/regexp/syntax/parse_test.go +++ b/src/regexp/syntax/parse_test.go @@ -200,6 +200,10 @@ var parseTests = []parseTest{ `cat{rep{2,2 lit{x}}alt{emp{}cc{0x30-0x39}}}`}, {`x{2}y|x{2}[0-9]y`, `cat{rep{2,2 lit{x}}alt{lit{y}cat{cc{0x30-0x39}lit{y}}}}`}, + + // Valid repetitions. + {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``}, + {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``}, } const testFlags = MatchNL | PerlX | UnicodeGroups @@ -262,6 +266,10 @@ func testParseDump(t *testing.T, tests []parseTest, flags Flags) { t.Errorf("Parse(%#q): %v", tt.Regexp, err) continue } + if tt.Dump == "" { + // It parsed. That's all we care about. + continue + } d := dump(re) if d != tt.Dump { t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump) @@ -470,6 +478,7 @@ var invalidRegexps = []string{ `(?i)[a-Z]`, `a{100000}`, `a{100000,}`, + "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", } var onlyPerl = []string{ @@ -527,6 +536,10 @@ func TestToStringEquivalentParse(t *testing.T) { t.Errorf("Parse(%#q): %v", tt.Regexp, err) continue } + if tt.Dump == "" { + // It parsed. That's all we care about. + continue + } d := dump(re) if d != tt.Dump { t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump) From 7de0c315f68035456c764f6edea393bc1581dc80 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 30 Sep 2014 12:08:22 -0400 Subject: [PATCH 246/430] CONTRIBUTORS: add Raul Silvera (Google CLA) Raul wrote the pprof code in CL 153750043. LGTM=bradfitz, r R=r, bradfitz CC=golang-codereviews https://golang.org/cl/146450043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 48465bea5c..2c7ac66a0a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -496,6 +496,7 @@ Preetam Jinka Quan Yong Zhai Raif S. Naffah Raph Levien +Raul Silvera Rémy Oudompheng Richard Crowley Richard Eric Gavaletz From c75f81f0edd73d5f7d6528cec795b49c5d205c0c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 30 Sep 2014 12:28:24 -0400 Subject: [PATCH 247/430] cmd/objdump: move armasm, x86asm into internal packages For Go 1.3 these external packages were collapsed into large single-file implementations stored in the cmd/objdump directory. For Go 1.4 we want pprof to be able to link against them too, so move them into cmd/internal, where they can be shared. The new files are copied from the repo in the file path (rsc.io/...). Those repos were code reviewed during development (mainly by crawshaw and minux), because we knew the main repo would use them. Update #8798 LGTM=bradfitz R=crawshaw, bradfitz CC=golang-codereviews https://golang.org/cl/153750044 --- src/cmd/internal/rsc.io/arm/armasm/Makefile | 2 + src/cmd/internal/rsc.io/arm/armasm/decode.go | 567 + .../internal/rsc.io/arm/armasm/decode_test.go | 69 + .../internal/rsc.io/arm/armasm/ext_test.go | 614 + src/cmd/internal/rsc.io/arm/armasm/gnu.go | 164 + src/cmd/internal/rsc.io/arm/armasm/inst.go | 438 + .../rsc.io/arm/armasm/objdump_test.go | 258 + .../rsc.io/arm/armasm/objdumpext_test.go | 260 + src/cmd/internal/rsc.io/arm/armasm/plan9x.go | 211 + src/cmd/internal/rsc.io/arm/armasm/tables.go | 9448 +++++++++++ .../rsc.io/arm/armasm/testdata/Makefile | 5 + .../rsc.io/arm/armasm/testdata/decode.txt | 306 + src/cmd/internal/rsc.io/x86/x86asm/Makefile | 3 + src/cmd/internal/rsc.io/x86/x86asm/decode.go | 1616 ++ .../internal/rsc.io/x86/x86asm/decode_test.go | 71 + .../internal/rsc.io/x86/x86asm/ext_test.go | 811 + src/cmd/internal/rsc.io/x86/x86asm/gnu.go | 926 ++ src/cmd/internal/rsc.io/x86/x86asm/inst.go | 641 + .../internal/rsc.io/x86/x86asm/inst_test.go | 20 + src/cmd/internal/rsc.io/x86/x86asm/intel.go | 518 + .../rsc.io/x86/x86asm/objdump_test.go | 383 + .../rsc.io/x86/x86asm/objdumpext_test.go | 314 + .../rsc.io/x86/x86asm/plan9ext_test.go | 120 + src/cmd/internal/rsc.io/x86/x86asm/plan9x.go | 346 + .../internal/rsc.io/x86/x86asm/plan9x_test.go | 54 + src/cmd/internal/rsc.io/x86/x86asm/tables.go | 9760 +++++++++++ .../rsc.io/x86/x86asm/testdata/Makefile | 12 + .../rsc.io/x86/x86asm/testdata/decode.txt | 6731 ++++++++ .../internal/rsc.io/x86/x86asm/xed_test.go | 211 + .../internal/rsc.io/x86/x86asm/xedext_test.go | 206 + src/cmd/objdump/armasm.go | 10821 ------------ src/cmd/objdump/main.go | 11 +- src/cmd/objdump/x86.go | 13800 ---------------- 33 files changed, 35092 insertions(+), 24625 deletions(-) create mode 100644 src/cmd/internal/rsc.io/arm/armasm/Makefile create mode 100644 src/cmd/internal/rsc.io/arm/armasm/decode.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/decode_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/ext_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/gnu.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/inst.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/objdump_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/plan9x.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/tables.go create mode 100644 src/cmd/internal/rsc.io/arm/armasm/testdata/Makefile create mode 100644 src/cmd/internal/rsc.io/arm/armasm/testdata/decode.txt create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/Makefile create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/decode.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/decode_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/ext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/gnu.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/inst.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/inst_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/intel.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/objdump_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/objdumpext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9ext_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9x.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/plan9x_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/tables.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/testdata/Makefile create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/testdata/decode.txt create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/xed_test.go create mode 100644 src/cmd/internal/rsc.io/x86/x86asm/xedext_test.go delete mode 100644 src/cmd/objdump/armasm.go delete mode 100644 src/cmd/objdump/x86.go diff --git a/src/cmd/internal/rsc.io/arm/armasm/Makefile b/src/cmd/internal/rsc.io/arm/armasm/Makefile new file mode 100644 index 0000000000..a3f57001f6 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/Makefile @@ -0,0 +1,2 @@ +tables.go: ../armmap/map.go ../arm.csv + go run ../armmap/map.go -fmt=decoder ../arm.csv >_tables.go && gofmt _tables.go >tables.go && rm _tables.go diff --git a/src/cmd/internal/rsc.io/arm/armasm/decode.go b/src/cmd/internal/rsc.io/arm/armasm/decode.go new file mode 100644 index 0000000000..6b4d73841b --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/decode.go @@ -0,0 +1,567 @@ +// 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 armasm + +import ( + "encoding/binary" + "fmt" +) + +// An instFormat describes the format of an instruction encoding. +// An instruction with 32-bit value x matches the format if x&mask == value +// and the condition matches. +// The condition matches if x>>28 == 0xF && value>>28==0xF +// or if x>>28 != 0xF and value>>28 == 0. +// If x matches the format, then the rest of the fields describe how to interpret x. +// The opBits describe bits that should be extracted from x and added to the opcode. +// For example opBits = 0x1234 means that the value +// (2 bits at offset 1) followed by (4 bits at offset 3) +// should be added to op. +// Finally the args describe how to decode the instruction arguments. +// args is stored as a fixed-size array; if there are fewer than len(args) arguments, +// args[i] == 0 marks the end of the argument list. +type instFormat struct { + mask uint32 + value uint32 + priority int8 + op Op + opBits uint64 + args instArgs +} + +type instArgs [4]instArg + +var ( + errMode = fmt.Errorf("unsupported execution mode") + errShort = fmt.Errorf("truncated instruction") + errUnknown = fmt.Errorf("unknown instruction") +) + +var decoderCover []bool + +// Decode decodes the leading bytes in src as a single instruction. +func Decode(src []byte, mode Mode) (inst Inst, err error) { + if mode != ModeARM { + return Inst{}, errMode + } + if len(src) < 4 { + return Inst{}, errShort + } + + if decoderCover == nil { + decoderCover = make([]bool, len(instFormats)) + } + + x := binary.LittleEndian.Uint32(src) + + // The instFormat table contains both conditional and unconditional instructions. + // Considering only the top 4 bits, the conditional instructions use mask=0, value=0, + // while the unconditional instructions use mask=f, value=f. + // Prepare a version of x with the condition cleared to 0 in conditional instructions + // and then assume mask=f during matching. + const condMask = 0xf0000000 + xNoCond := x + if x&condMask != condMask { + xNoCond &^= condMask + } + var priority int8 +Search: + for i := range instFormats { + f := &instFormats[i] + if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority { + continue + } + delta := uint32(0) + deltaShift := uint(0) + for opBits := f.opBits; opBits != 0; opBits >>= 16 { + n := uint(opBits & 0xFF) + off := uint((opBits >> 8) & 0xFF) + delta |= (x >> off) & (1<> 8) & (1<<4 - 1)) + case arg_R_12: + return Reg((x >> 12) & (1<<4 - 1)) + case arg_R_16: + return Reg((x >> 16) & (1<<4 - 1)) + + case arg_R_12_nzcv: + r := Reg((x >> 12) & (1<<4 - 1)) + if r == R15 { + return APSR_nzcv + } + return r + + case arg_R_16_WB: + mode := AddrLDM + if (x>>21)&1 != 0 { + mode = AddrLDM_WB + } + return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode} + + case arg_R_rotate: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1. + if typ == RotateRightExt { + return Reg(Rm) + } + return RegShift{Rm, typ, uint8(count)} + + case arg_R_shift_R: + Rm := Reg(x & (1<<4 - 1)) + Rs := Reg((x >> 8) & (1<<4 - 1)) + typ := Shift((x >> 5) & (1<<2 - 1)) + return RegShiftReg{Rm, typ, Rs} + + case arg_R_shift_imm: + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + if typ == ShiftLeft && count == 0 { + return Reg(Rm) + } + return RegShift{Rm, typ, uint8(count)} + + case arg_R1_0: + return Reg((x & (1<<4 - 1))) + case arg_R1_12: + return Reg(((x >> 12) & (1<<4 - 1))) + case arg_R2_0: + return Reg((x & (1<<4 - 1)) | 1) + case arg_R2_12: + return Reg(((x >> 12) & (1<<4 - 1)) | 1) + + case arg_SP: + return SP + + case arg_Sd_Dd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Dd_Sd: + return decodeArg(arg_Sd_Dd, x^(1<<8)) + + case arg_Sd: + v := (x >> 12) & (1<<4 - 1) + vx := (x >> 22) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Sm_Dm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sm: + v := (x >> 0) & (1<<4 - 1) + vx := (x >> 5) & 1 + return S0 + Reg(v<<1+vx) + + case arg_Dn_half: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)} + + case arg_Sn_Dn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + sz := (x >> 8) & 1 + if sz != 0 { + return D0 + Reg(vx<<4+v) + } else { + return S0 + Reg(v<<1+vx) + } + + case arg_Sn: + v := (x >> 16) & (1<<4 - 1) + vx := (x >> 7) & 1 + return S0 + Reg(v<<1+vx) + + case arg_const: + v := x & (1<<8 - 1) + rot := (x >> 8) & (1<<4 - 1) * 2 + if rot > 0 && v&3 == 0 { + // could rotate less + return ImmAlt{uint8(v), uint8(rot)} + } + if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v { + // could wrap around to rot==0. + return ImmAlt{uint8(v), uint8(rot)} + } + return Imm(v>>rot | v<<(32-rot)) + + case arg_endian: + return Endian((x >> 9) & 1) + + case arg_fbits: + return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1)) + + case arg_fp_0: + return Imm(0) + + case arg_imm24: + return Imm(x & (1<<24 - 1)) + + case arg_imm5: + return Imm((x >> 7) & (1<<5 - 1)) + + case arg_imm5_32: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + x = 32 + } + return Imm(x) + + case arg_imm5_nz: + x = (x >> 7) & (1<<5 - 1) + if x == 0 { + return nil + } + return Imm(x) + + case arg_imm_4at16_12at0: + return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1)) + + case arg_imm_12at8_4at0: + return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1)) + + case arg_imm_vfp: + x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1) + return Imm(x) + + case arg_label24: + imm := (x & (1<<24 - 1)) << 2 + return PCRel(int32(imm<<6) >> 6) + + case arg_label24H: + h := (x >> 24) & 1 + imm := (x&(1<<24-1))<<2 | h<<1 + return PCRel(int32(imm<<6) >> 6) + + case arg_label_m_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)} + + case arg_label_p_12: + d := int32(x & (1<<12 - 1)) + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_12: + d := int32(x & (1<<12 - 1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)} + + case arg_label_pm_4_4: + d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + u := (x >> 23) & 1 + if u == 0 { + d = -d + } + return PCRel(d) + + case arg_lsb_width: + lsb := (x >> 7) & (1<<5 - 1) + msb := (x >> 16) & (1<<5 - 1) + if msb < lsb || msb >= 32 { + return nil + } + return Imm(msb + 1 - lsb) + + case arg_mem_R: + Rn := Reg((x >> 16) & (1<<4 - 1)) + return Mem{Base: Rn, Mode: AddrOffset} + + case arg_mem_R_pm_R_postindex: + // Treat [],+/- like [,+/-{,}]{!} + // by forcing shift bits to <<0 and P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21)) + + case arg_mem_R_pm_R_W: + // Treat [,+/-]{!} like [,+/-{,}]{!} + // by forcing shift bits to <<0. + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5)) + + case arg_mem_R_pm_R_shift_imm_offset: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_R_shift_imm_postindex: + // Treat [],+/-{,} like [,+/-{,}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_R_shift_imm_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + Rm := Reg(x & (1<<4 - 1)) + typ, count := decodeShift(x) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count} + + case arg_mem_R_pm_imm12_offset: + // Treat [,#+/-] like [{,#+/-}]{!} + // by forcing P=1, W=0 (index=false, wback=false). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24) + + case arg_mem_R_pm_imm12_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm12_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x & (1<<12 - 1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8_postindex: + // Treat [],#+/- like [{,#+/-}]{!} + // by forcing P=0, W=0 (postindex=true). + return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21)) + + case arg_mem_R_pm_imm8_W: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + w := (x >> 21) & 1 + p := (x >> 24) & 1 + if p == 0 && w == 1 { + return nil + } + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1)) + mode := AddrMode(uint8(p<<1) | uint8(w^1)) + return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm} + + case arg_mem_R_pm_imm8at0_offset: + Rn := Reg((x >> 16) & (1<<4 - 1)) + u := (x >> 23) & 1 + sign := int8(+1) + if u == 0 { + sign = -1 + } + imm := int16(x&(1<<8-1)) << 2 + return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm} + + case arg_option: + return Imm(x & (1<<4 - 1)) + + case arg_registers: + return RegList(x & (1<<16 - 1)) + + case arg_registers2: + x &= 1<<16 - 1 + n := 0 + for i := 0; i < 16; i++ { + if x>>uint(i)&1 != 0 { + n++ + } + } + if n < 2 { + return nil + } + return RegList(x) + + case arg_registers1: + Rt := (x >> 12) & (1<<4 - 1) + return RegList(1 << Rt) + + case arg_satimm4: + return Imm((x >> 16) & (1<<4 - 1)) + + case arg_satimm5: + return Imm((x >> 16) & (1<<5 - 1)) + + case arg_satimm4m1: + return Imm((x>>16)&(1<<4-1) + 1) + + case arg_satimm5m1: + return Imm((x>>16)&(1<<5-1) + 1) + + case arg_widthm1: + return Imm((x>>16)&(1<<5-1) + 1) + + } +} + +// decodeShift decodes the shift-by-immediate encoded in x. +func decodeShift(x uint32) (Shift, uint8) { + count := (x >> 7) & (1<<5 - 1) + typ := Shift((x >> 5) & (1<<2 - 1)) + switch typ { + case ShiftRight, ShiftRightSigned: + if count == 0 { + count = 32 + } + case RotateRight: + if count == 0 { + typ = RotateRightExt + count = 1 + } + } + return typ, uint8(count) +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/decode_test.go b/src/cmd/internal/rsc.io/arm/armasm/decode_test.go new file mode 100644 index 0000000000..25a345a882 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/decode_test.go @@ -0,0 +1,69 @@ +// 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 armasm + +import ( + "encoding/hex" + "io/ioutil" + "strconv" + "strings" + "testing" +) + +func TestDecode(t *testing.T) { + data, err := ioutil.ReadFile("testdata/decode.txt") + if err != nil { + t.Fatal(err) + } + all := string(data) + for strings.Contains(all, "\t\t") { + all = strings.Replace(all, "\t\t", "\t", -1) + } + for _, line := range strings.Split(all, "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.SplitN(line, "\t", 4) + i := strings.Index(f[0], "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f[0]) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f[0]) + } + size := i / 2 + code, err := hex.DecodeString(f[0][:i] + f[0][i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f[0], err) + continue + } + mode, err := strconv.Atoi(f[1]) + if err != nil { + t.Errorf("invalid mode %q in: %s", f[1], line) + continue + } + syntax, asm := f[2], f[3] + inst, err := Decode(code, Mode(mode)) + var out string + if err != nil { + out = "error: " + err.Error() + } else { + switch syntax { + case "gnu": + out = GNUSyntax(inst) + case "plan9": + out = Plan9Syntax(inst, 0, nil, nil) + default: + t.Errorf("unknown syntax %q", syntax) + continue + } + } + if out != asm || inst.Len != size { + t.Errorf("Decode(%s) [%s] = %s, %d, want %s, %d", f[0], syntax, out, inst.Len, asm, size) + } + } +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go new file mode 100644 index 0000000000..b0bd855970 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go @@ -0,0 +1,614 @@ +// 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. + +// Support for testing against external disassembler program. +// Copied and simplified from rsc.io/x86/x86asm/ext_test.go. + +package armasm + +import ( + "bufio" + "bytes" + "encoding/hex" + "flag" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "os/exec" + "regexp" + "runtime" + "strings" + "testing" + "time" +) + +var ( + printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths") + dumpTest = flag.Bool("dump", false, "dump all encodings") + mismatch = flag.Bool("mismatch", false, "log allowed mismatches") + longTest = flag.Bool("long", false, "long test") + keep = flag.Bool("keep", false, "keep object files around") + debug = false +) + +// A ExtInst represents a single decoded instruction parsed +// from an external disassembler's output. +type ExtInst struct { + addr uint32 + enc [4]byte + nenc int + text string +} + +func (r ExtInst) String() string { + return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text) +} + +// An ExtDis is a connection between an external disassembler and a test. +type ExtDis struct { + Arch Mode + Dec chan ExtInst + File *os.File + Size int + KeepFile bool + Cmd *exec.Cmd +} + +// Run runs the given command - the external disassembler - and returns +// a buffered reader of its standard output. +func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) { + if *keep { + log.Printf("%s\n", strings.Join(cmd, " ")) + } + ext.Cmd = exec.Command(cmd[0], cmd[1:]...) + out, err := ext.Cmd.StdoutPipe() + if err != nil { + return nil, fmt.Errorf("stdoutpipe: %v", err) + } + if err := ext.Cmd.Start(); err != nil { + return nil, fmt.Errorf("exec: %v", err) + } + + b := bufio.NewReaderSize(out, 1<<20) + return b, nil +} + +// Wait waits for the command started with Run to exit. +func (ext *ExtDis) Wait() error { + return ext.Cmd.Wait() +} + +// testExtDis tests a set of byte sequences against an external disassembler. +// The disassembler is expected to produce the given syntax and be run +// in the given architecture mode (16, 32, or 64-bit). +// The extdis function must start the external disassembler +// and then parse its output, sending the parsed instructions on ext.Dec. +// The generate function calls its argument f once for each byte sequence +// to be tested. The generate function itself will be called twice, and it must +// make the same sequence of calls to f each time. +// When a disassembly does not match the internal decoding, +// allowedMismatch determines whether this mismatch should be +// allowed, or else considered an error. +func testExtDis( + t *testing.T, + syntax string, + arch Mode, + extdis func(ext *ExtDis) error, + generate func(f func([]byte)), + allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool, +) { + start := time.Now() + ext := &ExtDis{ + Dec: make(chan ExtInst), + Arch: arch, + } + errc := make(chan error) + + // First pass: write instructions to input file for external disassembler. + file, f, size, err := writeInst(generate) + if err != nil { + t.Fatal(err) + } + ext.Size = size + ext.File = f + defer func() { + f.Close() + if !*keep { + os.Remove(file) + } + }() + + // Second pass: compare disassembly against our decodings. + var ( + totalTests = 0 + totalSkips = 0 + totalErrors = 0 + + errors = make([]string, 0, 100) // sampled errors, at most cap + ) + go func() { + errc <- extdis(ext) + }() + generate(func(enc []byte) { + dec, ok := <-ext.Dec + if !ok { + t.Errorf("decoding stream ended early") + return + } + inst, text := disasm(syntax, arch, pad(enc)) + totalTests++ + if *dumpTest { + fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc) + } + if text != dec.text || inst.Len != dec.nenc { + suffix := "" + if allowedMismatch(text, size, &inst, dec) { + totalSkips++ + if !*mismatch { + return + } + suffix += " (allowed mismatch)" + } + totalErrors++ + if len(errors) >= cap(errors) { + j := rand.Intn(totalErrors) + if j >= cap(errors) { + return + } + errors = append(errors[:j], errors[j+1:]...) + } + errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix)) + } + }) + + if *mismatch { + totalErrors -= totalSkips + } + + for _, b := range errors { + t.Log(b) + } + + if totalErrors > 0 { + t.Fail() + } + t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds()) + + if err := <-errc; err != nil { + t.Fatal("external disassembler: %v", err) + } + +} + +const start = 0x8000 // start address of text + +// writeInst writes the generated byte sequences to a new file +// starting at offset start. That file is intended to be the input to +// the external disassembler. +func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) { + f, err = ioutil.TempFile("", "armasm") + if err != nil { + return + } + + file = f.Name() + + f.Seek(start, 0) + w := bufio.NewWriter(f) + defer w.Flush() + size = 0 + generate(func(x []byte) { + if len(x) > 4 { + x = x[:4] + } + if debug { + fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):]) + } + w.Write(x) + w.Write(zeros[len(x):]) + size += len(zeros) + }) + return file, f, size, nil +} + +var zeros = []byte{0, 0, 0, 0} + +// pad pads the code sequenc with pops. +func pad(enc []byte) []byte { + if len(enc) < 4 { + enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...) + } + return enc +} + +// disasm returns the decoded instruction and text +// for the given source bytes, using the given syntax and mode. +func disasm(syntax string, mode Mode, src []byte) (inst Inst, text string) { + // If printTests is set, we record the coverage value + // before and after, and we write out the inputs for which + // coverage went up, in the format expected in testdata/decode.text. + // This produces a fairly small set of test cases that exercise nearly + // all the code. + var cover float64 + if *printTests { + cover -= coverage() + } + + inst, err := Decode(src, mode) + if err != nil { + text = "error: " + err.Error() + } else { + text = inst.String() + switch syntax { + //case "arm": + // text = ARMSyntax(inst) + case "gnu": + text = GNUSyntax(inst) + //case "plan9": + // text = Plan9Syntax(inst, 0, nil) + default: + text = "error: unknown syntax " + syntax + } + } + + if *printTests { + cover += coverage() + if cover > 0 { + max := len(src) + if max > 4 && inst.Len <= 4 { + max = 4 + } + fmt.Printf("%x|%x\t%d\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], mode, syntax, text) + } + } + + return +} + +// coverage returns a floating point number denoting the +// test coverage until now. The number increases when new code paths are exercised, +// both in the Go program and in the decoder byte code. +func coverage() float64 { + /* + testing.Coverage is not in the main distribution. + The implementation, which must go in package testing, is: + + // Coverage reports the current code coverage as a fraction in the range [0, 1]. + func Coverage() float64 { + var n, d int64 + for _, counters := range cover.Counters { + for _, c := range counters { + if c > 0 { + n++ + } + d++ + } + } + if d == 0 { + return 0 + } + return float64(n) / float64(d) + } + */ + + var f float64 + f += testing.Coverage() + f += decodeCoverage() + return f +} + +func decodeCoverage() float64 { + n := 0 + for _, t := range decoderCover { + if t { + n++ + } + } + return float64(1+n) / float64(1+len(decoderCover)) +} + +// Helpers for writing disassembler output parsers. + +// hasPrefix reports whether any of the space-separated words in the text s +// begins with any of the given prefixes. +func hasPrefix(s string, prefixes ...string) bool { + for _, prefix := range prefixes { + for s := s; s != ""; { + if strings.HasPrefix(s, prefix) { + return true + } + i := strings.Index(s, " ") + if i < 0 { + break + } + s = s[i+1:] + } + } + return false +} + +// contains reports whether the text s contains any of the given substrings. +func contains(s string, substrings ...string) bool { + for _, sub := range substrings { + if strings.Contains(s, sub) { + return true + } + } + return false +} + +// isHex reports whether b is a hexadecimal character (0-9A-Fa-f). +func isHex(b byte) bool { return b == '0' || unhex[b] > 0 } + +// parseHex parses the hexadecimal byte dump in hex, +// appending the parsed bytes to raw and returning the updated slice. +// The returned bool signals whether any invalid hex was found. +// Spaces and tabs between bytes are okay but any other non-hex is not. +func parseHex(hex []byte, raw []byte) ([]byte, bool) { + hex = trimSpace(hex) + for j := 0; j < len(hex); { + for hex[j] == ' ' || hex[j] == '\t' { + j++ + } + if j >= len(hex) { + break + } + if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) { + return nil, false + } + raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]]) + j += 2 + } + return raw, true +} + +var unhex = [256]byte{ + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + 'A': 10, + 'B': 11, + 'C': 12, + 'D': 13, + 'E': 14, + 'F': 15, + 'a': 10, + 'b': 11, + 'c': 12, + 'd': 13, + 'e': 14, + 'f': 15, +} + +// index is like bytes.Index(s, []byte(t)) but avoids the allocation. +func index(s []byte, t string) int { + i := 0 + for { + j := bytes.IndexByte(s[i:], t[0]) + if j < 0 { + return -1 + } + i = i + j + if i+len(t) > len(s) { + return -1 + } + for k := 1; k < len(t); k++ { + if s[i+k] != t[k] { + goto nomatch + } + } + return i + nomatch: + i++ + } +} + +// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s. +// If s must be rewritten, it is rewritten in place. +func fixSpace(s []byte) []byte { + s = trimSpace(s) + for i := 0; i < len(s); i++ { + if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' { + goto Fix + } + } + return s + +Fix: + b := s + w := 0 + for i := 0; i < len(s); i++ { + c := s[i] + if c == '\t' || c == '\n' { + c = ' ' + } + if c == ' ' && w > 0 && b[w-1] == ' ' { + continue + } + b[w] = c + w++ + } + if w > 0 && b[w-1] == ' ' { + w-- + } + return b[:w] +} + +// trimSpace trims leading and trailing space from s, returning a subslice of s. +func trimSpace(s []byte) []byte { + j := len(s) + for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') { + j-- + } + i := 0 + for i < j && (s[i] == ' ' || s[i] == '\t') { + i++ + } + return s[i:j] +} + +// pcrel matches instructions using relative addressing mode. +var ( + pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bl)x?(?:eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le)?) 0x([0-9a-f]+)$`) +) + +// Generators. +// +// The test cases are described as functions that invoke a callback repeatedly, +// with a new input sequence each time. These helpers make writing those +// a little easier. + +// condCases generates conditional instructions. +func condCases(t *testing.T) func(func([]byte)) { + return func(try func([]byte)) { + // All the strides are relatively prime to 2 and therefore to 2²⁸, + // so we will not repeat any instructions until we have tried all 2²⁸. + // Using a stride other than 1 is meant to visit the instructions in a + // pseudorandom order, which gives better variety in the set of + // test cases chosen by -printtests. + stride := uint32(10007) + n := 1 << 28 / 7 + if testing.Short() { + stride = 100003 + n = 1 << 28 / 1001 + } else if *longTest { + stride = 200000033 + n = 1 << 28 + } + x := uint32(0) + for i := 0; i < n; i++ { + enc := (x%15)<<28 | x&(1<<28-1) + try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)}) + x += stride + } + } +} + +// uncondCases generates unconditional instructions. +func uncondCases(t *testing.T) func(func([]byte)) { + return func(try func([]byte)) { + condCases(t)(func(enc []byte) { + enc[3] |= 0xF0 + try(enc) + }) + } +} + +func countBits(x uint32) int { + n := 0 + for ; x != 0; x >>= 1 { + n += int(x & 1) + } + return n +} + +func expandBits(x, m uint32) uint32 { + var out uint32 + for i := uint(0); i < 32; i++ { + out >>= 1 + if m&1 != 0 { + out |= (x & 1) << 31 + x >>= 1 + } + m >>= 1 + } + return out +} + +func tryCondMask(mask, val uint32, try func([]byte)) { + n := countBits(^mask) + bits := uint32(0) + for i := 0; i < 1<> 8), byte(x >> 16), byte(x >> 24)}) + } +} + +// vfpCases generates VFP instructions. +func vfpCases(t *testing.T) func(func([]byte)) { + const ( + vfpmask uint32 = 0xFF00FE10 + vfp uint32 = 0x0E009A00 + ) + return func(try func([]byte)) { + tryCondMask(0xff00fe10, 0x0e009a00, try) // standard VFP instruction space + tryCondMask(0xffc00f7f, 0x0e000b10, try) // VFP MOV core reg to/from float64 half + tryCondMask(0xffe00f7f, 0x0e000a10, try) // VFP MOV core reg to/from float32 + tryCondMask(0xffef0fff, 0x0ee10a10, try) // VFP MOV core reg to/from cond codes + } +} + +// hexCases generates the cases written in hexadecimal in the encoded string. +// Spaces in 'encoded' separate entire test cases, not individual bytes. +func hexCases(t *testing.T, encoded string) func(func([]byte)) { + return func(try func([]byte)) { + for _, x := range strings.Fields(encoded) { + src, err := hex.DecodeString(x) + if err != nil { + t.Errorf("parsing %q: %v", x, err) + } + try(src) + } + } +} + +// testdataCases generates the test cases recorded in testdata/decode.txt. +// It only uses the inputs; it ignores the answers recorded in that file. +func testdataCases(t *testing.T) func(func([]byte)) { + var codes [][]byte + data, err := ioutil.ReadFile("testdata/decode.txt") + if err != nil { + t.Fatal(err) + } + for _, line := range strings.Split(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.Fields(line)[0] + i := strings.Index(f, "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f) + } + code, err := hex.DecodeString(f[:i] + f[i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f, err) + continue + } + codes = append(codes, code) + } + + return func(try func([]byte)) { + for _, code := range codes { + try(code) + } + } +} + +func caller(skip int) string { + pc, _, _, _ := runtime.Caller(skip) + f := runtime.FuncForPC(pc) + name := "?" + if f != nil { + name = f.Name() + if i := strings.LastIndex(name, "."); i >= 0 { + name = name[i+1:] + } + } + return name +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/gnu.go b/src/cmd/internal/rsc.io/arm/armasm/gnu.go new file mode 100644 index 0000000000..1a97a5a844 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/gnu.go @@ -0,0 +1,164 @@ +// 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 armasm + +import ( + "bytes" + "fmt" + "strings" +) + +var saveDot = strings.NewReplacer( + ".F16", "_dot_F16", + ".F32", "_dot_F32", + ".F64", "_dot_F64", + ".S32", "_dot_S32", + ".U32", "_dot_U32", + ".FXS", "_dot_S", + ".FXU", "_dot_U", + ".32", "_dot_32", +) + +// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. +// This form typically matches the syntax defined in the ARM Reference Manual. +func GNUSyntax(inst Inst) string { + var buf bytes.Buffer + op := inst.Op.String() + op = saveDot.Replace(op) + op = strings.Replace(op, ".", "", -1) + op = strings.Replace(op, "_dot_", ".", -1) + op = strings.ToLower(op) + buf.WriteString(op) + sep := " " + for i, arg := range inst.Args { + if arg == nil { + break + } + text := gnuArg(&inst, i, arg) + if text == "" { + continue + } + buf.WriteString(sep) + sep = ", " + buf.WriteString(text) + } + return buf.String() +} + +func gnuArg(inst *Inst, argIndex int, arg Arg) string { + switch inst.Op &^ 15 { + case LDRD_EQ, LDREXD_EQ, STRD_EQ: + if argIndex == 1 { + // second argument in consecutive pair not printed + return "" + } + case STREXD_EQ: + if argIndex == 2 { + // second argument in consecutive pair not printed + return "" + } + } + + switch arg := arg.(type) { + case Imm: + switch inst.Op &^ 15 { + case BKPT_EQ: + return fmt.Sprintf("%#04x", uint32(arg)) + case SVC_EQ: + return fmt.Sprintf("%#08x", uint32(arg)) + } + return fmt.Sprintf("#%d", int32(arg)) + + case ImmAlt: + return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot) + + case Mem: + R := gnuArg(inst, -1, arg.Base) + X := "" + if arg.Sign != 0 { + X = "" + if arg.Sign < 0 { + X = "-" + } + X += gnuArg(inst, -1, arg.Index) + if arg.Shift == ShiftLeft && arg.Count == 0 { + // nothing + } else if arg.Shift == RotateRightExt { + X += ", rrx" + } else { + X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count) + } + } else { + X = fmt.Sprintf("#%d", arg.Offset) + } + + switch arg.Mode { + case AddrOffset: + if X == "#0" { + return fmt.Sprintf("[%s]", R) + } + return fmt.Sprintf("[%s, %s]", R, X) + case AddrPreIndex: + return fmt.Sprintf("[%s, %s]!", R, X) + case AddrPostIndex: + return fmt.Sprintf("[%s], %s", R, X) + case AddrLDM: + if X == "#0" { + return R + } + case AddrLDM_WB: + if X == "#0" { + return R + "!" + } + } + return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X) + + case PCRel: + return fmt.Sprintf(".%+#x", int32(arg)+4) + + case Reg: + switch inst.Op &^ 15 { + case LDREX_EQ: + if argIndex == 0 { + return fmt.Sprintf("r%d", int32(arg)) + } + } + switch arg { + case R10: + return "sl" + case R11: + return "fp" + case R12: + return "ip" + } + + case RegList: + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if arg&(1<= Op(len(opstr)) || opstr[op] == "" { + return fmt.Sprintf("Op(%d)", int(op)) + } + return opstr[op] +} + +// An Inst is a single instruction. +type Inst struct { + Op Op // Opcode mnemonic + Enc uint32 // Raw encoding bits. + Len int // Length of encoding in bytes. + Args Args // Instruction arguments, in ARM manual order. +} + +func (i Inst) String() string { + var buf bytes.Buffer + buf.WriteString(i.Op.String()) + for j, arg := range i.Args { + if arg == nil { + break + } + if j == 0 { + buf.WriteString(" ") + } else { + buf.WriteString(", ") + } + buf.WriteString(arg.String()) + } + return buf.String() +} + +// An Args holds the instruction arguments. +// If an instruction has fewer than 4 arguments, +// the final elements in the array are nil. +type Args [4]Arg + +// An Arg is a single instruction argument, one of these types: +// Endian, Imm, Mem, PCRel, Reg, RegList, RegShift, RegShiftReg. +type Arg interface { + IsArg() + String() string +} + +type Float32Imm float32 + +func (Float32Imm) IsArg() {} + +func (f Float32Imm) String() string { + return fmt.Sprintf("#%v", float32(f)) +} + +type Float64Imm float32 + +func (Float64Imm) IsArg() {} + +func (f Float64Imm) String() string { + return fmt.Sprintf("#%v", float64(f)) +} + +// An Imm is an integer constant. +type Imm uint32 + +func (Imm) IsArg() {} + +func (i Imm) String() string { + return fmt.Sprintf("#%#x", uint32(i)) +} + +// A ImmAlt is an alternate encoding of an integer constant. +type ImmAlt struct { + Val uint8 + Rot uint8 +} + +func (ImmAlt) IsArg() {} + +func (i ImmAlt) Imm() Imm { + v := uint32(i.Val) + r := uint(i.Rot) + return Imm(v>>r | v<<(32-r)) +} + +func (i ImmAlt) String() string { + return fmt.Sprintf("#%#x, %d", i.Val, i.Rot) +} + +// A Label is a text (code) address. +type Label uint32 + +func (Label) IsArg() {} + +func (i Label) String() string { + return fmt.Sprintf("%#x", uint32(i)) +} + +// A Reg is a single register. +// The zero value denotes R0, not the absence of a register. +type Reg uint8 + +const ( + R0 Reg = iota + R1 + R2 + R3 + R4 + R5 + R6 + R7 + R8 + R9 + R10 + R11 + R12 + R13 + R14 + R15 + + S0 + S1 + S2 + S3 + S4 + S5 + S6 + S7 + S8 + S9 + S10 + S11 + S12 + S13 + S14 + S15 + S16 + S17 + S18 + S19 + S20 + S21 + S22 + S23 + S24 + S25 + S26 + S27 + S28 + S29 + S30 + S31 + + D0 + D1 + D2 + D3 + D4 + D5 + D6 + D7 + D8 + D9 + D10 + D11 + D12 + D13 + D14 + D15 + D16 + D17 + D18 + D19 + D20 + D21 + D22 + D23 + D24 + D25 + D26 + D27 + D28 + D29 + D30 + D31 + + APSR + APSR_nzcv + FPSCR + + SP = R13 + LR = R14 + PC = R15 +) + +func (Reg) IsArg() {} + +func (r Reg) String() string { + switch r { + case APSR: + return "APSR" + case APSR_nzcv: + return "APSR_nzcv" + case FPSCR: + return "FPSCR" + case SP: + return "SP" + case PC: + return "PC" + case LR: + return "LR" + } + if R0 <= r && r <= R15 { + return fmt.Sprintf("R%d", int(r-R0)) + } + if S0 <= r && r <= S31 { + return fmt.Sprintf("S%d", int(r-S0)) + } + if D0 <= r && r <= D31 { + return fmt.Sprintf("D%d", int(r-D0)) + } + return fmt.Sprintf("Reg(%d)", int(r)) +} + +// A RegX represents a fraction of a multi-value register. +// The Index field specifies the index number, +// but the size of the fraction is not specified. +// It must be inferred from the instruction and the register type. +// For example, in a VMOV instruction, RegX{D5, 1} represents +// the top 32 bits of the 64-bit D5 register. +type RegX struct { + Reg Reg + Index int +} + +func (RegX) IsArg() {} + +func (r RegX) String() string { + return fmt.Sprintf("%s[%d]", r.Reg, r.Index) +} + +// A RegList is a register list. +// Bits at indexes x = 0 through 15 indicate whether the corresponding Rx register is in the list. +type RegList uint16 + +func (RegList) IsArg() {} + +func (r RegList) String() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "{") + sep := "" + for i := 0; i < 16; i++ { + if r&(1<= 4 { + raw := binary.LittleEndian.Uint32(dec.enc[:4]) + + // word 21FFF0B5. + // the manual is clear that this is pre-indexed mode (with !) but libopcodes generates post-index (without !). + if raw&0x01200000 == 0x01200000 && strings.Replace(text, "!", "", -1) == dec.text { + return true + } + + // word C100543E: libopcodes says tst, but no evidence for that. + if strings.HasPrefix(dec.text, "tst") && raw&0x0ff00000 != 0x03100000 && raw&0x0ff00000 != 0x01100000 { + return true + } + + // word C3203CE8: libopcodes says teq, but no evidence for that. + if strings.HasPrefix(dec.text, "teq") && raw&0x0ff00000 != 0x03300000 && raw&0x0ff00000 != 0x01300000 { + return true + } + + // word D14C552E: libopcodes says cmp but no evidence for that. + if strings.HasPrefix(dec.text, "cmp") && raw&0x0ff00000 != 0x03500000 && raw&0x0ff00000 != 0x01500000 { + return true + } + + // word 2166AA4A: libopcodes says cmn but no evidence for that. + if strings.HasPrefix(dec.text, "cmn") && raw&0x0ff00000 != 0x03700000 && raw&0x0ff00000 != 0x01700000 { + return true + } + + // word E70AEEEF: libopcodes says str but no evidence for that. + if strings.HasPrefix(dec.text, "str") && len(dec.text) >= 5 && (dec.text[3] == ' ' || dec.text[5] == ' ') && raw&0x0e500018 != 0x06000000 && raw&0x0e500000 != 0x0400000 { + return true + } + + // word B0AF48F4: libopcodes says strd but P=0,W=1 which is unpredictable. + if hasPrefix(dec.text, "ldr", "str") && raw&0x01200000 == 0x00200000 { + return true + } + + // word B6CC1C76: libopcodes inexplicably says 'uxtab16lt r1, ip, r6, ROR #24' instead of 'uxtab16lt r1, ip, r6, ror #24' + if strings.ToLower(dec.text) == text { + return true + } + + // word F410FDA1: libopcodes says PLDW but the manual is clear that PLDW is F5/F7, not F4. + // word F7D0FB17: libopcodes says PLDW but the manual is clear that PLDW has 0x10 clear + if hasPrefix(dec.text, "pld") && raw&0xfd000010 != 0xf5000000 { + return true + } + + // word F650FE14: libopcodes says PLI but the manual is clear that PLI has 0x10 clear + if hasPrefix(dec.text, "pli") && raw&0xff000010 != 0xf6000000 { + return true + } + } + + return false +} + +// Instructions known to libopcodes (or xed) but not to us. +// Most of these are floating point coprocessor instructions. +var unsupported = strings.Fields(` + abs + acs + adf + aes + asn + atn + cdp + cf + cmf + cnf + cos + cps + crc32 + dvf + eret + exp + fadd + fcmp + fcpy + fcvt + fdiv + fdv + fix + fld + flt + fmac + fmd + fml + fmr + fms + fmul + fmx + fneg + fnm + frd + fsit + fsq + fst + fsu + fto + fui + hlt + hvc + lda + ldc + ldf + lfm + lgn + log + mar + mcr + mcrr + mia + mnf + mra + mrc + mrrc + mrs + msr + msr + muf + mvf + nrm + pol + pow + rdf + rfc + rfe + rfs + rmf + rnd + rpw + rsf + sdiv + sev + sfm + sha1 + sha256 + sin + smc + sqt + srs + stc + stf + stl + suf + tan + udf + udiv + urd + vfma + vfms + vfnma + vfnms + vrint + wfc + wfs +`) diff --git a/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go b/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go new file mode 100644 index 0000000000..d88c67fc05 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/objdumpext_test.go @@ -0,0 +1,260 @@ +// 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. + +// Copied and simplified from rsc.io/x86/x86asm/objdumpext_test.go. + +package armasm + +import ( + "bytes" + "debug/elf" + "encoding/binary" + "fmt" + "io" + "log" + "os" + "strconv" + "strings" + "testing" +) + +const objdumpPath = "/usr/local/bin/arm-linux-elf-objdump" + +func testObjdumpARM(t *testing.T, generate func(func([]byte))) { + testObjdumpArch(t, generate, ModeARM) +} + +func testObjdumpArch(t *testing.T, generate func(func([]byte)), arch Mode) { + if testing.Short() { + t.Skip("skipping objdump test in short mode") + } + + if _, err := os.Stat(objdumpPath); err != nil { + t.Fatal(err) + } + + testExtDis(t, "gnu", arch, objdump, generate, allowedMismatchObjdump) +} + +func objdump(ext *ExtDis) error { + // File already written with instructions; add ELF header. + if ext.Arch == ModeARM { + if err := writeELF32(ext.File, ext.Size); err != nil { + return err + } + } else { + panic("unknown arch") + } + + b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name()) + if err != nil { + return err + } + + var ( + nmatch int + reading bool + next uint32 = start + addr uint32 + encbuf [4]byte + enc []byte + text string + ) + flush := func() { + if addr == next { + if m := pcrel.FindStringSubmatch(text); m != nil { + targ, _ := strconv.ParseUint(m[2], 16, 64) + text = fmt.Sprintf("%s .%+#x", m[1], int32(uint32(targ)-addr-uint32(len(enc)))) + } + if strings.HasPrefix(text, "stmia") { + text = "stm" + text[5:] + } + if strings.HasPrefix(text, "stmfd") { + text = "stmdb" + text[5:] + } + if strings.HasPrefix(text, "ldmfd") { + text = "ldm" + text[5:] + } + text = strings.Replace(text, "#0.0", "#0", -1) + if text == "undefined" && len(enc) == 4 { + text = "error: unknown instruction" + enc = nil + } + if len(enc) == 4 { + // prints as word but we want to record bytes + enc[0], enc[3] = enc[3], enc[0] + enc[1], enc[2] = enc[2], enc[1] + } + ext.Dec <- ExtInst{addr, encbuf, len(enc), text} + encbuf = [4]byte{} + enc = nil + next += 4 + } + } + var textangle = []byte("<.text>:") + for { + line, err := b.ReadSlice('\n') + if err != nil { + if err == io.EOF { + break + } + return fmt.Errorf("reading objdump output: %v", err) + } + if bytes.Contains(line, textangle) { + reading = true + continue + } + if !reading { + continue + } + if debug { + os.Stdout.Write(line) + } + if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil { + enc = enc1 + continue + } + flush() + nmatch++ + addr, enc, text = parseLine(line, encbuf[:0]) + if addr > next { + return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line) + } + } + flush() + if next != start+uint32(ext.Size) { + return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size) + } + if err := ext.Wait(); err != nil { + return fmt.Errorf("exec: %v", err) + } + + return nil +} + +var ( + undefined = []byte("") + unpredictable = []byte("") + illegalShifter = []byte("") +) + +func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) { + oline := line + i := index(line, ":\t") + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32) + if err != nil { + log.Fatalf("cannot parse disassembly: %q", oline) + } + addr = uint32(x) + line = line[i+2:] + i = bytes.IndexByte(line, '\t') + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + enc, ok := parseHex(line[:i], encstart) + if !ok { + log.Fatalf("cannot parse disassembly: %q", oline) + } + line = trimSpace(line[i:]) + if bytes.Contains(line, undefined) { + text = "undefined" + return + } + if bytes.Contains(line, illegalShifter) { + text = "undefined" + return + } + if false && bytes.Contains(line, unpredictable) { + text = "unpredictable" + return + } + if i := bytes.IndexByte(line, ';'); i >= 0 { + line = trimSpace(line[:i]) + } + text = string(fixSpace(line)) + return +} + +func parseContinuation(line []byte, enc []byte) []byte { + i := index(line, ":\t") + if i < 0 { + return nil + } + line = line[i+1:] + enc, _ = parseHex(line, enc) + return enc +} + +// writeELF32 writes an ELF32 header to the file, +// describing a text segment that starts at start +// and extends for size bytes. +func writeELF32(f *os.File, size int) error { + f.Seek(0, 0) + var hdr elf.Header32 + var prog elf.Prog32 + var sect elf.Section32 + var buf bytes.Buffer + binary.Write(&buf, binary.LittleEndian, &hdr) + off1 := buf.Len() + binary.Write(&buf, binary.LittleEndian, &prog) + off2 := buf.Len() + binary.Write(&buf, binary.LittleEndian, §) + off3 := buf.Len() + buf.Reset() + data := byte(elf.ELFDATA2LSB) + hdr = elf.Header32{ + Ident: [16]byte{0x7F, 'E', 'L', 'F', 1, data, 1}, + Type: 2, + Machine: uint16(elf.EM_ARM), + Version: 1, + Entry: start, + Phoff: uint32(off1), + Shoff: uint32(off2), + Flags: 0x05000002, + Ehsize: uint16(off1), + Phentsize: uint16(off2 - off1), + Phnum: 1, + Shentsize: uint16(off3 - off2), + Shnum: 3, + Shstrndx: 2, + } + binary.Write(&buf, binary.LittleEndian, &hdr) + prog = elf.Prog32{ + Type: 1, + Off: start, + Vaddr: start, + Paddr: start, + Filesz: uint32(size), + Memsz: uint32(size), + Flags: 5, + Align: start, + } + binary.Write(&buf, binary.LittleEndian, &prog) + binary.Write(&buf, binary.LittleEndian, §) // NULL section + sect = elf.Section32{ + Name: 1, + Type: uint32(elf.SHT_PROGBITS), + Addr: start, + Off: start, + Size: uint32(size), + Flags: uint32(elf.SHF_ALLOC | elf.SHF_EXECINSTR), + Addralign: 4, + } + binary.Write(&buf, binary.LittleEndian, §) // .text + sect = elf.Section32{ + Name: uint32(len("\x00.text\x00")), + Type: uint32(elf.SHT_STRTAB), + Addr: 0, + Off: uint32(off2 + (off3-off2)*3), + Size: uint32(len("\x00.text\x00.shstrtab\x00")), + Addralign: 1, + } + binary.Write(&buf, binary.LittleEndian, §) + buf.WriteString("\x00.text\x00.shstrtab\x00") + f.Write(buf.Bytes()) + return nil +} diff --git a/src/cmd/internal/rsc.io/arm/armasm/plan9x.go b/src/cmd/internal/rsc.io/arm/armasm/plan9x.go new file mode 100644 index 0000000000..952c5190b6 --- /dev/null +++ b/src/cmd/internal/rsc.io/arm/armasm/plan9x.go @@ -0,0 +1,211 @@ +// 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 armasm + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "strings" +) + +// Plan9Syntax returns the Go assembler syntax for the instruction. +// The syntax was originally defined by Plan 9. +// The pc is the program counter of the instruction, used for expanding +// PC-relative addresses into absolute ones. +// The symname function queries the symbol table for the program +// being disassembled. Given a target address it returns the name and base +// address of the symbol containing the target, if any; otherwise it returns "", 0. +// The reader r should read from the text segment using text addresses +// as offsets; it is used to display pc-relative loads as constant loads. +func Plan9Syntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string { + if symname == nil { + symname = func(uint64) (string, uint64) { return "", 0 } + } + + var args []string + for _, a := range inst.Args { + if a == nil { + break + } + args = append(args, plan9Arg(&inst, pc, symname, a)) + } + + op := inst.Op.String() + + switch inst.Op &^ 15 { + case LDR_EQ, LDRB_EQ, LDRH_EQ: + // Check for RET + reg, _ := inst.Args[0].(Reg) + mem, _ := inst.Args[1].(Mem) + if inst.Op&^15 == LDR_EQ && reg == R15 && mem.Base == SP && mem.Sign == 0 && mem.Mode == AddrPostIndex { + return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset) + } + + // Check for PC-relative load. + if mem.Base == PC && mem.Sign == 0 && mem.Mode == AddrOffset && text != nil { + addr := uint32(pc) + 8 + uint32(mem.Offset) + buf := make([]byte, 4) + switch inst.Op &^ 15 { + case LDRB_EQ: + if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil { + break + } + args[1] = fmt.Sprintf("$%#x", buf[0]) + + case LDRH_EQ: + if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil { + break + } + args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf)) + + case LDR_EQ: + if _, err := text.ReadAt(buf, int64(addr)); err != nil { + break + } + x := binary.LittleEndian.Uint32(buf) + if s, base := symname(uint64(x)); s != "" && uint64(x) == base { + args[1] = fmt.Sprintf("$%s(SB)", s) + } else { + args[1] = fmt.Sprintf("$%#x", x) + } + } + } + } + + // Move addressing mode into opcode suffix. + suffix := "" + switch inst.Op &^ 15 { + case LDR_EQ, LDRB_EQ, LDRH_EQ, STR_EQ, STRB_EQ, STRH_EQ: + mem, _ := inst.Args[1].(Mem) + switch mem.Mode { + case AddrOffset, AddrLDM: + // no suffix + case AddrPreIndex, AddrLDM_WB: + suffix = ".W" + case AddrPostIndex: + suffix = ".P" + } + off := "" + if mem.Offset != 0 { + off = fmt.Sprintf("%#x", mem.Offset) + } + base := fmt.Sprintf("(R%d)", int(mem.Base)) + index := "" + if mem.Sign != 0 { + sign := "" + if mem.Sign < 0 { + sign = "" + } + shift := "" + if mem.Count != 0 { + shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count) + } + index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift) + } + args[1] = off + base + index + } + + // Reverse args, placing dest last. + for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { + args[i], args[j] = args[j], args[i] + } + + switch inst.Op &^ 15 { + case MOV_EQ: + op = "MOVW" + op[3:] + + case LDR_EQ: + op = "MOVW" + op[3:] + suffix + case LDRB_EQ: + op = "MOVB" + op[4:] + suffix + case LDRH_EQ: + op = "MOVH" + op[4:] + suffix + + case STR_EQ: + op = "MOVW" + op[3:] + suffix + args[0], args[1] = args[1], args[0] + case STRB_EQ: + op = "MOVB" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + case STRH_EQ: + op = "MOVH" + op[4:] + suffix + args[0], args[1] = args[1], args[0] + } + + if args != nil { + op += " " + strings.Join(args, ", ") + } + + return op +} + +// assembler syntax for the various shifts. +// @x> is a lie; the assembler uses @> 0 +// instead of @x> 1, but i wanted to be clear that it +// was a different operation (rotate right extended, not rotate right). +var plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"} + +func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { + switch a := arg.(type) { + case Endian: + + case Imm: + return fmt.Sprintf("$%d", int(a)) + + case Mem: + + case PCRel: + addr := uint32(pc) + 8 + uint32(a) + if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { + return fmt.Sprintf("%s(SB)", s) + } + return fmt.Sprintf("%#x", addr) + + case Reg: + if a < 16 { + return fmt.Sprintf("R%d", int(a)) + } + + case RegList: + var buf bytes.Buffer + start := -2 + end := -2 + fmt.Fprintf(&buf, "[") + flush := func() { + if start >= 0 { + if buf.Len() > 1 { + fmt.Fprintf(&buf, ",") + } + if start == end { + fmt.Fprintf(&buf, "R%d", start) + } else { + fmt.Fprintf(&buf, "R%d-R%d", start, end) + } + } + } + for i := 0; i < 16; i++ { + if a&(1< ,,# cond:4|0|0|1|0|1|0|1|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00a00010, 4, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADC{S} ,,, cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00a00000, 2, ADC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADC{S} ,,{,} cond:4|0|0|0|0|1|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // ADD{S} ,,# cond:4|0|0|1|0|1|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00800010, 4, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // ADD{S} ,,, cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00800000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // ADD{S} ,,{,} cond:4|0|0|0|0|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0000, 0x028d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_const}}, // ADD{S} ,SP,# cond:4|0|0|1|0|1|0|0|S|1|1|0|1|Rd:4|imm12:12 + {0x0fef0010, 0x008d0000, 2, ADD_EQ, 0x14011c04, instArgs{arg_R_12, arg_SP, arg_R_shift_imm}}, // ADD{S} ,SP,{,} cond:4|0|0|0|0|1|0|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fe00000, 0x02000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // AND{S} ,,# cond:4|0|0|1|0|0|0|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x00000010, 4, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // AND{S} ,,, cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x00000000, 2, AND_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // AND{S} ,,{,} cond:4|0|0|0|0|0|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0fef0070, 0x01a00040, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_imm5_32}}, // ASR{S} ,,# cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|0|0|Rm:4 + {0x0fef00f0, 0x01a00050, 4, ASR_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_0, arg_R_8}}, // ASR{S} ,, cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|0|1|Rn:4 + {0x0f000000, 0x0a000000, 4, B_EQ, 0x1c04, instArgs{arg_label24}}, // B cond:4|1|0|1|0|imm24:24 + {0x0fe0007f, 0x07c0001f, 4, BFC_EQ, 0x1c04, instArgs{arg_R_12, arg_imm5, arg_lsb_width}}, // BFC ,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|1|1|1|1 + {0x0fe00070, 0x07c00010, 2, BFI_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0, arg_imm5, arg_lsb_width}}, // BFI ,,#,# cond:4|0|1|1|1|1|1|0|msb:5|Rd:4|lsb:5|0|0|1|Rn:4 + {0x0fe00000, 0x03c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_const}}, // BIC{S} ,,# cond:4|0|0|1|1|1|1|0|S|Rn:4|Rd:4|imm12:12 + {0x0fe00090, 0x01c00010, 4, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_R}}, // BIC{S} ,,, cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4 + {0x0fe00010, 0x01c00000, 2, BIC_EQ, 0x14011c04, instArgs{arg_R_12, arg_R_16, arg_R_shift_imm}}, // BIC{S} ,,{,} cond:4|0|0|0|1|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4 + {0x0ff000f0, 0x01200070, 4, BKPT_EQ, 0x1c04, instArgs{arg_imm_12at8_4at0}}, // BKPT # cond:4|0|0|0|1|0|0|1|0|imm12:12|0|1|1|1|imm4:4 + {0x0f000000, 0x0b000000, 4, BL_EQ, 0x1c04, instArgs{arg_label24}}, // BL cond:4|1|0|1|1|imm24:24 + {0xfe000000, 0xfa000000, 4, BLX, 0x0, instArgs{arg_label24H}}, // BLX 1|1|1|1|1|0|1|H|imm24:24 + {0x0ffffff0, 0x012fff30, 4, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ff000f0, 0x012fff30, 3, BLX_EQ, 0x1c04, instArgs{arg_R_0}}, // BLX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4 + {0x0ffffff0, 0x012fff10, 4, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x012fff10, 3, BX_EQ, 0x1c04, instArgs{arg_R_0}}, // BX cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ffffff0, 0x012fff20, 4, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0x0ff000f0, 0x012fff20, 3, BXJ_EQ, 0x1c04, instArgs{arg_R_0}}, // BXJ cond:4|0|0|0|1|0|0|1|0|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|0|0|1|0|Rm:4 + {0xffffffff, 0xf57ff01f, 4, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0xfff000f0, 0xf57ff01f, 3, CLREX, 0x0, instArgs{}}, // CLREX 1|1|1|1|0|1|0|1|0|1|1|1|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|1|(1)|(1)|(1)|(1) + {0x0fff0ff0, 0x016f0f10, 4, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff000f0, 0x016f0f10, 3, CLZ_EQ, 0x1c04, instArgs{arg_R_12, arg_R_0}}, // CLZ , cond:4|0|0|0|1|0|1|1|0|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4 + {0x0ff0f000, 0x03700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMN ,# cond:4|0|0|1|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01700010, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01700010, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMN ,, cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01700000, 4, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01700000, 3, CMN_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMN ,{,} cond:4|0|0|0|1|0|1|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff0f000, 0x03500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff00000, 0x03500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_const}}, // CMP ,# cond:4|0|0|1|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12 + {0x0ff0f090, 0x01500010, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff00090, 0x01500010, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_R}}, // CMP ,, cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4 + {0x0ff0f010, 0x01500000, 4, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ff00010, 0x01500000, 3, CMP_EQ, 0x1c04, instArgs{arg_R_16, arg_R_shift_imm}}, // CMP ,{,} cond:4|0|0|0|1|0|1|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4 + {0x0ffffff0, 0x0320f0f0, 4, DBG_EQ, 0x1c04, instArgs{arg_option}}, // DBG #

%s
Total: %s
`, + strings.Join(labels, "
\n"), + rpt.formatValue(rpt.total), + ) +} + +// printFunctionHeader prints a function header for a weblist report. +func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) { + fmt.Fprintf(w, `

%s

%s +
+  Total:  %10s %10s (flat, cum) %s
+`,
+		template.HTMLEscapeString(name), template.HTMLEscapeString(path),
+		rpt.formatValue(flatSum), rpt.formatValue(cumSum),
+		percentage(cumSum, rpt.total))
+}
+
+// printFunctionSourceLine prints a source line and the corresponding assembly.
+func printFunctionSourceLine(w io.Writer, fn *node, assembly nodes, rpt *Report) {
+	if len(assembly) == 0 {
+		fmt.Fprintf(w,
+			" %6d   %10s %10s %s \n",
+			fn.info.lineno,
+			valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
+			template.HTMLEscapeString(fn.info.name))
+		return
+	}
+
+	fmt.Fprintf(w,
+		" %6d   %10s %10s %s ",
+		fn.info.lineno,
+		valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
+		template.HTMLEscapeString(fn.info.name))
+	fmt.Fprint(w, "")
+	for _, an := range assembly {
+		var fileline string
+		class := "disasmloc"
+		if an.info.file != "" {
+			fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.info.file), an.info.lineno)
+			if an.info.lineno != fn.info.lineno {
+				class = "unimportant"
+			}
+		}
+		fmt.Fprintf(w, " %8s %10s %10s %8x: %-48s %s\n", "",
+			valueOrDot(an.flat, rpt), valueOrDot(an.cum, rpt),
+			an.info.address,
+			template.HTMLEscapeString(an.info.name),
+			class,
+			template.HTMLEscapeString(fileline))
+	}
+	fmt.Fprintln(w, "")
+}
+
+// printFunctionClosing prints the end of a function in a weblist report.
+func printFunctionClosing(w io.Writer) {
+	fmt.Fprintln(w, "
") +} + +// printPageClosing prints the end of the page in a weblist report. +func printPageClosing(w io.Writer) { + fmt.Fprintln(w, weblistPageClosing) +} + +// getFunctionSource collects the sources of a function from a source +// file and annotates it with the samples in fns. Returns the sources +// as nodes, using the info.name field to hold the source code. +func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, string, error) { + f, file, err := adjustSourcePath(file) + if err != nil { + return nil, file, err + } + + lineNodes := make(map[int]nodes) + + // Collect source coordinates from profile. + const margin = 5 // Lines before first/after last sample. + if start == 0 { + if fns[0].info.startLine != 0 { + start = fns[0].info.startLine + } else { + start = fns[0].info.lineno - margin + } + } else { + start -= margin + } + if end == 0 { + end = fns[0].info.lineno + } + end += margin + for _, n := range fns { + lineno := n.info.lineno + nodeStart := n.info.startLine + if nodeStart == 0 { + nodeStart = lineno - margin + } + nodeEnd := lineno + margin + if nodeStart < start { + start = nodeStart + } else if nodeEnd > end { + end = nodeEnd + } + lineNodes[lineno] = append(lineNodes[lineno], n) + } + + var src nodes + buf := bufio.NewReader(f) + lineno := 1 + for { + line, err := buf.ReadString('\n') + if err != nil { + if line == "" || err != io.EOF { + return nil, file, err + } + } + if lineno >= start { + flat, cum := sumNodes(lineNodes[lineno]) + + src = append(src, &node{ + info: nodeInfo{ + name: strings.TrimRight(line, "\n"), + lineno: lineno, + }, + flat: flat, + cum: cum, + }) + } + lineno++ + if lineno > end { + break + } + } + return src, file, nil +} + +// getMissingFunctionSource creates a dummy function body to point to +// the source file and annotates it with the samples in asm. +func getMissingFunctionSource(filename string, asm map[int]nodes, start, end int) (nodes, string) { + var fnodes nodes + for i := start; i <= end; i++ { + lrs := asm[i] + if len(lrs) == 0 { + continue + } + flat, cum := sumNodes(lrs) + fnodes = append(fnodes, &node{ + info: nodeInfo{ + name: "???", + lineno: i, + }, + flat: flat, + cum: cum, + }) + } + return fnodes, filename +} + +// adjustSourcePath adjusts the pathe for a source file by trimmming +// known prefixes and searching for the file on all parents of the +// current working dir. +func adjustSourcePath(path string) (*os.File, string, error) { + path = trimPath(path) + f, err := os.Open(path) + if err == nil { + return f, path, nil + } + + if dir, wderr := os.Getwd(); wderr == nil { + for { + parent := filepath.Dir(dir) + if parent == dir { + break + } + if f, err := os.Open(filepath.Join(parent, path)); err == nil { + return f, filepath.Join(parent, path), nil + } + + dir = parent + } + } + + return nil, path, err +} + +// trimPath cleans up a path by removing prefixes that are commonly +// found on profiles. +func trimPath(path string) string { + basePaths := []string{ + "/proc/self/cwd/./", + "/proc/self/cwd/", + } + + sPath := filepath.ToSlash(path) + + for _, base := range basePaths { + if strings.HasPrefix(sPath, base) { + return filepath.FromSlash(sPath[len(base):]) + } + } + return path +} diff --git a/src/cmd/pprof/internal/report/source_html.go b/src/cmd/pprof/internal/report/source_html.go new file mode 100644 index 0000000000..267fabdc4b --- /dev/null +++ b/src/cmd/pprof/internal/report/source_html.go @@ -0,0 +1,77 @@ +// 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 report + +const weblistPageHeader = ` + + + +Pprof listing + + + + +` + +const weblistPageClosing = ` + + +` diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/pprof/internal/svg/svg.go new file mode 100644 index 0000000000..aa65a1a08d --- /dev/null +++ b/src/cmd/pprof/internal/svg/svg.go @@ -0,0 +1,75 @@ +// 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 svg provides tools related to handling of SVG files +package svg + +import ( + "bytes" + "regexp" + "strings" +) + +var ( + viewBox = regexp.MustCompile(``) +) + +// Massage enhances the SVG output from DOT to provide bettern +// panning inside a web browser. It uses the SVGPan library, which is +// accessed through the svgPan URL. +func Massage(in bytes.Buffer, svgPan string) string { + svg := string(in.Bytes()) + + // Work around for dot bug which misses quoting some ampersands, + // resulting on unparsable SVG. + svg = strings.Replace(svg, "&;", "&;", -1) + if svgPan == "" { + return svg + } + + //Dot's SVG output is + // + // + // + // ... + // + // + // + // Change it to + // + // + // + + // + // + // ... + // + // + // + + if loc := viewBox.FindStringIndex(svg); loc != nil { + svg = svg[:loc[0]] + + `` + + `` + + svg[loc[0]:] + } + + if loc := svgClose.FindStringIndex(svg); loc != nil { + svg = svg[:loc[0]] + + `` + + svg[loc[0]:] + } + + return svg +} diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go new file mode 100644 index 0000000000..cabddaa76e --- /dev/null +++ b/src/cmd/pprof/internal/symbolizer/symbolizer.go @@ -0,0 +1,191 @@ +// 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 symbolizer provides a routine to populate a profile with +// symbol, file and line number information. It relies on the +// addr2liner and demangler packages to do the actual work. +package symbolizer + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "cmd/pprof/internal/plugin" + "cmd/pprof/internal/profile" +) + +// Symbolize adds symbol and line number information to all locations +// in a profile. mode enables some options to control +// symbolization. Currently only recognizes "force", which causes it +// to overwrite any existing data. +func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error { + force := false + // Disable some mechanisms based on mode string. + for _, o := range strings.Split(strings.ToLower(mode), ":") { + switch o { + case "force": + force = true + default: + } + } + + mt, err := newMapping(prof, obj, ui, force) + if err != nil { + return err + } + defer mt.close() + + functions := make(map[profile.Function]*profile.Function) + for _, l := range mt.prof.Location { + m := l.Mapping + segment := mt.segments[m] + if segment == nil { + // Nothing to do + continue + } + + stack, err := segment.SourceLine(l.Address) + if err != nil || len(stack) == 0 { + // No answers from addr2line + continue + } + + l.Line = make([]profile.Line, len(stack)) + for i, frame := range stack { + if frame.Func != "" { + m.HasFunctions = true + } + if frame.File != "" { + m.HasFilenames = true + } + if frame.Line != 0 { + m.HasLineNumbers = true + } + f := &profile.Function{ + Name: frame.Func, + SystemName: frame.Func, + Filename: frame.File, + } + if fp := functions[*f]; fp != nil { + f = fp + } else { + functions[*f] = f + f.ID = uint64(len(mt.prof.Function)) + 1 + mt.prof.Function = append(mt.prof.Function, f) + } + l.Line[i] = profile.Line{ + Function: f, + Line: int64(frame.Line), + } + } + + if len(stack) > 0 { + m.HasInlineFrames = true + } + } + return nil +} + +// newMapping creates a mappingTable for a profile. +func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) { + mt := &mappingTable{ + prof: prof, + segments: make(map[*profile.Mapping]plugin.ObjFile), + } + + // Identify used mappings + mappings := make(map[*profile.Mapping]bool) + for _, l := range prof.Location { + mappings[l.Mapping] = true + } + + for _, m := range prof.Mapping { + if !mappings[m] { + continue + } + // Do not attempt to re-symbolize a mapping that has already been symbolized. + if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) { + continue + } + + f, err := locateFile(obj, m.File, m.BuildID, m.Start) + if err != nil { + ui.PrintErr("Local symbolization failed for ", filepath.Base(m.File), ": ", err) + // Move on to other mappings + continue + } + + if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID { + // Build ID mismatch - ignore. + f.Close() + continue + } + + mt.segments[m] = f + } + + return mt, nil +} + +// locateFile opens a local file for symbolization on the search path +// at $PPROF_BINARY_PATH. Looks inside these directories for files +// named $BUILDID/$BASENAME and $BASENAME (if build id is available). +func locateFile(obj plugin.ObjTool, file, buildID string, start uint64) (plugin.ObjFile, error) { + // Construct search path to examine + searchPath := os.Getenv("PPROF_BINARY_PATH") + if searchPath == "" { + // Use $HOME/pprof/binaries as default directory for local symbolization binaries + searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries") + } + + // Collect names to search: {buildid/basename, basename} + var fileNames []string + if baseName := filepath.Base(file); buildID != "" { + fileNames = []string{filepath.Join(buildID, baseName), baseName} + } else { + fileNames = []string{baseName} + } + for _, path := range filepath.SplitList(searchPath) { + for nameIndex, name := range fileNames { + file := filepath.Join(path, name) + if f, err := obj.Open(file, start); err == nil { + fileBuildID := f.BuildID() + if buildID == "" || buildID == fileBuildID { + return f, nil + } + f.Close() + if nameIndex == 0 { + // If this is the first name, the path includes the build id. Report inconsistency. + return nil, fmt.Errorf("found file %s with inconsistent build id %s", file, fileBuildID) + } + } + } + } + // Try original file name + f, err := obj.Open(file, start) + if err == nil && buildID != "" { + if fileBuildID := f.BuildID(); fileBuildID != "" && fileBuildID != buildID { + // Mismatched build IDs, ignore + f.Close() + return nil, fmt.Errorf("mismatched build ids %s != %s", fileBuildID, buildID) + } + } + return f, err +} + +// mappingTable contains the mechanisms for symbolization of a +// profile. +type mappingTable struct { + prof *profile.Profile + segments map[*profile.Mapping]plugin.ObjFile +} + +// Close releases any external processes being used for the mapping. +func (mt *mappingTable) close() { + for _, segment := range mt.segments { + segment.Close() + } +} diff --git a/src/cmd/pprof/internal/symbolz/symbolz.go b/src/cmd/pprof/internal/symbolz/symbolz.go new file mode 100644 index 0000000000..c81e522208 --- /dev/null +++ b/src/cmd/pprof/internal/symbolz/symbolz.go @@ -0,0 +1,111 @@ +// 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 symbolz symbolizes a profile using the output from the symbolz +// service. +package symbolz + +import ( + "bytes" + "fmt" + "io" + "net/url" + "regexp" + "strconv" + "strings" + + "cmd/pprof/internal/profile" +) + +var ( + symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`) +) + +// Symbolize symbolizes profile p by parsing data returned by a +// symbolz handler. syms receives the symbolz query (hex addresses +// separated by '+') and returns the symbolz output in a string. It +// symbolizes all locations based on their addresses, regardless of +// mapping. +func Symbolize(source string, syms func(string, string) ([]byte, error), p *profile.Profile) error { + if source = symbolz(source, p); source == "" { + // If the source is not a recognizable URL, do nothing. + return nil + } + + // Construct query of addresses to symbolize. + var a []string + for _, l := range p.Location { + if l.Address != 0 && len(l.Line) == 0 { + a = append(a, fmt.Sprintf("%#x", l.Address)) + } + } + + if len(a) == 0 { + // No addresses to symbolize. + return nil + } + lines := make(map[uint64]profile.Line) + functions := make(map[string]*profile.Function) + if b, err := syms(source, strings.Join(a, "+")); err == nil { + buf := bytes.NewBuffer(b) + for { + l, err := buf.ReadString('\n') + + if err != nil { + if err == io.EOF { + break + } + return err + } + + if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 { + addr, err := strconv.ParseUint(symbol[1], 0, 64) + if err != nil { + return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err) + } + + name := symbol[2] + fn := functions[name] + if fn == nil { + fn = &profile.Function{ + ID: uint64(len(p.Function) + 1), + Name: name, + SystemName: name, + } + functions[name] = fn + p.Function = append(p.Function, fn) + } + + lines[addr] = profile.Line{Function: fn} + } + } + } + + for _, l := range p.Location { + if line, ok := lines[l.Address]; ok { + l.Line = []profile.Line{line} + if l.Mapping != nil { + l.Mapping.HasFunctions = true + } + } + } + + return nil +} + +// symbolz returns the corresponding symbolz source for a profile URL. +func symbolz(source string, p *profile.Profile) string { + if url, err := url.Parse(source); err == nil && url.Host != "" { + if last := strings.LastIndex(url.Path, "/"); last != -1 { + if strings.HasSuffix(url.Path[:last], "pprof") { + url.Path = url.Path[:last] + "/symbol" + } else { + url.Path = url.Path[:last] + "/symbolz" + } + return url.String() + } + } + + return "" +} diff --git a/src/cmd/pprof/internal/tempfile/tempfile.go b/src/cmd/pprof/internal/tempfile/tempfile.go new file mode 100644 index 0000000000..31c117690a --- /dev/null +++ b/src/cmd/pprof/internal/tempfile/tempfile.go @@ -0,0 +1,45 @@ +// 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 tempfile provides tools to create and delete temporary files +package tempfile + +import ( + "fmt" + "os" + "path/filepath" + "sync" +) + +// New returns an unused filename for output files. +func New(dir, prefix, suffix string) (*os.File, error) { + for index := 1; index < 10000; index++ { + path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix)) + if _, err := os.Stat(path); err != nil { + return os.Create(path) + } + } + // Give up + return nil, fmt.Errorf("could not create file of the form %s%03d%s", prefix, 1, suffix) +} + +var tempFiles []string +var tempFilesMu = sync.Mutex{} + +// DeferDelete marks a file to be deleted by next call to Cleanup() +func DeferDelete(path string) { + tempFilesMu.Lock() + tempFiles = append(tempFiles, path) + tempFilesMu.Unlock() +} + +// Cleanup removes any temporary files selected for deferred cleaning. +func Cleanup() { + tempFilesMu.Lock() + for _, f := range tempFiles { + os.Remove(f) + } + tempFiles = nil + tempFilesMu.Unlock() +} diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go new file mode 100644 index 0000000000..89a5bb7d22 --- /dev/null +++ b/src/cmd/pprof/pprof.go @@ -0,0 +1,202 @@ +// 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 ( + "debug/gosym" + "flag" + "fmt" + "os" + "regexp" + "strings" + + "cmd/internal/objfile" + "cmd/pprof/internal/commands" + "cmd/pprof/internal/driver" + "cmd/pprof/internal/fetch" + "cmd/pprof/internal/plugin" + "cmd/pprof/internal/profile" + "cmd/pprof/internal/symbolizer" + "cmd/pprof/internal/symbolz" +) + +func main() { + var extraCommands map[string]*commands.Command // no added Go-specific commands + if err := driver.PProf(flags{}, fetch.Fetcher, symbolize, new(objTool), plugin.StandardUI(), extraCommands); err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// symbolize attempts to symbolize profile p. +// If the source is a local binary, it tries using symbolizer and obj. +// If the source is a URL, it fetches symbol information using symbolz. +func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error { + remote, local := true, true + for _, o := range strings.Split(strings.ToLower(mode), ":") { + switch o { + case "none", "no": + return nil + case "local": + remote, local = false, true + case "remote": + remote, local = true, false + default: + ui.PrintErr("ignoring unrecognized symbolization option: " + mode) + ui.PrintErr("expecting -symbolize=[local|remote|none][:force]") + fallthrough + case "", "force": + // Ignore these options, -force is recognized by symbolizer.Symbolize + } + } + + var err error + if local { + // Symbolize using binutils. + if err = symbolizer.Symbolize(mode, p, obj, ui); err == nil { + return nil + } + } + if remote { + err = symbolz.Symbolize(source, fetch.PostURL, p) + } + return err +} + +// flags implements the driver.FlagPackage interface using the builtin flag package. +type flags struct { +} + +func (flags) Bool(o string, d bool, c string) *bool { + return flag.Bool(o, d, c) +} + +func (flags) Int(o string, d int, c string) *int { + return flag.Int(o, d, c) +} + +func (flags) Float64(o string, d float64, c string) *float64 { + return flag.Float64(o, d, c) +} + +func (flags) String(o, d, c string) *string { + return flag.String(o, d, c) +} + +func (flags) Parse(usage func()) []string { + flag.Usage = usage + flag.Parse() + args := flag.Args() + if len(args) == 0 { + usage() + } + return args +} + +func (flags) ExtraUsage() string { + return "" +} + +// objTool implements plugin.ObjTool using Go libraries +// (instead of invoking GNU binutils). +type objTool struct{} + +func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) { + of, err := objfile.Open(name) + if err != nil { + return nil, err + } + f := &file{ + name: name, + file: of, + } + return f, nil +} + +func (*objTool) Demangle(names []string) (map[string]string, error) { + // No C++, nothing to demangle. + return make(map[string]string), nil +} + +func (*objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) { + return nil, fmt.Errorf("disassembly not supported") +} + +func (*objTool) SetConfig(config string) { + // config is usually used to say what binaries to invoke. + // Ignore entirely. +} + +// file implements plugin.ObjFile using Go libraries +// (instead of invoking GNU binutils). +// A file represents a single executable being analyzed. +type file struct { + name string + sym []objfile.Sym + file *objfile.File + pcln *gosym.Table +} + +func (f *file) Name() string { + return f.name +} + +func (f *file) Base() uint64 { + // No support for shared libraries. + return 0 +} + +func (f *file) BuildID() string { + // No support for build ID. + return "" +} + +func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) { + if f.pcln == nil { + pcln, err := f.file.PCLineTable() + if err != nil { + return nil, err + } + f.pcln = pcln + } + file, line, fn := f.pcln.PCToLine(addr) + if fn == nil { + return nil, fmt.Errorf("no line information for PC=%#x", addr) + } + frame := []plugin.Frame{ + { + Func: fn.Name, + File: file, + Line: line, + }, + } + return frame, nil +} + +func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) { + if f.sym == nil { + sym, err := f.file.Symbols() + if err != nil { + return nil, err + } + f.sym = sym + } + var out []*plugin.Sym + for _, s := range f.sym { + if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) { + out = append(out, &plugin.Sym{ + Name: []string{s.Name}, + File: f.name, + Start: s.Addr, + End: s.Addr + uint64(s.Size) - 1, + }) + } + } + return out, nil +} + +func (f *file) Close() error { + f.file.Close() + return nil +} From c017a4e118c9574c0b1eefa661b46bf81ab6e7c2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 30 Sep 2014 14:30:40 -0400 Subject: [PATCH 253/430] cmd/go: sometimes name tmp test binary test.test.exe on Windows Right now it is always pkgname.test.exe, but if pkgname is patch or install or setup or update, Windows thinks that running it will install new software, so it pops up a dialog box asking for more permission. Renaming the binary avoids the Windows security check. This only applies to the binary that the Go command writes to its temporary work directory. If the user runs 'go test -c' or any of the other ways to generate a test binary, it will continue to use pkgname.test.exe. Fixes #8711. LGTM=bradfitz R=golang-codereviews, r CC=alex.brainman, bradfitz, golang-codereviews, iant https://golang.org/cl/146580043 --- src/cmd/go/test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index 0962e5bb50..c81e40639e 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -535,6 +535,13 @@ func contains(x []string, s string) bool { return false } +var windowsBadWords = []string{ + "install", + "patch", + "setup", + "update", +} + func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, err error) { if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { build := b.action(modeBuild, modeBuild, p) @@ -794,6 +801,36 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, a.objdir = testDir + string(filepath.Separator) a.objpkg = filepath.Join(testDir, "main.a") a.target = filepath.Join(testDir, testBinary) + exeSuffix + if goos == "windows" { + // There are many reserved words on Windows that, + // if used in the name of an executable, cause Windows + // to try to ask for extra permissions. + // The word list includes setup, install, update, and patch, + // but it does not appear to be defined anywhere. + // We have run into this trying to run the + // go.codereview/patch tests. + // For package names containing those words, use test.test.exe + // instead of pkgname.test.exe. + // Note that this file name is only used in the Go command's + // temporary directory. If the -c or other flags are + // given, the code below will still use pkgname.test.exe. + // There are two user-visible effects of this change. + // First, you can actually run 'go test' in directories that + // have names that Windows thinks are installer-like, + // without getting a dialog box asking for more permissions. + // Second, in the Windows process listing during go test, + // the test shows up as test.test.exe, not pkgname.test.exe. + // That second one is a drawback, but it seems a small + // price to pay for the test running at all. + // If maintaining the list of bad words is too onerous, + // we could just do this always on Windows. + for _, bad := range windowsBadWords { + if strings.Contains(testBinary, bad) { + a.target = filepath.Join(testDir, "test.test") + exeSuffix + break + } + } + } buildAction = a if testC || testNeedBinary { From 47094dcf09ca5dce1ae76bbb3a4e4311c552fd7b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 30 Sep 2014 11:44:29 -0700 Subject: [PATCH 254/430] spec: clarify variable declaration type rules Not a language change. Several inaccuracies were fixed: 1) A variable declaration may declare more than just one variable. 2) Variable initialization follows the rules of assignments, including n:1 assignments. The existing wording implied a 1:1 or n:n rule and generally was somewhat unspecific. 3) The rules for variable declarations with no types and untyped initialization expressions had minor holes (issue 8088). 4) Clarified the special cases of assignments of untyped values (we don't just have untyped constants, but also untyped bools, e.g. from comparisons). The new wording is more direct. To that end, introduced the notion of an untyped constant's "default type" so that the same concept doesn't have to be repeatedly introduced. Fixes #8088. LGTM=iant, r, rsc R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/142320043 --- doc/go_spec.html | 81 ++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index de79f7ee4b..7fa02e4192 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -577,7 +577,7 @@ Numeric constants represent values of arbitrary precision and do not overflow.

-Constants may be typed or untyped. +Constants may be typed or untyped. Literal constants, true, false, iota, and certain constant expressions containing only untyped constant operands are untyped. @@ -597,6 +597,17 @@ can be given the types float32, float64, or uint not int32 or string.

+

+An untyped constant has a default type which is the type to which the +constant is implicitly converted in contexts where a typed value is required, +for instance, in a short variable declaration +such as i := 0 where there is no explicit type. +The default type of an untyped constant is bool, rune, +int, float64, complex128 or string +respectively, depending on whether it is a boolean, rune, integer, floating-point, +complex, or string constant. +

+

There are no constants denoting the IEEE-754 infinity and not-a-number values, but the math package's @@ -1882,9 +1893,10 @@ func (tz TimeZone) String() string {

Variable declarations

-A variable declaration creates a variable, binds an identifier to it and -gives it a type and optionally an initial value. +A variable declaration creates one or more variables, binds corresponding +identifiers to them, and gives each a type and an initial value.

+
 VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
 VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
@@ -1905,22 +1917,27 @@ var _, found = entries[name]  // map lookup; only interested in "found"
 
 

If a list of expressions is given, the variables are initialized -by assigning the expressions to the variables -in order; all expressions must be consumed and all variables initialized from them. +with the expressions following the rules for assignments. Otherwise, each variable is initialized to its zero value.

-If the type is present, each variable is given that type. -Otherwise, the types are deduced from the assignment -of the expression list. +If a type is present, each variable is given that type. +Otherwise, each variable is given the type of the corresponding +initialization value in the assignment. +If that value is an untyped constant, it is first +converted to its default type; +if it is an untyped boolean value, it is first converted to type bool. +The predeclared value nil cannot be used to initialize a variable +with no explicit type.

-

-If the type is absent and the corresponding expression evaluates to an -untyped constant, the type of the declared variable -is as described in §Assignments. -

+
+var d = math.Sin(0.5)  // d is int64
+var i = 42             // i is int
+var t, ok = x.(T)      // t is T, ok is bool
+var n = nil            // illegal
+

Implementation restriction: A compiler may make it illegal to declare a variable @@ -4318,7 +4335,7 @@ a[i] = 23

An assignment operation x op= -y where op is a binary arithmetic operation equivalent +y where op is a binary arithmetic operation is equivalent to x = x op y but evaluates x only once. The op= construct is a single token. @@ -4336,8 +4353,8 @@ i &^= 1<<n A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression -such as a function evaluation or channel or -map operation or a type assertion. +such as a function call, a channel or +map operation, or a type assertion. The number of operands on the left hand side must match the number of values. For instance, if f is a function returning two values, @@ -4411,23 +4428,21 @@ to the type of the operand to which it is assigned, with the following special c

    -
  1. - If an untyped constant - is assigned to a variable of interface type or the blank identifier, - the constant is first converted to type - bool, rune, int, float64, - complex128 or string respectively, depending on - whether the value is a boolean, rune, integer, floating-point, complex, or - string constant. -

  2. +
  3. + Any typed value may be assigned to the blank identifier. +
  4. -
  5. - - If a left-hand side is the blank identifier, any typed or non-constant - value except for the predeclared identifier - nil - may be assigned to it. -

  6. +
  7. + If an untyped constant + is assigned to a variable of interface type or the blank identifier, + the constant is first converted to its + default type. +
  8. + +
  9. + If an untyped boolean value is assigned to a variable of interface type or + the blank identifier, it is first converted to type bool. +

If statements

From 1b89cd16589c223f1d5fb73b88a2612800d68e67 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Tue, 30 Sep 2014 11:49:15 -0700 Subject: [PATCH 255/430] encoding/asn1: fix unmarshaling of implicitly tagged UTF-8 strings. Fixes #8541. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/153770043 --- src/encoding/asn1/asn1.go | 12 ++++++++---- src/encoding/asn1/asn1_test.go | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index b06aec3e40..3aeb3dcc4b 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -640,15 +640,19 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam // when it sees a string, so if we see a different string type on the // wire, we change the universal type to match. if universalTag == tagPrintableString { - switch t.tag { - case tagIA5String, tagGeneralString, tagT61String, tagUTF8String: - universalTag = t.tag + if params.tag == nil { + switch t.tag { + case tagIA5String, tagGeneralString, tagT61String, tagUTF8String: + universalTag = t.tag + } + } else if params.stringType != 0 { + universalTag = params.stringType } } // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. - if universalTag == tagUTCTime && t.tag == tagGeneralizedTime { + if universalTag == tagUTCTime && params.tag == nil && t.tag == tagGeneralizedTime { universalTag = tagGeneralizedTime } diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index b553f78e0a..b94d59d369 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -392,6 +392,10 @@ type TestContextSpecificTags2 struct { B int } +type TestContextSpecificTags3 struct { + S string `asn1:"tag:1,utf8"` +} + type TestElementsAfterString struct { S string A, B int @@ -420,6 +424,7 @@ var unmarshalTestData = []struct { {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}}, {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}}, {[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}}, + {[]byte{0x30, 0x03, 0x81, 0x01, '@'}, &TestContextSpecificTags3{"@"}}, {[]byte{0x01, 0x01, 0x00}, newBool(false)}, {[]byte{0x01, 0x01, 0xff}, newBool(true)}, {[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}}, From 4a532c664df5d0c6edd4955a80006490827179d7 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 30 Sep 2014 12:09:34 -0700 Subject: [PATCH 256/430] net/http/httputil: ensure DumpRequestOut dumps all of Body Bodies larger than 8KB (the default bufio reader size) weren't being dumped. Force a read of the body so they're teed into the response buffer. Thanks to Steven Hartland for identifying the problem. Fixes #8089 LGTM=r R=golang-codereviews, r CC=adg, golang-codereviews https://golang.org/cl/144650044 --- src/net/http/httputil/dump.go | 12 ++++++++++-- src/net/http/httputil/dump_test.go | 30 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go index 2a7a413d01..ac8f103f9b 100644 --- a/src/net/http/httputil/dump.go +++ b/src/net/http/httputil/dump.go @@ -95,19 +95,27 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { // with a dummy response. var buf bytes.Buffer // records the output pr, pw := io.Pipe() + defer pr.Close() + defer pw.Close() dr := &delegateReader{c: make(chan io.Reader)} // Wait for the request before replying with a dummy response: go func() { - http.ReadRequest(bufio.NewReader(pr)) + req, err := http.ReadRequest(bufio.NewReader(pr)) + if err == nil { + // Ensure all the body is read; otherwise + // we'll get a partial dump. + io.Copy(ioutil.Discard, req.Body) + req.Body.Close() + } dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n") }() t := &http.Transport{ + DisableKeepAlives: true, Dial: func(net, addr string) (net.Conn, error) { return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil }, } - defer t.CloseIdleConnections() _, err := t.RoundTrip(reqSend) diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go index e1ffb3935a..024ee5a86f 100644 --- a/src/net/http/httputil/dump_test.go +++ b/src/net/http/httputil/dump_test.go @@ -111,6 +111,30 @@ var dumpTests = []dumpTest{ NoBody: true, }, + + // Request with Body > 8196 (default buffer size) + { + Req: http.Request{ + Method: "POST", + URL: &url.URL{ + Scheme: "http", + Host: "post.tld", + Path: "/", + }, + ContentLength: 8193, + ProtoMajor: 1, + ProtoMinor: 1, + }, + + Body: bytes.Repeat([]byte("a"), 8193), + + WantDumpOut: "POST / HTTP/1.1\r\n" + + "Host: post.tld\r\n" + + "User-Agent: Go 1.1 package http\r\n" + + "Content-Length: 8193\r\n" + + "Accept-Encoding: gzip\r\n\r\n" + + strings.Repeat("a", 8193), + }, } func TestDumpRequest(t *testing.T) { @@ -125,6 +149,8 @@ func TestDumpRequest(t *testing.T) { tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b)) case func() io.ReadCloser: tt.Req.Body = b() + default: + t.Fatalf("Test %d: unsupported Body of %T", i, tt.Body) } } setBody() @@ -159,7 +185,9 @@ func TestDumpRequest(t *testing.T) { } } if dg := runtime.NumGoroutine() - numg0; dg > 4 { - t.Errorf("Unexpectedly large number of new goroutines: %d new", dg) + buf := make([]byte, 4096) + buf = buf[:runtime.Stack(buf, true)] + t.Errorf("Unexpectedly large number of new goroutines: %d new: %s", dg, buf) } } From 146713b67ac6628350abd74f76fd2955de66b3c6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 30 Sep 2014 12:26:38 -0700 Subject: [PATCH 257/430] go/format, cmd/gofmt: added missing comments, minor internal cleanup This is a minor cleanup following CL 142360043: The internal parse and format functions in both packages were almost identical - made them identical by adding an extra parameter, and documented them as identical. Eventually we should find a nice way to factor these functions out, but we cannot do this now while in prep for 1.4. No functionality change. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/146520043 --- src/cmd/gofmt/gofmt.go | 29 +++++++++++++++++++++++------ src/go/format/format.go | 36 +++++++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 8542957248..81da21ff10 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -106,7 +106,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error simplify(file) } - res, err := format(fileSet, file, sourceAdj, indentAdj, src) + res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) if err != nil { return err } @@ -235,8 +235,16 @@ func diff(b1, b2 []byte) (data []byte, err error) { } -// parse parses src, which was read from filename, -// as a Go source file or statement list. +// ---------------------------------------------------------------------------- +// Support functions +// +// The functions parse, format, and isSpace below are identical to the +// respective functions in src/go/format/format.go - keep them in sync! +// +// TODO(gri) Factor out this functionality, eventually. + +// parse parses src, which was read from the named file, +// as a Go source file, declaration, or statement list. func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( file *ast.File, sourceAdj func(src []byte, indent int) []byte, @@ -303,11 +311,21 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( return } -func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, indent int) []byte, indentAdj int, src []byte) ([]byte, error) { +// format formats the given package file originally obtained from src +// and adjusts the result based on the original source via sourceAdj +// and indentAdj. +func format( + fset *token.FileSet, + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + src []byte, + cfg printer.Config, +) ([]byte, error) { if sourceAdj == nil { // Complete source file. var buf bytes.Buffer - err := (&printer.Config{Mode: printerMode, Tabwidth: tabWidth}).Fprint(&buf, fset, file) + err := cfg.Fprint(&buf, fset, file) if err != nil { return nil, err } @@ -348,7 +366,6 @@ func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, inde // Format the source. // Write it without any leading and trailing space. - cfg := &printer.Config{Mode: printerMode, Tabwidth: tabWidth} cfg.Indent = indent + indentAdj var buf bytes.Buffer err := cfg.Fprint(&buf, fset, file) diff --git a/src/go/format/format.go b/src/go/format/format.go index 08a9047b99..668a42df2d 100644 --- a/src/go/format/format.go +++ b/src/go/format/format.go @@ -87,7 +87,13 @@ func Source(src []byte) ([]byte, error) { return nil, err } - return format(fset, file, sourceAdj, indentAdj, src) + if sourceAdj == nil { + // Complete source file. + // TODO(gri) consider doing this always. + ast.SortImports(fset, file) + } + + return format(fset, file, sourceAdj, indentAdj, src, config) } func hasUnsortedImports(file *ast.File) bool { @@ -108,8 +114,16 @@ func hasUnsortedImports(file *ast.File) bool { return false } -// parse parses src, which was read from filename, -// as a Go source file or statement list. +// ---------------------------------------------------------------------------- +// Support functions +// +// The functions parse, format, and isSpace below are identical to the +// respective functions in cmd/gofmt/gofmt.go - keep them in sync! +// +// TODO(gri) Factor out this functionality, eventually. + +// parse parses src, which was read from the named file, +// as a Go source file, declaration, or statement list. func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( file *ast.File, sourceAdj func(src []byte, indent int) []byte, @@ -176,12 +190,21 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( return } -func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, indent int) []byte, indentAdj int, src []byte) ([]byte, error) { +// format formats the given package file originally obtained from src +// and adjusts the result based on the original source via sourceAdj +// and indentAdj. +func format( + fset *token.FileSet, + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + src []byte, + cfg printer.Config, +) ([]byte, error) { if sourceAdj == nil { // Complete source file. - ast.SortImports(fset, file) var buf bytes.Buffer - err := config.Fprint(&buf, fset, file) + err := cfg.Fprint(&buf, fset, file) if err != nil { return nil, err } @@ -222,7 +245,6 @@ func format(fset *token.FileSet, file *ast.File, sourceAdj func(src []byte, inde // Format the source. // Write it without any leading and trailing space. - cfg := config cfg.Indent = indent + indentAdj var buf bytes.Buffer err := cfg.Fprint(&buf, fset, file) From 74b8693c544abffbce69262b609410459d8796f8 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Tue, 30 Sep 2014 16:08:04 -0400 Subject: [PATCH 258/430] cmd/cgo: add missing ast.SliceExpr.Max case to AST traversal. + static test NB: there's a preexisting (dynamic) failure of test issue7978.go. LGTM=iant R=rsc, iant CC=golang-codereviews https://golang.org/cl/144650045 --- misc/cgo/test/basic.go | 5 +++++ src/cmd/cgo/ast.go | 3 +++ 2 files changed, 8 insertions(+) diff --git a/misc/cgo/test/basic.go b/misc/cgo/test/basic.go index 79cbf2b9cf..019139d010 100644 --- a/misc/cgo/test/basic.go +++ b/misc/cgo/test/basic.go @@ -157,3 +157,8 @@ func testUnsignedInt(t *testing.T) { t.Errorf("Incorrect unsigned int - got %x, want %x", a, b) } } + +// Static (build-time) test that syntax traversal visits all operands of s[i:j:k]. +func sliceOperands(array [2000]int) { + _ = array[C.KILO:C.KILO:C.KILO] // no type error +} diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 6c5a160866..10e2278a1d 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -308,6 +308,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} if n.High != nil { f.walk(&n.High, "expr", visit) } + if n.Max != nil { + f.walk(&n.Max, "expr", visit) + } case *ast.TypeAssertExpr: f.walk(&n.X, "expr", visit) f.walk(&n.Type, "type", visit) From e7488b2189c6a0628f7df45bc84c565f185af04d Mon Sep 17 00:00:00 2001 From: Paul van Brouwershaven Date: Tue, 30 Sep 2014 13:38:48 -0700 Subject: [PATCH 259/430] x509: Fixed ASN.1 encoding in CRL Distribution Points extension The ASN.1 encoding of the CRL Distribution Points extension showed an invalid false 'IsCompound' which caused a display problem in the Windows certificate viewer. LGTM=agl R=agl CC=golang-codereviews https://golang.org/cl/143320043 --- src/crypto/x509/x509.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index c347fb384d..6e57e913ac 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1328,7 +1328,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { dp := distributionPoint{ DistributionPoint: distributionPointName{ - FullName: asn1.RawValue{Tag: 0, Class: 2, Bytes: rawFullName}, + FullName: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: rawFullName}, }, } crlDp = append(crlDp, dp) From 7210753f1f1b951817c71ceb0af5cefff9c69c31 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 1 Oct 2014 08:30:51 +1000 Subject: [PATCH 260/430] doc: document go1.3.3 LGTM=r R=r CC=golang-codereviews https://golang.org/cl/149280044 --- doc/devel/release.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/devel/release.html b/doc/devel/release.html index f8ffaf716e..1a84391345 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -32,6 +32,11 @@ go1.3.2 (released 2014/09/25) includes bug fixes to cgo and the crypto/tls packa See the change history for details.

+

+go1.3.3 (released 2014/09/30) includes further bug fixes to cgo, the runtime package, and the nacl port. +See the change history for details. +

+

go1.2 (released 2013/12/01)

From 6587557660ac2fece3e2af8b44ca37799cde7b6a Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Wed, 1 Oct 2014 09:16:55 +0900 Subject: [PATCH 261/430] misc/nacl/README: fix typo LGTM=dave R=golang-codereviews, dave CC=golang-codereviews https://golang.org/cl/151870043 --- misc/nacl/README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/misc/nacl/README b/misc/nacl/README index 2044b356b6..72d0e08ad0 100644 --- a/misc/nacl/README +++ b/misc/nacl/README @@ -59,9 +59,9 @@ Support scripts Symlink the two scripts in this directory into your $PATH, just as you did with NaCl sdk above. - % ln -nfs $GOROOT/go/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec - % ln -nfs $GOROOT/go/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec - % ln -nfs $GOROOT/go/misc/nacl/go_nacl_arm_exec $GOPATH/bin/go_nacl_arm_exec + % ln -nfs $GOROOT/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec + % ln -nfs $GOROOT/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec + % ln -nfs $GOROOT/misc/nacl/go_nacl_arm_exec $GOPATH/bin/go_nacl_arm_exec Building and testing -------------------- From 1a1341afed8454c40d86b20aa3950b75c60068ea Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 1 Oct 2014 13:38:00 +1000 Subject: [PATCH 262/430] tag go1.3.3 LGTM=crawshaw R=golang-codereviews, crawshaw CC=golang-codereviews https://golang.org/cl/146610043 --- .hgtags | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.hgtags b/.hgtags index a018693891..5a5c4aed44 100644 --- a/.hgtags +++ b/.hgtags @@ -133,4 +133,5 @@ f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1 9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3 073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1 85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2 -85518b1d6f8d6e16133b9ed2c9db6807522d37de release +f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3 +f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release From 85cdc49e8abed5c48d9b24eedff85e44e38269b9 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 1 Oct 2014 11:17:15 -0700 Subject: [PATCH 263/430] os, syscall: add Unsetenv Also address a TODO, making Clearenv pass through to cgo. Based largely on Minux's earlier https://golang.org/cl/82040044 Fixes #6423 LGTM=iant, alex.brainman, r, rsc R=rsc, iant, r, alex.brainman CC=golang-codereviews https://golang.org/cl/148370043 --- src/os/env.go | 5 ++++ src/os/env_test.go | 26 +++++++++++++++++++++ src/runtime/cgo/gcc_setenv.c | 7 ++++++ src/runtime/cgo/setenv.c | 3 +++ src/runtime/env_posix.go | 13 ++++++++++- src/runtime/thunk.s | 3 +++ src/syscall/env_plan9.go | 38 ++++++++++++++++++++++++++++--- src/syscall/env_unix.go | 44 +++++++++++++++++++++++++++++------- src/syscall/env_windows.go | 8 +++++++ 9 files changed, 135 insertions(+), 12 deletions(-) diff --git a/src/os/env.go b/src/os/env.go index db7fc72b8a..d0494a4763 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -91,6 +91,11 @@ func Setenv(key, value string) error { return nil } +// Unsetenv unsets a single environment variable. +func Unsetenv(key string) error { + return syscall.Unsetenv(key) +} + // Clearenv deletes all environment variables. func Clearenv() { syscall.Clearenv() diff --git a/src/os/env_test.go b/src/os/env_test.go index 991fa4d057..e618067513 100644 --- a/src/os/env_test.go +++ b/src/os/env_test.go @@ -7,6 +7,7 @@ package os_test import ( . "os" "reflect" + "strings" "testing" ) @@ -68,3 +69,28 @@ func TestConsistentEnviron(t *testing.T) { } } } + +func TestUnsetenv(t *testing.T) { + const testKey = "GO_TEST_UNSETENV" + set := func() bool { + prefix := testKey + "=" + for _, key := range Environ() { + if strings.HasPrefix(key, prefix) { + return true + } + } + return false + } + if err := Setenv(testKey, "1"); err != nil { + t.Fatalf("Setenv: %v", err) + } + if !set() { + t.Error("Setenv didn't set TestUnsetenv") + } + if err := Unsetenv(testKey); err != nil { + t.Fatalf("Unsetenv: %v", err) + } + if set() { + t.Fatal("Unsetenv didn't clear TestUnsetenv") + } +} diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c index 8b128b9465..af0fc5d8d8 100644 --- a/src/runtime/cgo/gcc_setenv.c +++ b/src/runtime/cgo/gcc_setenv.c @@ -14,3 +14,10 @@ x_cgo_setenv(char **arg) { setenv(arg[0], arg[1], 1); } + +/* Stub for calling unsetenv */ +void +x_cgo_unsetenv(char *arg) +{ + unsetenv(arg); +} diff --git a/src/runtime/cgo/setenv.c b/src/runtime/cgo/setenv.c index ee529904f7..76d88cbf13 100644 --- a/src/runtime/cgo/setenv.c +++ b/src/runtime/cgo/setenv.c @@ -5,6 +5,9 @@ // +build darwin dragonfly freebsd linux netbsd openbsd #pragma cgo_import_static x_cgo_setenv +#pragma cgo_import_static x_cgo_unsetenv void x_cgo_setenv(char**); void (*runtime·_cgo_setenv)(char**) = x_cgo_setenv; +void x_cgo_unsetenv(char**); +void (*runtime·_cgo_unsetenv)(char**) = x_cgo_unsetenv; diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go index 6c04f6cc70..dd57872d7c 100644 --- a/src/runtime/env_posix.go +++ b/src/runtime/env_posix.go @@ -32,7 +32,8 @@ func gogetenv(key string) string { return "" } -var _cgo_setenv uintptr // pointer to C function +var _cgo_setenv uintptr // pointer to C function +var _cgo_unsetenv uintptr // pointer to C function // Update the C environment if cgo is loaded. // Called from syscall.Setenv. @@ -44,6 +45,16 @@ func syscall_setenv_c(k string, v string) { asmcgocall(unsafe.Pointer(_cgo_setenv), unsafe.Pointer(&arg)) } +// Update the C environment if cgo is loaded. +// Called from syscall.unsetenv. +func syscall_unsetenv_c(k string) { + if _cgo_unsetenv == 0 { + return + } + arg := [1]unsafe.Pointer{cstring(k)} + asmcgocall(unsafe.Pointer(_cgo_unsetenv), unsafe.Pointer(&arg)) +} + func cstring(s string) unsafe.Pointer { p := make([]byte, len(s)+1) sp := (*_string)(unsafe.Pointer(&s)) diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s index d6a2d399e6..0a0f147c4b 100644 --- a/src/runtime/thunk.s +++ b/src/runtime/thunk.s @@ -110,6 +110,9 @@ TEXT net·runtime_pollUnblock(SB),NOSPLIT,$0-0 TEXT syscall·setenv_c(SB), NOSPLIT, $0-0 JMP runtime·syscall_setenv_c(SB) +TEXT syscall·unsetenv_c(SB), NOSPLIT, $0-0 + JMP runtime·syscall_unsetenv_c(SB) + TEXT reflect·makemap(SB),NOSPLIT,$0-0 JMP runtime·reflect_makemap(SB) diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go index 9587ab5af9..3044b410a9 100644 --- a/src/syscall/env_plan9.go +++ b/src/syscall/env_plan9.go @@ -12,16 +12,22 @@ import ( ) var ( - // envOnce guards copyenv, which populates env. + // envOnce guards copyenv, which populates env, envi and envs. envOnce sync.Once - // envLock guards env and envs. + // envLock guards env, envi and envs. envLock sync.RWMutex // env maps from an environment variable to its value. + // TODO: remove this? golang.org/issue/8849 env = make(map[string]string) + // envi maps from an environment variable to its index in envs. + // TODO: remove this? golang.org/issue/8849 + envi = make(map[string]int) + // envs contains elements of env in the form "key=value". + // empty strings mean deleted. envs []string errZeroLengthKey = errors.New("zero length key") @@ -83,6 +89,7 @@ func copyenv() { } env[key] = v envs[i] = key + "=" + v + envi[key] = i i++ } } @@ -129,14 +136,39 @@ func Clearenv() { defer envLock.Unlock() env = make(map[string]string) + envi = make(map[string]int) envs = []string{} RawSyscall(SYS_RFORK, RFCENVG, 0, 0) } +func Unsetenv(key string) error { + if len(key) == 0 { + return errZeroLengthKey + } + + envLock.Lock() + defer envLock.Unlock() + + Remove("/env/" + key) + + if i, ok := envi[key]; ok { + delete(env, key) + delete(envi, key) + envs[i] = "" + } + return nil +} + func Environ() []string { envLock.RLock() defer envLock.RUnlock() envOnce.Do(copyenv) - return append([]string(nil), envs...) + ret := make([]string, 0, len(envs)) + for _, pair := range envs { + if pair != "" { + ret = append(ret, pair) + } + } + return ret } diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go index 01ac38af13..b5ded9c763 100644 --- a/src/syscall/env_unix.go +++ b/src/syscall/env_unix.go @@ -20,16 +20,18 @@ var ( // env maps from an environment variable to its first occurrence in envs. env map[string]int - // envs is provided by the runtime. elements are expected to be - // of the form "key=value". + // envs is provided by the runtime. elements are expected to + // be of the form "key=value". An empty string means deleted + // (or a duplicate to be ignored). envs []string = runtime_envs() ) func runtime_envs() []string // in package runtime -// setenv_c is provided by the runtime, but is a no-op if cgo isn't -// loaded. +// setenv_c and unsetenv_c are provided by the runtime but are no-ops +// if cgo isn't loaded. func setenv_c(k, v string) +func unsetenv_c(k string) func copyenv() { env = make(map[string]int) @@ -38,7 +40,13 @@ func copyenv() { if s[j] == '=' { key := s[:j] if _, ok := env[key]; !ok { - env[key] = i + env[key] = i // first mention of key + } else { + // Clear duplicate keys. This permits Unsetenv to + // safely delete only the first item without + // worrying about unshadowing a later one, + // which might be a security problem. + envs[i] = "" } break } @@ -46,6 +54,20 @@ func copyenv() { } } +func Unsetenv(key string) error { + envOnce.Do(copyenv) + + envLock.Lock() + defer envLock.Unlock() + + if i, ok := env[key]; ok { + envs[i] = "" + delete(env, key) + } + unsetenv_c(key) + return nil +} + func Getenv(key string) (value string, found bool) { envOnce.Do(copyenv) if len(key) == 0 { @@ -106,16 +128,22 @@ func Clearenv() { envLock.Lock() defer envLock.Unlock() + for k := range env { + unsetenv_c(k) + } env = make(map[string]int) envs = []string{} - // TODO(bradfitz): pass through to C } func Environ() []string { envOnce.Do(copyenv) envLock.RLock() defer envLock.RUnlock() - a := make([]string, len(envs)) - copy(a, envs) + a := make([]string, 0, len(envs)) + for _, env := range envs { + if env != "" { + a = append(a, env) + } + } return a } diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go index 420b387246..bc21690d9f 100644 --- a/src/syscall/env_windows.go +++ b/src/syscall/env_windows.go @@ -47,6 +47,14 @@ func Setenv(key, value string) error { return nil } +func Unsetenv(key string) error { + keyp, err := UTF16PtrFromString(key) + if err != nil { + return err + } + return SetEnvironmentVariable(keyp, nil) +} + func Clearenv() { for _, s := range Environ() { // Environment variables can begin with = From cd5b785efe3cf67a8e065f8ff2ee8a39badbec40 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 1 Oct 2014 13:18:44 -0700 Subject: [PATCH 264/430] net/rpc: shut down connection if gob has error The nicest solution would be to buffer the message and only write it if it encodes correctly, but that adds considerable memory and CPU overhead for a very rare condition. Instead, we just shut down the connection if this happens. Fixes #7689. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/146670043 --- src/net/rpc/server.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go index 6b264b46b8..83728d55a1 100644 --- a/src/net/rpc/server.go +++ b/src/net/rpc/server.go @@ -395,6 +395,7 @@ type gobServerCodec struct { dec *gob.Decoder enc *gob.Encoder encBuf *bufio.Writer + closed bool } func (c *gobServerCodec) ReadRequestHeader(r *Request) error { @@ -407,15 +408,32 @@ func (c *gobServerCodec) ReadRequestBody(body interface{}) error { func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) { if err = c.enc.Encode(r); err != nil { + if c.encBuf.Flush() == nil { + // Gob couldn't encode the header. Should not happen, so if it does, + // shut down the connection to signal that the connection is broken. + log.Println("rpc: gob error encoding response:", err) + c.Close() + } return } if err = c.enc.Encode(body); err != nil { + if c.encBuf.Flush() == nil { + // Was a gob problem encoding the body but the header has been written. + // Shut down the connection to signal that the connection is broken. + log.Println("rpc: gob error encoding body:", err) + c.Close() + } return } return c.encBuf.Flush() } func (c *gobServerCodec) Close() error { + if c.closed { + // Only call c.rwc.Close once; otherwise the semantics are undefined. + return nil + } + c.closed = true return c.rwc.Close() } @@ -426,7 +444,12 @@ func (c *gobServerCodec) Close() error { // connection. To use an alternate codec, use ServeCodec. func (server *Server) ServeConn(conn io.ReadWriteCloser) { buf := bufio.NewWriter(conn) - srv := &gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(buf), buf} + srv := &gobServerCodec{ + rwc: conn, + dec: gob.NewDecoder(conn), + enc: gob.NewEncoder(buf), + encBuf: buf, + } server.ServeCodec(srv) } From 5edff3270479962ca67769947eb66adbe75e7fb4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Oct 2014 13:19:40 -0700 Subject: [PATCH 265/430] testing: clearer comment Fixes #8797. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/146680043 --- src/testing/testing.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testing/testing.go b/src/testing/testing.go index 21460b0ed4..f91d860a94 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -44,7 +44,7 @@ // } // // The benchmark function must run the target code b.N times. -// The benchmark package will vary b.N until the benchmark function lasts +// During benchark execution, b.N is adjusted until the benchmark function lasts // long enough to be timed reliably. The output // BenchmarkHello 10000000 282 ns/op // means that the loop ran 10000000 times at a speed of 282 ns per loop. From 62d3202aaa0fb131be1f0dbf21e97dbe11b177dc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 1 Oct 2014 16:51:32 -0400 Subject: [PATCH 266/430] reflect: fix IsValid vs Kind mismatch after Elem of nil interface LGTM=r R=r CC=golang-codereviews https://golang.org/cl/151960044 --- src/reflect/all_test.go | 14 ++++++++++++++ src/reflect/value.go | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index b72c4b176d..d17ef5c5e9 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -3939,3 +3939,17 @@ func TestValueString(t *testing.T) { t.Errorf("ValueOf(Impl{}).Method(0).String() = %q, want %q", method.String(), "") } } + +func TestInvalid(t *testing.T) { + // Used to have inconsistency between IsValid() and Kind() != Invalid. + type T struct{ v interface{} } + + v := ValueOf(T{}).Field(0) + if v.IsValid() != true || v.Kind() != Interface { + t.Errorf("field: IsValid=%v, Kind=%v, want true, Interface", v.IsValid(), v.Kind()) + } + v = v.Elem() + if v.IsValid() != false || v.Kind() != Invalid { + t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind()) + } +} diff --git a/src/reflect/value.go b/src/reflect/value.go index 12d423f3c3..9c65ee2703 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -791,7 +791,9 @@ func (v Value) Elem() Value { })(v.ptr)) } x := unpackEface(eface) - x.flag |= v.flag & flagRO + if x.flag != 0 { + x.flag |= v.flag & flagRO + } return x case Ptr: ptr := v.ptr From 9f4084278fd0038ef4deedab78ee4d7d2bc1a636 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 1 Oct 2014 21:35:12 +0000 Subject: [PATCH 267/430] fmt: fix internal unknownType function This thing should never be called, but before 151960044 it was being called, incorrectly. This is now just a precaution but let's pretend it Fixes #8843 even though that was fixed by 151960044. The test case was already there and ran, another mystery. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/151970043 --- src/fmt/print.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fmt/print.go b/src/fmt/print.go index 679c577dbd..de69e90fb7 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -297,13 +297,13 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) { return } -func (p *pp) unknownType(v interface{}) { - if v == nil { +func (p *pp) unknownType(v reflect.Value) { + if !v.IsValid() { p.buf.Write(nilAngleBytes) return } p.buf.WriteByte('?') - p.buf.WriteString(reflect.TypeOf(v).String()) + p.buf.WriteString(v.Type().String()) p.buf.WriteByte('?') } From dba2faf2c60bd3bf249641c7f09af2cbc984f645 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Wed, 1 Oct 2014 15:25:56 -0700 Subject: [PATCH 268/430] doc/go_faq.html: explain the policy about unused imports a little better This new text won't stop the whining but it might focus the whining a little more. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/146680044 --- doc/go_faq.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/go_faq.html b/doc/go_faq.html index 5813e1d047..ec3689aeb0 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -1661,14 +1661,17 @@ Can I stop these complaints about my unused variable/import?

The presence of an unused variable may indicate a bug, while -unused imports just slow down compilation. -Accumulate enough unused imports in your code tree and -things can get very slow. -For these reasons, Go allows neither. +unused imports just slow down compilation, +an effect that can become substantial as a program accumulates +code and programmers over time. +For these reasons, Go refuses to compile programs with unused +variables or imports, +trading short-term convenience for long-term build speed and +program clarity.

-When developing code, it's common to create these situations +Still, when developing code, it's common to create these situations temporarily and it can be annoying to have to edit them out before the program will compile.

From 94f3d8cfed14e4bcb99a0389ea083cfc2ae3ab1d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Oct 2014 16:09:55 -0700 Subject: [PATCH 269/430] encoding/binary: slightly better documentation Fixes #7306. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/153820044 --- src/encoding/binary/binary.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index a5694876ac..b5a377430f 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -10,9 +10,10 @@ // type (int8, uint8, int16, float32, complex64, ...) // or an array or struct containing only fixed-size values. // -// Varints are a method of encoding integers using one or more bytes; -// numbers with smaller absolute value take a smaller number of bytes. -// For a specification, see http://code.google.com/apis/protocolbuffers/docs/encoding.html. +// The varint functions encode and decode single integer values using +// a variable-length encoding; smaller values require fewer bytes. +// For a specification, see +// http://code.google.com/apis/protocolbuffers/docs/encoding.html. // // This package favors simplicity over efficiency. Clients that require // high-performance serialization, especially for large data structures, From 7e8218aedd30a3dacb2642ef37ff1f68657071b2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Oct 2014 16:24:17 -0700 Subject: [PATCH 270/430] encoding/json: don't panic on incorrect map argument Fixes #8305. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/145680044 --- src/encoding/json/decode.go | 6 ++++-- src/encoding/json/decode_test.go | 12 +++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index af1c908ad7..67ec37388f 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -445,7 +445,7 @@ func (d *decodeState) array(v reflect.Value) { } // object consumes an object from d.data[d.off-1:], decoding into the value v. -// the first byte of the object ('{') has been read already. +// the first byte ('{') of the object has been read already. func (d *decodeState) object(v reflect.Value) { // Check for unmarshaler. u, ut, pv := d.indirect(v, false) @@ -478,7 +478,9 @@ func (d *decodeState) object(v reflect.Value) { t := v.Type() if t.Key().Kind() != reflect.String { d.saveError(&UnmarshalTypeError{"object", v.Type()}) - break + d.off-- + d.next() // skip over { } in input + return } if v.IsNil() { v.Set(reflect.MakeMap(t)) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 238a87fd66..d95657d729 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -406,6 +406,13 @@ var unmarshalTests = []unmarshalTest{ ptr: new(string), out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", }, + + // issue 8305 + { + in: `{"2009-11-10T23:00:00Z": "hello world"}`, + ptr: &map[time.Time]string{}, + err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})}, + }, } func TestMarshal(t *testing.T) { @@ -514,6 +521,7 @@ func TestUnmarshal(t *testing.T) { if tt.ptr == nil { continue } + // v = new(right-type) v := reflect.New(reflect.TypeOf(tt.ptr).Elem()) dec := NewDecoder(bytes.NewReader(in)) @@ -521,7 +529,9 @@ func TestUnmarshal(t *testing.T) { dec.UseNumber() } if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) { - t.Errorf("#%d: %v want %v", i, err, tt.err) + t.Errorf("#%d: %v, want %v", i, err, tt.err) + continue + } else if err != nil { continue } if !reflect.DeepEqual(v.Elem().Interface(), tt.out) { From bc89e8c575be08ef261a4d76db14f7f65a6da923 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 1 Oct 2014 16:44:52 -0700 Subject: [PATCH 271/430] time: A Timer must be properly created before use (documentation). Fixes #8776. LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/145710043 --- src/time/sleep.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/time/sleep.go b/src/time/sleep.go index 33c349de46..61660d14ff 100644 --- a/src/time/sleep.go +++ b/src/time/sleep.go @@ -43,6 +43,7 @@ func stopTimer(*runtimeTimer) bool // The Timer type represents a single event. // When the Timer expires, the current time will be sent on C, // unless the Timer was created by AfterFunc. +// A Timer must be created with NewTimer or AfterFunc. type Timer struct { C <-chan Time r runtimeTimer From 714461740cafdcdc16e675f761544022dc25c723 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 2 Oct 2014 16:15:36 +1000 Subject: [PATCH 272/430] run.bat: comment text properly LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/153830044 --- src/run.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/run.bat b/src/run.bat index 309e06d507..14c1b45fda 100644 --- a/src/run.bat +++ b/src/run.bat @@ -90,7 +90,7 @@ go run "%GOROOT%\test\run.go" - ..\misc\cgo\stdio if errorlevel 1 goto fail echo. -# cgo tests inspect the traceback for runtime functions +:: cgo tests inspect the traceback for runtime functions set OLDGOTRACEBACK=%GOTRACEBACK% set GOTRACEBACK=2 From e9d5fca9f30dc92dd659ce88030f9a5f4676b142 Mon Sep 17 00:00:00 2001 From: Nicolas Owens Date: Thu, 2 Oct 2014 10:25:56 +0200 Subject: [PATCH 273/430] syscall: fix Setenv for plan 9 envi needs to be updated during Setenv so the key can be correctly deleted later with Unsetenv. Update #8849. LGTM=0intro R=bradfitz, 0intro CC=golang-codereviews https://golang.org/cl/149300046 --- src/syscall/env_plan9.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go index 3044b410a9..9345079052 100644 --- a/src/syscall/env_plan9.go +++ b/src/syscall/env_plan9.go @@ -128,6 +128,7 @@ func Setenv(key, value string) error { } env[key] = value envs = append(envs, key+"="+value) + envi[key] = len(envs) - 1 return nil } From ea491c5f96697cd6fc9852dd86efc3788d0664ee Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 2 Oct 2014 11:36:39 -0700 Subject: [PATCH 274/430] A+C: add Mrunal Patel (Red Hat corporate CLA) LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/152010043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 9f41e5f285..f22fe4c982 100644 --- a/AUTHORS +++ b/AUTHORS @@ -360,6 +360,7 @@ Pietro Gagliardi Preetam Jinka Quan Yong Zhai Raif S. Naffah +Red Hat, Inc. Rémy Oudompheng Richard Crowley Richard Eric Gavaletz diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 2c7ac66a0a..5dadda0ca4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -437,6 +437,7 @@ Mikkel Krautz Miquel Sabaté Solà Moriyoshi Koizumi Môshe van der Sterre +Mrunal Patel Nan Deng Nathan John Youngman Nicholas Katsaros From f9d7e139552b186f4c68a3a87b470847167a9076 Mon Sep 17 00:00:00 2001 From: Mrunal Patel Date: Thu, 2 Oct 2014 11:37:06 -0700 Subject: [PATCH 275/430] syscall: support UID/GID map files for Linux user namespaces Fixes #8447. LGTM=iant R=golang-codereviews, bradfitz, iant CC=golang-codereviews https://golang.org/cl/126190043 --- src/syscall/exec_linux.go | 123 ++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index f61dfc424a..72e2f0b69c 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -10,19 +10,29 @@ import ( "unsafe" ) +// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. +// See user_namespaces(7). +type SysProcIDMap struct { + ContainerID int // Container ID. + HostID int // Host ID. + Size int // Size. +} + type SysProcAttr struct { - Chroot string // Chroot. - Credential *Credential // Credential. - Ptrace bool // Enable tracing. - Setsid bool // Create session. - Setpgid bool // Set process group ID to new pid (SYSV setpgrp) - Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd (Linux only) - Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) - Cloneflags uintptr // Flags for clone calls (Linux only) - Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) - Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) + Chroot string // Chroot. + Credential *Credential // Credential. + Ptrace bool // Enable tracing. + Setsid bool // Create session. + Setpgid bool // Set process group ID to new pid (SYSV setpgrp) + Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd (Linux only) + Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) + Cloneflags uintptr // Flags for clone calls (Linux only) + Foreground bool // Set foreground process group to child's pid. (Implies Setpgid. Stdin should be a TTY) + Joinpgrp int // If != 0, child's process group ID. (Setpgid must not be set) + UidMappings []SysProcIDMap // User ID mappings for user namespaces. + GidMappings []SysProcIDMap // Group ID mappings for user namespaces. } // Implemented in runtime package. @@ -44,8 +54,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr var ( r1 uintptr err1 Errno + err2 Errno nextfd int i int + p [2]int ) // Guard against side effects of shuffling fds below. @@ -61,6 +73,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } nextfd++ + // Allocate another pipe for parent to child communication for + // synchronizing writing of User ID/Group ID mappings. + if sys.UidMappings != nil || sys.GidMappings != nil { + if err := forkExecPipe(p[:]); err != nil { + return 0, err.(Errno) + } + } + // About to call fork. // No more allocation or calls of non-assembly functions. runtime_BeforeFork() @@ -75,6 +95,16 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr runtime_AfterFork() pid = int(r1) + if sys.UidMappings != nil || sys.GidMappings != nil { + Close(p[0]) + err := writeUidGidMappings(pid, sys) + if err != nil { + err2 = err.(Errno) + } + RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) + Close(p[1]) + } + if sys.Joinpgrp != 0 { // Place the child in the specified process group. RawSyscall(SYS_SETPGID, r1, uintptr(sys.Joinpgrp), 0) @@ -93,6 +123,25 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // Fork succeeded, now in child. + // Wait for User ID/Group ID mappings to be written. + if sys.UidMappings != nil || sys.GidMappings != nil { + if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 { + goto childerror + } + r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) + if err1 != 0 { + goto childerror + } + if r1 != unsafe.Sizeof(err2) { + err1 = EINVAL + goto childerror + } + if err2 != 0 { + err1 = err2 + goto childerror + } + } + // Parent death signal if sys.Pdeathsig != 0 { _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0) @@ -296,3 +345,53 @@ func forkExecPipe(p []int) (err error) { } return } + +// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path. +func writeIDMappings(path string, idMap []SysProcIDMap) error { + fd, err := Open(path, O_RDWR, 0) + if err != nil { + return err + } + + data := "" + for _, im := range idMap { + data = data + itoa(im.ContainerID) + " " + itoa(im.HostID) + " " + itoa(im.Size) + "\n" + } + + bytes, err := ByteSliceFromString(data) + if err != nil { + Close(fd) + return err + } + + if _, err := Write(fd, bytes); err != nil { + Close(fd) + return err + } + + if err := Close(fd); err != nil { + return err + } + + return nil +} + +// writeUidGidMappings writes User ID and Group ID mappings for user namespaces +// for a process and it is called from the parent process. +func writeUidGidMappings(pid int, sys *SysProcAttr) error { + if sys.UidMappings != nil { + uidf := "/proc/" + itoa(pid) + "/uid_map" + if err := writeIDMappings(uidf, sys.UidMappings); err != nil { + return err + } + } + + if sys.GidMappings != nil { + gidf := "/proc/" + itoa(pid) + "/gid_map" + if err := writeIDMappings(gidf, sys.GidMappings); err != nil { + return err + } + } + + return nil +} From 1dba6eb4645f0528ed1ce5e0dd5a4661afa8bd07 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 2 Oct 2014 12:53:51 -0700 Subject: [PATCH 276/430] encoding/binary: fix error message In the process, simplified internal sizeOf and dataSize functions. Minor positive impact on performance. Added test case. benchmark old ns/op new ns/op delta BenchmarkReadSlice1000Int32s 14006 14122 +0.83% BenchmarkReadStruct 2508 2447 -2.43% BenchmarkReadInts 921 928 +0.76% BenchmarkWriteInts 2086 2081 -0.24% BenchmarkWriteSlice1000Int32s 13440 13497 +0.42% BenchmarkPutUvarint32 28.5 26.3 -7.72% BenchmarkPutUvarint64 81.3 76.7 -5.66% benchmark old MB/s new MB/s speedup BenchmarkReadSlice1000Int32s 285.58 283.24 0.99x BenchmarkReadStruct 27.90 28.60 1.03x BenchmarkReadInts 32.57 32.31 0.99x BenchmarkWriteInts 14.38 14.41 1.00x BenchmarkWriteSlice1000Int32s 297.60 296.36 1.00x BenchmarkPutUvarint32 140.55 151.92 1.08x BenchmarkPutUvarint64 98.36 104.33 1.06x Fixes #6818. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/149290045 --- src/encoding/binary/binary.go | 70 ++++++++++++++---------------- src/encoding/binary/binary_test.go | 23 +++++++++- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index b5a377430f..466bf97c97 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -200,18 +200,17 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error { } // Fallback to reflect-based decoding. - var v reflect.Value - switch d := reflect.ValueOf(data); d.Kind() { + v := reflect.ValueOf(data) + size := -1 + switch v.Kind() { case reflect.Ptr: - v = d.Elem() + v = v.Elem() + size = dataSize(v) case reflect.Slice: - v = d - default: - return errors.New("binary.Read: invalid type " + d.Type().String()) + size = dataSize(v) } - size, err := dataSize(v) - if err != nil { - return errors.New("binary.Read: " + err.Error()) + if size < 0 { + return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String()) } d := &decoder{order: order, buf: make([]byte, size)} if _, err := io.ReadFull(r, d.buf); err != nil { @@ -324,68 +323,64 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error { // Fallback to reflect-based encoding. v := reflect.Indirect(reflect.ValueOf(data)) - size, err := dataSize(v) - if err != nil { - return errors.New("binary.Write: " + err.Error()) + size := dataSize(v) + if size < 0 { + return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String()) } buf := make([]byte, size) e := &encoder{order: order, buf: buf} e.value(v) - _, err = w.Write(buf) + _, err := w.Write(buf) return err } // Size returns how many bytes Write would generate to encode the value v, which // must be a fixed-size value or a slice of fixed-size values, or a pointer to such data. +// If v is neither of these, Size returns -1. func Size(v interface{}) int { - n, err := dataSize(reflect.Indirect(reflect.ValueOf(v))) - if err != nil { - return -1 - } - return n + return dataSize(reflect.Indirect(reflect.ValueOf(v))) } // dataSize returns the number of bytes the actual data represented by v occupies in memory. // For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice // it returns the length of the slice times the element size and does not count the memory -// occupied by the header. -func dataSize(v reflect.Value) (int, error) { +// occupied by the header. If the type of v is not acceptable, dataSize returns -1. +func dataSize(v reflect.Value) int { if v.Kind() == reflect.Slice { - elem, err := sizeof(v.Type().Elem()) - if err != nil { - return 0, err + if s := sizeof(v.Type().Elem()); s >= 0 { + return s * v.Len() } - return v.Len() * elem, nil + return -1 } return sizeof(v.Type()) } -func sizeof(t reflect.Type) (int, error) { +// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable. +func sizeof(t reflect.Type) int { switch t.Kind() { case reflect.Array: - n, err := sizeof(t.Elem()) - if err != nil { - return 0, err + if s := sizeof(t.Elem()); s >= 0 { + return s * t.Len() } - return t.Len() * n, nil case reflect.Struct: sum := 0 for i, n := 0, t.NumField(); i < n; i++ { - s, err := sizeof(t.Field(i).Type) - if err != nil { - return 0, err + s := sizeof(t.Field(i).Type) + if s < 0 { + return -1 } sum += s } - return sum, nil + return sum case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: - return int(t.Size()), nil + return int(t.Size()) } - return 0, errors.New("invalid type " + t.String()) + + return -1 } type coder struct { @@ -595,12 +590,11 @@ func (e *encoder) value(v reflect.Value) { } func (d *decoder) skip(v reflect.Value) { - n, _ := dataSize(v) - d.buf = d.buf[n:] + d.buf = d.buf[dataSize(v):] } func (e *encoder) skip(v reflect.Value) { - n, _ := dataSize(v) + n := dataSize(v) for i := range e.buf[0:n] { e.buf[i] = 0 } diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go index c80c90383a..8ee595fa47 100644 --- a/src/encoding/binary/binary_test.go +++ b/src/encoding/binary/binary_test.go @@ -289,6 +289,26 @@ func TestUnexportedRead(t *testing.T) { Read(&buf, LittleEndian, &u2) } +func TestReadErrorMsg(t *testing.T) { + var buf bytes.Buffer + read := func(data interface{}) { + err := Read(&buf, LittleEndian, data) + want := "binary.Read: invalid type " + reflect.TypeOf(data).String() + if err == nil { + t.Errorf("%T: got no error; want %q", data, want) + return + } + if got := err.Error(); got != want { + t.Errorf("%T: got %q; want %q", data, got, want) + } + } + read(0) + s := new(struct{}) + read(&s) + p := &s + read(&p) +} + type byteSliceReader struct { remain []byte } @@ -315,8 +335,7 @@ func BenchmarkReadStruct(b *testing.B) { bsr := &byteSliceReader{} var buf bytes.Buffer Write(&buf, BigEndian, &s) - n, _ := dataSize(reflect.ValueOf(s)) - b.SetBytes(int64(n)) + b.SetBytes(int64(dataSize(reflect.ValueOf(s)))) t := s b.ResetTimer() for i := 0; i < b.N; i++ { From 28ddfb090c2824d60e30007cf171b5dc1e8935e2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 2 Oct 2014 13:02:25 -0700 Subject: [PATCH 277/430] math/big: math.Exp should return result >= 0 for |m| > 0 The documentation states that Exp(x, y, m) computes x**y mod |m| for m != nil && m > 0. In math.big, Mod is the Euclidean modulus, which is always >= 0. Fixes #8822. LGTM=agl, r, rsc R=agl, r, rsc CC=golang-codereviews https://golang.org/cl/145650043 --- src/math/big/int.go | 6 ++++++ src/math/big/int_test.go | 14 +++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/math/big/int.go b/src/math/big/int.go index e70d0489be..3998652e93 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -605,6 +605,12 @@ func (z *Int) Exp(x, y, m *Int) *Int { z.abs = z.abs.expNN(x.abs, yWords, mWords) z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign + if z.neg && len(mWords) > 0 { + // make modulus result positive + z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m| + z.neg = false + } + return z } diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go index 299dc72fb1..ec05fbb1c0 100644 --- a/src/math/big/int_test.go +++ b/src/math/big/int_test.go @@ -787,6 +787,7 @@ var expTests = []struct { {"-5", "0", "", "1"}, {"5", "1", "", "5"}, {"-5", "1", "", "-5"}, + {"-5", "1", "7", "2"}, {"-2", "3", "2", "0"}, {"5", "2", "", "25"}, {"1", "65537", "2", "1"}, @@ -802,6 +803,13 @@ var expTests = []struct { "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464", "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291", }, + // test case for issue 8822 + { + "-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B988E23D4D954F322C3540541BC649ABD504C50FADFD9F0987D58A2BF689313A285E773FF02899A6EF887D1D4A0D2", + "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD", + "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", + "21484252197776302499639938883777710321993113097987201050501182909581359357618579566746556372589385361683610524730509041328855066514963385522570894839035884713051640171474186548713546686476761306436434146475140156284389181808675016576845833340494848283681088886584219750554408060556769486628029028720727393293111678826356480455433909233520504112074401376133077150471237549474149190242010469539006449596611576612573955754349042329130631128234637924786466585703488460540228477440853493392086251021228087076124706778899179648655221663765993962724699135217212118535057766739392069738618682722216712319320435674779146070442", + }, } func TestExp(t *testing.T) { @@ -833,12 +841,12 @@ func TestExp(t *testing.T) { } if m == nil { - // the result should be the same as for m == 0; - // specifically, there should be no div-zero panic + // The result should be the same as for m == 0; + // specifically, there should be no div-zero panic. m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0 z2 := new(Int).Exp(x, y, m) if z2.Cmp(z1) != 0 { - t.Errorf("#%d: got %s want %s", i, z1, z2) + t.Errorf("#%d: got %s want %s", i, z2, z1) } } } From 7c8e057ad3b4fed16719d9ef91936537dff90ecd Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 2 Oct 2014 14:16:58 -0700 Subject: [PATCH 278/430] fmt: make the %#v verb a special flag The %#v verb is special: it says all values below need to print as %#v. However, for some situations the # flag has other meanings and this causes some issues, particularly in how Formatters work. Since %#v dominates all formatting, translate it into actual state of the formatter and decouple it from the # flag itself within the calculations (although it must be restored when methods are doing the work.) The result is cleaner code and correct handling of # for Formatters. TODO: Apply the same thinking to the + flag in a followup CL. Also, the wasString return value in handleMethods is always false, so eliminate it. Update #8835 LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/146650043 --- src/fmt/fmt_test.go | 95 +++++++++++++++++++++++- src/fmt/format.go | 12 ++- src/fmt/print.go | 173 ++++++++++++++++++++++++-------------------- 3 files changed, 196 insertions(+), 84 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 4586fcf933..f3b527d1ff 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -1144,10 +1144,10 @@ var panictests = []struct { } func TestPanics(t *testing.T) { - for _, tt := range panictests { + for i, tt := range panictests { s := Sprintf(tt.fmt, tt.in) if s != tt.out { - t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out) + t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) } } } @@ -1207,3 +1207,94 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) } } + +// Formatters did not get delivered flags correctly in all cases. Issue 8835. +type fp struct{} + +func (fp) Format(f State, c rune) { + s := "%" + for i := 0; i < 128; i++ { + if f.Flag(i) { + s += string(i) + } + } + if w, ok := f.Width(); ok { + s += Sprintf("%d", w) + } + if p, ok := f.Precision(); ok { + s += Sprintf(".%d", p) + } + s += string(c) + io.WriteString(f, "["+s+"]") +} + +var formatterFlagTests = []struct { + in string + val interface{} + out string +}{ + // scalar values with the (unused by fmt) 'a' verb. + {"%a", fp{}, "[%a]"}, + {"%-a", fp{}, "[%-a]"}, + {"%+a", fp{}, "[%+a]"}, + {"%#a", fp{}, "[%#a]"}, + {"% a", fp{}, "[% a]"}, + {"%0a", fp{}, "[%0a]"}, + {"%1.2a", fp{}, "[%1.2a]"}, + {"%-1.2a", fp{}, "[%-1.2a]"}, + {"%+1.2a", fp{}, "[%+1.2a]"}, + {"%-+1.2a", fp{}, "[%+-1.2a]"}, + {"%-+1.2abc", fp{}, "[%+-1.2a]bc"}, + {"%-1.2abc", fp{}, "[%-1.2a]bc"}, + + // composite values with the 'a' verb + {"%a", [1]fp{}, "[[%a]]"}, + {"%-a", [1]fp{}, "[[%-a]]"}, + {"%+a", [1]fp{}, "[[%+a]]"}, + {"%#a", [1]fp{}, "[[%#a]]"}, + {"% a", [1]fp{}, "[[% a]]"}, + {"%0a", [1]fp{}, "[[%0a]]"}, + {"%1.2a", [1]fp{}, "[[%1.2a]]"}, + {"%-1.2a", [1]fp{}, "[[%-1.2a]]"}, + {"%+1.2a", [1]fp{}, "[[%+1.2a]]"}, + {"%-+1.2a", [1]fp{}, "[[%+-1.2a]]"}, + {"%-+1.2abc", [1]fp{}, "[[%+-1.2a]]bc"}, + {"%-1.2abc", [1]fp{}, "[[%-1.2a]]bc"}, + + // simple values with the 'v' verb + {"%v", fp{}, "[%v]"}, + {"%-v", fp{}, "[%-v]"}, + {"%+v", fp{}, "[%+v]"}, + {"%#v", fp{}, "[%#v]"}, + {"% v", fp{}, "[% v]"}, + {"%0v", fp{}, "[%0v]"}, + {"%1.2v", fp{}, "[%1.2v]"}, + {"%-1.2v", fp{}, "[%-1.2v]"}, + {"%+1.2v", fp{}, "[%+1.2v]"}, + {"%-+1.2v", fp{}, "[%+-1.2v]"}, + {"%-+1.2vbc", fp{}, "[%+-1.2v]bc"}, + {"%-1.2vbc", fp{}, "[%-1.2v]bc"}, + + // composite values with the 'v' verb. Some are still broken. + {"%v", [1]fp{}, "[[%v]]"}, + {"%-v", [1]fp{}, "[[%-v]]"}, + //{"%+v", [1]fp{}, "[[%+v]]"}, + {"%#v", [1]fp{}, "[1]fmt_test.fp{[%#v]}"}, + {"% v", [1]fp{}, "[[% v]]"}, + {"%0v", [1]fp{}, "[[%0v]]"}, + {"%1.2v", [1]fp{}, "[[%1.2v]]"}, + {"%-1.2v", [1]fp{}, "[[%-1.2v]]"}, + //{"%+1.2v", [1]fp{}, "[[%+1.2v]]"}, + //{"%-+1.2v", [1]fp{}, "[[%+-1.2v]]"}, + //{"%-+1.2vbc", [1]fp{}, "[[%+-1.2v]]bc"}, + {"%-1.2vbc", [1]fp{}, "[[%-1.2v]]bc"}, +} + +func TestFormatterFlags(t *testing.T) { + for _, tt := range formatterFlagTests { + s := Sprintf(tt.in, tt.val) + if s != tt.out { + t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out) + } + } +} diff --git a/src/fmt/format.go b/src/fmt/format.go index a92f3c2f86..355b732622 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -49,9 +49,14 @@ type fmt struct { plus bool sharp bool space bool - unicode bool - uniQuote bool // Use 'x'= prefix for %U if printable. - zero bool + // For the format %#v, we set this flag and + // clear the plus flag, since it is in effect + // a different, flagless format set at the top level. + // TODO: plusV could use this too. + sharpV bool + unicode bool + uniQuote bool // Use 'x'= prefix for %U if printable. + zero bool } func (f *fmt) clearflags() { @@ -63,6 +68,7 @@ func (f *fmt) clearflags() { f.plus = false f.sharp = false f.space = false + f.sharpV = false f.unicode = false f.uniQuote = false f.zero = false diff --git a/src/fmt/print.go b/src/fmt/print.go index de69e90fb7..f141d39daf 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -317,11 +317,11 @@ func (p *pp) badVerb(verb rune) { case p.arg != nil: p.buf.WriteString(reflect.TypeOf(p.arg).String()) p.add('=') - p.printArg(p.arg, 'v', false, false, 0) + p.printArg(p.arg, 'v', false, 0) case p.value.IsValid(): p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printValue(p.value, 'v', false, false, 0) + p.printValue(p.value, 'v', false, 0) default: p.buf.Write(nilAngleBytes) } @@ -406,7 +406,7 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.sharp = sharp } -func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { +func (p *pp) fmtUint64(v uint64, verb rune) { switch verb { case 'b': p.fmt.integer(int64(v), 2, unsigned, ldigits) @@ -415,7 +415,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) { case 'd': p.fmt.integer(int64(v), 10, unsigned, ldigits) case 'v': - if goSyntax { + if p.fmt.sharpV { p.fmt0x64(v, true) } else { p.fmt.integer(int64(v), 10, unsigned, ldigits) @@ -499,10 +499,10 @@ func (p *pp) fmtComplex128(v complex128, verb rune) { } } -func (p *pp) fmtString(v string, verb rune, goSyntax bool) { +func (p *pp) fmtString(v string, verb rune) { switch verb { case 'v': - if goSyntax { + if p.fmt.sharpV { p.fmt.fmt_q(v) } else { p.fmt.fmt_s(v) @@ -520,9 +520,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) { } } -func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) { +func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) { if verb == 'v' || verb == 'd' { - if goSyntax { + if p.fmt.sharpV { if v == nil { if typ == nil { p.buf.WriteString("[]byte(nil)") @@ -543,15 +543,15 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept } for i, c := range v { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printArg(c, 'v', p.fmt.plus, goSyntax, depth+1) + p.printArg(c, 'v', p.fmt.plus, depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') @@ -572,7 +572,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, dept } } -func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { +func (p *pp) fmtPointer(value reflect.Value, verb rune) { use0x64 := true switch verb { case 'p', 'v': @@ -594,7 +594,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { return } - if goSyntax { + if p.fmt.sharpV { p.add('(') p.buf.WriteString(value.Type().String()) p.add(')') @@ -611,7 +611,7 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) { if use0x64 { p.fmt0x64(uint64(u), !p.fmt.sharp) } else { - p.fmtUint64(uint64(u), verb, false) + p.fmtUint64(uint64(u), verb) } } } @@ -636,24 +636,44 @@ func (p *pp) catchPanic(arg interface{}, verb rune) { // Nested panics; the recursion in printArg cannot succeed. panic(err) } + p.fmt.clearflags() // We are done, and for this output we want default behavior. p.buf.Write(percentBangBytes) p.add(verb) p.buf.Write(panicBytes) p.panicking = true - p.printArg(err, 'v', false, false, 0) + p.printArg(err, 'v', false, 0) p.panicking = false p.buf.WriteByte(')') } } -func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) { +// clearSpecialFlags pushes %#v back into the regular flags and returns their old state. +func (p *pp) clearSpecialFlags() bool { + ret := p.fmt.sharpV + if ret { + p.fmt.sharp = true + p.fmt.sharpV = false + } + return ret +} + +// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags, +// restores the setting of the sharpV flag. +func (p *pp) restoreSpecialFlags(sharpV bool) { + if sharpV { + p.fmt.sharp = false + p.fmt.sharpV = true + } +} + +func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) { if p.erroring { return } // Is it a Formatter? if formatter, ok := p.arg.(Formatter); ok { handled = true - wasString = false + defer p.restoreSpecialFlags(p.clearSpecialFlags()) defer p.catchPanic(p.arg, verb) formatter.Format(p, verb) return @@ -664,14 +684,13 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString } // If we're doing Go syntax and the argument knows how to supply it, take care of it now. - if goSyntax { - p.fmt.sharp = false + if p.fmt.sharpV { if stringer, ok := p.arg.(GoStringer); ok { - wasString = false handled = true + defer p.restoreSpecialFlags(p.clearSpecialFlags()) defer p.catchPanic(p.arg, verb) // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's', false) + p.fmtString(stringer.GoString(), 's') return } } else { @@ -682,30 +701,27 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString case 'v', 's', 'x', 'X', 'q': // Is it an error or Stringer? // The duplication in the bodies is necessary: - // setting wasString and handled, and deferring catchPanic, + // setting handled and deferring catchPanic // must happen before calling the method. switch v := p.arg.(type) { case error: - wasString = false handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.Error(), verb, plus, false, depth) + p.printArg(v.Error(), verb, plus, depth) return case Stringer: - wasString = false handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.String(), verb, plus, false, depth) + p.printArg(v.String(), verb, plus, depth) return } } } - handled = false - return + return false } -func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) printArg(arg interface{}, verb rune, plus bool, depth int) (wasString bool) { p.arg = arg p.value = reflect.Value{} @@ -722,10 +738,10 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(reflect.TypeOf(arg).String(), 's', false, false, 0) + p.printArg(reflect.TypeOf(arg).String(), 's', false, 0) return false case 'p': - p.fmtPointer(reflect.ValueOf(arg), verb, goSyntax) + p.fmtPointer(reflect.ValueOf(arg), verb) return false } @@ -734,13 +750,9 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int // We could call handleMethods here and avoid this work, but // handleMethods is expensive enough to be worth delaying. oldPlus := p.fmt.plus - oldSharp := p.fmt.sharp if plus { p.fmt.plus = false } - if goSyntax { - p.fmt.sharp = false - } // Some types can be done without reflection. switch f := arg.(type) { @@ -765,40 +777,39 @@ func (p *pp) printArg(arg interface{}, verb rune, plus, goSyntax bool, depth int case int64: p.fmtInt64(f, verb) case uint: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint8: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint16: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint32: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case uint64: - p.fmtUint64(f, verb, goSyntax) + p.fmtUint64(f, verb) case uintptr: - p.fmtUint64(uint64(f), verb, goSyntax) + p.fmtUint64(uint64(f), verb) case string: - p.fmtString(f, verb, goSyntax) + p.fmtString(f, verb) wasString = verb == 's' || verb == 'v' case []byte: - p.fmtBytes(f, verb, goSyntax, nil, depth) + p.fmtBytes(f, verb, nil, depth) wasString = verb == 's' default: // Restore flags in case handleMethods finds a Formatter. p.fmt.plus = oldPlus - p.fmt.sharp = oldSharp // If the type is not simple, it might have methods. - if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { - return isString + if handled := p.handleMethods(verb, plus, depth); handled { + return false } // Need to use reflection - return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth) + return p.printReflectValue(reflect.ValueOf(arg), verb, plus, depth) } p.arg = nil return } // printValue is like printArg but starts with a reflect value, not an interface{} value. -func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) printValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) { if !value.IsValid() { if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) @@ -812,10 +823,10 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(value.Type().String(), 's', false, false, 0) + p.printArg(value.Type().String(), 's', false, 0) return false case 'p': - p.fmtPointer(value, verb, goSyntax) + p.fmtPointer(value, verb) return false } @@ -825,18 +836,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, dep if value.CanInterface() { p.arg = value.Interface() } - if isString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled { - return isString + if handled := p.handleMethods(verb, plus, depth); handled { + return false } - return p.printReflectValue(value, verb, plus, goSyntax, depth) + return p.printReflectValue(value, verb, plus, depth) } var byteType = reflect.TypeOf(byte(0)) // printReflectValue is the fallback for both printArg and printValue. // It uses reflect to print the value. -func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) { +func (p *pp) printReflectValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) { oldValue := p.value p.value = value BigSwitch: @@ -846,7 +857,7 @@ BigSwitch: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p.fmtInt64(f.Int(), verb) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - p.fmtUint64(f.Uint(), verb, goSyntax) + p.fmtUint64(f.Uint(), verb) case reflect.Float32, reflect.Float64: if f.Type().Size() == 4 { p.fmtFloat32(float32(f.Float()), verb) @@ -860,9 +871,9 @@ BigSwitch: p.fmtComplex128(f.Complex(), verb) } case reflect.String: - p.fmtString(f.String(), verb, goSyntax) + p.fmtString(f.String(), verb) case reflect.Map: - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(f.Type().String()) if f.IsNil() { p.buf.WriteString("(nil)") @@ -875,23 +886,23 @@ BigSwitch: keys := f.MapKeys() for i, key := range keys { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printValue(key, verb, plus, goSyntax, depth+1) + p.printValue(key, verb, plus, depth+1) p.buf.WriteByte(':') - p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1) + p.printValue(f.MapIndex(key), verb, plus, depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') } case reflect.Struct: - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(value.Type().String()) } p.add('{') @@ -899,32 +910,32 @@ BigSwitch: t := v.Type() for i := 0; i < v.NumField(); i++ { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - if plus || goSyntax { + if plus || p.fmt.sharpV { if f := t.Field(i); f.Name != "" { p.buf.WriteString(f.Name) p.buf.WriteByte(':') } } - p.printValue(getField(v, i), verb, plus, goSyntax, depth+1) + p.printValue(getField(v, i), verb, plus, depth+1) } p.buf.WriteByte('}') case reflect.Interface: value := f.Elem() if !value.IsValid() { - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(f.Type().String()) p.buf.Write(nilParenBytes) } else { p.buf.Write(nilAngleBytes) } } else { - wasString = p.printValue(value, verb, plus, goSyntax, depth+1) + wasString = p.printValue(value, verb, plus, depth+1) } case reflect.Array, reflect.Slice: // Byte slices are special: @@ -947,11 +958,11 @@ BigSwitch: bytes[i] = byte(f.Index(i).Uint()) } } - p.fmtBytes(bytes, verb, goSyntax, typ, depth) + p.fmtBytes(bytes, verb, typ, depth) wasString = verb == 's' break } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteString(value.Type().String()) if f.Kind() == reflect.Slice && f.IsNil() { p.buf.WriteString("(nil)") @@ -963,15 +974,15 @@ BigSwitch: } for i := 0; i < f.Len(); i++ { if i > 0 { - if goSyntax { + if p.fmt.sharpV { p.buf.Write(commaSpaceBytes) } else { p.buf.WriteByte(' ') } } - p.printValue(f.Index(i), verb, plus, goSyntax, depth+1) + p.printValue(f.Index(i), verb, plus, depth+1) } - if goSyntax { + if p.fmt.sharpV { p.buf.WriteByte('}') } else { p.buf.WriteByte(']') @@ -984,17 +995,17 @@ BigSwitch: switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice: p.buf.WriteByte('&') - p.printValue(a, verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, depth+1) break BigSwitch case reflect.Struct: p.buf.WriteByte('&') - p.printValue(a, verb, plus, goSyntax, depth+1) + p.printValue(a, verb, plus, depth+1) break BigSwitch } } fallthrough case reflect.Chan, reflect.Func, reflect.UnsafePointer: - p.fmtPointer(value, verb, goSyntax) + p.fmtPointer(value, verb) default: p.unknownType(f) } @@ -1160,9 +1171,13 @@ func (p *pp) doPrintf(format string, a []interface{}) { arg := a[argNum] argNum++ - goSyntax := c == 'v' && p.fmt.sharp + if c == 'v' && p.fmt.sharp { + // Go syntax. Set the flag in the fmt and clear the sharp flag. + p.fmt.sharp = false + p.fmt.sharpV = true + } plus := c == 'v' && p.fmt.plus - p.printArg(arg, c, plus, goSyntax, 0) + p.printArg(arg, c, plus, 0) } // Check for extra arguments unless the call accessed the arguments @@ -1176,7 +1191,7 @@ func (p *pp) doPrintf(format string, a []interface{}) { p.buf.WriteString(reflect.TypeOf(arg).String()) p.buf.WriteByte('=') } - p.printArg(arg, 'v', false, false, 0) + p.printArg(arg, 'v', false, 0) if argNum+1 < len(a) { p.buf.Write(commaSpaceBytes) } @@ -1197,7 +1212,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) { p.buf.WriteByte(' ') } } - prevString = p.printArg(arg, 'v', false, false, 0) + prevString = p.printArg(arg, 'v', false, 0) } if addnewline { p.buf.WriteByte('\n') From c65a47f890e33eeed6ee9d8b6d965a5534fb6e0e Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 3 Oct 2014 10:36:54 +1000 Subject: [PATCH 279/430] undo CL 138250043 / 4eda5e4001fd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I will use different approach to solve this problem. See CL 143160046 for details. ««« original CL description syscall: keep Windows syscall pointers live too Like https://golang.org/cl/139360044 LGTM=rsc, alex.brainman R=alex.brainman, rsc CC=golang-codereviews https://golang.org/cl/138250043 »»» LGTM=r R=golang-codereviews, bradfitz, r CC=golang-codereviews https://golang.org/cl/147440043 --- src/syscall/mksyscall_windows.go | 24 ++---------------------- src/syscall/zsyscall_windows.go | 15 ++++----------- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index ea9ee45511..1cdd6b4d22 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -158,7 +158,6 @@ func (p *Param) SyscallArgList() []string { case p.Type[0] == '*': s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name) case p.Type == "string": - p.fn.use(p.tmpVar()) s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar()) case p.Type == "bool": s = p.tmpVar() @@ -304,7 +303,6 @@ type Fn struct { Params []*Param Rets *Rets PrintTrace bool - Used []string dllname string dllfuncname string src string @@ -312,15 +310,6 @@ type Fn struct { curTmpVarIdx int // insure tmp variables have uniq names } -func (f *Fn) use(v string) { - for _, e := range f.Used { - if e == v { - return - } - } - f.Used = append(f.Used, v) -} - // extractParams parses s to extract function parameters. func extractParams(s string, f *Fn) ([]*Param, error) { s = trim(s) @@ -339,7 +328,7 @@ func extractParams(s string, f *Fn) ([]*Param, error) { } } ps[i] = &Param{ - Name: sanitizeName(trim(b[0])), + Name: trim(b[0]), Type: trim(b[1]), fn: f, tmpVarIdx: -1, @@ -348,13 +337,6 @@ func extractParams(s string, f *Fn) ([]*Param, error) { return ps, nil } -func sanitizeName(n string) string { - if n == "use" { - return "use_" - } - return n -} - // extractSection extracts text out of string s starting after start // and ending just before end. found return value will indicate success, // and prefix, body and suffix will contain correspondent parts of string s. @@ -698,7 +680,7 @@ var ( {{define "funcbody"}} func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{ {{template "tmpvars" .}} {{template "syscall" .}} -{{template "used" .}}{{template "seterror" .}}{{template "printtrace" .}} return +{{template "seterror" .}}{{template "printtrace" .}} return } {{end}} @@ -707,8 +689,6 @@ func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{ {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} -{{define "used"}}{{range .Used}}use(unsafe.Pointer({{.}}));{{end}}{{end}} - {{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}} {{end}}{{end}} diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 9f2c84fb1f..1f44750b7f 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -177,7 +177,6 @@ func LoadLibrary(libname string) (handle Handle, err error) { return } r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) - use(unsafe.Pointer(_p0)) handle = Handle(r0) if handle == 0 { if e1 != 0 { @@ -208,7 +207,6 @@ func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { return } r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(_p0)), 0) - use(unsafe.Pointer(_p0)) proc = uintptr(r0) if proc == 0 { if e1 != 0 { @@ -1561,7 +1559,6 @@ func GetHostByName(name string) (h *Hostent, err error) { return } r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) - use(unsafe.Pointer(_p0)) h = (*Hostent)(unsafe.Pointer(r0)) if h == nil { if e1 != 0 { @@ -1585,8 +1582,6 @@ func GetServByName(name string, proto string) (s *Servent, err error) { return } r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) - use(unsafe.Pointer(_p0)) - use(unsafe.Pointer(_p1)) s = (*Servent)(unsafe.Pointer(r0)) if s == nil { if e1 != 0 { @@ -1611,7 +1606,6 @@ func GetProtoByName(name string) (p *Protoent, err error) { return } r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) - use(unsafe.Pointer(_p0)) p = (*Protoent)(unsafe.Pointer(r0)) if p == nil { if e1 != 0 { @@ -1630,7 +1624,6 @@ func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSR return } r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(_p0)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) - use(unsafe.Pointer(_p0)) if r0 != 0 { status = Errno(r0) } @@ -1750,8 +1743,8 @@ func NetApiBufferFree(buf *byte) (neterr error) { return } -func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use_ *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use_)), 0, 0) +func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) if r1 == 0 { if e1 != 0 { err = error(e1) @@ -1762,8 +1755,8 @@ func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint3 return } -func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use_ *uint32) (err error) { - r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use_)), 0, 0) +func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) { + r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0) if r1 == 0 { if e1 != 0 { err = error(e1) From 3ffd29fb2cfeee77c7f58fcae3496665695eb938 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 3 Oct 2014 12:44:20 -0400 Subject: [PATCH 280/430] cmd/cc, runtime: disallow structs without tags Structs without tags have no unique name to use in the Go definitions generated from the C types. This caused issue 8812, fixed by CL 149260043. Avoid future problems by requiring struct tags. Update runtime as needed. (There is no other C code in the tree.) LGTM=bradfitz, iant R=golang-codereviews, bradfitz, dave, iant CC=golang-codereviews, khr, r https://golang.org/cl/150360043 --- src/cmd/cc/cc.y | 1 + src/cmd/cc/y.tab.c | 1149 +++++++++++++------------------- src/cmd/cc/y.tab.h | 68 +- src/runtime/malloc.h | 6 +- src/runtime/os_plan9.h | 2 +- src/runtime/proc.c | 2 +- src/runtime/runtime.h | 4 +- src/runtime/vdso_linux_amd64.c | 20 +- 8 files changed, 496 insertions(+), 756 deletions(-) diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y index 11ee444b7d..8d7cb1472c 100644 --- a/src/cmd/cc/cc.y +++ b/src/cmd/cc/cc.y @@ -1043,6 +1043,7 @@ complex: } | LSTRUCT sbody { + diag(Z, "struct must have tag"); taggen++; sprint(symb, "_%d_", taggen); $$ = dotag(lookup(), TSTRUCT, autobn); diff --git a/src/cmd/cc/y.tab.c b/src/cmd/cc/y.tab.c index 8588515ab9..94932efe58 100644 --- a/src/cmd/cc/y.tab.c +++ b/src/cmd/cc/y.tab.c @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.7.12-4996. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,7 +29,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -44,7 +47,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.7.12-4996" +#define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -52,54 +55,11 @@ /* Pure parsers. */ #define YYPURE 0 -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 +/* Using locations. */ +#define YYLSP_NEEDED 0 - -/* Copy the first part of user declarations. */ -/* Line 371 of yacc.c */ -#line 31 "cc.y" - -#include -#include /* if we don't, bison will, and cc.h re-#defines getc */ -#include "cc.h" - -/* Line 371 of yacc.c */ -#line 74 "y.tab.c" - -# ifndef YY_NULL -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULL nullptr -# else -# define YY_NULL 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "y.tab.h". */ -#ifndef YY_YY_Y_TAB_H_INCLUDED -# define YY_YY_Y_TAB_H_INCLUDED -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -256,12 +216,37 @@ extern int yydebug; + +/* Copy the first part of user declarations. */ +#line 31 "cc.y" + +#include +#include /* if we don't, bison will, and cc.h re-#defines getc */ +#include "cc.h" + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ -/* Line 387 of yacc.c */ #line 36 "cc.y" - +{ Node* node; Sym* sym; Type* type; @@ -285,38 +270,22 @@ typedef union YYSTYPE int32 lval; double dval; vlong vval; - - -/* Line 387 of yacc.c */ -#line 292 "y.tab.c" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 193 of yacc.c. */ +#line 276 "y.tab.c" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif -extern YYSTYPE yylval; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - -#endif /* !YY_YY_Y_TAB_H_INCLUDED */ /* Copy the second part of user declarations. */ -/* Line 390 of yacc.c */ -#line 320 "y.tab.c" + +/* Line 216 of yacc.c. */ +#line 289 "y.tab.c" #ifdef short # undef short @@ -369,45 +338,36 @@ typedef short int yytype_int16; # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if (! defined __GNUC__ || __GNUC__ < 2 \ - || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)) -# define __attribute__(Spec) /* empty */ +# define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) +# define YYUSE(e) ((void) (e)) #else -# define YYUSE(E) /* empty */ +# define YYUSE(e) /* empty */ #endif - /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint -# define YYID(N) (N) +# define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int yyi) +YYID (int i) #else static int -YYID (yyi) - int yyi; +YYID (i) + int i; #endif { - return yyi; + return i; } #endif @@ -428,12 +388,11 @@ YYID (yyi) # define alloca _alloca # else # define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # endif @@ -456,24 +415,24 @@ YYID (yyi) # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ +# if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 +# ifndef _STDLIB_H +# define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif @@ -489,9 +448,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; + yytype_int16 yyss; + YYSTYPE yyvs; + }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -502,19 +461,35 @@ union yyalloc ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) -# define YYCOPY_NEEDED 1 +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ +# define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ @@ -522,26 +497,6 @@ union yyalloc #endif -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ @@ -737,16 +692,16 @@ static const yytype_uint16 yyrline[] = 794, 798, 802, 803, 810, 817, 824, 831, 838, 845, 852, 859, 860, 863, 873, 891, 901, 919, 922, 925, 926, 933, 932, 955, 959, 962, 967, 972, 978, 986, - 992, 998, 1004, 1012, 1020, 1027, 1033, 1032, 1044, 1052, - 1058, 1057, 1069, 1077, 1086, 1090, 1085, 1107, 1106, 1115, - 1121, 1122, 1128, 1131, 1137, 1138, 1139, 1142, 1143, 1149, - 1150, 1153, 1157, 1161, 1162, 1165, 1166, 1167, 1168, 1169, - 1170, 1171, 1172, 1173, 1176, 1177, 1178, 1179, 1180, 1181, - 1182, 1185, 1186, 1187, 1190, 1205, 1217, 1218 + 992, 998, 1004, 1012, 1020, 1027, 1033, 1032, 1044, 1053, + 1059, 1058, 1070, 1078, 1087, 1091, 1086, 1108, 1107, 1116, + 1122, 1123, 1129, 1132, 1138, 1139, 1140, 1143, 1144, 1150, + 1151, 1154, 1158, 1162, 1163, 1166, 1167, 1168, 1169, 1170, + 1171, 1172, 1173, 1174, 1177, 1178, 1179, 1180, 1181, 1182, + 1183, 1186, 1187, 1188, 1191, 1206, 1218, 1219 }; #endif -#if YYDEBUG || YYERROR_VERBOSE || 0 +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = @@ -764,16 +719,16 @@ static const char *const yytname[] = "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID", "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF", "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'", - "$accept", "prog", "xdecl", "$@1", "$@2", "xdlist", "$@3", "xdecor", - "xdecor2", "adecl", "adlist", "$@4", "pdecl", "pdlist", "edecl", "$@5", - "$@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2", + "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor", + "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5", + "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2", "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist", - "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", - "$@7", "$@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", - "uexpr", "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9", - "zctlist", "types", "tlist", "ctlist", "complex", "$@10", "$@11", "$@12", - "$@13", "$@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname", - "enum", "tname", "cname", "gname", "name", "tag", "ltag", YY_NULL + "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7", + "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr", + "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9", + "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12", + "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname", + "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0 }; #endif @@ -855,8 +810,8 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1 }; -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { @@ -981,7 +936,8 @@ static const yytype_int16 yypgoto[] = /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -205 static const yytype_int16 yytable[] = { @@ -1106,12 +1062,6 @@ static const yytype_int16 yytable[] = 178, 179, 180, 181, 182, 183, 184, 185, 186 }; -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-331))) - -#define yytable_value_is_error(Yytable_value) \ - YYID (0) - static const yytype_int16 yycheck[] = { 1, 27, 14, 91, 131, 17, 30, 58, 20, 33, @@ -1295,50 +1245,78 @@ static const yytype_uint8 yystos[] = /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ + Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif #define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) -/* Error token number */ + #define YYTERROR 1 #define YYERRCODE 256 -/* This macro is provided for backward compatibility. */ +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + #ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ + #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else @@ -1388,8 +1366,6 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) YYSTYPE const * const yyvaluep; #endif { - FILE *yyo = yyoutput; - YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT @@ -1398,7 +1374,11 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) # else YYUSE (yyoutput); # endif - YYUSE (yytype); + switch (yytype) + { + default: + break; + } } @@ -1435,20 +1415,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } @@ -1482,11 +1459,11 @@ yy_reduce_print (yyvsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - YYFPRINTF (stderr, " $%d = ", yyi + 1); + fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); - YYFPRINTF (stderr, "\n"); + fprintf (stderr, "\n"); } } @@ -1523,6 +1500,7 @@ int yydebug; # define YYMAXDEPTH 10000 #endif + #if YYERROR_VERBOSE @@ -1625,145 +1603,115 @@ yytnamerr (char *yyres, const char *yystr) } # endif -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) { - YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULL; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; + int yyn = yypact[yystate]; - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; } #endif /* YYERROR_VERBOSE */ + /*-----------------------------------------------. | Release the memory associated to this symbol. | @@ -1788,31 +1736,44 @@ yydestruct (yymsg, yytype, yyvaluep) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - YYUSE (yytype); + switch (yytype) + { + + default: + break; + } } + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ - -/* The lookahead symbol. */ +/* The look-ahead symbol. */ int yychar; - -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; + /*----------. | yyparse. | `----------*/ @@ -1839,37 +1800,14 @@ yyparse () #endif #endif { - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - + + int yystate; int yyn; int yyresult; - /* Lookahead token as an internal (translated) token number. */ + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; @@ -1877,22 +1815,54 @@ yyparse () YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yystacksize = YYINITDEPTH; - YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + goto yysetstate; /*------------------------------------------------------------. @@ -1919,6 +1889,7 @@ yyparse () YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; + /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might @@ -1926,6 +1897,7 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); yyss = yyss1; @@ -1948,8 +1920,9 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1960,6 +1933,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; + YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1969,9 +1943,6 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - if (yystate == YYFINAL) - YYACCEPT; - goto yybackup; /*-----------. @@ -1980,16 +1951,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ + look-ahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to lookahead token. */ + /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) + if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a lookahead token if don't already have one. */ + /* Not known => get a look-ahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -2015,27 +1986,29 @@ yybackup: yyn = yytable[yyn]; if (yyn <= 0) { - if (yytable_value_is_error (yyn)) - goto yyerrlab; + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; yyn = -yyn; goto yyreduce; } + if (yyn == YYFINAL) + YYACCEPT; + /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the lookahead token. */ + /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token. */ - yychar = YYEMPTY; + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; @@ -2072,7 +2045,6 @@ yyreduce: switch (yyn) { case 4: -/* Line 1787 of yacc.c */ #line 109 "cc.y" { dodecl(xdecl, lastclass, lasttype, Z); @@ -2080,7 +2052,6 @@ yyreduce: break; case 6: -/* Line 1787 of yacc.c */ #line 114 "cc.y" { lastdcl = T; @@ -2098,7 +2069,6 @@ yyreduce: break; case 7: -/* Line 1787 of yacc.c */ #line 128 "cc.y" { argmark((yyvsp[(2) - (4)].node), 1); @@ -2106,7 +2076,6 @@ yyreduce: break; case 8: -/* Line 1787 of yacc.c */ #line 132 "cc.y" { Node *n; @@ -2120,7 +2089,6 @@ yyreduce: break; case 9: -/* Line 1787 of yacc.c */ #line 144 "cc.y" { dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2128,7 +2096,6 @@ yyreduce: break; case 10: -/* Line 1787 of yacc.c */ #line 148 "cc.y" { (yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2136,7 +2103,6 @@ yyreduce: break; case 11: -/* Line 1787 of yacc.c */ #line 152 "cc.y" { doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node)); @@ -2144,7 +2110,6 @@ yyreduce: break; case 14: -/* Line 1787 of yacc.c */ #line 160 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z); @@ -2153,7 +2118,6 @@ yyreduce: break; case 16: -/* Line 1787 of yacc.c */ #line 168 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2161,7 +2125,6 @@ yyreduce: break; case 17: -/* Line 1787 of yacc.c */ #line 172 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2169,7 +2132,6 @@ yyreduce: break; case 18: -/* Line 1787 of yacc.c */ #line 176 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2177,7 +2139,6 @@ yyreduce: break; case 19: -/* Line 1787 of yacc.c */ #line 185 "cc.y" { (yyval.node) = dodecl(adecl, lastclass, lasttype, Z); @@ -2185,7 +2146,6 @@ yyreduce: break; case 20: -/* Line 1787 of yacc.c */ #line 189 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2193,7 +2153,6 @@ yyreduce: break; case 21: -/* Line 1787 of yacc.c */ #line 195 "cc.y" { dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2202,7 +2161,6 @@ yyreduce: break; case 22: -/* Line 1787 of yacc.c */ #line 200 "cc.y" { (yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2210,7 +2168,6 @@ yyreduce: break; case 23: -/* Line 1787 of yacc.c */ #line 204 "cc.y" { int32 w; @@ -2222,7 +2179,6 @@ yyreduce: break; case 24: -/* Line 1787 of yacc.c */ #line 212 "cc.y" { (yyval.node) = (yyvsp[(1) - (3)].node); @@ -2235,7 +2191,6 @@ yyreduce: break; case 27: -/* Line 1787 of yacc.c */ #line 229 "cc.y" { dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node)); @@ -2243,7 +2198,6 @@ yyreduce: break; case 29: -/* Line 1787 of yacc.c */ #line 239 "cc.y" { lasttype = (yyvsp[(1) - (1)].type); @@ -2251,7 +2205,6 @@ yyreduce: break; case 31: -/* Line 1787 of yacc.c */ #line 244 "cc.y" { lasttype = (yyvsp[(2) - (2)].type); @@ -2259,7 +2212,6 @@ yyreduce: break; case 33: -/* Line 1787 of yacc.c */ #line 250 "cc.y" { lastfield = 0; @@ -2268,7 +2220,6 @@ yyreduce: break; case 35: -/* Line 1787 of yacc.c */ #line 258 "cc.y" { dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node)); @@ -2276,7 +2227,6 @@ yyreduce: break; case 37: -/* Line 1787 of yacc.c */ #line 265 "cc.y" { lastbit = 0; @@ -2285,7 +2235,6 @@ yyreduce: break; case 38: -/* Line 1787 of yacc.c */ #line 270 "cc.y" { (yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2293,7 +2242,6 @@ yyreduce: break; case 39: -/* Line 1787 of yacc.c */ #line 274 "cc.y" { (yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node)); @@ -2301,7 +2249,6 @@ yyreduce: break; case 40: -/* Line 1787 of yacc.c */ #line 282 "cc.y" { (yyval.node) = (Z); @@ -2309,7 +2256,6 @@ yyreduce: break; case 42: -/* Line 1787 of yacc.c */ #line 289 "cc.y" { (yyval.node) = new(OIND, (Z), Z); @@ -2318,7 +2264,6 @@ yyreduce: break; case 43: -/* Line 1787 of yacc.c */ #line 294 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z); @@ -2327,7 +2272,6 @@ yyreduce: break; case 46: -/* Line 1787 of yacc.c */ #line 303 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2335,7 +2279,6 @@ yyreduce: break; case 47: -/* Line 1787 of yacc.c */ #line 307 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); @@ -2343,7 +2286,6 @@ yyreduce: break; case 48: -/* Line 1787 of yacc.c */ #line 313 "cc.y" { (yyval.node) = new(OFUNC, (Z), Z); @@ -2351,7 +2293,6 @@ yyreduce: break; case 49: -/* Line 1787 of yacc.c */ #line 317 "cc.y" { (yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node)); @@ -2359,7 +2300,6 @@ yyreduce: break; case 50: -/* Line 1787 of yacc.c */ #line 321 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -2367,7 +2307,6 @@ yyreduce: break; case 52: -/* Line 1787 of yacc.c */ #line 328 "cc.y" { (yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z); @@ -2375,7 +2314,6 @@ yyreduce: break; case 53: -/* Line 1787 of yacc.c */ #line 334 "cc.y" { (yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z); @@ -2383,7 +2321,6 @@ yyreduce: break; case 54: -/* Line 1787 of yacc.c */ #line 338 "cc.y" { (yyval.node) = new(OELEM, Z, Z); @@ -2392,7 +2329,6 @@ yyreduce: break; case 57: -/* Line 1787 of yacc.c */ #line 347 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node)); @@ -2400,7 +2336,6 @@ yyreduce: break; case 59: -/* Line 1787 of yacc.c */ #line 352 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2408,7 +2343,6 @@ yyreduce: break; case 62: -/* Line 1787 of yacc.c */ #line 360 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2416,7 +2350,6 @@ yyreduce: break; case 63: -/* Line 1787 of yacc.c */ #line 365 "cc.y" { (yyval.node) = Z; @@ -2424,7 +2357,6 @@ yyreduce: break; case 64: -/* Line 1787 of yacc.c */ #line 369 "cc.y" { (yyval.node) = invert((yyvsp[(1) - (1)].node)); @@ -2432,7 +2364,6 @@ yyreduce: break; case 66: -/* Line 1787 of yacc.c */ #line 377 "cc.y" { (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z); @@ -2441,7 +2372,6 @@ yyreduce: break; case 67: -/* Line 1787 of yacc.c */ #line 382 "cc.y" { (yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z); @@ -2450,7 +2380,6 @@ yyreduce: break; case 68: -/* Line 1787 of yacc.c */ #line 387 "cc.y" { (yyval.node) = new(ODOTDOT, Z, Z); @@ -2458,7 +2387,6 @@ yyreduce: break; case 69: -/* Line 1787 of yacc.c */ #line 391 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2466,7 +2394,6 @@ yyreduce: break; case 70: -/* Line 1787 of yacc.c */ #line 397 "cc.y" { (yyval.node) = invert((yyvsp[(2) - (3)].node)); @@ -2478,7 +2405,6 @@ yyreduce: break; case 71: -/* Line 1787 of yacc.c */ #line 406 "cc.y" { (yyval.node) = Z; @@ -2486,7 +2412,6 @@ yyreduce: break; case 72: -/* Line 1787 of yacc.c */ #line 410 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2494,7 +2419,6 @@ yyreduce: break; case 73: -/* Line 1787 of yacc.c */ #line 414 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2502,7 +2426,6 @@ yyreduce: break; case 75: -/* Line 1787 of yacc.c */ #line 421 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2510,7 +2433,6 @@ yyreduce: break; case 76: -/* Line 1787 of yacc.c */ #line 427 "cc.y" { (yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z); @@ -2518,7 +2440,6 @@ yyreduce: break; case 77: -/* Line 1787 of yacc.c */ #line 431 "cc.y" { (yyval.node) = new(OCASE, Z, Z); @@ -2526,7 +2447,6 @@ yyreduce: break; case 78: -/* Line 1787 of yacc.c */ #line 435 "cc.y" { (yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z); @@ -2534,7 +2454,6 @@ yyreduce: break; case 79: -/* Line 1787 of yacc.c */ #line 441 "cc.y" { (yyval.node) = Z; @@ -2542,7 +2461,6 @@ yyreduce: break; case 81: -/* Line 1787 of yacc.c */ #line 446 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); @@ -2550,7 +2468,6 @@ yyreduce: break; case 83: -/* Line 1787 of yacc.c */ #line 453 "cc.y" { (yyval.node) = (yyvsp[(2) - (2)].node); @@ -2558,7 +2475,6 @@ yyreduce: break; case 85: -/* Line 1787 of yacc.c */ #line 459 "cc.y" { markdcl(); @@ -2566,7 +2482,6 @@ yyreduce: break; case 86: -/* Line 1787 of yacc.c */ #line 463 "cc.y" { (yyval.node) = revertdcl(); @@ -2578,7 +2493,6 @@ yyreduce: break; case 87: -/* Line 1787 of yacc.c */ #line 471 "cc.y" { (yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z)); @@ -2588,7 +2502,6 @@ yyreduce: break; case 88: -/* Line 1787 of yacc.c */ #line 477 "cc.y" { (yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node))); @@ -2600,13 +2513,11 @@ yyreduce: break; case 89: -/* Line 1787 of yacc.c */ #line 484 "cc.y" { markdcl(); } break; case 90: -/* Line 1787 of yacc.c */ #line 485 "cc.y" { (yyval.node) = revertdcl(); @@ -2621,7 +2532,6 @@ yyreduce: break; case 91: -/* Line 1787 of yacc.c */ #line 496 "cc.y" { (yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); @@ -2629,7 +2539,6 @@ yyreduce: break; case 92: -/* Line 1787 of yacc.c */ #line 500 "cc.y" { (yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node)); @@ -2637,7 +2546,6 @@ yyreduce: break; case 93: -/* Line 1787 of yacc.c */ #line 504 "cc.y" { (yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z); @@ -2646,7 +2554,6 @@ yyreduce: break; case 94: -/* Line 1787 of yacc.c */ #line 509 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -2664,7 +2571,6 @@ yyreduce: break; case 95: -/* Line 1787 of yacc.c */ #line 523 "cc.y" { (yyval.node) = new(OBREAK, Z, Z); @@ -2672,7 +2578,6 @@ yyreduce: break; case 96: -/* Line 1787 of yacc.c */ #line 527 "cc.y" { (yyval.node) = new(OCONTINUE, Z, Z); @@ -2680,7 +2585,6 @@ yyreduce: break; case 97: -/* Line 1787 of yacc.c */ #line 531 "cc.y" { (yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z); @@ -2688,7 +2592,6 @@ yyreduce: break; case 98: -/* Line 1787 of yacc.c */ #line 535 "cc.y" { (yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z); @@ -2696,7 +2599,6 @@ yyreduce: break; case 99: -/* Line 1787 of yacc.c */ #line 539 "cc.y" { (yyval.node) = new(OPREFETCH, (yyvsp[(3) - (5)].node), Z); @@ -2704,7 +2606,6 @@ yyreduce: break; case 100: -/* Line 1787 of yacc.c */ #line 543 "cc.y" { (yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z); @@ -2712,7 +2613,6 @@ yyreduce: break; case 101: -/* Line 1787 of yacc.c */ #line 548 "cc.y" { (yyval.node) = Z; @@ -2720,7 +2620,6 @@ yyreduce: break; case 103: -/* Line 1787 of yacc.c */ #line 554 "cc.y" { (yyval.node) = Z; @@ -2728,7 +2627,6 @@ yyreduce: break; case 105: -/* Line 1787 of yacc.c */ #line 561 "cc.y" { (yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z); @@ -2737,7 +2635,6 @@ yyreduce: break; case 107: -/* Line 1787 of yacc.c */ #line 569 "cc.y" { (yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2745,7 +2642,6 @@ yyreduce: break; case 109: -/* Line 1787 of yacc.c */ #line 576 "cc.y" { (yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2753,7 +2649,6 @@ yyreduce: break; case 110: -/* Line 1787 of yacc.c */ #line 580 "cc.y" { (yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2761,7 +2656,6 @@ yyreduce: break; case 111: -/* Line 1787 of yacc.c */ #line 584 "cc.y" { (yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2769,7 +2663,6 @@ yyreduce: break; case 112: -/* Line 1787 of yacc.c */ #line 588 "cc.y" { (yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2777,7 +2670,6 @@ yyreduce: break; case 113: -/* Line 1787 of yacc.c */ #line 592 "cc.y" { (yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2785,7 +2677,6 @@ yyreduce: break; case 114: -/* Line 1787 of yacc.c */ #line 596 "cc.y" { (yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2793,7 +2684,6 @@ yyreduce: break; case 115: -/* Line 1787 of yacc.c */ #line 600 "cc.y" { (yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2801,7 +2691,6 @@ yyreduce: break; case 116: -/* Line 1787 of yacc.c */ #line 604 "cc.y" { (yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2809,7 +2698,6 @@ yyreduce: break; case 117: -/* Line 1787 of yacc.c */ #line 608 "cc.y" { (yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2817,7 +2705,6 @@ yyreduce: break; case 118: -/* Line 1787 of yacc.c */ #line 612 "cc.y" { (yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2825,7 +2712,6 @@ yyreduce: break; case 119: -/* Line 1787 of yacc.c */ #line 616 "cc.y" { (yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2833,7 +2719,6 @@ yyreduce: break; case 120: -/* Line 1787 of yacc.c */ #line 620 "cc.y" { (yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2841,7 +2726,6 @@ yyreduce: break; case 121: -/* Line 1787 of yacc.c */ #line 624 "cc.y" { (yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2849,7 +2733,6 @@ yyreduce: break; case 122: -/* Line 1787 of yacc.c */ #line 628 "cc.y" { (yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2857,7 +2740,6 @@ yyreduce: break; case 123: -/* Line 1787 of yacc.c */ #line 632 "cc.y" { (yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2865,7 +2747,6 @@ yyreduce: break; case 124: -/* Line 1787 of yacc.c */ #line 636 "cc.y" { (yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2873,7 +2754,6 @@ yyreduce: break; case 125: -/* Line 1787 of yacc.c */ #line 640 "cc.y" { (yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2881,7 +2761,6 @@ yyreduce: break; case 126: -/* Line 1787 of yacc.c */ #line 644 "cc.y" { (yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2889,7 +2768,6 @@ yyreduce: break; case 127: -/* Line 1787 of yacc.c */ #line 648 "cc.y" { (yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node))); @@ -2897,7 +2775,6 @@ yyreduce: break; case 128: -/* Line 1787 of yacc.c */ #line 652 "cc.y" { (yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2905,7 +2782,6 @@ yyreduce: break; case 129: -/* Line 1787 of yacc.c */ #line 656 "cc.y" { (yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2913,7 +2789,6 @@ yyreduce: break; case 130: -/* Line 1787 of yacc.c */ #line 660 "cc.y" { (yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2921,7 +2796,6 @@ yyreduce: break; case 131: -/* Line 1787 of yacc.c */ #line 664 "cc.y" { (yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2929,7 +2803,6 @@ yyreduce: break; case 132: -/* Line 1787 of yacc.c */ #line 668 "cc.y" { (yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2937,7 +2810,6 @@ yyreduce: break; case 133: -/* Line 1787 of yacc.c */ #line 672 "cc.y" { (yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2945,7 +2817,6 @@ yyreduce: break; case 134: -/* Line 1787 of yacc.c */ #line 676 "cc.y" { (yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2953,7 +2824,6 @@ yyreduce: break; case 135: -/* Line 1787 of yacc.c */ #line 680 "cc.y" { (yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2961,7 +2831,6 @@ yyreduce: break; case 136: -/* Line 1787 of yacc.c */ #line 684 "cc.y" { (yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2969,7 +2838,6 @@ yyreduce: break; case 137: -/* Line 1787 of yacc.c */ #line 688 "cc.y" { (yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2977,7 +2845,6 @@ yyreduce: break; case 138: -/* Line 1787 of yacc.c */ #line 692 "cc.y" { (yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -2985,7 +2852,6 @@ yyreduce: break; case 140: -/* Line 1787 of yacc.c */ #line 699 "cc.y" { (yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z); @@ -2996,7 +2862,6 @@ yyreduce: break; case 141: -/* Line 1787 of yacc.c */ #line 706 "cc.y" { (yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z); @@ -3006,7 +2871,6 @@ yyreduce: break; case 143: -/* Line 1787 of yacc.c */ #line 715 "cc.y" { (yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z); @@ -3014,7 +2878,6 @@ yyreduce: break; case 144: -/* Line 1787 of yacc.c */ #line 719 "cc.y" { (yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z); @@ -3022,7 +2885,6 @@ yyreduce: break; case 145: -/* Line 1787 of yacc.c */ #line 723 "cc.y" { (yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z); @@ -3030,7 +2892,6 @@ yyreduce: break; case 146: -/* Line 1787 of yacc.c */ #line 727 "cc.y" { (yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z); @@ -3038,7 +2899,6 @@ yyreduce: break; case 147: -/* Line 1787 of yacc.c */ #line 731 "cc.y" { (yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z); @@ -3046,7 +2906,6 @@ yyreduce: break; case 148: -/* Line 1787 of yacc.c */ #line 735 "cc.y" { (yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z); @@ -3054,7 +2913,6 @@ yyreduce: break; case 149: -/* Line 1787 of yacc.c */ #line 739 "cc.y" { (yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z); @@ -3062,7 +2920,6 @@ yyreduce: break; case 150: -/* Line 1787 of yacc.c */ #line 743 "cc.y" { (yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z); @@ -3070,7 +2927,6 @@ yyreduce: break; case 151: -/* Line 1787 of yacc.c */ #line 747 "cc.y" { (yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z); @@ -3078,7 +2934,6 @@ yyreduce: break; case 152: -/* Line 1787 of yacc.c */ #line 751 "cc.y" { (yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z); @@ -3086,7 +2941,6 @@ yyreduce: break; case 153: -/* Line 1787 of yacc.c */ #line 757 "cc.y" { (yyval.node) = (yyvsp[(2) - (3)].node); @@ -3094,7 +2948,6 @@ yyreduce: break; case 154: -/* Line 1787 of yacc.c */ #line 761 "cc.y" { (yyval.node) = new(OSIZE, Z, Z); @@ -3104,7 +2957,6 @@ yyreduce: break; case 155: -/* Line 1787 of yacc.c */ #line 767 "cc.y" { (yyval.node) = new(OSIGN, Z, Z); @@ -3114,7 +2966,6 @@ yyreduce: break; case 156: -/* Line 1787 of yacc.c */ #line 773 "cc.y" { (yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z); @@ -3126,7 +2977,6 @@ yyreduce: break; case 157: -/* Line 1787 of yacc.c */ #line 781 "cc.y" { (yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z); @@ -3134,7 +2984,6 @@ yyreduce: break; case 158: -/* Line 1787 of yacc.c */ #line 785 "cc.y" { (yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z); @@ -3143,7 +2992,6 @@ yyreduce: break; case 159: -/* Line 1787 of yacc.c */ #line 790 "cc.y" { (yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z); @@ -3152,7 +3000,6 @@ yyreduce: break; case 160: -/* Line 1787 of yacc.c */ #line 795 "cc.y" { (yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z); @@ -3160,7 +3007,6 @@ yyreduce: break; case 161: -/* Line 1787 of yacc.c */ #line 799 "cc.y" { (yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z); @@ -3168,7 +3014,6 @@ yyreduce: break; case 163: -/* Line 1787 of yacc.c */ #line 804 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3179,7 +3024,6 @@ yyreduce: break; case 164: -/* Line 1787 of yacc.c */ #line 811 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3190,7 +3034,6 @@ yyreduce: break; case 165: -/* Line 1787 of yacc.c */ #line 818 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3201,7 +3044,6 @@ yyreduce: break; case 166: -/* Line 1787 of yacc.c */ #line 825 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3212,7 +3054,6 @@ yyreduce: break; case 167: -/* Line 1787 of yacc.c */ #line 832 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3223,7 +3064,6 @@ yyreduce: break; case 168: -/* Line 1787 of yacc.c */ #line 839 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3234,7 +3074,6 @@ yyreduce: break; case 169: -/* Line 1787 of yacc.c */ #line 846 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3245,7 +3084,6 @@ yyreduce: break; case 170: -/* Line 1787 of yacc.c */ #line 853 "cc.y" { (yyval.node) = new(OCONST, Z, Z); @@ -3256,7 +3094,6 @@ yyreduce: break; case 173: -/* Line 1787 of yacc.c */ #line 864 "cc.y" { (yyval.node) = new(OSTRING, Z, Z); @@ -3270,7 +3107,6 @@ yyreduce: break; case 174: -/* Line 1787 of yacc.c */ #line 874 "cc.y" { char *s; @@ -3290,7 +3126,6 @@ yyreduce: break; case 175: -/* Line 1787 of yacc.c */ #line 892 "cc.y" { (yyval.node) = new(OLSTRING, Z, Z); @@ -3304,7 +3139,6 @@ yyreduce: break; case 176: -/* Line 1787 of yacc.c */ #line 902 "cc.y" { char *s; @@ -3324,7 +3158,6 @@ yyreduce: break; case 177: -/* Line 1787 of yacc.c */ #line 919 "cc.y" { (yyval.node) = Z; @@ -3332,7 +3165,6 @@ yyreduce: break; case 180: -/* Line 1787 of yacc.c */ #line 927 "cc.y" { (yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); @@ -3340,7 +3172,6 @@ yyreduce: break; case 181: -/* Line 1787 of yacc.c */ #line 933 "cc.y" { (yyval.tyty).t1 = strf; @@ -3357,7 +3188,6 @@ yyreduce: break; case 182: -/* Line 1787 of yacc.c */ #line 946 "cc.y" { (yyval.type) = strf; @@ -3369,7 +3199,6 @@ yyreduce: break; case 183: -/* Line 1787 of yacc.c */ #line 955 "cc.y" { lastclass = CXXX; @@ -3378,7 +3207,6 @@ yyreduce: break; case 185: -/* Line 1787 of yacc.c */ #line 963 "cc.y" { (yyval.tycl).t = (yyvsp[(1) - (1)].type); @@ -3387,7 +3215,6 @@ yyreduce: break; case 186: -/* Line 1787 of yacc.c */ #line 968 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval)); @@ -3396,7 +3223,6 @@ yyreduce: break; case 187: -/* Line 1787 of yacc.c */ #line 973 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval)); @@ -3406,7 +3232,6 @@ yyreduce: break; case 188: -/* Line 1787 of yacc.c */ #line 979 "cc.y" { (yyval.tycl).t = (yyvsp[(1) - (2)].type); @@ -3418,7 +3243,6 @@ yyreduce: break; case 189: -/* Line 1787 of yacc.c */ #line 987 "cc.y" { (yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval))); @@ -3428,7 +3252,6 @@ yyreduce: break; case 190: -/* Line 1787 of yacc.c */ #line 993 "cc.y" { (yyval.tycl).t = (yyvsp[(2) - (3)].type); @@ -3438,7 +3261,6 @@ yyreduce: break; case 191: -/* Line 1787 of yacc.c */ #line 999 "cc.y" { (yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval)); @@ -3448,7 +3270,6 @@ yyreduce: break; case 192: -/* Line 1787 of yacc.c */ #line 1005 "cc.y" { (yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval))); @@ -3458,7 +3279,6 @@ yyreduce: break; case 193: -/* Line 1787 of yacc.c */ #line 1013 "cc.y" { (yyval.type) = (yyvsp[(1) - (1)].tycl).t; @@ -3468,7 +3288,6 @@ yyreduce: break; case 194: -/* Line 1787 of yacc.c */ #line 1021 "cc.y" { lasttype = (yyvsp[(1) - (1)].tycl).t; @@ -3477,7 +3296,6 @@ yyreduce: break; case 195: -/* Line 1787 of yacc.c */ #line 1028 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0); @@ -3486,7 +3304,6 @@ yyreduce: break; case 196: -/* Line 1787 of yacc.c */ #line 1033 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn); @@ -3494,7 +3311,6 @@ yyreduce: break; case 197: -/* Line 1787 of yacc.c */ #line 1037 "cc.y" { (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag; @@ -3506,9 +3322,9 @@ yyreduce: break; case 198: -/* Line 1787 of yacc.c */ #line 1045 "cc.y" { + diag(Z, "struct must have tag"); taggen++; sprint(symb, "_%d_", taggen); (yyval.type) = dotag(lookup(), TSTRUCT, autobn); @@ -3518,8 +3334,7 @@ yyreduce: break; case 199: -/* Line 1787 of yacc.c */ -#line 1053 "cc.y" +#line 1054 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TUNION, 0); (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag; @@ -3527,16 +3342,14 @@ yyreduce: break; case 200: -/* Line 1787 of yacc.c */ -#line 1058 "cc.y" +#line 1059 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TUNION, autobn); } break; case 201: -/* Line 1787 of yacc.c */ -#line 1062 "cc.y" +#line 1063 "cc.y" { (yyval.type) = (yyvsp[(2) - (4)].sym)->suetag; if((yyval.type)->link != T) @@ -3547,8 +3360,7 @@ yyreduce: break; case 202: -/* Line 1787 of yacc.c */ -#line 1070 "cc.y" +#line 1071 "cc.y" { taggen++; sprint(symb, "_%d_", taggen); @@ -3559,8 +3371,7 @@ yyreduce: break; case 203: -/* Line 1787 of yacc.c */ -#line 1078 "cc.y" +#line 1079 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TENUM, 0); (yyval.type) = (yyvsp[(2) - (2)].sym)->suetag; @@ -3571,16 +3382,14 @@ yyreduce: break; case 204: -/* Line 1787 of yacc.c */ -#line 1086 "cc.y" +#line 1087 "cc.y" { dotag((yyvsp[(2) - (2)].sym), TENUM, autobn); } break; case 205: -/* Line 1787 of yacc.c */ -#line 1090 "cc.y" +#line 1091 "cc.y" { en.tenum = T; en.cenum = T; @@ -3588,8 +3397,7 @@ yyreduce: break; case 206: -/* Line 1787 of yacc.c */ -#line 1095 "cc.y" +#line 1096 "cc.y" { (yyval.type) = (yyvsp[(2) - (7)].sym)->suetag; if((yyval.type)->link != T) @@ -3604,8 +3412,7 @@ yyreduce: break; case 207: -/* Line 1787 of yacc.c */ -#line 1107 "cc.y" +#line 1108 "cc.y" { en.tenum = T; en.cenum = T; @@ -3613,186 +3420,158 @@ yyreduce: break; case 208: -/* Line 1787 of yacc.c */ -#line 1112 "cc.y" +#line 1113 "cc.y" { (yyval.type) = en.tenum; } break; case 209: -/* Line 1787 of yacc.c */ -#line 1116 "cc.y" +#line 1117 "cc.y" { (yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type); } break; case 211: -/* Line 1787 of yacc.c */ -#line 1123 "cc.y" +#line 1124 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 212: -/* Line 1787 of yacc.c */ -#line 1128 "cc.y" +#line 1129 "cc.y" { (yyval.lval) = 0; } break; case 213: -/* Line 1787 of yacc.c */ -#line 1132 "cc.y" +#line 1133 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 218: -/* Line 1787 of yacc.c */ -#line 1144 "cc.y" +#line 1145 "cc.y" { (yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)); } break; case 221: -/* Line 1787 of yacc.c */ -#line 1154 "cc.y" +#line 1155 "cc.y" { doenum((yyvsp[(1) - (1)].sym), Z); } break; case 222: -/* Line 1787 of yacc.c */ -#line 1158 "cc.y" +#line 1159 "cc.y" { doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node)); } break; case 225: -/* Line 1787 of yacc.c */ -#line 1165 "cc.y" +#line 1166 "cc.y" { (yyval.lval) = BCHAR; } break; case 226: -/* Line 1787 of yacc.c */ -#line 1166 "cc.y" +#line 1167 "cc.y" { (yyval.lval) = BSHORT; } break; case 227: -/* Line 1787 of yacc.c */ -#line 1167 "cc.y" +#line 1168 "cc.y" { (yyval.lval) = BINT; } break; case 228: -/* Line 1787 of yacc.c */ -#line 1168 "cc.y" +#line 1169 "cc.y" { (yyval.lval) = BLONG; } break; case 229: -/* Line 1787 of yacc.c */ -#line 1169 "cc.y" +#line 1170 "cc.y" { (yyval.lval) = BSIGNED; } break; case 230: -/* Line 1787 of yacc.c */ -#line 1170 "cc.y" +#line 1171 "cc.y" { (yyval.lval) = BUNSIGNED; } break; case 231: -/* Line 1787 of yacc.c */ -#line 1171 "cc.y" +#line 1172 "cc.y" { (yyval.lval) = BFLOAT; } break; case 232: -/* Line 1787 of yacc.c */ -#line 1172 "cc.y" +#line 1173 "cc.y" { (yyval.lval) = BDOUBLE; } break; case 233: -/* Line 1787 of yacc.c */ -#line 1173 "cc.y" +#line 1174 "cc.y" { (yyval.lval) = BVOID; } break; case 234: -/* Line 1787 of yacc.c */ -#line 1176 "cc.y" +#line 1177 "cc.y" { (yyval.lval) = BAUTO; } break; case 235: -/* Line 1787 of yacc.c */ -#line 1177 "cc.y" +#line 1178 "cc.y" { (yyval.lval) = BSTATIC; } break; case 236: -/* Line 1787 of yacc.c */ -#line 1178 "cc.y" +#line 1179 "cc.y" { (yyval.lval) = BEXTERN; } break; case 237: -/* Line 1787 of yacc.c */ -#line 1179 "cc.y" +#line 1180 "cc.y" { (yyval.lval) = BTYPEDEF; } break; case 238: -/* Line 1787 of yacc.c */ -#line 1180 "cc.y" +#line 1181 "cc.y" { (yyval.lval) = BTYPESTR; } break; case 239: -/* Line 1787 of yacc.c */ -#line 1181 "cc.y" +#line 1182 "cc.y" { (yyval.lval) = BREGISTER; } break; case 240: -/* Line 1787 of yacc.c */ -#line 1182 "cc.y" +#line 1183 "cc.y" { (yyval.lval) = 0; } break; case 241: -/* Line 1787 of yacc.c */ -#line 1185 "cc.y" +#line 1186 "cc.y" { (yyval.lval) = BCONSTNT; } break; case 242: -/* Line 1787 of yacc.c */ -#line 1186 "cc.y" +#line 1187 "cc.y" { (yyval.lval) = BVOLATILE; } break; case 243: -/* Line 1787 of yacc.c */ -#line 1187 "cc.y" +#line 1188 "cc.y" { (yyval.lval) = 0; } break; case 244: -/* Line 1787 of yacc.c */ -#line 1191 "cc.y" +#line 1192 "cc.y" { (yyval.node) = new(ONAME, Z, Z); if((yyvsp[(1) - (1)].sym)->class == CLOCAL) @@ -3809,8 +3588,7 @@ yyreduce: break; case 245: -/* Line 1787 of yacc.c */ -#line 1206 "cc.y" +#line 1207 "cc.y" { (yyval.node) = new(ONAME, Z, Z); (yyval.node)->sym = (yyvsp[(1) - (1)].sym); @@ -3824,21 +3602,10 @@ yyreduce: break; -/* Line 1787 of yacc.c */ -#line 3829 "y.tab.c" +/* Line 1267 of yacc.c. */ +#line 3607 "y.tab.c" default: break; } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); @@ -3847,6 +3614,7 @@ yyreduce: *++yyvsp = yyval; + /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ @@ -3866,10 +3634,6 @@ yyreduce: | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { @@ -3877,36 +3641,37 @@ yyerrlab: #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } } -# undef YYSYNTAX_ERROR #endif } @@ -3914,7 +3679,7 @@ yyerrlab: if (yyerrstatus == 3) { - /* If just tried and failed to reuse lookahead token after an + /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -3931,7 +3696,7 @@ yyerrlab: } } - /* Else will try to reuse lookahead token after shifting the error + /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; @@ -3965,7 +3730,7 @@ yyerrlab1: for (;;) { yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) + if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) @@ -3988,9 +3753,10 @@ yyerrlab1: YY_STACK_PRINT (yyss, yyssp); } - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + if (yyn == YYFINAL) + YYACCEPT; + *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ @@ -4014,7 +3780,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#if !defined yyoverflow || YYERROR_VERBOSE +#ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -4025,14 +3791,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -4056,6 +3817,6 @@ yyreturn: } -/* Line 2050 of yacc.c */ -#line 1219 "cc.y" +#line 1220 "cc.y" + diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h index b26d659ef4..32daca9b67 100644 --- a/src/cmd/cc/y.tab.h +++ b/src/cmd/cc/y.tab.h @@ -1,21 +1,24 @@ -/* A Bison parser, made by GNU Bison 2.7.12-4996. */ +/* A Bison parser, made by GNU Bison 2.3. */ -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - + the Free Software Foundation; either version 2, or (at your option) + any later version. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -26,20 +29,10 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ -#ifndef YY_YY_Y_TAB_H_INCLUDED -# define YY_YY_Y_TAB_H_INCLUDED -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int yydebug; -#endif - /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -196,12 +189,11 @@ extern int yydebug; + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -{ -/* Line 2053 of yacc.c */ #line 36 "cc.y" - +{ Node* node; Sym* sym; Type* type; @@ -225,30 +217,14 @@ typedef union YYSTYPE int32 lval; double dval; vlong vval; - - -/* Line 2053 of yacc.c */ -#line 232 "y.tab.h" -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 +} +/* Line 1529 of yacc.c. */ +#line 223 "y.tab.h" + YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - -#endif /* !YY_YY_Y_TAB_H_INCLUDED */ diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index b90f1baf29..d1930756a2 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -273,7 +273,8 @@ struct MStats bool debuggc; // Statistics about allocation size classes. - struct { + + struct MStatsBySize { uint32 size; uint64 nmalloc; uint64 nfree; @@ -282,6 +283,7 @@ struct MStats uint64 tinyallocs; // number of tiny allocations that didn't cause actual allocation; not exported to Go directly }; + #define mstats runtime·memstats extern MStats mstats; void runtime·updatememstats(GCStats *stats); @@ -489,7 +491,7 @@ struct MHeap // the padding makes sure that the MCentrals are // spaced CacheLineSize bytes apart, so that each MCentral.lock // gets its own cache line. - struct { + struct MHeapCentral { MCentral mcentral; byte pad[CacheLineSize]; } central[NumSizeClasses]; diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h index 7ebaa9c0c6..6d18024834 100644 --- a/src/runtime/os_plan9.h +++ b/src/runtime/os_plan9.h @@ -63,7 +63,7 @@ typedef struct Tos Tos; typedef intptr _Plink; struct Tos { - struct /* Per process profiling */ + struct TosProf /* Per process profiling */ { _Plink *pp; /* known to be 0(ptr) */ _Plink *next; /* known to be 4(ptr) */ diff --git a/src/runtime/proc.c b/src/runtime/proc.c index e84dc1d048..1426790f40 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2421,7 +2421,7 @@ runtime·mcount(void) return runtime·sched.mcount; } -static struct { +static struct ProfState { uint32 lock; int32 hz; } prof; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index aa300d7bb8..c4d8786089 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -384,11 +384,11 @@ struct M // these are here because they are too large to be on the stack // of low-level NOSPLIT functions. LibCall libcall; - struct { + struct MTs { int64 tv_sec; int64 tv_nsec; } ts; - struct { + struct MScratch { uintptr v[6]; } scratch; #endif diff --git a/src/runtime/vdso_linux_amd64.c b/src/runtime/vdso_linux_amd64.c index 41a41fdd6a..681340c5b6 100644 --- a/src/runtime/vdso_linux_amd64.c +++ b/src/runtime/vdso_linux_amd64.c @@ -52,7 +52,7 @@ typedef uint16 Elf64_Section; typedef Elf64_Half Elf64_Versym; -typedef struct +typedef struct Elf64_Sym { Elf64_Word st_name; byte st_info; @@ -62,7 +62,7 @@ typedef struct Elf64_Xword st_size; } Elf64_Sym; -typedef struct +typedef struct Elf64_Verdef { Elf64_Half vd_version; /* Version revision */ Elf64_Half vd_flags; /* Version information */ @@ -73,7 +73,7 @@ typedef struct Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf64_Verdef; -typedef struct +typedef struct Elf64_Ehdr { byte e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ @@ -91,7 +91,7 @@ typedef struct Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr; -typedef struct +typedef struct Elf64_Phdr { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ @@ -103,7 +103,7 @@ typedef struct Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; -typedef struct +typedef struct Elf64_Shdr { Elf64_Word sh_name; /* Section name (string tbl index) */ Elf64_Word sh_type; /* Section type */ @@ -117,7 +117,7 @@ typedef struct Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; -typedef struct +typedef struct Elf64_Dyn { Elf64_Sxword d_tag; /* Dynamic entry type */ union @@ -127,13 +127,13 @@ typedef struct } d_un; } Elf64_Dyn; -typedef struct +typedef struct Elf64_Verdaux { Elf64_Word vda_name; /* Version or dependency names */ Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf64_Verdaux; -typedef struct +typedef struct Elf64_auxv_t { uint64 a_type; /* Entry type */ union @@ -143,13 +143,13 @@ typedef struct } Elf64_auxv_t; -typedef struct { +typedef struct symbol_key { byte* name; int32 sym_hash; void** var_ptr; } symbol_key; -typedef struct { +typedef struct version_key { byte* version; int32 ver_hash; } version_key; From 0120f8378d4de043471fc948fca765abd51a9f4c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 3 Oct 2014 13:36:48 -0400 Subject: [PATCH 281/430] 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 --- src/runtime/chan.go | 11 +++++++++-- src/runtime/proc.go | 10 ++++++++++ src/runtime/select.go | 7 +++++++ src/runtime/sema.go | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 48925b2e3e..10503f4e10 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -140,10 +140,11 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin unlock(&c.lock) recvg := sg.g - recvg.param = unsafe.Pointer(sg) if sg.elem != nil { memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize)) + sg.elem = nil } + recvg.param = unsafe.Pointer(sg) if sg.releasetime != 0 { sg.releasetime = cputicks() } @@ -179,6 +180,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin } panic("send on closed channel") } + gp.param = nil if mysg.releasetime > 0 { blockevent(int64(mysg.releasetime)-t0, 2) } @@ -278,6 +280,7 @@ func closechan(c *hchan) { break } gp := sg.g + sg.elem = nil gp.param = nil if sg.releasetime != 0 { sg.releasetime = cputicks() @@ -292,6 +295,7 @@ func closechan(c *hchan) { break } gp := sg.g + sg.elem = nil gp.param = nil if sg.releasetime != 0 { sg.releasetime = cputicks() @@ -372,6 +376,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r if ep != nil { memmove(ep, sg.elem, uintptr(c.elemsize)) } + sg.elem = nil gp := sg.g gp.param = unsafe.Pointer(sg) if sg.releasetime != 0 { @@ -409,9 +414,11 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r if mysg.releasetime > 0 { blockevent(mysg.releasetime-t0, 2) } + haveData := gp.param != nil + gp.param = nil releaseSudog(mysg) - if gp.param != nil { + if haveData { // a sender sent us some data. It already wrote to ep. selected = true received = true diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 4bb661b54b..76e3ff8851 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -148,6 +148,9 @@ func acquireSudog() *sudog { c := gomcache() s := c.sudogcache if s != nil { + if s.elem != nil { + gothrow("acquireSudog: found s.elem != nil in cache") + } c.sudogcache = s.next return s } @@ -168,6 +171,13 @@ func acquireSudog() *sudog { //go:nosplit 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() s.next = c.sudogcache c.sudogcache = s diff --git a/src/runtime/select.go b/src/runtime/select.go index 7716d2d4b2..1bcea8c4b4 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -368,6 +368,7 @@ loop: // someone woke us up sellock(sel) sg = (*sudog)(gp.param) + gp.param = nil // pass 3 - dequeue from unsuccessful chans // otherwise they stack up on quiet channels @@ -376,6 +377,10 @@ loop: // iterating through the linked list they are in reverse order. cas = nil 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 for i := int(sel.ncase) - 1; i >= 0; i-- { k = &scases[pollorder[i]] @@ -506,6 +511,7 @@ syncrecv: if cas.elem != nil { memmove(cas.elem, sg.elem, uintptr(c.elemsize)) } + sg.elem = nil gp = sg.g gp.param = unsafe.Pointer(sg) if sg.releasetime != 0 { @@ -541,6 +547,7 @@ syncsend: if sg.elem != nil { memmove(sg.elem, cas.elem, uintptr(c.elemsize)) } + sg.elem = nil gp = sg.g gp.param = unsafe.Pointer(sg) if sg.releasetime != 0 { diff --git a/src/runtime/sema.go b/src/runtime/sema.go index 504462de33..a42a29988a 100644 --- a/src/runtime/sema.go +++ b/src/runtime/sema.go @@ -173,6 +173,7 @@ func (root *semaRoot) dequeue(s *sudog) { } else { root.head = s.next } + s.elem = nil s.next = nil s.prev = nil } From 13da3608453f7d50c0c810d5a0df79691bca8b64 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 3 Oct 2014 15:33:29 -0400 Subject: [PATCH 282/430] runtime: clear sg.selectdone before saving in SudoG cache Removes another dangling pointer that might cause a memory leak in 1.4 or crash the GC in 1.5. LGTM=rlh R=golang-codereviews CC=golang-codereviews, iant, khr, r, rlh https://golang.org/cl/150520043 --- src/runtime/proc.go | 3 +++ src/runtime/select.go | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 76e3ff8851..5b8c7d8ae9 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -174,6 +174,9 @@ func releaseSudog(s *sudog) { if s.elem != nil { gothrow("runtime: sudog with non-nil elem") } + if s.selectdone != nil { + gothrow("runtime: sudog with non-nil selectdone") + } gp := getg() if gp.param != nil { gothrow("runtime: releaseSudog with non-nil gp.param") diff --git a/src/runtime/select.go b/src/runtime/select.go index 1bcea8c4b4..9de057b871 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -377,8 +377,14 @@ loop: // iterating through the linked list they are in reverse order. cas = nil sglist = gp.waiting - // Clear all elem before unlinking from gp.waiting. + // Clear all selectdone and elem before unlinking from gp.waiting. + // They must be cleared before being put back into the sudog cache. + // Clear before unlinking, because if a stack copy happens after the unlink, + // they will not be updated, they will be left pointing to the old stack, + // which creates dangling pointers, which may be detected by the + // garbage collector. for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { + sg1.selectdone = nil sg1.elem = nil } gp.waiting = nil From a22424567c622ee0b111787a37e775c815d2e14b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 3 Oct 2014 13:23:35 -0700 Subject: [PATCH 283/430] fmt: part 2 of the great flag rebuild: make %+v work in formatters Apply a similar transformation to %+v that we did to %#v, making it a top-level setting separate from the + flag itself. This fixes the appearance of flags in Formatters and cleans up the code too, probably making it a little faster. Fixes #8835. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/154820043 --- src/fmt/fmt_test.go | 120 ++++++++++++++++++-------------------------- src/fmt/format.go | 48 ++++++++---------- src/fmt/print.go | 111 ++++++++++++++++++++-------------------- 3 files changed, 126 insertions(+), 153 deletions(-) diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index f3b527d1ff..4c3ba8fad1 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -919,7 +919,7 @@ func TestCountMallocs(t *testing.T) { type flagPrinter struct{} -func (*flagPrinter) Format(f State, c rune) { +func (flagPrinter) Format(f State, c rune) { s := "%" for i := 0; i < 128; i++ { if f.Flag(i) { @@ -1208,86 +1208,66 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { } } -// Formatters did not get delivered flags correctly in all cases. Issue 8835. -type fp struct{} - -func (fp) Format(f State, c rune) { - s := "%" - for i := 0; i < 128; i++ { - if f.Flag(i) { - s += string(i) - } - } - if w, ok := f.Width(); ok { - s += Sprintf("%d", w) - } - if p, ok := f.Precision(); ok { - s += Sprintf(".%d", p) - } - s += string(c) - io.WriteString(f, "["+s+"]") -} - var formatterFlagTests = []struct { in string val interface{} out string }{ // scalar values with the (unused by fmt) 'a' verb. - {"%a", fp{}, "[%a]"}, - {"%-a", fp{}, "[%-a]"}, - {"%+a", fp{}, "[%+a]"}, - {"%#a", fp{}, "[%#a]"}, - {"% a", fp{}, "[% a]"}, - {"%0a", fp{}, "[%0a]"}, - {"%1.2a", fp{}, "[%1.2a]"}, - {"%-1.2a", fp{}, "[%-1.2a]"}, - {"%+1.2a", fp{}, "[%+1.2a]"}, - {"%-+1.2a", fp{}, "[%+-1.2a]"}, - {"%-+1.2abc", fp{}, "[%+-1.2a]bc"}, - {"%-1.2abc", fp{}, "[%-1.2a]bc"}, + {"%a", flagPrinter{}, "[%a]"}, + {"%-a", flagPrinter{}, "[%-a]"}, + {"%+a", flagPrinter{}, "[%+a]"}, + {"%#a", flagPrinter{}, "[%#a]"}, + {"% a", flagPrinter{}, "[% a]"}, + {"%0a", flagPrinter{}, "[%0a]"}, + {"%1.2a", flagPrinter{}, "[%1.2a]"}, + {"%-1.2a", flagPrinter{}, "[%-1.2a]"}, + {"%+1.2a", flagPrinter{}, "[%+1.2a]"}, + {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"}, + {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"}, + {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"}, // composite values with the 'a' verb - {"%a", [1]fp{}, "[[%a]]"}, - {"%-a", [1]fp{}, "[[%-a]]"}, - {"%+a", [1]fp{}, "[[%+a]]"}, - {"%#a", [1]fp{}, "[[%#a]]"}, - {"% a", [1]fp{}, "[[% a]]"}, - {"%0a", [1]fp{}, "[[%0a]]"}, - {"%1.2a", [1]fp{}, "[[%1.2a]]"}, - {"%-1.2a", [1]fp{}, "[[%-1.2a]]"}, - {"%+1.2a", [1]fp{}, "[[%+1.2a]]"}, - {"%-+1.2a", [1]fp{}, "[[%+-1.2a]]"}, - {"%-+1.2abc", [1]fp{}, "[[%+-1.2a]]bc"}, - {"%-1.2abc", [1]fp{}, "[[%-1.2a]]bc"}, + {"%a", [1]flagPrinter{}, "[[%a]]"}, + {"%-a", [1]flagPrinter{}, "[[%-a]]"}, + {"%+a", [1]flagPrinter{}, "[[%+a]]"}, + {"%#a", [1]flagPrinter{}, "[[%#a]]"}, + {"% a", [1]flagPrinter{}, "[[% a]]"}, + {"%0a", [1]flagPrinter{}, "[[%0a]]"}, + {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"}, + {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"}, + {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"}, + {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"}, + {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"}, + {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"}, // simple values with the 'v' verb - {"%v", fp{}, "[%v]"}, - {"%-v", fp{}, "[%-v]"}, - {"%+v", fp{}, "[%+v]"}, - {"%#v", fp{}, "[%#v]"}, - {"% v", fp{}, "[% v]"}, - {"%0v", fp{}, "[%0v]"}, - {"%1.2v", fp{}, "[%1.2v]"}, - {"%-1.2v", fp{}, "[%-1.2v]"}, - {"%+1.2v", fp{}, "[%+1.2v]"}, - {"%-+1.2v", fp{}, "[%+-1.2v]"}, - {"%-+1.2vbc", fp{}, "[%+-1.2v]bc"}, - {"%-1.2vbc", fp{}, "[%-1.2v]bc"}, + {"%v", flagPrinter{}, "[%v]"}, + {"%-v", flagPrinter{}, "[%-v]"}, + {"%+v", flagPrinter{}, "[%+v]"}, + {"%#v", flagPrinter{}, "[%#v]"}, + {"% v", flagPrinter{}, "[% v]"}, + {"%0v", flagPrinter{}, "[%0v]"}, + {"%1.2v", flagPrinter{}, "[%1.2v]"}, + {"%-1.2v", flagPrinter{}, "[%-1.2v]"}, + {"%+1.2v", flagPrinter{}, "[%+1.2v]"}, + {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"}, + {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"}, + {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"}, - // composite values with the 'v' verb. Some are still broken. - {"%v", [1]fp{}, "[[%v]]"}, - {"%-v", [1]fp{}, "[[%-v]]"}, - //{"%+v", [1]fp{}, "[[%+v]]"}, - {"%#v", [1]fp{}, "[1]fmt_test.fp{[%#v]}"}, - {"% v", [1]fp{}, "[[% v]]"}, - {"%0v", [1]fp{}, "[[%0v]]"}, - {"%1.2v", [1]fp{}, "[[%1.2v]]"}, - {"%-1.2v", [1]fp{}, "[[%-1.2v]]"}, - //{"%+1.2v", [1]fp{}, "[[%+1.2v]]"}, - //{"%-+1.2v", [1]fp{}, "[[%+-1.2v]]"}, - //{"%-+1.2vbc", [1]fp{}, "[[%+-1.2v]]bc"}, - {"%-1.2vbc", [1]fp{}, "[[%-1.2v]]bc"}, + // composite values with the 'v' verb. + {"%v", [1]flagPrinter{}, "[[%v]]"}, + {"%-v", [1]flagPrinter{}, "[[%-v]]"}, + {"%+v", [1]flagPrinter{}, "[[%+v]]"}, + {"%#v", [1]flagPrinter{}, "[1]fmt_test.flagPrinter{[%#v]}"}, + {"% v", [1]flagPrinter{}, "[[% v]]"}, + {"%0v", [1]flagPrinter{}, "[[%0v]]"}, + {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"}, + {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"}, + {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"}, + {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"}, + {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"}, + {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"}, } func TestFormatterFlags(t *testing.T) { diff --git a/src/fmt/format.go b/src/fmt/format.go index 355b732622..4d97d1443e 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -34,6 +34,25 @@ func init() { } } +// flags placed in a separate struct for easy clearing. +type fmtFlags struct { + widPresent bool + precPresent bool + minus bool + plus bool + sharp bool + space bool + unicode bool + uniQuote bool // Use 'x'= prefix for %U if printable. + zero bool + + // For the formats %+v %#v, we set the plusV/sharpV flags + // and clear the plus/sharp flags since %+v and %#v are in effect + // different, flagless formats set at the top level. + plusV bool + sharpV bool +} + // A fmt is the raw formatter used by Printf etc. // It prints into a buffer that must be set up separately. type fmt struct { @@ -42,36 +61,11 @@ type fmt struct { // width, precision wid int prec int - // flags - widPresent bool - precPresent bool - minus bool - plus bool - sharp bool - space bool - // For the format %#v, we set this flag and - // clear the plus flag, since it is in effect - // a different, flagless format set at the top level. - // TODO: plusV could use this too. - sharpV bool - unicode bool - uniQuote bool // Use 'x'= prefix for %U if printable. - zero bool + fmtFlags } func (f *fmt) clearflags() { - f.wid = 0 - f.widPresent = false - f.prec = 0 - f.precPresent = false - f.minus = false - f.plus = false - f.sharp = false - f.space = false - f.sharpV = false - f.unicode = false - f.uniQuote = false - f.zero = false + f.fmtFlags = fmtFlags{} } func (f *fmt) init(buf *buffer) { diff --git a/src/fmt/print.go b/src/fmt/print.go index f141d39daf..0c66c57817 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -128,7 +128,7 @@ var ppFree = sync.Pool{ New: func() interface{} { return new(pp) }, } -// newPrinter allocates a new pp struct or grab a cached one. +// newPrinter allocates a new pp struct or grabs a cached one. func newPrinter() *pp { p := ppFree.Get().(*pp) p.panicking = false @@ -317,11 +317,11 @@ func (p *pp) badVerb(verb rune) { case p.arg != nil: p.buf.WriteString(reflect.TypeOf(p.arg).String()) p.add('=') - p.printArg(p.arg, 'v', false, 0) + p.printArg(p.arg, 'v', 0) case p.value.IsValid(): p.buf.WriteString(p.value.Type().String()) p.add('=') - p.printValue(p.value, 'v', false, 0) + p.printValue(p.value, 'v', 0) default: p.buf.Write(nilAngleBytes) } @@ -549,7 +549,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) { p.buf.WriteByte(' ') } } - p.printArg(c, 'v', p.fmt.plus, depth+1) + p.printArg(c, 'v', depth+1) } if p.fmt.sharpV { p.buf.WriteByte('}') @@ -641,32 +641,41 @@ func (p *pp) catchPanic(arg interface{}, verb rune) { p.add(verb) p.buf.Write(panicBytes) p.panicking = true - p.printArg(err, 'v', false, 0) + p.printArg(err, 'v', 0) p.panicking = false p.buf.WriteByte(')') } } // clearSpecialFlags pushes %#v back into the regular flags and returns their old state. -func (p *pp) clearSpecialFlags() bool { - ret := p.fmt.sharpV - if ret { +func (p *pp) clearSpecialFlags() (plusV, sharpV bool) { + plusV = p.fmt.plusV + if plusV { + p.fmt.plus = true + p.fmt.plusV = false + } + sharpV = p.fmt.sharpV + if sharpV { p.fmt.sharp = true p.fmt.sharpV = false } - return ret + return } // restoreSpecialFlags, whose argument should be a call to clearSpecialFlags, -// restores the setting of the sharpV flag. -func (p *pp) restoreSpecialFlags(sharpV bool) { +// restores the setting of the plusV and sharpV flags. +func (p *pp) restoreSpecialFlags(plusV, sharpV bool) { + if plusV { + p.fmt.plus = false + p.fmt.plusV = true + } if sharpV { p.fmt.sharp = false p.fmt.sharpV = true } } -func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) { +func (p *pp) handleMethods(verb rune, depth int) (handled bool) { if p.erroring { return } @@ -678,19 +687,14 @@ func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) { formatter.Format(p, verb) return } - // Must not touch flags before Formatter looks at them. - if plus { - p.fmt.plus = false - } // If we're doing Go syntax and the argument knows how to supply it, take care of it now. if p.fmt.sharpV { if stringer, ok := p.arg.(GoStringer); ok { handled = true - defer p.restoreSpecialFlags(p.clearSpecialFlags()) defer p.catchPanic(p.arg, verb) // Print the result of GoString unadorned. - p.fmtString(stringer.GoString(), 's') + p.fmt.fmt_s(stringer.GoString()) return } } else { @@ -707,13 +711,13 @@ func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) { case error: handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.Error(), verb, plus, depth) + p.printArg(v.Error(), verb, depth) return case Stringer: handled = true defer p.catchPanic(p.arg, verb) - p.printArg(v.String(), verb, plus, depth) + p.printArg(v.String(), verb, depth) return } } @@ -721,7 +725,7 @@ func (p *pp) handleMethods(verb rune, plus bool, depth int) (handled bool) { return false } -func (p *pp) printArg(arg interface{}, verb rune, plus bool, depth int) (wasString bool) { +func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) { p.arg = arg p.value = reflect.Value{} @@ -738,22 +742,13 @@ func (p *pp) printArg(arg interface{}, verb rune, plus bool, depth int) (wasStri // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(reflect.TypeOf(arg).String(), 's', false, 0) + p.printArg(reflect.TypeOf(arg).String(), 's', 0) return false case 'p': p.fmtPointer(reflect.ValueOf(arg), verb) return false } - // Clear flags for base formatters. - // handleMethods needs them, so we must restore them later. - // We could call handleMethods here and avoid this work, but - // handleMethods is expensive enough to be worth delaying. - oldPlus := p.fmt.plus - if plus { - p.fmt.plus = false - } - // Some types can be done without reflection. switch f := arg.(type) { case bool: @@ -795,21 +790,19 @@ func (p *pp) printArg(arg interface{}, verb rune, plus bool, depth int) (wasStri p.fmtBytes(f, verb, nil, depth) wasString = verb == 's' default: - // Restore flags in case handleMethods finds a Formatter. - p.fmt.plus = oldPlus // If the type is not simple, it might have methods. - if handled := p.handleMethods(verb, plus, depth); handled { + if handled := p.handleMethods(verb, depth); handled { return false } // Need to use reflection - return p.printReflectValue(reflect.ValueOf(arg), verb, plus, depth) + return p.printReflectValue(reflect.ValueOf(arg), verb, depth) } p.arg = nil return } // printValue is like printArg but starts with a reflect value, not an interface{} value. -func (p *pp) printValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) { +func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) { if !value.IsValid() { if verb == 'T' || verb == 'v' { p.buf.Write(nilAngleBytes) @@ -823,7 +816,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus bool, depth int) (w // %T (the value's type) and %p (its address) are special; we always do them first. switch verb { case 'T': - p.printArg(value.Type().String(), 's', false, 0) + p.printArg(value.Type().String(), 's', 0) return false case 'p': p.fmtPointer(value, verb) @@ -836,18 +829,18 @@ func (p *pp) printValue(value reflect.Value, verb rune, plus bool, depth int) (w if value.CanInterface() { p.arg = value.Interface() } - if handled := p.handleMethods(verb, plus, depth); handled { + if handled := p.handleMethods(verb, depth); handled { return false } - return p.printReflectValue(value, verb, plus, depth) + return p.printReflectValue(value, verb, depth) } var byteType = reflect.TypeOf(byte(0)) // printReflectValue is the fallback for both printArg and printValue. // It uses reflect to print the value. -func (p *pp) printReflectValue(value reflect.Value, verb rune, plus bool, depth int) (wasString bool) { +func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) { oldValue := p.value p.value = value BigSwitch: @@ -892,9 +885,9 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printValue(key, verb, plus, depth+1) + p.printValue(key, verb, depth+1) p.buf.WriteByte(':') - p.printValue(f.MapIndex(key), verb, plus, depth+1) + p.printValue(f.MapIndex(key), verb, depth+1) } if p.fmt.sharpV { p.buf.WriteByte('}') @@ -916,13 +909,13 @@ BigSwitch: p.buf.WriteByte(' ') } } - if plus || p.fmt.sharpV { + if p.fmt.plusV || p.fmt.sharpV { if f := t.Field(i); f.Name != "" { p.buf.WriteString(f.Name) p.buf.WriteByte(':') } } - p.printValue(getField(v, i), verb, plus, depth+1) + p.printValue(getField(v, i), verb, depth+1) } p.buf.WriteByte('}') case reflect.Interface: @@ -935,7 +928,7 @@ BigSwitch: p.buf.Write(nilAngleBytes) } } else { - wasString = p.printValue(value, verb, plus, depth+1) + wasString = p.printValue(value, verb, depth+1) } case reflect.Array, reflect.Slice: // Byte slices are special: @@ -980,7 +973,7 @@ BigSwitch: p.buf.WriteByte(' ') } } - p.printValue(f.Index(i), verb, plus, depth+1) + p.printValue(f.Index(i), verb, depth+1) } if p.fmt.sharpV { p.buf.WriteByte('}') @@ -995,11 +988,11 @@ BigSwitch: switch a := f.Elem(); a.Kind() { case reflect.Array, reflect.Slice: p.buf.WriteByte('&') - p.printValue(a, verb, plus, depth+1) + p.printValue(a, verb, depth+1) break BigSwitch case reflect.Struct: p.buf.WriteByte('&') - p.printValue(a, verb, plus, depth+1) + p.printValue(a, verb, depth+1) break BigSwitch } } @@ -1171,13 +1164,19 @@ func (p *pp) doPrintf(format string, a []interface{}) { arg := a[argNum] argNum++ - if c == 'v' && p.fmt.sharp { - // Go syntax. Set the flag in the fmt and clear the sharp flag. - p.fmt.sharp = false - p.fmt.sharpV = true + if c == 'v' { + if p.fmt.sharp { + // Go syntax. Set the flag in the fmt and clear the sharp flag. + p.fmt.sharp = false + p.fmt.sharpV = true + } + if p.fmt.plus { + // Struct-field syntax. Set the flag in the fmt and clear the plus flag. + p.fmt.plus = false + p.fmt.plusV = true + } } - plus := c == 'v' && p.fmt.plus - p.printArg(arg, c, plus, 0) + p.printArg(arg, c, 0) } // Check for extra arguments unless the call accessed the arguments @@ -1191,7 +1190,7 @@ func (p *pp) doPrintf(format string, a []interface{}) { p.buf.WriteString(reflect.TypeOf(arg).String()) p.buf.WriteByte('=') } - p.printArg(arg, 'v', false, 0) + p.printArg(arg, 'v', 0) if argNum+1 < len(a) { p.buf.Write(commaSpaceBytes) } @@ -1212,7 +1211,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) { p.buf.WriteByte(' ') } } - prevString = p.printArg(arg, 'v', false, 0) + prevString = p.printArg(arg, 'v', 0) } if addnewline { p.buf.WriteByte('\n') From 46302185383a079957a0e72c785ef0c507ab1d46 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 3 Oct 2014 16:42:18 -0400 Subject: [PATCH 284/430] misc/cgo/test: fail issue 7978 with clearer error when GOTRACEBACK != 2 The test doesn't work with GOTRACEBACK != 2. Diagnose that failure mode. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/152970043 --- misc/cgo/test/issue7978.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go index 39864476ce..5feed07b95 100644 --- a/misc/cgo/test/issue7978.go +++ b/misc/cgo/test/issue7978.go @@ -29,6 +29,7 @@ static void issue7978c(uint32_t *sync) { import "C" import ( + "os" "runtime" "strings" "sync/atomic" @@ -81,6 +82,9 @@ func issue7978go() { } func test7978(t *testing.T) { + if os.Getenv("GOTRACEBACK") != "2" { + t.Fatalf("GOTRACEBACK must be 2") + } issue7978sync = 0 go issue7978go() // test in c code, before callback From 19104dc532bb15896090c2f8a72080a342fcad20 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Sat, 4 Oct 2014 08:09:39 +1000 Subject: [PATCH 285/430] crypto/x509: add OpenELEC system root location. Fixes #8349. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/147320043 --- src/crypto/x509/root_unix.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go index 10057c0c03..c65f626ac8 100644 --- a/src/crypto/x509/root_unix.go +++ b/src/crypto/x509/root_unix.go @@ -15,6 +15,7 @@ var certFiles = []string{ "/etc/ssl/ca-bundle.pem", // OpenSUSE "/etc/ssl/cert.pem", // OpenBSD "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly + "/etc/pki/tls/cacert.pem", // OpenELEC } // Possible directories with certificate files; stop after successfully From 668ea79283735b35d5234d0b4c4e9f87ce0615d1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 3 Oct 2014 18:12:05 -0700 Subject: [PATCH 286/430] doc/go1.4: mention that we are going to need a new version of SWIG Update #8750 CC=golang-codereviews https://golang.org/cl/153950044 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 7895ddd03c..75354643d5 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -32,6 +32,7 @@ runtime: implement monotonic clocks on windows (CL 108700045) runtime: stack size 2K (4K on plan 9 and windows) (CL 145790043) runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043). runtime/race: freebsd is supported (CL 107270043) +swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released) sync/atomic: add Value (CL 136710045) syscall: Setuid, Setgid are disabled on linux platforms. On linux those syscalls operate on the calling thread, not the whole process. This does not match the semantics of other platforms, nor the expectations of the caller, so the operations have been disabled until issue 1435 is resolved (CL 106170043) syscall: now frozen (CL 129820043) From a0c5adc35cbfe071786b6115d63abc7ad90578a9 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 3 Oct 2014 20:27:08 -0700 Subject: [PATCH 287/430] fmt: print &map like &slice and &struct It was inconsistent. Also test these better. Also document the default format for types. This wasn't written down. Fixes #8470. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/154870043 --- src/fmt/doc.go | 17 ++++++++++++++++- src/fmt/fmt_test.go | 34 ++++++++++++++++++++++++++++++++-- src/fmt/print.go | 4 ++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index 00dd8d01cd..304b9e9581 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -13,7 +13,7 @@ The verbs: General: - %v the value in a default format. + %v the value in a default format when printing structs, the plus flag (%+v) adds field names %#v a Go-syntax representation of the value %T a Go-syntax representation of the type of the value @@ -51,6 +51,21 @@ There is no 'u' flag. Integers are printed unsigned if they have unsigned type. Similarly, there is no need to specify the size of the operand (int8, int64). + The default format for %v is: + bool: %t + int, int8 etc.: %d + uint, uint8 etc.: %d, %x if printed with %#v + float32, complex64, etc: %g + string: %s + chan: %p + pointer: %p + For compound objects, the elements are printed using these rules, recursively, + laid out like this: + struct: {field0 field1 ...} + array, slice: [elem0 elem1 ...] + maps: map[key1:value1 key2:value2] + pointer to above: &{}, &[], &map[] + Width is specified by an optional decimal number immediately following the verb. If absent, the width is whatever is necessary to represent the value. Precision is specified after the (optional) width by a period followed by a diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 4c3ba8fad1..ff5fa79a32 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -965,11 +965,12 @@ func TestFlagParser(t *testing.T) { } func TestStructPrinter(t *testing.T) { - var s struct { + type T struct { a string b string c int } + var s T s.a = "abc" s.b = "def" s.c = 123 @@ -979,12 +980,35 @@ func TestStructPrinter(t *testing.T) { }{ {"%v", "{abc def 123}"}, {"%+v", "{a:abc b:def c:123}"}, + {"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`}, } for _, tt := range tests { out := Sprintf(tt.fmt, s) if out != tt.out { - t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out) + t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out) } + // The same but with a pointer. + out = Sprintf(tt.fmt, &s) + if out != "&"+tt.out { + t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out) + } + } +} + +func TestSlicePrinter(t *testing.T) { + slice := []int{} + s := Sprint(slice) + if s != "[]" { + t.Errorf("empty slice printed as %q not %q", s, "[]") + } + slice = []int{1, 2, 3} + s = Sprint(slice) + if s != "[1 2 3]" { + t.Errorf("slice: got %q expected %q", s, "[1 2 3]") + } + s = Sprint(&slice) + if s != "&[1 2 3]" { + t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]") } } @@ -1014,6 +1038,12 @@ func TestMapPrinter(t *testing.T) { a := []string{"1:one", "2:two", "3:three"} presentInMap(Sprintf("%v", m1), a, t) presentInMap(Sprint(m1), a, t) + // Pointer to map prints the same but with initial &. + if !strings.HasPrefix(Sprint(&m1), "&") { + t.Errorf("no initial & for address of map") + } + presentInMap(Sprintf("%v", &m1), a, t) + presentInMap(Sprint(&m1), a, t) } func TestEmptyMap(t *testing.T) { diff --git a/src/fmt/print.go b/src/fmt/print.go index 0c66c57817..59a30d221e 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -994,6 +994,10 @@ BigSwitch: p.buf.WriteByte('&') p.printValue(a, verb, depth+1) break BigSwitch + case reflect.Map: + p.buf.WriteByte('&') + p.printValue(a, verb, depth+1) + break BigSwitch } } fallthrough From c4e2e0de1adbdae6f397d1fe1f96f0eb774360bc Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 3 Oct 2014 20:30:06 -0700 Subject: [PATCH 288/430] doc/go1.4.txt: fmt: document printing of &map rather than just pointer CC=golang-codereviews https://golang.org/cl/152160043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 75354643d5..0f79389a56 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -21,6 +21,7 @@ cmd/go: compile and link all _test.go files during 'go test', even in packages w asm: make textflag.h available outside of cmd/ld (CL 128050043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) crypto/tls: support programmatic selection of server certificates (CL 107400043) +fmt: print type *map[T]T as &map[k:v] (CL 154870043) encoding/gob: remove unsafe (CL 102680045) misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) net/http: add Request.BasicAuth method (CL 76540043) From 0a6f8b042d168986cc2c07a62c05c769310a6c3e Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Sat, 4 Oct 2014 12:02:04 +0400 Subject: [PATCH 289/430] doc/go1.4: document memory consumption reduction R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/149370043 --- doc/go1.4.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 0f79389a56..3564e7d2d2 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -30,7 +30,7 @@ net/http/httputil: add ReverseProxy.ErrorLog (CL 132750043) os: implement symlink support for windows (CL 86160044) reflect: add type.Comparable (CL 144020043) runtime: implement monotonic clocks on windows (CL 108700045) -runtime: stack size 2K (4K on plan 9 and windows) (CL 145790043) +runtime: memory consumption is reduced by 10-30% (CL 106260045 removes type info from heap, CL 145790043 reduces stack size to 2K (4K on plan 9 and windows)) runtime: MemStats.Mallocs now counts very small allocations missed in Go 1.3. This may break tests using runtime.ReadMemStats or testing.AllocsPerRun by giving a more accurate answer than Go 1.3 did (CL 143150043). runtime/race: freebsd is supported (CL 107270043) swig: Due to runtime changes Go 1.4 will require SWIG 3.0.3 (not yet released) From ee8e28d328567b5f12a94b1156b5f6d20d1f67fe Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sun, 5 Oct 2014 13:15:13 +1100 Subject: [PATCH 290/430] syscall: another attempt to keep windows syscall pointers live This approach was suggested in https://golang.org/cl/138250043/#msg15. Unlike current version of mksyscall_windows.go, new code could be used in go.sys and other external repos without help from asm. LGTM=iant R=golang-codereviews, iant, r CC=golang-codereviews https://golang.org/cl/143160046 --- src/syscall/mksyscall_windows.go | 79 ++++++++++++++++++++++++++++---- src/syscall/zsyscall_windows.go | 36 ++++++++++++--- 2 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index 1cdd6b4d22..316e88d7ea 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -138,8 +138,6 @@ func (p *Param) StringTmpVarCode() string { // TmpVarCode returns source code for temp variable. func (p *Param) TmpVarCode() string { switch { - case p.Type == "string": - return p.StringTmpVarCode() case p.Type == "bool": return p.BoolTmpVarCode() case strings.HasPrefix(p.Type, "[]"): @@ -149,19 +147,26 @@ func (p *Param) TmpVarCode() string { } } +// TmpVarHelperCode returns source code for helper's temp variable. +func (p *Param) TmpVarHelperCode() string { + if p.Type != "string" { + return "" + } + return p.StringTmpVarCode() +} + // SyscallArgList returns source code fragments representing p parameter // in syscall. Slices are translated into 2 syscall parameters: pointer to // the first element and length. func (p *Param) SyscallArgList() []string { + t := p.HelperType() var s string switch { - case p.Type[0] == '*': + case t[0] == '*': s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name) - case p.Type == "string": - s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar()) - case p.Type == "bool": + case t == "bool": s = p.tmpVar() - case strings.HasPrefix(p.Type, "[]"): + case strings.HasPrefix(t, "[]"): return []string{ fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()), fmt.Sprintf("uintptr(len(%s))", p.Name), @@ -177,6 +182,14 @@ func (p *Param) IsError() bool { return p.Name == "err" && p.Type == "error" } +// HelperType returns type of parameter p used in helper function. +func (p *Param) HelperType() string { + if p.Type == "string" { + return p.fn.StrconvType() + } + return p.Type +} + // join concatenates parameters ps into a string with sep separator. // Each parameter is converted into string by applying fn to it // before conversion. @@ -454,6 +467,11 @@ func (f *Fn) ParamList() string { return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ") } +// HelperParamList returns source code for helper function f parameters. +func (f *Fn) HelperParamList() string { + return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ") +} + // ParamPrintList returns source code of trace printing part correspondent // to syscall input parameters. func (f *Fn) ParamPrintList() string { @@ -510,6 +528,19 @@ func (f *Fn) SyscallParamList() string { return strings.Join(a, ", ") } +// HelperCallParamList returns source code of call into function f helper. +func (f *Fn) HelperCallParamList() string { + a := make([]string, 0, len(f.Params)) + for _, p := range f.Params { + s := p.Name + if p.Type == "string" { + s = p.tmpVar() + } + a = append(a, s) + } + return strings.Join(a, ", ") +} + // IsUTF16 is true, if f is W (utf16) function. It is false // for all A (ascii) functions. func (f *Fn) IsUTF16() bool { @@ -533,6 +564,25 @@ func (f *Fn) StrconvType() string { return "*byte" } +// HasStringParam is true, if f has at least one string parameter. +// Otherwise it is false. +func (f *Fn) HasStringParam() bool { + for _, p := range f.Params { + if p.Type == "string" { + return true + } + } + return false +} + +// HelperName returns name of function f helper. +func (f *Fn) HelperName() string { + if !f.HasStringParam() { + return f.Name + } + return "_" + f.Name +} + // Source files and functions. type Source struct { Funcs []*Fn @@ -666,7 +716,7 @@ import "syscall"{{end}} var ( {{template "dlls" .}} {{template "funcnames" .}}) -{{range .Funcs}}{{template "funcbody" .}}{{end}} +{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}} {{end}} {{/* help functions */}} @@ -677,16 +727,27 @@ var ( {{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}") {{end}}{{end}} +{{define "helperbody"}} +func {{.Name}}({{.ParamList}}) {{template "results" .}}{ +{{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}}) +} +{{end}} + {{define "funcbody"}} -func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{ +func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{ {{template "tmpvars" .}} {{template "syscall" .}} {{template "seterror" .}}{{template "printtrace" .}} return } {{end}} +{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}} +{{end}}{{end}}{{end}} + {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}} {{end}}{{end}}{{end}} +{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}} + {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} {{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}} diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 1f44750b7f..afc28f9939 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -176,7 +176,11 @@ func LoadLibrary(libname string) (handle Handle, err error) { if err != nil { return } - r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + return _LoadLibrary(_p0) +} + +func _LoadLibrary(libname *uint16) (handle Handle, err error) { + r0, _, e1 := Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0) handle = Handle(r0) if handle == 0 { if e1 != 0 { @@ -206,7 +210,11 @@ func GetProcAddress(module Handle, procname string) (proc uintptr, err error) { if err != nil { return } - r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(_p0)), 0) + return _GetProcAddress(module, _p0) +} + +func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) { + r0, _, e1 := Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0) proc = uintptr(r0) if proc == 0 { if e1 != 0 { @@ -1558,7 +1566,11 @@ func GetHostByName(name string) (h *Hostent, err error) { if err != nil { return } - r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + return _GetHostByName(_p0) +} + +func _GetHostByName(name *byte) (h *Hostent, err error) { + r0, _, e1 := Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) h = (*Hostent)(unsafe.Pointer(r0)) if h == nil { if e1 != 0 { @@ -1581,7 +1593,11 @@ func GetServByName(name string, proto string) (s *Servent, err error) { if err != nil { return } - r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + return _GetServByName(_p0, _p1) +} + +func _GetServByName(name *byte, proto *byte) (s *Servent, err error) { + r0, _, e1 := Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0) s = (*Servent)(unsafe.Pointer(r0)) if s == nil { if e1 != 0 { @@ -1605,7 +1621,11 @@ func GetProtoByName(name string) (p *Protoent, err error) { if err != nil { return } - r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0) + return _GetProtoByName(_p0) +} + +func _GetProtoByName(name *byte) (p *Protoent, err error) { + r0, _, e1 := Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) p = (*Protoent)(unsafe.Pointer(r0)) if p == nil { if e1 != 0 { @@ -1623,7 +1643,11 @@ func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSR if status != nil { return } - r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(_p0)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + return _DnsQuery(_p0, qtype, options, extra, qrs, pr) +} + +func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) { + r0, _, _ := Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) if r0 != 0 { status = Errno(r0) } From 83001ffaaf90dcb32a7a1e2c95f6913bf1503618 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 13:09:14 -0400 Subject: [PATCH 291/430] net: disable TestDualStackUDPListener in short mode This test is flaky, just like TestDualStackTCPListener. That one was disabled. Disable this one too. Update #5001 LGTM=bradfitz R=rlh, bradfitz CC=golang-codereviews https://golang.org/cl/154950043 --- src/net/unicast_posix_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/net/unicast_posix_test.go b/src/net/unicast_posix_test.go index 452ac92542..ab7ef40a75 100644 --- a/src/net/unicast_posix_test.go +++ b/src/net/unicast_posix_test.go @@ -204,6 +204,9 @@ func TestDualStackTCPListener(t *testing.T) { // to a test listener with various address families, differnet // listening address and same port. func TestDualStackUDPListener(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode, see issue 5001") + } switch runtime.GOOS { case "plan9": t.Skipf("skipping test on %q", runtime.GOOS) From 52fe7c56cd9541e3c27711cf5a4e98bc3b4dc328 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 6 Oct 2014 10:41:24 -0700 Subject: [PATCH 292/430] A+C: Jens Frederich (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/151450043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index f22fe4c982..a924ea965f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -214,6 +214,7 @@ Jeff Hodges Jeff R. Allen Jeff Sickel Jeff Wendling +Jens Frederich Jeremy Jackins Jim McGrath Jimmy Zelinskie diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 5dadda0ca4..9dce23b2d5 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -300,6 +300,7 @@ Jeff Hodges Jeff R. Allen Jeff Sickel Jeff Wendling +Jens Frederich Jeremiah Harmsen Jeremy Jackins Jeremy Schlatter From 609d996fac7f68b34032572b7bde627f658b95f2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 14:17:48 -0400 Subject: [PATCH 293/430] cmd/8l: accept R_386_GOT32 in push instruction Fixes #8382. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/149540045 --- src/cmd/8l/asm.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index c135dce709..98c0424037 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -117,13 +117,21 @@ adddynrel(LSym *s, Reloc *r) case 256 + R_386_GOT32: if(targ->type != SDYNIMPORT) { // have symbol - // turn MOVL of GOT entry into LEAL of symbol itself - if(r->off < 2 || s->p[r->off-2] != 0x8b) { - diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); + if(r->off >= 2 && s->p[r->off-2] == 0x8b) { + // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT. + s->p[r->off-2] = 0x8d; + r->type = R_GOTOFF; return; } - s->p[r->off-2] = 0x8d; - r->type = R_GOTOFF; + if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) { + // turn PUSHL of GOT entry into PUSHL of symbol itself. + // use unnecessary SS prefix to keep instruction same length. + s->p[r->off-2] = 0x36; + s->p[r->off-1] = 0x68; + r->type = R_ADDR; + return; + } + diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name); return; } addgotsym(ctxt, targ); From 9a5b055b95c6719083f32c1f8089725a0a890425 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 14:18:09 -0400 Subject: [PATCH 294/430] runtime: update docs, code for SetFinalizer At last minute before 1.3 we relaxed SetFinalizer to avoid crashes when you pass the result of a global alloc to it. This avoids the crash but makes SetFinalizer a bit too relaxed. Document that the finalizer of a global allocation may not run. Tighten the SetFinalizer check to ignore a global allocation but not ignore everything else. Fixes #7656. LGTM=r, iant R=golang-codereviews, iant, r CC=dvyukov, golang-codereviews, khr, rlh https://golang.org/cl/145930043 --- src/runtime/malloc.go | 37 +++++++++++++++++++++++-------------- src/runtime/mfinal_test.go | 13 ++++++++++--- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index fc22cc29e4..99d14e3145 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -488,6 +488,10 @@ func GC() { gogc(2) } +// linker-provided +var noptrdata struct{} +var enoptrbss struct{} + // SetFinalizer sets the finalizer associated with x to f. // When the garbage collector finds an unreachable block // with an associated finalizer, it clears the association and runs @@ -527,6 +531,10 @@ func GC() { // It is not guaranteed that a finalizer will run if the size of *x is // zero bytes. // +// It is not guaranteed that a finalizer will run for objects allocated +// in initializers for package-level variables. Such objects may be +// linker-allocated, not heap-allocated. +// // A single goroutine runs all finalizers for a program, sequentially. // If a finalizer must run for a long time, it should do so by starting // a new goroutine. @@ -544,24 +552,25 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { gothrow("nil elem type!") } - // As an implementation detail we do not run finalizers for zero-sized objects, - // because we use &runtime·zerobase for all such allocations. - if ot.elem.size == 0 { - return - } - // find the containing object _, base, _ := findObject(e.data) - // The following check is required for cases when a user passes a pointer to composite - // literal, but compiler makes it a pointer to global. For example: - // var Foo = &Object{} - // func main() { - // runtime.SetFinalizer(Foo, nil) - // } - // See issue 7656. if base == nil { - return + // 0-length objects are okay. + if e.data == unsafe.Pointer(&zerobase) { + return + } + + // Global initializers might be linker-allocated. + // var Foo = &Object{} + // func main() { + // runtime.SetFinalizer(Foo, nil) + // } + // The segments are, in order: text, rodata, noptrdata, data, bss, noptrbss. + if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { + return + } + gothrow("runtime.SetFinalizer: pointer not in allocated block") } if e.data != base { diff --git a/src/runtime/mfinal_test.go b/src/runtime/mfinal_test.go index 6b53888ab6..d2cead2876 100644 --- a/src/runtime/mfinal_test.go +++ b/src/runtime/mfinal_test.go @@ -44,10 +44,17 @@ func TestFinalizerType(t *testing.T) { {func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }}, } - for _, tt := range finalizerTests { + for i, tt := range finalizerTests { done := make(chan bool, 1) go func() { - v := new(int) + // allocate struct with pointer to avoid hitting tinyalloc. + // Otherwise we can't be sure when the allocation will + // be freed. + type T struct { + v int + p unsafe.Pointer + } + v := &new(T).v *v = 97531 runtime.SetFinalizer(tt.convert(v), tt.finalizer) v = nil @@ -58,7 +65,7 @@ func TestFinalizerType(t *testing.T) { select { case <-ch: case <-time.After(time.Second * 4): - t.Errorf("finalizer for type %T didn't run", tt.finalizer) + t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer) } } } From 7e6e502f9b9a253603c43bb783b82a043a67c3d4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 14:49:22 -0400 Subject: [PATCH 295/430] cmd/go: fix 'go vet' of package with external tests For example, fixes 'go vet syscall', which has source files in package syscall_test. Fixes #8511. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/152220044 --- src/cmd/go/test.bash | 14 ++++++++++++++ src/cmd/go/testdata/src/vetpkg/a_test.go | 1 + src/cmd/go/testdata/src/vetpkg/b.go | 7 +++++++ src/cmd/go/vet.go | 23 ++++++++++++++++++----- 4 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 src/cmd/go/testdata/src/vetpkg/a_test.go create mode 100644 src/cmd/go/testdata/src/vetpkg/b.go diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash index 6a72bcde07..652ef3b5b6 100755 --- a/src/cmd/go/test.bash +++ b/src/cmd/go/test.bash @@ -1085,6 +1085,20 @@ fi unset GOPATH rm -rf $d +TEST go vet with external tests +d=$(mktemp -d -t testgoXXX) +export GOPATH=$(pwd)/testdata +if ./testgo vet vetpkg >$d/err 2>&1; then + echo "go vet vetpkg passes incorrectly" + ok=false +elif ! grep -q 'missing argument for Printf' $d/err; then + echo "go vet vetpkg did not find missing argument for Printf" + cat $d/err + ok=false +fi +unset GOPATH +rm -rf $d + # clean up if $started; then stop; fi rm -rf testdata/bin testdata/bin1 diff --git a/src/cmd/go/testdata/src/vetpkg/a_test.go b/src/cmd/go/testdata/src/vetpkg/a_test.go new file mode 100644 index 0000000000..9b64e8e1a2 --- /dev/null +++ b/src/cmd/go/testdata/src/vetpkg/a_test.go @@ -0,0 +1 @@ +package p_test diff --git a/src/cmd/go/testdata/src/vetpkg/b.go b/src/cmd/go/testdata/src/vetpkg/b.go new file mode 100644 index 0000000000..99e18f63dc --- /dev/null +++ b/src/cmd/go/testdata/src/vetpkg/b.go @@ -0,0 +1,7 @@ +package p + +import "fmt" + +func f() { + fmt.Printf("%d") +} diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go index ffb4318373..de7befc611 100644 --- a/src/cmd/go/vet.go +++ b/src/cmd/go/vet.go @@ -4,6 +4,8 @@ package main +import "path/filepath" + func init() { addBuildFlagsNX(cmdVet) } @@ -28,10 +30,21 @@ See also: go fmt, go fix. } func runVet(cmd *Command, args []string) { - for _, pkg := range packages(args) { - // Use pkg.gofiles instead of pkg.Dir so that - // the command only applies to this package, - // not to packages in subdirectories. - run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles))) + for _, p := range packages(args) { + // Vet expects to be given a set of files all from the same package. + // Run once for package p and once for package p_test. + if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles) > 0 { + runVetFiles(p, stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.SFiles)) + } + if len(p.XTestGoFiles) > 0 { + runVetFiles(p, stringList(p.XTestGoFiles)) + } } } + +func runVetFiles(p *Package, files []string) { + for i := range files { + files[i] = filepath.Join(p.Dir, files[i]) + } + run(tool("vet"), relPaths(files)) +} From 85fd0fd7c432e1f1fb1fa1ccf18c1f935a9b2720 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 15:32:11 -0400 Subject: [PATCH 296/430] regexp/syntax: regenerate doc.go from re2 syntax Generated using re2/doc/mksyntaxgo. Fixes #8505. LGTM=iant R=r, iant CC=golang-codereviews https://golang.org/cl/155890043 --- src/regexp/syntax/doc.go | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/regexp/syntax/doc.go b/src/regexp/syntax/doc.go index 8e72c90d3e..e5e71f14f5 100644 --- a/src/regexp/syntax/doc.go +++ b/src/regexp/syntax/doc.go @@ -21,8 +21,8 @@ Single characters: [^xyz] negated character class \d Perl character class \D negated Perl character class - [:alpha:] ASCII character class - [:^alpha:] negated ASCII character class + [[:alpha:]] ASCII character class + [[:^alpha:]] negated ASCII character class \pN Unicode character class (one-letter name) \p{Greek} Unicode character class \PN negated Unicode character class (one-letter name) @@ -46,14 +46,14 @@ Repetitions: x{n,}? n or more x, prefer fewer x{n}? exactly n x -Implementation restriction: The counting forms x{n} etc. (but not the other -forms x* etc.) have an upper limit of n=1000. Negative or higher explicit -counts yield the parse error ErrInvalidRepeatSize. +Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} +reject forms that create a minimum or maximum repetition count above 1000. +Unlimited repetitions are not subject to this restriction. Grouping: (re) numbered capturing group (submatch) (?Pre) named & numbered capturing group (submatch) - (?:re) non-capturing group (submatch) + (?:re) non-capturing group (?flags) set flags within current group; non-capturing (?flags:re) set flags during re; non-capturing @@ -69,7 +69,7 @@ Empty strings: $ at end of text (like \z not \Z) or line (flag m=true) \A at beginning of text \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) - \B not an ASCII word boundary + \B not at ASCII word boundary \z at end of text Escape sequences: @@ -103,29 +103,29 @@ Named character classes as character class elements: [\p{Name}] named Unicode property inside character class (== \p{Name}) [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) -Perl character classes: +Perl character classes (all ASCII-only): \d digits (== [0-9]) \D not digits (== [^0-9]) \s whitespace (== [\t\n\f\r ]) \S not whitespace (== [^\t\n\f\r ]) - \w ASCII word characters (== [0-9A-Za-z_]) - \W not ASCII word characters (== [^0-9A-Za-z_]) + \w word characters (== [0-9A-Za-z_]) + \W not word characters (== [^0-9A-Za-z_]) ASCII character classes: - [:alnum:] alphanumeric (== [0-9A-Za-z]) - [:alpha:] alphabetic (== [A-Za-z]) - [:ascii:] ASCII (== [\x00-\x7F]) - [:blank:] blank (== [\t ]) - [:cntrl:] control (== [\x00-\x1F\x7F]) - [:digit:] digits (== [0-9]) - [:graph:] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) - [:lower:] lower case (== [a-z]) - [:print:] printable (== [ -~] == [ [:graph:]]) - [:punct:] punctuation (== [!-/:-@[-`{-~]) - [:space:] whitespace (== [\t\n\v\f\r ]) - [:upper:] upper case (== [A-Z]) - [:word:] word characters (== [0-9A-Za-z_]) - [:xdigit:] hex digit (== [0-9A-Fa-f]) + [[:alnum:]] alphanumeric (== [0-9A-Za-z]) + [[:alpha:]] alphabetic (== [A-Za-z]) + [[:ascii:]] ASCII (== [\x00-\x7F]) + [[:blank:]] blank (== [\t ]) + [[:cntrl:]] control (== [\x00-\x1F\x7F]) + [[:digit:]] digits (== [0-9]) + [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) + [[:lower:]] lower case (== [a-z]) + [[:print:]] printable (== [ -~] == [ [:graph:]]) + [[:punct:]] punctuation (== [!-/:-@[-`{-~]) + [[:space:]] whitespace (== [\t\n\v\f\r ]) + [[:upper:]] upper case (== [A-Z]) + [[:word:]] word characters (== [0-9A-Za-z_]) + [[:xdigit:]] hex digit (== [0-9A-Fa-f]) */ package syntax From 8fd56bf8c49b7ffcae4f4fbebdc3bed9c7acb9ea Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 15:48:17 -0400 Subject: [PATCH 297/430] encoding/json: document that embedded interfaces look like non-embedded ones Fixes #8386. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/149570043 --- src/encoding/json/encode.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index b63538c922..9b7b9d5fd1 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -93,6 +93,8 @@ import ( // as described in the next paragraph. // An anonymous struct field with a name given in its JSON tag is treated as // having that name, rather than being anonymous. +// An anonymous struct field of interface type is treated the same as having +// that type as its name, rather than being anonymous. // // The Go visibility rules for struct fields are amended for JSON when // deciding which field to marshal or unmarshal. If there are From 5b829cca12d029ca25a363637479373a6583dc93 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 15:49:07 -0400 Subject: [PATCH 298/430] net/url: document result of String Fixes #8742. LGTM=bradfitz R=golang-codereviews CC=adg, bradfitz, golang-codereviews, iant https://golang.org/cl/155910043 --- src/net/url/url.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/net/url/url.go b/src/net/url/url.go index 0b32cd7c8a..f167408fab 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -441,6 +441,24 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) { } // String reassembles the URL into a valid URL string. +// The general form of the result is one of: +// +// scheme:opaque +// scheme://userinfo@host/path?query#fragment +// +// If u.Opaque is non-empty, String uses the first form; +// otherwise it uses the second form. +// +// In the second form, the following rules apply: +// - if u.Scheme is empty, scheme: is omitted. +// - if u.User is nil, userinfo@ is omitted. +// - if u.Host is empty, host/ is omitted. +// - if u.Scheme and u.Host are empty and u.User is nil, +// the entire scheme://userinfo@host/ is omitted. +// - if u.Host is non-empty and u.Path begins with a /, +// the form host/path does not add its own /. +// - if u.RawQuery is empty, ?query is omitted. +// - if u.Fragment is empty, #fragment is omitted. func (u *URL) String() string { var buf bytes.Buffer if u.Scheme != "" { From d21b37bbe7b98316cc58df65a6032c3f3c20a605 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 15:49:19 -0400 Subject: [PATCH 299/430] os: make Process.Signal 'process finished' error consistent on Unix While we're here, fix the implementation of Release on both Unix and Windows: Release is supposed to make Signal an error. While we're here, make sure we never Signal pid 0. (Don't try this at home.) Fixes #7658. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant https://golang.org/cl/152240043 --- src/os/exec_unix.go | 14 +++++++++++--- src/os/exec_windows.go | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go index 1b1e3350b8..ed97f85e22 100644 --- a/src/os/exec_unix.go +++ b/src/os/exec_unix.go @@ -34,18 +34,26 @@ func (p *Process) wait() (ps *ProcessState, err error) { return ps, nil } +var errFinished = errors.New("os: process already finished") + func (p *Process) signal(sig Signal) error { - if p.done() { - return errors.New("os: process already finished") - } if p.Pid == -1 { return errors.New("os: process already released") } + if p.Pid == 0 { + return errors.New("os: process not initialized") + } + if p.done() { + return errFinished + } s, ok := sig.(syscall.Signal) if !ok { return errors.New("os: unsupported signal type") } if e := syscall.Kill(p.Pid, s); e != nil { + if e == syscall.ESRCH { + return errFinished + } return e } return nil diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go index c4f3d4f853..393393b237 100644 --- a/src/os/exec_windows.go +++ b/src/os/exec_windows.go @@ -53,6 +53,9 @@ func terminateProcess(pid, exitcode int) error { } func (p *Process) signal(sig Signal) error { + if p.handle == uintptr(syscall.InvalidHandle) { + return syscall.EINVAL + } if p.done() { return errors.New("os: process already finished") } From 1eea5caa30b33c4222f24f3cce995e2bae42659a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 15:49:33 -0400 Subject: [PATCH 300/430] os: recomment MkdirAll The internal comments are not completely precise about what is going on, and they are causing confusion. Fixes #8283. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/151460043 --- src/os/path.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/os/path.go b/src/os/path.go index 24a3415b46..84a3be3348 100644 --- a/src/os/path.go +++ b/src/os/path.go @@ -17,7 +17,7 @@ import ( // If path is already a directory, MkdirAll does nothing // and returns nil. func MkdirAll(path string, perm FileMode) error { - // If path exists, stop with success or error. + // Fast path: if we can tell whether path is a directory or file, stop with success or error. dir, err := Stat(path) if err == nil { if dir.IsDir() { @@ -26,7 +26,7 @@ func MkdirAll(path string, perm FileMode) error { return &PathError{"mkdir", path, syscall.ENOTDIR} } - // Doesn't already exist; make sure parent does. + // Slow path: make sure parent exists and then call Mkdir for path. i := len(path) for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator. i-- @@ -45,7 +45,7 @@ func MkdirAll(path string, perm FileMode) error { } } - // Now parent exists, try to create. + // Parent now exists; invoke Mkdir and use its result. err = Mkdir(path, perm) if err != nil { // Handle arguments like "foo/." by From 55df81d37f632e5f45f95b210f862c73a758b124 Mon Sep 17 00:00:00 2001 From: Evan Kroske Date: Mon, 6 Oct 2014 17:16:39 -0400 Subject: [PATCH 301/430] cmd/gc: prohibit short variable declarations containing duplicate symbols Fixes #6764. Fixes #8435. LGTM=rsc R=golang-codereviews, r, gobot, rsc CC=golang-codereviews https://golang.org/cl/116440046 --- src/cmd/gc/dcl.c | 11 +++++++++++ test/assign.go | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 73c2581beb..cc010d901c 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -488,6 +488,10 @@ colasdefn(NodeList *left, Node *defn) NodeList *l; Node *n; + for(l=left; l; l=l->next) + if(l->n->sym != S) + l->n->sym->flags |= SymUniq; + nnew = 0; nerr = 0; for(l=left; l; l=l->next) { @@ -499,6 +503,13 @@ colasdefn(NodeList *left, Node *defn) nerr++; continue; } + if((n->sym->flags & SymUniq) == 0) { + yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym); + n->diag++; + nerr++; + continue; + } + n->sym->flags &= ~SymUniq; if(n->sym->block == block) continue; diff --git a/test/assign.go b/test/assign.go index da0192f838..6611f8ce3e 100644 --- a/test/assign.go +++ b/test/assign.go @@ -53,4 +53,16 @@ func main() { _ = x _ = y } + { + var x = 1 + { + x, x := 2, 3 // ERROR "x repeated on left side of :=" + _ = x + } + _ = x + } + { + a, a := 1, 2 // ERROR "a repeated on left side of :=" + _ = a + } } From d396b9df10bcdb14f06c14b82c293a07ebdee77b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 6 Oct 2014 14:50:58 -0700 Subject: [PATCH 302/430] go/build: do not consider "android.go" to be android-specific A file name must have a non-empty underscore-separated prefix before its suffix matches GOOS. This is what the documentation already said but is not what the code did. Fixes #8838. This needs to be called out in the release notes. The he single affected file code.google.com/p/go.text/collate/tools/colcmp/darwin.go could use a renaming but works because it has a build tag inside. LGTM=adg, rsc R=golang-codereviews, adg, rsc CC=golang-codereviews https://golang.org/cl/147690043 --- src/go/build/build.go | 12 ++++++++++++ src/go/build/build_test.go | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/go/build/build.go b/src/go/build/build.go index 5e11c9b9c5..3ac7980833 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -1291,6 +1291,18 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { if dot := strings.Index(name, "."); dot != -1 { name = name[:dot] } + + // Before Go 1.4, a file called "linux.go" would be equivalent to having a + // build tag "linux" in that file. For Go 1.4 and beyond, we require this + // auto-tagging to apply only to files with a non-empty prefix, so + // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating + // sytems, such as android, to arrive without breaking existing code with + // innocuous source code in "android.go". The easiest fix: files without + // underscores are always included. + if !strings.ContainsRune(name, '_') { + return true + } + l := strings.Split(name, "_") if n := len(l); n > 0 && l[n-1] == "test" { l = l[:n-1] diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 0040101134..23ce89b4bd 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -173,6 +173,10 @@ var matchFileTests = []struct { {ctxtAndroid, "foo_linux.go", "", true}, {ctxtAndroid, "foo_android.go", "", true}, {ctxtAndroid, "foo_plan9.go", "", false}, + {ctxtAndroid, "android.go", "", true}, + {ctxtAndroid, "plan9.go", "", true}, + {ctxtAndroid, "arm.s", "", true}, + {ctxtAndroid, "amd64.s", "", true}, } func TestMatchFile(t *testing.T) { From cce2d8891a75db7cdf82af9d4f0df77af8241b2b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 6 Oct 2014 14:58:59 -0700 Subject: [PATCH 303/430] doc/go1.4.txt: GOOS suffixes require underscores to act as build tags CC=golang-codereviews https://golang.org/cl/151490043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 3564e7d2d2..1f6275f7d4 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -17,6 +17,7 @@ cmd/go: disallow C sources except when using cgo (CL 149720043) cmd/go: add test -o flag (CL 149070043) cmd/go: redefine build -a to skip standard library in releases (CL 151730045) cmd/go: compile and link all _test.go files during 'go test', even in packages where there are no Test functions (CL 150980043) +cmd/go: (via go/build): a GOOS prefix acts as a tag only if preceded by an underscore. this is a breaking change. (CL 147690043) asm: make textflag.h available outside of cmd/ld (CL 128050043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) From f8f95590d946bb4619599f909b6facf14f9bed03 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 6 Oct 2014 15:08:31 -0700 Subject: [PATCH 304/430] go/build: update docs for GOOS.go change Forgotten in https://golang.org/cl/147690043/ Update #8838 LGTM=r R=r CC=golang-codereviews, rsc https://golang.org/cl/152220045 --- src/go/build/doc.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/go/build/doc.go b/src/go/build/doc.go index 56878f2b4a..75a827bb91 100644 --- a/src/go/build/doc.go +++ b/src/go/build/doc.go @@ -108,12 +108,10 @@ // *_GOOS // *_GOARCH // *_GOOS_GOARCH -// (example: source_windows_amd64.go) or the literals: -// GOOS -// GOARCH -// (example: windows.go) where GOOS and GOARCH represent any known operating -// system and architecture values respectively, then the file is considered to -// have an implicit build constraint requiring those terms. +// (example: source_windows_amd64.go) where GOOS and GOARCH represent +// any known operating system and architecture values respectively, then +// the file is considered to have an implicit build constraint requiring +// those terms. // // To keep a file from being considered for the build: // From 4731c382f6875863dc27f33088f53bce8f82c620 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 6 Oct 2014 15:10:51 -0700 Subject: [PATCH 305/430] strings: use fast path for IndexRune Noticed while reviewing https://golang.org/cl/147690043/ I'd never seen anybody use IndexRune before, and unsurprisingly it doesn't use the other fast paths in the strings/bytes packages. IndexByte uses assembly. Also, less code this way. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/147700043 --- src/strings/strings.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/strings/strings.go b/src/strings/strings.go index 1b9df2e757..27d384983e 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -225,13 +225,8 @@ func LastIndex(s, sep string) int { // r, or -1 if rune is not present in s. func IndexRune(s string, r rune) int { switch { - case r < 0x80: - b := byte(r) - for i := 0; i < len(s); i++ { - if s[i] == b { - return i - } - } + case r < utf8.RuneSelf: + return IndexByte(s, byte(r)) default: for i, c := range s { if c == r { From ab724f928fa8dd95e3fccbf112e7a87a5f37d408 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 19:22:48 -0400 Subject: [PATCH 306/430] os, syscall: test Chtimes on directories, fix on Windows Fixes #8090. LGTM=alex.brainman R=alex.brainman CC=golang-codereviews https://golang.org/cl/154020043 --- src/os/os_test.go | 47 +++++++++++++++++++++++++++------- src/syscall/syscall_windows.go | 4 +-- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/os/os_test.go b/src/os/os_test.go index 973cc3a7bf..a30a2b0313 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -124,7 +124,22 @@ func newFile(testName string, t *testing.T) (f *File) { } f, err := ioutil.TempFile(dir, "_Go_"+testName) if err != nil { - t.Fatalf("open %s: %s", testName, err) + t.Fatalf("TempFile %s: %s", testName, err) + } + return +} + +func newDir(testName string, t *testing.T) (name string) { + // Use a local file system, not NFS. + // On Unix, override $TMPDIR in case the user + // has it set to an NFS-mounted directory. + dir := "" + if runtime.GOOS != "android" && runtime.GOOS != "windows" { + dir = "/tmp" + } + name, err := ioutil.TempDir(dir, "_Go_"+testName) + if err != nil { + t.Fatalf("TempDir %s: %s", testName, err) } return } @@ -755,35 +770,49 @@ func TestTruncate(t *testing.T) { } } -// Use TempDir() to make sure we're on a local file system, +// Use TempDir (via newFile) to make sure we're on a local file system, // so that timings are not distorted by latency and caching. // On NFS, timings can be off due to caching of meta-data on // NFS servers (Issue 848). func TestChtimes(t *testing.T) { f := newFile("TestChtimes", t) defer Remove(f.Name()) - defer f.Close() f.Write([]byte("hello, world\n")) f.Close() - st, err := Stat(f.Name()) + testChtimes(t, f.Name()) +} + +// Use TempDir (via newDir) to make sure we're on a local file system, +// so that timings are not distorted by latency and caching. +// On NFS, timings can be off due to caching of meta-data on +// NFS servers (Issue 848). +func TestChtimesDir(t *testing.T) { + name := newDir("TestChtimes", t) + defer RemoveAll(name) + + testChtimes(t, name) +} + +func testChtimes(t *testing.T, name string) { + st, err := Stat(name) if err != nil { - t.Fatalf("Stat %s: %s", f.Name(), err) + t.Fatalf("Stat %s: %s", name, err) } preStat := st // Move access and modification time back a second at := Atime(preStat) mt := preStat.ModTime() - err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second)) + err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second)) if err != nil { - t.Fatalf("Chtimes %s: %s", f.Name(), err) + t.Fatalf("Chtimes %s: %s", name, err) } - st, err = Stat(f.Name()) + st, err = Stat(name) if err != nil { - t.Fatalf("second Stat %s: %s", f.Name(), err) + t.Fatalf("second Stat %s: %s", name, err) } postStat := st diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index bda8214c3c..e89fd096ac 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -468,7 +468,7 @@ func Utimes(path string, tv []Timeval) (err error) { } h, e := CreateFile(pathp, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) if e != nil { return e } @@ -488,7 +488,7 @@ func UtimesNano(path string, ts []Timespec) (err error) { } h, e := CreateFile(pathp, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0) if e != nil { return e } From 82a5e95ccc9c37b887570661fd11b051d6ca9b72 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Oct 2014 20:51:05 -0400 Subject: [PATCH 307/430] cmd/ld: ignore .Linfo_stringNN variables in clang .o files http://build.golang.org/log/c7a91b6eac8f8daa2bd17801be273e58403a15f2 # cmd/pprof /linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#16: ignoring .Linfo_string0 in section 16 (type 0) /linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#17: ignoring .Linfo_string1 in section 16 (type 0) /linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#18: ignoring .Linfo_string2 in section 16 (type 0) /linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#20: ignoring .Linfo_string0 in section 16 (type 0) /linux-386-clang-9115aad1dc4a/go/pkg/linux_386/net.a(_all.o): sym#21: ignoring .Linfo_string1 in section 16 (type 0) ... I don't know what these are. Let's ignore them and see if we get any further. TBR=iant CC=golang-codereviews https://golang.org/cl/155030043 --- src/cmd/ld/ldelf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 38e4147556..35f8b49856 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -582,6 +582,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn) continue; sect = obj->sect+sym.shndx; if(sect->sym == nil) { + if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this + continue; diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type); continue; } From 6e8f7b4f3e98deb90c8e2bc183b514c6780cb3a9 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 6 Oct 2014 22:22:47 -0700 Subject: [PATCH 308/430] doc/go1.4.txt: useless change to tickle builders Debugging the builders and need a commit to make them run. R=adg CC=golang-codereviews https://golang.org/cl/149600043 --- doc/go1.4.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 1f6275f7d4..6d5f845789 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -43,6 +43,6 @@ testing: add TestMain support (CL 148770043) text/scanner: add IsIdentRune field of Scanner. (CL 108030044) text/template: allow comparison of signed and unsigned integers (CL 149780043) time: use the micro symbol (µ (U+00B5)) to print microsecond duration (CL 105030046) -encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045). +encoding/asn1: optional elements with a default value will now only be omitted if they have that value (CL 86960045) go.sys subrepo created: http://golang.org/s/go1.4-syscall From f739b7750853f2d620c78eca9fc14c32e48a14d5 Mon Sep 17 00:00:00 2001 From: Jens Frederich Date: Tue, 7 Oct 2014 07:13:42 -0700 Subject: [PATCH 309/430] net/http: fix authentication info leakage in Referer header (potential security risk) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit http.Client calls URL.String() to fill in the Referer header, which may contain authentication info. This patch removes authentication info from the Referer header without introducing any API changes. A new test for net/http is also provided. This is the polished version of Alberto García Hierro's https://golang.org/cl/9766046/ It should handle https Referer right. Fixes #8417 LGTM=bradfitz R=golang-codereviews, gobot, bradfitz, mikioh.mikioh CC=golang-codereviews https://golang.org/cl/151430043 --- src/net/http/client.go | 28 ++++++++++++++++++++++++++-- src/net/http/client_test.go | 37 +++++++++++++++++++++++++++++++++++++ src/net/http/export_test.go | 5 +++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/net/http/client.go b/src/net/http/client.go index a5a3abe613..ce884d1f07 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -101,6 +101,30 @@ type RoundTripper interface { // return true if the string includes a port. func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } +// refererForURL returns a referer without any authentication info or +// an empty string if lastReq scheme is https and newReq scheme is http. +func refererForURL(lastReq, newReq *url.URL) string { + // https://tools.ietf.org/html/rfc7231#section-5.5.2 + // "Clients SHOULD NOT include a Referer header field in a + // (non-secure) HTTP request if the referring page was + // transferred with a secure protocol." + if lastReq.Scheme == "https" && newReq.Scheme == "http" { + return "" + } + referer := lastReq.String() + if lastReq.User != nil { + // This is not very efficient, but is the best we can + // do without: + // - introducing a new method on URL + // - creating a race condition + // - copying the URL struct manually, which would cause + // maintenance problems down the line + auth := lastReq.User.String() + "@" + referer = strings.Replace(referer, auth, "", 1) + } + return referer +} + // Used in Send to implement io.ReadCloser by bundling together the // bufio.Reader through which we read the response, and the underlying // network connection. @@ -324,8 +348,8 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo if len(via) > 0 { // Add the Referer header. lastReq := via[len(via)-1] - if lastReq.URL.Scheme != "https" { - nreq.Header.Set("Referer", lastReq.URL.String()) + if ref := refererForURL(lastReq.URL, nreq.URL); ref != "" { + nreq.Header.Set("Referer", ref) } err = redirectChecker(nreq, via) diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 6392c1baf3..56b6563c48 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -1036,3 +1036,40 @@ func TestClientTrailers(t *testing.T) { t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want) } } + +func TestReferer(t *testing.T) { + tests := []struct { + lastReq, newReq string // from -> to URLs + want string + }{ + // don't send user: + {"http://gopher@test.com", "http://link.com", "http://test.com"}, + {"https://gopher@test.com", "https://link.com", "https://test.com"}, + + // don't send a user and password: + {"http://gopher:go@test.com", "http://link.com", "http://test.com"}, + {"https://gopher:go@test.com", "https://link.com", "https://test.com"}, + + // nothing to do: + {"http://test.com", "http://link.com", "http://test.com"}, + {"https://test.com", "https://link.com", "https://test.com"}, + + // https to http doesn't send a referer: + {"https://test.com", "http://link.com", ""}, + {"https://gopher:go@test.com", "http://link.com", ""}, + } + for _, tt := range tests { + l, err := url.Parse(tt.lastReq) + if err != nil { + t.Fatal(err) + } + n, err := url.Parse(tt.newReq) + if err != nil { + t.Fatal(err) + } + r := ExportRefererForURL(l, n) + if r != tt.want { + t.Errorf("refererForURL(%q, %q) = %q; want %q", tt.lastReq, tt.newReq, r, tt.want) + } + } +} diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index a6980b5389..87b6c0773a 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -9,6 +9,7 @@ package http import ( "net" + "net/url" "time" ) @@ -92,6 +93,10 @@ func ResetCachedEnvironment() { var DefaultUserAgent = defaultUserAgent +func ExportRefererForURL(lastReq, newReq *url.URL) string { + return refererForURL(lastReq, newReq) +} + // SetPendingDialHooks sets the hooks that run before and after handling // pending dials. func SetPendingDialHooks(before, after func()) { From 18172c42ff48611df564e5af8bf00515bbac612a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 11:06:51 -0400 Subject: [PATCH 310/430] runtime: remove type-punning for Type.gc[0], gc[1] Depending on flags&KindGCProg, gc[0] and gc[1] are either pointers or inlined bitmap bits. That's not compatible with a precise garbage collector: it needs to be always pointers or never pointers. Change the inlined bitmap case to store a pointer to an out-of-line bitmap in gc[0]. The out-of-line bitmaps are dedup'ed, so that for example all pointer types share the same out-of-line bitmap. Fixes #8864. LGTM=r R=golang-codereviews, dvyukov, r CC=golang-codereviews, iant, khr, rlh https://golang.org/cl/155820043 --- src/cmd/gc/reflect.c | 25 ++++++++++++++++++++++--- src/cmd/ld/decodesym.c | 5 ++++- src/reflect/type.go | 4 ++-- src/runtime/malloc.go | 2 +- src/runtime/type.h | 2 +- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 4892ab7570..d0ebf6b481 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -716,9 +716,10 @@ static int dcommontype(Sym *s, int ot, Type *t) { int i, alg, sizeofAlg, gcprog; - Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1; + Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits; uint8 gcmask[16]; static Sym *algarray; + uint64 x1, x2; char *p; if(ot != 0) @@ -804,8 +805,26 @@ dcommontype(Sym *s, int ot, Type *t) ot = dsymptr(s, ot, gcprog1, 0); } else { gengcmask(t, gcmask); - for(i = 0; i < 2*widthptr; i++) - ot = duint8(s, ot, gcmask[i]); + x1 = 0; + for(i=0; i<8; i++) + x1 = x1<<8 | gcmask[i]; + if(widthptr == 4) { + p = smprint("gcbits.%#016x", x1); + } else { + x2 = 0; + for(i=0; i<8; i++) + x2 = x2<<8 | gcmask[i+8]; + p = smprint("gcbits.%#016llux%016llux", x1, x2); + } + sbits = pkglookup(p, runtimepkg); + if((sbits->flags & SymUniq) == 0) { + sbits->flags |= SymUniq; + for(i = 0; i < 2*widthptr; i++) + duint8(sbits, i, gcmask[i]); + ggloblsym(sbits, 2*widthptr, DUPOK|RODATA); + } + ot = dsymptr(s, ot, sbits, 0); + ot = duintptr(s, ot, 0); } p = smprint("%-uT", t); //print("dcommontype: %s\n", p); diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c index c530669425..037263dce7 100644 --- a/src/cmd/ld/decodesym.c +++ b/src/cmd/ld/decodesym.c @@ -111,7 +111,10 @@ decodetype_gcprog(LSym *s) uint8* decodetype_gcmask(LSym *s) { - return (uint8*)(s->p + 1*PtrSize + 8 + 1*PtrSize); + LSym *mask; + + mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize); + return mask->p; } // Type.ArrayType.elem and Type.SliceType.Elem diff --git a/src/reflect/type.go b/src/reflect/type.go index f099546d27..a36c0ba604 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1523,8 +1523,8 @@ func (gc *gcProg) appendProg(t *rtype) { // The program is stored in t.gc[0], skip unroll flag. prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:] } else { - // The mask is embed directly in t.gc. - prog = (*[1 << 30]byte)(unsafe.Pointer(&t.gc[0]))[:] + // The mask is linked directly in t.gc. + prog = (*[2 * ptrSize]byte)(unsafe.Pointer(t.gc[0]))[:] } for i := uintptr(0); i < nptr; i++ { gc.appendWord(extractGCWord(prog, i)) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 99d14e3145..9b4264f2b3 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -270,7 +270,7 @@ func mallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { } ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte } else { - ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask + ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask } if size == 2*ptrSize { *xbits = *ptrmask | bitBoundary diff --git a/src/runtime/type.h b/src/runtime/type.h index de82e886f2..f5b4f9d13f 100644 --- a/src/runtime/type.h +++ b/src/runtime/type.h @@ -23,7 +23,7 @@ struct Type uint8 kind; void* alg; // gc stores type info required for garbage collector. - // If (kind&KindGCProg)==0, then gc directly contains sparse GC bitmap + // If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap // (no indirection), 4 bits per word. // If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated // read-only GC program; and gc[0] points to BSS space for sparse GC bitmap. From 7b2b8edee60788358938dc7d7e04aabeae357b85 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 11:07:04 -0400 Subject: [PATCH 311/430] encoding/json: fix handling of null with ,string fields Fixes #8587. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews, iant, r https://golang.org/cl/152270044 --- src/encoding/json/decode.go | 40 ++++++++++++++++++++++++++++---- src/encoding/json/decode_test.go | 21 +++++++++++------ 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 67ec37388f..705bc2e17a 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -173,7 +173,6 @@ type decodeState struct { scan scanner nextscan scanner // for calls to nextValue savedError error - tempstr string // scratch space to avoid some allocations useNumber bool } @@ -293,6 +292,32 @@ func (d *decodeState) value(v reflect.Value) { } } +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch op := d.scanWhile(scanSkipSpace); op { + default: + d.error(errPhase) + + case scanBeginArray: + d.array(reflect.Value{}) + + case scanBeginObject: + d.object(reflect.Value{}) + + case scanBeginLiteral: + switch v := d.literalInterface().(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + // indirect walks down v allocating pointers as needed, // until it gets to a non-pointer. // if it encounters an Unmarshaler, indirect stops and returns that. @@ -444,6 +469,8 @@ func (d *decodeState) array(v reflect.Value) { } } +var nullLiteral = []byte("null") + // object consumes an object from d.data[d.off-1:], decoding into the value v. // the first byte ('{') of the object has been read already. func (d *decodeState) object(v reflect.Value) { @@ -566,9 +593,14 @@ func (d *decodeState) object(v reflect.Value) { // Read value. if destring { - d.value(reflect.ValueOf(&d.tempstr)) - d.literalStore([]byte(d.tempstr), subv, true) - d.tempstr = "" // Zero scratch space for successive values. + switch qv := d.valueQuoted().(type) { + case nil: + d.literalStore(nullLiteral, subv, false) + case string: + d.literalStore([]byte(qv), subv, true) + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type())) + } } else { d.value(subv) } diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index d95657d729..7235969b9f 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -1070,18 +1070,25 @@ func TestEmptyString(t *testing.T) { } } -// Test that the returned error is non-nil when trying to unmarshal null string into int, for successive ,string option -// Issue 7046 +// Test that a null for ,string is not replaced with the previous quoted string (issue 7046). +// It should also not be an error (issue 2540, issue 8587). func TestNullString(t *testing.T) { type T struct { - A int `json:",string"` - B int `json:",string"` + A int `json:",string"` + B int `json:",string"` + C *int `json:",string"` } - data := []byte(`{"A": "1", "B": null}`) + data := []byte(`{"A": "1", "B": null, "C": null}`) var s T + s.B = 1 + s.C = new(int) + *s.C = 2 err := Unmarshal(data, &s) - if err == nil { - t.Fatalf("expected error; got %v", s) + if err != nil { + t.Fatalf("Unmarshal: %v") + } + if s.B != 1 || s.C != nil { + t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) } } From 11e53e46a64102554197d987a364a60236f4326b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 11:07:18 -0400 Subject: [PATCH 312/430] runtime: crash if we see an invalid pointer into GC arena This will help find bugs during the release freeze. It's not clear it should be kept for the release itself. That's issue 8861. The most likely thing that would trigger this is stale pointers that previously were ignored or caused memory leaks. These were allowed due to the use of conservative collection. Now that everything is precise, we should not see them anymore. The small number check reinforces what the stack copier is already doing, catching the storage of integers in pointers. It caught issue 8864. The check is disabled if _cgo_allocate is linked into the binary, which is to say if the binary is using SWIG to allocate untyped Go memory. In that case, there are invalid pointers and there's nothing we can do about it. LGTM=rlh R=golang-codereviews, dvyukov, rlh CC=golang-codereviews, iant, khr, r https://golang.org/cl/148470043 --- src/cmd/cc/godefs.c | 6 ++- src/runtime/mgc0.c | 99 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c index d3ab52fde4..d9f67f0ae5 100644 --- a/src/cmd/cc/godefs.c +++ b/src/cmd/cc/godefs.c @@ -353,8 +353,10 @@ godefvar(Sym *s) case CSTATIC: case CEXTERN: case CGLOBL: - if(strchr(s->name, '$') != nil) // TODO(lvd) - break; + if(strchr(s->name, '$') != nil) + break; + if(strncmp(s->name, "go.weak.", 8) == 0) + break; Bprint(&outbuf, "var %U\t", s->name); printtypename(t); Bprint(&outbuf, "\n"); diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 9b9bc0ef13..5876ea5c3e 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -64,6 +64,7 @@ enum { Debug = 0, + DebugPtrs = 0, // if 1, print trace of every pointer load during GC ConcurrentSweep = 1, WorkbufSize = 4*1024, @@ -127,6 +128,9 @@ BitVector runtime·gcbssmask; Mutex runtime·gclock; +static uintptr badblock[1024]; +static int32 nbadblock; + static Workbuf* getempty(Workbuf*); static Workbuf* getfull(Workbuf*); static void putempty(Workbuf*); @@ -158,6 +162,14 @@ struct WorkData { }; WorkData runtime·work; +// Is _cgo_allocate linked into the binary? +static bool +have_cgo_allocate(void) +{ + extern byte go·weak·runtime·_cgo_allocate_internal[1]; + return go·weak·runtime·_cgo_allocate_internal != nil; +} + // scanblock scans a block of n bytes starting at pointer b for references // to other objects, scanning any it finds recursively until there are no // unscanned objects left. Instead of using an explicit recursion, it keeps @@ -167,8 +179,8 @@ WorkData runtime·work; static void scanblock(byte *b, uintptr n, byte *ptrmask) { - byte *obj, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp, bits, xbits, shift, cached; - uintptr i, nobj, size, idx, x, off, scanbufpos; + byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp, bits, xbits, shift, cached; + uintptr i, j, nobj, size, idx, x, off, scanbufpos; intptr ncached; Workbuf *wbuf; Iface *iface; @@ -241,6 +253,8 @@ scanblock(byte *b, uintptr n, byte *ptrmask) ptrmask = nil; // use GC bitmap for pointer info scanobj: + if(DebugPtrs) + runtime·printf("scanblock %p +%p %p\n", b, n, ptrmask); // Find bits of the beginning of the object. if(ptrmask == nil) { off = (uintptr*)b - (uintptr*)arena_start; @@ -279,6 +293,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) continue; if(bits == BitsPointer) { obj = *(byte**)(b+i); + obj0 = obj; goto markobj; } @@ -321,12 +336,20 @@ scanblock(byte *b, uintptr n, byte *ptrmask) cached >>= gcBits; ncached--; + obj0 = obj; markobj: // At this point we have extracted the next potential pointer. // Check if it points into heap. - if(obj == nil || obj < arena_start || obj >= arena_used) + if(obj == nil) + continue; + if((uintptr)obj < PhysPageSize) { + s = nil; + goto badobj; + } + if(obj < arena_start || obj >= arena_used) continue; // Mark the object. + obj = (byte*)((uintptr)obj & ~(PtrSize-1)); off = (uintptr*)obj - (uintptr*)arena_start; bitp = arena_start - off/wordsPerBitmapByte - 1; shift = (off % wordsPerBitmapByte) * gcBits; @@ -338,8 +361,40 @@ scanblock(byte *b, uintptr n, byte *ptrmask) x = k; x -= (uintptr)arena_start>>PageShift; s = runtime·mheap.spans[x]; - if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) + if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) { + // Stack pointers lie within the arena bounds but are not part of the GC heap. + // Ignore them. + if(s != nil && s->state == MSpanStack) + continue; + + badobj: + // If cgo_allocate is linked into the binary, it can allocate + // memory as []unsafe.Pointer that may not contain actual + // pointers and must be scanned conservatively. + // In this case alone, allow the bad pointer. + if(have_cgo_allocate() && ptrmask == nil) + continue; + + // Anything else indicates a bug somewhere. + // If we're in the middle of chasing down a different bad pointer, + // don't confuse the trace by printing about this one. + if(nbadblock > 0) + continue; + + runtime·printf("runtime: garbage collector found invalid heap pointer *(%p+%p)=%p", b, i, obj); + if(s == nil) + runtime·printf(" s=nil\n"); + else + runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<limit, (uintptr)(s->start+s->npages)<state); + if(ptrmask != nil) + runtime·throw("bad pointer"); + // Add to badblock list, which will cause the garbage collection + // to keep repeating until it has traced the chain of pointers + // leading to obj all the way back to a root. + if(nbadblock == 0) + badblock[nbadblock++] = (uintptr)b; continue; + } p = (byte*)((uintptr)s->start<sizeclass != 0) { size = s->elemsize; @@ -354,6 +409,24 @@ scanblock(byte *b, uintptr n, byte *ptrmask) obj = p; goto markobj; } + if(DebugPtrs) + runtime·printf("scan *%p = %p => base %p\n", b+i, obj0, obj); + + if(nbadblock > 0 && (uintptr)obj == badblock[nbadblock-1]) { + // Running garbage collection again because + // we want to find the path from a root to a bad pointer. + // Found possible next step; extend or finish path. + for(j=0; j= nelem(badblock)) + runtime·throw("badblock trace too long"); + badblock[nbadblock++] = (uintptr)b; + AlreadyBad:; + } // Now we have bits, bitp, and shift correct for // obj pointing at the base of the object. @@ -381,7 +454,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask) // Queue the obj for scanning. PREFETCH(obj); - obj = (byte*)((uintptr)obj & ~(PtrSize-1)); p = scanbuf[scanbufpos]; scanbuf[scanbufpos++] = obj; if(scanbufpos == nelem(scanbuf)) @@ -400,6 +472,8 @@ scanblock(byte *b, uintptr n, byte *ptrmask) wp++; nobj++; } + if(DebugPtrs) + runtime·printf("end scanblock %p +%p %p\n", b, n, ptrmask); if(Debug && ptrmask == nil) { // For heap objects ensure that we did not overscan. @@ -1306,6 +1380,15 @@ runtime·gc_m(void) a.eagersweep = g->m->scalararg[2]; gc(&a); + if(nbadblock > 0) { + // Work out path from root to bad block. + for(;;) { + gc(&a); + if(nbadblock >= nelem(badblock)) + runtime·throw("cannot find path to bad pointer"); + } + } + runtime·casgstatus(gp, Gwaiting, Grunning); } @@ -1316,6 +1399,9 @@ gc(struct gc_args *args) uint64 heap0, heap1, obj; GCStats stats; + if(DebugPtrs) + runtime·printf("GC start\n"); + if(runtime·debug.allocfreetrace) runtime·tracegc(); @@ -1450,6 +1536,9 @@ gc(struct gc_args *args) runtime·mProf_GC(); g->m->traceback = 0; + + if(DebugPtrs) + runtime·printf("GC end\n"); } extern uintptr runtime·sizeof_C_MStats; From 8b7da4de488461500641d6147f1b544e892386ae Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 12:03:48 -0400 Subject: [PATCH 313/430] cmd/gc: fix print format Fixes 386 build. TBR=r CC=golang-codereviews https://golang.org/cl/149620043 --- src/cmd/gc/reflect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index d0ebf6b481..b2ff2fbc5e 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -809,7 +809,7 @@ dcommontype(Sym *s, int ot, Type *t) for(i=0; i<8; i++) x1 = x1<<8 | gcmask[i]; if(widthptr == 4) { - p = smprint("gcbits.%#016x", x1); + p = smprint("gcbits.%#016llux", x1); } else { x2 = 0; for(i=0; i<8; i++) From 3147d2c4eef5da0110d392cd5128d64042dbbae5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 12:07:40 -0400 Subject: [PATCH 314/430] cmd/5c, cmd/6c, cmd/8c: make failure to optimize fatal LGTM=bradfitz, dave, r R=r, bradfitz, dave CC=golang-codereviews https://golang.org/cl/152250044 --- src/cmd/5c/reg.c | 9 +++------ src/cmd/6c/reg.c | 14 ++++---------- src/cmd/8c/reg.c | 9 +++------ 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c index 2fbe031f44..9024d5f496 100644 --- a/src/cmd/5c/reg.c +++ b/src/cmd/5c/reg.c @@ -406,7 +406,7 @@ loop2: rgp->cost = change; nregion++; if(nregion >= NRGN) { - warn(Z, "too many regions"); + fatal(Z, "too many regions"); goto brk; } rgp++; @@ -642,11 +642,8 @@ mkvar(Addr *a, int docon) if(s) if(s->name[0] == '.') goto none; - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c index 348d747b72..6f8d3ce14d 100644 --- a/src/cmd/6c/reg.c +++ b/src/cmd/6c/reg.c @@ -585,14 +585,11 @@ loop2: } rgp->cost = change; nregion++; - if(nregion >= NRGN) { - warn(Z, "too many regions"); - goto brk; - } + if(nregion >= NRGN) + fatal(Z, "too many regions"); rgp++; } } -brk: qsort(region, nregion, sizeof(region[0]), rcmp); /* @@ -808,11 +805,8 @@ mkvar(Reg *r, Addr *a) goto out; v++; } - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c index e6ba8bcb3e..ea862f3888 100644 --- a/src/cmd/8c/reg.c +++ b/src/cmd/8c/reg.c @@ -518,7 +518,7 @@ loop2: rgp->cost = change; nregion++; if(nregion >= NRGN) { - warn(Z, "too many regions"); + fatal(Z, "too many regions"); goto brk; } rgp++; @@ -746,11 +746,8 @@ mkvar(Reg *r, Addr *a) goto out; v++; } - if(nvar >= NVAR) { - if(debug['w'] > 1 && s) - warn(Z, "variable not optimized: %s", s->name); - goto none; - } + if(nvar >= NVAR) + fatal(Z, "variable not optimized: %s", s->name); i = nvar; nvar++; v = &var[i]; From 6ee36a9151212f6f303740bf59d3e3d500d7f279 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 7 Oct 2014 10:52:16 -0700 Subject: [PATCH 315/430] net/rpc: add test for issue 7689 (gob error should cause EOF) Helpfully supplied by tommi.virtanen in issue 8173. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/151370043 --- src/net/rpc/client_test.go | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go index bbfc1ec3a3..c138c06b8d 100644 --- a/src/net/rpc/client_test.go +++ b/src/net/rpc/client_test.go @@ -6,6 +6,9 @@ package rpc import ( "errors" + "fmt" + "net" + "strings" "testing" ) @@ -34,3 +37,51 @@ func TestCloseCodec(t *testing.T) { t.Error("client.Close did not close codec") } } + +// Test that errors in gob shut down the connection. Issue 7689. + +type R struct { + msg []byte // Not exported, so R does not work with gob. +} + +type S struct{} + +func (s *S) Recv(nul *struct{}, reply *R) error { + *reply = R{[]byte("foo")} + return nil +} + +func TestGobError(t *testing.T) { + defer func() { + err := recover() + if err == nil { + t.Fatal("no error") + } + if !strings.Contains("reading body EOF", err.(error).Error()) { + t.Fatal("expected `reading body EOF', got", err) + } + }() + Register(new(S)) + + listen, err := net.Listen("tcp", ":5555") + if err != nil { + panic(err) + } + go Accept(listen) + + client, err := Dial("tcp", ":5555") + if err != nil { + panic(err) + } + + var reply Reply + err = client.Call("S.Recv", &struct{}{}, &reply) + if err != nil { + panic(err) + } + + fmt.Printf("%#v\n", reply) + client.Close() + + listen.Close() +} From 87f51f103181e47c78a5c3fd9a41d43fb707817b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 7 Oct 2014 10:56:58 -0700 Subject: [PATCH 316/430] math/big: fix doc comments Fixes #8904. TBR=iant R=iant CC=golang-codereviews https://golang.org/cl/148650043 --- src/math/big/int.go | 4 ++-- src/math/big/rat.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/math/big/int.go b/src/math/big/int.go index 3998652e93..fc53719d71 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -1016,12 +1016,12 @@ func (z *Int) UnmarshalJSON(text []byte) error { return nil } -// MarshalText implements the encoding.TextMarshaler interface +// MarshalText implements the encoding.TextMarshaler interface. func (z *Int) MarshalText() (text []byte, err error) { return []byte(z.String()), nil } -// UnmarshalText implements the encoding.TextUnmarshaler interface +// UnmarshalText implements the encoding.TextUnmarshaler interface. func (z *Int) UnmarshalText(text []byte) error { if _, ok := z.SetString(string(text), 0); !ok { return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text) diff --git a/src/math/big/rat.go b/src/math/big/rat.go index e6ab0bb483..0bcec30252 100644 --- a/src/math/big/rat.go +++ b/src/math/big/rat.go @@ -699,12 +699,12 @@ func (z *Rat) GobDecode(buf []byte) error { return nil } -// MarshalText implements the encoding.TextMarshaler interface +// MarshalText implements the encoding.TextMarshaler interface. func (r *Rat) MarshalText() (text []byte, err error) { return []byte(r.RatString()), nil } -// UnmarshalText implements the encoding.TextUnmarshaler interface +// UnmarshalText implements the encoding.TextUnmarshaler interface. func (r *Rat) UnmarshalText(text []byte) error { if _, ok := r.SetString(string(text)); !ok { return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) From 685204747d39b4a5d111406389f7a63bc34c7287 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 16:27:40 -0400 Subject: [PATCH 317/430] runtime: fix _cgo_allocate(0) Fixes a SWIG bug reported off-list. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/155990043 --- misc/cgo/test/callback_c_gc.c | 10 ++++++++++ misc/cgo/test/callback_c_gccgo.c | 7 +++++++ src/runtime/cgocallback.go | 3 +++ 3 files changed, 20 insertions(+) diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c index 32bfed0c02..28a62c6dbc 100644 --- a/misc/cgo/test/callback_c_gc.c +++ b/misc/cgo/test/callback_c_gc.c @@ -39,6 +39,16 @@ callCgoAllocate(void) int i; struct { size_t n; void *ret; } a; List *l, *head, **tail; + + // Make sure this doesn't crash. + // And make sure it returns non-nil. + a.n = 0; + a.ret = 0; + crosscall2(_cgo_allocate, &a, sizeof a); + if(a.ret == 0) { + fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n"); + exit(2); + } head = 0; tail = &head; diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c index d92dca0093..d367b7b68b 100644 --- a/misc/cgo/test/callback_c_gccgo.c +++ b/misc/cgo/test/callback_c_gccgo.c @@ -35,6 +35,13 @@ callCgoAllocate(void) int i; List *l, *head, **tail; + // Make sure this doesn't crash. + // And make sure it returns non-nil. + if(_cgo_allocate(0) == 0) { + fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n"); + exit(2); + } + head = 0; tail = &head; for(i=0; i<100; i++) { diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go index 1e1b576072..2c89143208 100644 --- a/src/runtime/cgocallback.go +++ b/src/runtime/cgocallback.go @@ -21,6 +21,9 @@ import "unsafe" // Either we need to add types or we need to stop using it. func _cgo_allocate_internal(len uintptr) unsafe.Pointer { + if len == 0 { + len = 1 + } ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0]) c := new(cgomal) c.alloc = ret From 6ea3746adfd924ef5a389165c22c0eaddd35ddf2 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 7 Oct 2014 13:36:16 -0700 Subject: [PATCH 318/430] runtime: update heap dump format for 1.4 We no longer have full type information in the heap, so we can't dump that any more. Instead we dump ptr/noptr maps so at least we can compute graph connectivity. In addition, we still dump Iface/Eface types so together with dwarf type info we might be able to reconstruct types of most things in the heap. LGTM=dvyukov R=golang-codereviews, dvyukov, rsc, khr CC=golang-codereviews https://golang.org/cl/155940043 --- src/runtime/heapdump.c | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c index 54b9666b55..71da419f15 100644 --- a/src/runtime/heapdump.c +++ b/src/runtime/heapdump.c @@ -7,7 +7,7 @@ // finalizers, etc.) to a file. // The format of the dumped file is described at -// http://code.google.com/p/go-wiki/wiki/heapdump13 +// http://code.google.com/p/go-wiki/wiki/heapdump14 #include "runtime.h" #include "arch_GOARCH.h" @@ -27,10 +27,8 @@ extern byte runtime·ebss[]; enum { FieldKindEol = 0, FieldKindPtr = 1, - FieldKindString = 2, - FieldKindSlice = 3, - FieldKindIface = 4, - FieldKindEface = 5, + FieldKindIface = 2, + FieldKindEface = 3, TagEOF = 0, TagObject = 1, @@ -200,7 +198,6 @@ dumptype(Type *t) write(t->x->name->str, t->x->name->len); } dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0); - dumpfields((BitVector){0, nil}); } // dump an object @@ -210,9 +207,8 @@ dumpobj(byte *obj, uintptr size, BitVector bv) dumpbvtypes(&bv, obj); dumpint(TagObject); dumpint((uintptr)obj); - dumpint(0); // Type* - dumpint(0); // kind dumpmemrange(obj, size); + dumpfields(bv); } static void @@ -255,6 +251,7 @@ dumpbv(BitVector *bv, uintptr offset) for(i = 0; i < bv->n; i += BitsPerPointer) { switch(bv->bytedata[i/8] >> i%8 & 3) { case BitsDead: + return; case BitsScalar: break; case BitsPointer: @@ -489,16 +486,18 @@ dumproots(void) byte *p; // data segment + dumpbvtypes(&runtime·gcdatamask, runtime·data); dumpint(TagData); dumpint((uintptr)runtime·data); dumpmemrange(runtime·data, runtime·edata - runtime·data); dumpfields(runtime·gcdatamask); // bss segment + dumpbvtypes(&runtime·gcbssmask, runtime·bss); dumpint(TagBss); dumpint((uintptr)runtime·bss); dumpmemrange(runtime·bss, runtime·ebss - runtime·bss); - dumpfields(runtime·gcdatamask); + dumpfields(runtime·gcbssmask); // MSpan.types allspans = runtime·mheap.allspans; @@ -578,10 +577,29 @@ itab_callback(Itab *tab) { Type *t; - dumpint(TagItab); - dumpint((uintptr)tab); t = tab->type; - dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0); + // Dump a map from itab* to the type of its data field. + // We want this map so we can deduce types of interface referents. + if((t->kind & KindDirectIface) == 0) { + // indirect - data slot is a pointer to t. + dumptype(t->ptrto); + dumpint(TagItab); + dumpint((uintptr)tab); + dumpint((uintptr)t->ptrto); + } else if((t->kind & KindNoPointers) == 0) { + // t is pointer-like - data slot is a t. + dumptype(t); + dumpint(TagItab); + dumpint((uintptr)tab); + dumpint((uintptr)t); + } else { + // Data slot is a scalar. Dump type just for fun. + // With pointer-only interfaces, this shouldn't happen. + dumptype(t); + dumpint(TagItab); + dumpint((uintptr)tab); + dumpint((uintptr)t); + } } static void @@ -726,7 +744,7 @@ mdump(void) } runtime·memclr((byte*)&typecache[0], sizeof(typecache)); - hdr = (byte*)"go1.3 heap dump\n"; + hdr = (byte*)"go1.4 heap dump\n"; write(hdr, runtime·findnull(hdr)); dumpparams(); dumpitabs(); From dcc4a674d85fc2b0a434d71c1a504ebc559118bf Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 7 Oct 2014 15:21:00 -0700 Subject: [PATCH 319/430] runtime: zero pointer-looking scalararg values I have a CL which at every gc looks through data and bss sections for nonpointer data (according to gc maps) that looks like a pointer. These are potential missing roots. The only thing it finds are begnign, storing stack pointers into m0.scalararg[1] and never cleaning them up. Let's clean them up now so the test CL passes all.bash cleanly. The test CL can't be checked in because we might store pointer-looking things in nonpointer data by accident. LGTM=iant R=golang-codereviews, iant, khr CC=golang-codereviews https://golang.org/cl/153210043 --- src/runtime/panic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/panic.c b/src/runtime/panic.c index 1cd0aa8654..55ad80e9bc 100644 --- a/src/runtime/panic.c +++ b/src/runtime/panic.c @@ -31,6 +31,7 @@ runtime·deferproc_m(void) argp = g->m->scalararg[1]; callerpc = g->m->scalararg[2]; g->m->ptrarg[0] = nil; + g->m->scalararg[1] = 0; d = runtime·newdefer(siz); d->fn = fn; @@ -131,6 +132,7 @@ runtime·dopanic_m(void) g->m->ptrarg[0] = nil; pc = g->m->scalararg[0]; sp = g->m->scalararg[1]; + g->m->scalararg[1] = 0; if(gp->sig != 0) runtime·printf("[signal %x code=%p addr=%p pc=%p]\n", gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpc); From fdc047fbe5b71e8b6233d8d51466fad249af3577 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 8 Oct 2014 13:22:31 +1100 Subject: [PATCH 320/430] cmd/go: add ImportComment to Package struct It seems reasonable that people might want to look up the ImportComment with "go list". LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/143600043 --- src/cmd/go/doc.go | 39 ++++++++++++++++++++------------------- src/cmd/go/list.go | 39 ++++++++++++++++++++------------------- src/cmd/go/pkg.go | 22 ++++++++++++---------- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go index 8e2facd044..314c69bd8c 100644 --- a/src/cmd/go/doc.go +++ b/src/cmd/go/doc.go @@ -385,28 +385,29 @@ syntax of package template. The default output is equivalent to -f '{{.ImportPath}}'. The struct being passed to the template is: type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - Name string // package name - Doc string // package documentation string - Target string // install path - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - Root string // Go root or Go path dir containing this package + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + Root string // Go root or Go path dir containing this package // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go sources files that import "C" IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive // Cgo directives CgoCFLAGS []string // cgo: flags for C compiler diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go index 0ead435023..fbf96167fe 100644 --- a/src/cmd/go/list.go +++ b/src/cmd/go/list.go @@ -30,28 +30,29 @@ syntax of package template. The default output is equivalent to -f '{{.ImportPath}}'. The struct being passed to the template is: type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - Name string // package name - Doc string // package documentation string - Target string // install path - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - Root string // Go root or Go path dir containing this package + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + Root string // Go root or Go path dir containing this package // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go sources files that import "C" IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive // Cgo directives CgoCFLAGS []string // cgo: flags for C compiler diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go index 7f7a3b04fd..e17326442c 100644 --- a/src/cmd/go/pkg.go +++ b/src/cmd/go/pkg.go @@ -26,16 +26,17 @@ type Package struct { // Note: These fields are part of the go command's public API. // See list.go. It is okay to add fields, but not to change or // remove existing ones. Keep in sync with list.go - Dir string `json:",omitempty"` // directory containing package sources - ImportPath string `json:",omitempty"` // import path of package in dir - Name string `json:",omitempty"` // package name - Doc string `json:",omitempty"` // package documentation string - Target string `json:",omitempty"` // install path - Goroot bool `json:",omitempty"` // is this package found in the Go root? - Standard bool `json:",omitempty"` // is this package part of the standard Go library? - Stale bool `json:",omitempty"` // would 'go install' do anything for this package? - Root string `json:",omitempty"` // Go root or Go path dir containing this package - ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory + Dir string `json:",omitempty"` // directory containing package sources + ImportPath string `json:",omitempty"` // import path of package in dir + ImportComment string `json:",omitempty"` // path in import comment on package statement + Name string `json:",omitempty"` // package name + Doc string `json:",omitempty"` // package documentation string + Target string `json:",omitempty"` // install path + Goroot bool `json:",omitempty"` // is this package found in the Go root? + Standard bool `json:",omitempty"` // is this package part of the standard Go library? + Stale bool `json:",omitempty"` // would 'go install' do anything for this package? + Root string `json:",omitempty"` // Go root or Go path dir containing this package + ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory // Source files GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) @@ -104,6 +105,7 @@ func (p *Package) copyBuild(pp *build.Package) { p.Dir = pp.Dir p.ImportPath = pp.ImportPath + p.ImportComment = pp.ImportComment p.Name = pp.Name p.Doc = pp.Doc p.Root = pp.Root From f3eece74922b55dcf279477a2c2267571dba82fa Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 8 Oct 2014 13:23:05 +1100 Subject: [PATCH 321/430] doc: use "keyed" instead of "tagged" in Go 1 compatibility doc LGTM=bradfitz, r R=r, bradfitz CC=golang-codereviews https://golang.org/cl/156730043 --- doc/go1compat.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/go1compat.html b/doc/go1compat.html index 8ceaf32f97..04a6c1124b 100644 --- a/doc/go1compat.html +++ b/doc/go1compat.html @@ -83,16 +83,16 @@ break if the bug is fixed. We reserve the right to fix such bugs.
  • Struct literals. For the addition of features in later point releases, it may be necessary to add fields to exported structs in -the API. Code that uses untagged struct literals (such as pkg.T{3, +the API. Code that uses unkeyed struct literals (such as pkg.T{3, "x"}) to create values of these types would fail to compile after -such a change. However, code that uses tagged literals (pkg.T{A: +such a change. However, code that uses keyed literals (pkg.T{A: 3, B: "x"}) will continue to compile after such a change. We will -update such data structures in a way that allows tagged struct -literals to remain compatible, although untagged literals may fail +update such data structures in a way that allows keyed struct +literals to remain compatible, although unkeyed literals may fail to compile. (There are also more intricate cases involving nested data structures or interfaces, but they have the same resolution.) We therefore recommend that composite literals whose type is defined -in a separate package should use the tagged notation. +in a separate package should use the keyed notation.
  • From 3492ee5d3a7f7d41194378d9e1d74fadacef0c5e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 23:08:07 -0400 Subject: [PATCH 322/430] net/rpc: listen on localhost, let kernel pick port This avoids a pop-up box on OS X and it avoids a test failure if something is using 5555. I apologize for not noticing this during the review. TBR=r CC=golang-codereviews https://golang.org/cl/152320044 --- src/net/rpc/client_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go index c138c06b8d..d116d2acc9 100644 --- a/src/net/rpc/client_test.go +++ b/src/net/rpc/client_test.go @@ -63,13 +63,13 @@ func TestGobError(t *testing.T) { }() Register(new(S)) - listen, err := net.Listen("tcp", ":5555") + listen, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { panic(err) } go Accept(listen) - client, err := Dial("tcp", ":5555") + client, err := Dial("tcp", listen.Addr().String()) if err != nil { panic(err) } From e6708ee9b1a0713a10cb15ba4b7e4415c543851a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 23:17:31 -0400 Subject: [PATCH 323/430] runtime: clear Defer.panic before removing from G.defer list Another dangling stack pointer in a cached structure. Same as SudoG.elem and SudoG.selectdone. Definitely a fix, and the new test in freedefer makes the crash reproducible, but probably not a complete fix. I have seen one dangling pointer in a Defer.panic even after this fix; I cannot see where it could be coming from. I think this will fix the solaris build. I do not think this will fix the occasional failure on the darwin build. TBR=khr R=khr CC=golang-codereviews https://golang.org/cl/155080043 --- src/runtime/panic.c | 2 ++ src/runtime/panic.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/runtime/panic.c b/src/runtime/panic.c index 55ad80e9bc..24eb6dbfe0 100644 --- a/src/runtime/panic.c +++ b/src/runtime/panic.c @@ -34,6 +34,8 @@ runtime·deferproc_m(void) g->m->scalararg[1] = 0; d = runtime·newdefer(siz); + if(d->panic != nil) + runtime·throw("deferproc: d->panic != nil after newdefer"); d->fn = fn; d->pc = callerpc; d->argp = argp; diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 7eb2d6055a..c78102f8a3 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -188,6 +188,10 @@ func newdefer(siz int32) *_defer { // The defer cannot be used after this call. //go:nosplit func freedefer(d *_defer) { + if d._panic != nil { + // _panic must be cleared before d is unlinked from gp. + gothrow("freedefer with d._panic != nil") + } sc := deferclass(uintptr(d.siz)) if sc < uintptr(len(p{}.deferpool)) { mp := acquirem() @@ -258,6 +262,7 @@ func Goexit() { if d.started { if d._panic != nil { d._panic.aborted = true + d._panic = nil } gp._defer = d.link freedefer(d) @@ -268,6 +273,7 @@ func Goexit() { if gp._defer != d { gothrow("bad defer entry in Goexit") } + d._panic = nil gp._defer = d.link freedefer(d) // Note: we ignore recovers here because Goexit isn't a panic @@ -343,6 +349,7 @@ func gopanic(e interface{}) { if d._panic != nil { d._panic.aborted = true } + d._panic = nil gp._defer = d.link freedefer(d) continue @@ -366,6 +373,7 @@ func gopanic(e interface{}) { if gp._defer != d { gothrow("bad defer entry in panic") } + d._panic = nil gp._defer = d.link // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic From 2b1659b57d6e021029636ee39b4a30c4f9074c6c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 23:27:25 -0400 Subject: [PATCH 324/430] runtime: change Windows M.thread from void* to uintptr It appears to be an opaque bit pattern more than a pointer. The Go garbage collector has discovered that for m0 it is set to 0x4c. Should fix Windows build. TBR=brainman CC=golang-codereviews https://golang.org/cl/149640043 --- src/runtime/asm_386.s | 3 +++ src/runtime/asm_amd64.s | 3 +++ src/runtime/asm_amd64p32.s | 3 +++ src/runtime/asm_arm.s | 3 +++ src/runtime/os_windows.c | 14 +++++++------- src/runtime/runtime.h | 4 +++- 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index 1495246a25..c401741ef9 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -479,6 +479,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-8 TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-8 JMP runtime·atomicload(SB) +TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-8 + JMP runtime·atomicstore(SB) + // bool runtime·cas64(uint64 *val, uint64 old, uint64 new) // Atomically: // if(*val == *old){ diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 3f7f608410..e21270d8cc 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -491,6 +491,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-16 TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-16 JMP runtime·atomicload64(SB) +TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16 + JMP runtime·atomicstore64(SB) + // bool casp(void **val, void *old, void *new) // Atomically: // if(*val == old){ diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index 13a1642568..c2bc91a3f5 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -440,6 +440,9 @@ TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $0-12 TEXT runtime·atomicloaduint(SB), NOSPLIT, $0-12 JMP runtime·atomicload(SB) +TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-12 + JMP runtime·atomicstore(SB) + // bool runtime·cas64(uint64 *val, uint64 old, uint64 new) // Atomically: // if(*val == *old){ diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 36fb022f95..a1535aeec3 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -724,6 +724,9 @@ TEXT runtime·atomicloaduintptr(SB),NOSPLIT,$0-8 TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8 B runtime·atomicload(SB) +TEXT runtime·atomicstoreuintptr(SB),NOSPLIT,$0-8 + B runtime·atomicstore(SB) + // AES hashing not implemented for ARM TEXT runtime·aeshash(SB),NOSPLIT,$-4-0 MOVW $0, R0 diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 77f99062cf..6337dde2af 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -268,19 +268,19 @@ runtime·mpreinit(M *mp) void runtime·minit(void) { - void *thandle; + uintptr thandle; // -1 = current process, -2 = current thread runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS); - runtime·atomicstorep(&g->m->thread, thandle); + runtime·atomicstoreuintptr(&g->m->thread, thandle); } // Called from dropm to undo the effect of an minit. void runtime·unminit(void) { - runtime·stdcall1(runtime·CloseHandle, (uintptr)g->m->thread); - g->m->thread = nil; + runtime·stdcall1(runtime·CloseHandle, g->m->thread); + g->m->thread = 0; } // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/ @@ -532,7 +532,7 @@ void runtime·profileloop1(void) { M *mp, *allm; - void *thread; + uintptr thread; runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST); @@ -540,11 +540,11 @@ runtime·profileloop1(void) runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1); allm = runtime·atomicloadp(&runtime·allm); for(mp = allm; mp != nil; mp = mp->alllink) { - thread = runtime·atomicloadp(&mp->thread); + thread = runtime·atomicloaduintptr(&mp->thread); // Do not profile threads blocked on Notes, // this includes idle worker threads, // idle timer thread, idle heap scavenger, etc. - if(thread == nil || mp->profilehz == 0 || mp->blocked) + if(thread == 0 || mp->profilehz == 0 || mp->blocked) continue; runtime·stdcall1(runtime·SuspendThread, (uintptr)thread); if(mp->profilehz != 0 && !mp->blocked) diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index c4d8786089..27a809a07e 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -371,7 +371,7 @@ struct M uintptr scalararg[4]; // scalar argument/return for mcall void* ptrarg[4]; // pointer argument/return for mcall #ifdef GOOS_windows - void* thread; // thread handle + uintptr thread; // thread handle // these are here because they are too large to be on the stack // of low-level NOSPLIT functions. LibCall libcall; @@ -885,7 +885,9 @@ void runtime·atomicstore(uint32 volatile*, uint32); void runtime·atomicstore64(uint64 volatile*, uint64); uint64 runtime·atomicload64(uint64 volatile*); void* runtime·atomicloadp(void* volatile*); +uintptr runtime·atomicloaduintptr(uintptr volatile*); void runtime·atomicstorep(void* volatile*, void*); +void runtime·atomicstoreuintptr(uintptr volatile*, uintptr); void runtime·atomicor8(byte volatile*, byte); void runtime·setg(G*); From f950a14bb555938cd3878dd59cc447026e1108b9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Oct 2014 23:39:00 -0400 Subject: [PATCH 325/430] runtime: fix windows/amd64 build Out of stack space due to new 2-word call in freedefer. Go back to smaller function calls. TBR=brainman CC=golang-codereviews https://golang.org/cl/152340043 --- src/runtime/panic.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index c78102f8a3..58b14b09e3 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -189,8 +189,7 @@ func newdefer(siz int32) *_defer { //go:nosplit func freedefer(d *_defer) { if d._panic != nil { - // _panic must be cleared before d is unlinked from gp. - gothrow("freedefer with d._panic != nil") + freedeferpanic() } sc := deferclass(uintptr(d.siz)) if sc < uintptr(len(p{}.deferpool)) { @@ -203,6 +202,13 @@ func freedefer(d *_defer) { } } +// Separate function so that it can split stack. +// Windows otherwise runs out of stack space. +func freedeferpanic() { + // _panic must be cleared before d is unlinked from gp. + gothrow("freedefer with d._panic != nil") +} + // Run a deferred function if there is one. // The compiler inserts a call to this at the end of any // function which calls defer. From 94bdf13497f8a72673d71cc4d4c1a6e05a35b2dc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 8 Oct 2014 00:03:50 -0400 Subject: [PATCH 326/430] runtime: clear Defer.fn before removing from the G.defer list Should fix the remaining 'invalid heap pointer' build failures. TBR=khr CC=golang-codereviews https://golang.org/cl/152360043 --- src/runtime/panic.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 58b14b09e3..685ff5ca0b 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -191,6 +191,9 @@ func freedefer(d *_defer) { if d._panic != nil { freedeferpanic() } + if d.fn != nil { + freedeferfn() + } sc := deferclass(uintptr(d.siz)) if sc < uintptr(len(p{}.deferpool)) { mp := acquirem() @@ -209,6 +212,11 @@ func freedeferpanic() { gothrow("freedefer with d._panic != nil") } +func freedeferfn() { + // fn must be cleared before d is unlinked from gp. + gothrow("freedefer with d.fn != nil") +} + // Run a deferred function if there is one. // The compiler inserts a call to this at the end of any // function which calls defer. @@ -241,6 +249,7 @@ func deferreturn(arg0 uintptr) { mp := acquirem() memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz)) fn := d.fn + d.fn = nil gp._defer = d.link freedefer(d) releasem(mp) @@ -270,6 +279,7 @@ func Goexit() { d._panic.aborted = true d._panic = nil } + d.fn = nil gp._defer = d.link freedefer(d) continue @@ -280,6 +290,7 @@ func Goexit() { gothrow("bad defer entry in Goexit") } d._panic = nil + d.fn = nil gp._defer = d.link freedefer(d) // Note: we ignore recovers here because Goexit isn't a panic @@ -356,6 +367,7 @@ func gopanic(e interface{}) { d._panic.aborted = true } d._panic = nil + d.fn = nil gp._defer = d.link freedefer(d) continue @@ -380,6 +392,7 @@ func gopanic(e interface{}) { gothrow("bad defer entry in panic") } d._panic = nil + d.fn = nil gp._defer = d.link // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic From b8fdaaf028c54c97be20fa9dfbe372578902fad8 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 8 Oct 2014 13:51:12 +0400 Subject: [PATCH 327/430] runtime: faster GC scan The change contains 3 spot optimizations to scan loop: 1. Don't use byte vars, use uintptr's instead. This seems to alleviate some codegen issue, and alone accounts to a half of speedup. 2. Remove bitmap cache. Currently we cache only 1 byte, so caching is not particularly effective anyway. Removal of the cache simplifies code and positively affects regalloc. 3. Replace BitsMultiword switch with if and do debug checks only in Debug mode. I've benchmarked changes separately and ensured that each of them provides speedup on top of the previous one. This change as a whole fixes the unintentional regressions of scan loop that were introduced during development cycle. Fixes #8625. Fixes #8565. On go.benchmarks/garbage benchmark: GOMAXPROCS=1 time: -3.13% cputime: -3.22% gc-pause-one: -15.71% gc-pause-total: -15.71% GOMAXPROCS=32 time: -1.96% cputime: -4.43% gc-pause-one: -6.22% gc-pause-total: -6.22% LGTM=khr, rsc R=golang-codereviews, khr CC=golang-codereviews, rlh, rsc https://golang.org/cl/153990043 --- src/runtime/mgc0.c | 50 +++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 5876ea5c3e..e369e5425c 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -179,9 +179,8 @@ have_cgo_allocate(void) static void scanblock(byte *b, uintptr n, byte *ptrmask) { - byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp, bits, xbits, shift, cached; - uintptr i, j, nobj, size, idx, x, off, scanbufpos; - intptr ncached; + byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp; + uintptr i, j, nobj, size, idx, x, off, scanbufpos, bits, xbits, shift; Workbuf *wbuf; Iface *iface; Eface *eface; @@ -203,8 +202,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask) scanbuf[i] = nil; ptrbitp = nil; - cached = 0; - ncached = 0; // ptrmask can have 2 possible values: // 1. nil - obtain pointer mask from GC bitmap. @@ -259,10 +256,6 @@ scanblock(byte *b, uintptr n, byte *ptrmask) if(ptrmask == nil) { off = (uintptr*)b - (uintptr*)arena_start; ptrbitp = arena_start - off/wordsPerBitmapByte - 1; - shift = (off % wordsPerBitmapByte) * gcBits; - cached = *ptrbitp >> shift; - cached &= ~bitBoundary; - ncached = (8 - shift)/gcBits; } for(i = 0; i < n; i += PtrSize) { obj = nil; @@ -273,15 +266,12 @@ scanblock(byte *b, uintptr n, byte *ptrmask) runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift]) break; // Consult GC bitmap. - if(ncached <= 0) { - // Refill cache. - cached = *--ptrbitp; - ncached = 2; + bits = *ptrbitp; + if((((uintptr)b+i)%(PtrSize*wordsPerBitmapByte)) != 0) { + ptrbitp--; + bits >>= gcBits; } - bits = cached; - cached >>= gcBits; - ncached--; - if((bits&bitBoundary) != 0) + if((bits&bitBoundary) != 0 && i != 0) break; // reached beginning of the next object bits = (bits>>2)&BitsMask; if(bits == BitsDead) @@ -289,7 +279,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) } else // dense mask (stack or data) bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask; - if(bits == BitsScalar || bits == BitsDead) + if(bits <= BitsScalar) // BitsScalar || BitsDead continue; if(bits == BitsPointer) { obj = *(byte**)(b+i); @@ -298,43 +288,39 @@ scanblock(byte *b, uintptr n, byte *ptrmask) } // With those three out of the way, must be multi-word. - if(bits != BitsMultiWord) + if(Debug && bits != BitsMultiWord) runtime·throw("unexpected garbage collection bits"); // Find the next pair of bits. if(ptrmask == nil) { - if(ncached <= 0) { - // Refill cache. - cached = *--ptrbitp; - ncached = 2; + bits = *ptrbitp; + if((((uintptr)b+i)%(PtrSize*wordsPerBitmapByte)) == 0) { + ptrbitp--; + bits >>= gcBits; } - bits = (cached>>2)&BitsMask; + bits = (bits>>2)&BitsMask; } else bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask; - switch(bits) { - default: + if(Debug && bits != BitsIface && bits != BitsEface) runtime·throw("unexpected garbage collection bits"); - case BitsIface: + + if(bits == BitsIface) { iface = (Iface*)(b+i); if(iface->tab != nil) { typ = iface->tab->type; if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers)) obj = iface->data; } - break; - case BitsEface: + } else { eface = (Eface*)(b+i); typ = eface->type; if(typ != nil) { if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers)) obj = eface->data; } - break; } i += PtrSize; - cached >>= gcBits; - ncached--; obj0 = obj; markobj: From 83367781f56938de67b71b2e272f5222b8d34484 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 8 Oct 2014 07:10:04 -0700 Subject: [PATCH 328/430] A+C: Ron Hashimoto (individual CLA) Generated by a+c. R=gobot CC=golang-codereviews https://golang.org/cl/153240043 --- AUTHORS | 1 + CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index a924ea965f..03e686e751 100644 --- a/AUTHORS +++ b/AUTHORS @@ -378,6 +378,7 @@ Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné Roger Peppe +Ron Hashimoto Ron Minnich Ross Light Rowan Worth diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9dce23b2d5..a44e4be2e8 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -520,6 +520,7 @@ Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné Roger Peppe +Ron Hashimoto Ron Minnich Ross Light Rowan Worth From 6920b2a1f93a2ff6876eafc7f8747e82aa59d015 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 8 Oct 2014 15:48:46 -0700 Subject: [PATCH 329/430] reflect: add tests for variadic method calls These tests fail when using gccgo. In gccgo using Interface on the value of a method function is implemented using a variant of MakeFunc. That approach did not correctly handle variadic functions. LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/151280043 --- src/reflect/all_test.go | 54 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index d17ef5c5e9..f13b91b742 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -1569,6 +1569,24 @@ func (p Point) Dist(scale int) int { return p.x*p.x*scale + p.y*p.y*scale } +// This will be index 2. +func (p Point) GCMethod(k int) int { + runtime.GC() + return k + p.x +} + +// This will be index 3. +func (p Point) TotalDist(points ...Point) int { + tot := 0 + for _, q := range points { + dx := q.x - p.x + dy := q.y - p.y + tot += dx*dx + dy*dy // Should call Sqrt, but it's just a test. + + } + return tot +} + func TestMethod(t *testing.T) { // Non-curried method of type. p := Point{3, 4} @@ -1751,6 +1769,37 @@ func TestMethodValue(t *testing.T) { } } +func TestVariadicMethodValue(t *testing.T) { + p := Point{3, 4} + points := []Point{{20, 21}, {22, 23}, {24, 25}} + want := int64(p.TotalDist(points[0], points[1], points[2])) + + // Curried method of value. + tfunc := TypeOf((func(...Point) int)(nil)) + v := ValueOf(p).Method(3) + if tt := v.Type(); tt != tfunc { + t.Errorf("Variadic Method Type is %s; want %s", tt, tfunc) + } + i := ValueOf(v.Interface()).Call([]Value{ValueOf(points[0]), ValueOf(points[1]), ValueOf(points[2])})[0].Int() + if i != want { + t.Errorf("Variadic Method returned %d; want %d", i, want) + } + i = ValueOf(v.Interface()).CallSlice([]Value{ValueOf(points)})[0].Int() + if i != want { + t.Errorf("Variadic Method CallSlice returned %d; want %d", i, want) + } + + f := v.Interface().(func(...Point) int) + i = int64(f(points[0], points[1], points[2])) + if i != want { + t.Errorf("Variadic Method Interface returned %d; want %d", i, want) + } + i = int64(f(points...)) + if i != want { + t.Errorf("Variadic Method Interface Slice returned %d; want %d", i, want) + } +} + // Reflect version of $GOROOT/test/method5.go // Concrete types implementing M method. @@ -3770,11 +3819,6 @@ func TestReflectFuncTraceback(t *testing.T) { f.Call([]Value{}) } -func (p Point) GCMethod(k int) int { - runtime.GC() - return k + p.x -} - func TestReflectMethodTraceback(t *testing.T) { p := Point{3, 4} m := ValueOf(p).MethodByName("GCMethod") From 91e8554b8b9edfb4b05b2c04a50daf4df8ffed7b Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 8 Oct 2014 15:57:20 -0700 Subject: [PATCH 330/430] runtime: delay freeing of shrunk stacks until gc is done. This change prevents confusion in the garbage collector. The collector wants to make sure that every pointer it finds isn't junk. Its criteria for junk is (among others) points to a "free" span. Because the stack shrinker modifies pointers in the heap, there is a race condition between the GC scanner and the shrinker. The GC scanner can see old pointers (pointers to freed stacks). In particular this happens with SudoG.elem pointers. Normally this is not a problem, as pointers into stack spans are ok. But if the freed stack is the last one in its span, the span is marked as "free" instead of "contains stacks". This change makes sure that even if the GC scanner sees an old pointer, the span into which it points is still marked as "contains stacks", and thus the GC doesn't complain about it. This change will make the GC pause a tiny bit slower, as the stack freeing now happens in serial with the mark pause. We could delay the freeing until the mutators start back up, but this is the simplest change for now. TBR=dvyukov CC=golang-codereviews https://golang.org/cl/158750043 --- src/runtime/mgc0.c | 2 ++ src/runtime/runtime.h | 1 + src/runtime/stack.c | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index e369e5425c..0de7b1bf4a 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1445,6 +1445,8 @@ gc(struct gc_args *args) if(runtime·work.nproc > 1) runtime·notesleep(&runtime·work.alldone); + runtime·shrinkfinish(); + cachestats(); // next_gc calculation is tricky with concurrent sweep since we don't know size of live heap // estimate what was live heap size after previous GC (for tracing only) diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 27a809a07e..a84a32525e 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -852,6 +852,7 @@ void runtime·stackinit(void); Stack runtime·stackalloc(uint32); void runtime·stackfree(Stack); void runtime·shrinkstack(G*); +void runtime·shrinkfinish(void); MCache* runtime·allocmcache(void); void runtime·freemcache(MCache*); void runtime·mallocinit(void); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 8562b94076..d1ea3ff73b 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -36,6 +36,8 @@ MSpan runtime·stackpool[NumStackOrders]; Mutex runtime·stackpoolmu; // TODO: one lock per order? +static Stack stackfreequeue; + void runtime·stackinit(void) { @@ -656,7 +658,24 @@ copystack(G *gp, uintptr newsize) while(p < ep) *p++ = 0xfc; } - runtime·stackfree(old); + if(newsize > old.hi-old.lo) { + // growing, free stack immediately + runtime·stackfree(old); + } else { + // shrinking, queue up free operation. We can't actually free the stack + // just yet because we might run into the following situation: + // 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer + // 2) The stack that pointer points to is shrunk + // 3) The old stack is freed + // 4) The containing span is marked free + // 5) GC attempts to mark the SudoG.elem pointer. The marking fails because + // the pointer looks like a pointer into a free span. + // By not freeing, we prevent step #4 until GC is done. + runtime·lock(&runtime·stackpoolmu); + *(Stack*)old.lo = stackfreequeue; + stackfreequeue = old; + runtime·unlock(&runtime·stackpoolmu); + } } // round x up to a power of 2. @@ -841,6 +860,23 @@ runtime·shrinkstack(G *gp) copystack(gp, newsize); } +// Do any delayed stack freeing that was queued up during GC. +void +runtime·shrinkfinish(void) +{ + Stack s, t; + + runtime·lock(&runtime·stackpoolmu); + s = stackfreequeue; + stackfreequeue = (Stack){0,0}; + runtime·unlock(&runtime·stackpoolmu); + while(s.lo != 0) { + t = *(Stack*)s.lo; + runtime·stackfree(s); + s = t; + } +} + static void badc(void); #pragma textflag NOSPLIT From 14cd40d91267820c2db888a6d11e79a413f766b5 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Wed, 8 Oct 2014 15:58:56 -0700 Subject: [PATCH 331/430] reflect: add direct call tests to TestMakeFuncVariadic TestMakeFuncVariadic only called the variadic function via Call and CallSlice, not via a direct function call. I thought these tests would fail under gccgo tip, but they don't. Still seems worth having though. LGTM=iant R=golang-codereviews, gobot, iant CC=golang-codereviews https://golang.org/cl/152060043 --- src/reflect/all_test.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index f13b91b742..f0cd6a4128 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -1543,7 +1543,17 @@ func TestMakeFuncVariadic(t *testing.T) { fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] }) ValueOf(&fn).Elem().Set(fv) - r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) + r := fn(1, 2, 3) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + + r = fn(1, []int{2, 3}...) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + + r = fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int) if r[0] != 2 || r[1] != 3 { t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) } @@ -1552,6 +1562,17 @@ func TestMakeFuncVariadic(t *testing.T) { if r[0] != 2 || r[1] != 3 { t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) } + + f := fv.Interface().(func(int, ...int) []int) + + r = f(1, 2, 3) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } + r = f(1, []int{2, 3}...) + if r[0] != 2 || r[1] != 3 { + t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1]) + } } type Point struct { From 060b24006a7efbd4ec9d966759482428a421cbe8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 8 Oct 2014 16:17:34 -0700 Subject: [PATCH 332/430] cmd/ld: don't add line number info for the final address of an FDE This makes dwardump --verify happy. Update #8846 LGTM=r R=golang-codereviews, r CC=golang-codereviews https://golang.org/cl/150370043 --- src/cmd/ld/dwarf.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 4efb0ed537..a3ba523253 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -1733,6 +1733,7 @@ writeframes(void) LSym *s; vlong fdeo, fdesize, pad; Pciter pcsp; + uint32 nextpc; if(framesec == S) framesec = linklookup(ctxt, ".dwarfframe", 0); @@ -1775,8 +1776,17 @@ writeframes(void) addrput(0); // initial location addrput(0); // address range - for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) - putpccfadelta(pcsp.nextpc - pcsp.pc, PtrSize + pcsp.value); + for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) { + nextpc = pcsp.nextpc; + // pciterinit goes up to the end of the function, + // but DWARF expects us to stop just before the end. + if(nextpc == s->size) { + nextpc--; + if(nextpc < pcsp.pc) + continue; + } + putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value); + } fdesize = cpos() - fdeo - 4; // exclude the length field. pad = rnd(fdesize, PtrSize) - fdesize; From b02450da0227c757205fd16b6648bddceb980d83 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 8 Oct 2014 17:22:34 -0700 Subject: [PATCH 333/430] runtime: zero a few more dead pointers. In channels, zeroing of gp.waiting is missed on a closed channel panic. m.morebuf.g is not zeroed. I don't expect the latter causes any problems, but just in case. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/151610043 --- src/runtime/chan.go | 11 +++++++---- src/runtime/stack.c | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/runtime/chan.go b/src/runtime/chan.go index 10503f4e10..0049701826 100644 --- a/src/runtime/chan.go +++ b/src/runtime/chan.go @@ -174,6 +174,10 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin goparkunlock(&c.lock, "chan send") // someone woke us up. + if mysg != gp.waiting { + gothrow("G waiting list is corrupted!") + } + gp.waiting = nil if gp.param == nil { if c.closed == 0 { gothrow("chansend: spurious wakeup") @@ -184,10 +188,6 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin if mysg.releasetime > 0 { blockevent(int64(mysg.releasetime)-t0, 2) } - if mysg != gp.waiting { - gothrow("G waiting list is corrupted!") - } - gp.waiting = nil releaseSudog(mysg) return true } @@ -410,6 +410,9 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r goparkunlock(&c.lock, "chan receive") // someone woke us up + if mysg != gp.waiting { + gothrow("G waiting list is corrupted!") + } gp.waiting = nil if mysg.releasetime > 0 { blockevent(mysg.releasetime-t0, 2) diff --git a/src/runtime/stack.c b/src/runtime/stack.c index d1ea3ff73b..e402691f45 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -725,6 +725,7 @@ runtime·newstack(void) g->m->morebuf.pc = (uintptr)nil; g->m->morebuf.lr = (uintptr)nil; g->m->morebuf.sp = (uintptr)nil; + g->m->morebuf.g = (G*)nil; runtime·casgstatus(gp, Grunning, Gwaiting); gp->waitreason = runtime·gostringnocopy((byte*)"stack growth"); From 9ca836844496fe8723d8fe215d78530d1bba032e Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 9 Oct 2014 16:10:51 +1100 Subject: [PATCH 334/430] misc/cgo/test: add Test8517 CL 145890044 did not provide test. Rectify that. Update #8517 LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/148790043 --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue8517.go | 13 +++++++++ misc/cgo/test/issue8517_windows.c | 24 ++++++++++++++++ misc/cgo/test/issue8517_windows.go | 45 ++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 misc/cgo/test/issue8517.go create mode 100644 misc/cgo/test/issue8517_windows.c create mode 100644 misc/cgo/test/issue8517_windows.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index fcfad83049..05deb4197c 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -58,6 +58,7 @@ func Test5242(t *testing.T) { test5242(t) } func Test8092(t *testing.T) { test8092(t) } func Test7978(t *testing.T) { test7978(t) } func Test8694(t *testing.T) { test8694(t) } +func Test8517(t *testing.T) { test8517(t) } func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) } func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) } diff --git a/misc/cgo/test/issue8517.go b/misc/cgo/test/issue8517.go new file mode 100644 index 0000000000..4e431df921 --- /dev/null +++ b/misc/cgo/test/issue8517.go @@ -0,0 +1,13 @@ +// 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. + +// +build !windows + +package cgotest + +import "testing" + +func test8517(t *testing.T) { + t.Skip("skipping windows only test") +} diff --git a/misc/cgo/test/issue8517_windows.c b/misc/cgo/test/issue8517_windows.c new file mode 100644 index 0000000000..a0b94c126f --- /dev/null +++ b/misc/cgo/test/issue8517_windows.c @@ -0,0 +1,24 @@ +// 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. + +#include "windows.h" + +extern void testHandleLeaksCallback(); + +DWORD WINAPI testHandleLeaksFunc(LPVOID lpThreadParameter) +{ + int i; + for(i = 0; i < 100; i++) { + testHandleLeaksCallback(); + } + return 0; +} + +void testHandleLeaks() +{ + HANDLE h; + h = CreateThread(NULL, 0, &testHandleLeaksFunc, 0, 0, NULL); + WaitForSingleObject(h, INFINITE); + CloseHandle(h); +} diff --git a/misc/cgo/test/issue8517_windows.go b/misc/cgo/test/issue8517_windows.go new file mode 100644 index 0000000000..3782631e91 --- /dev/null +++ b/misc/cgo/test/issue8517_windows.go @@ -0,0 +1,45 @@ +// 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 cgotest + +//void testHandleLeaks(); +import "C" + +import ( + "syscall" + "testing" + "unsafe" +) + +var issue8517counter int + +var ( + kernel32 = syscall.MustLoadDLL("kernel32.dll") + getProcessHandleCount = kernel32.MustFindProc("GetProcessHandleCount") +) + +func processHandleCount(t *testing.T) int { + const current_process = ^uintptr(0) + var c uint32 + r, _, err := getProcessHandleCount.Call(current_process, uintptr(unsafe.Pointer(&c))) + if r == 0 { + t.Fatal(err) + } + return int(c) +} + +func test8517(t *testing.T) { + c1 := processHandleCount(t) + C.testHandleLeaks() + c2 := processHandleCount(t) + if c1+issue8517counter <= c2 { + t.Fatalf("too many handles leaked: issue8517counter=%v c1=%v c2=%v", issue8517counter, c1, c2) + } +} + +//export testHandleLeaksCallback +func testHandleLeaksCallback() { + issue8517counter++ +} From 17a108ba079cd3e94fa4d847d651d3a813569a9b Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 9 Oct 2014 16:52:28 +1100 Subject: [PATCH 335/430] runtime: handle all windows exception Fixes #8006. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/145150043 --- src/runtime/defs_windows.go | 3 + src/runtime/defs_windows_386.h | 3 + src/runtime/defs_windows_amd64.h | 3 + src/runtime/os_windows.c | 35 +++++++++-- src/runtime/os_windows_386.c | 80 +++++++++++++++---------- src/runtime/os_windows_amd64.c | 93 +++++++++++++++++++---------- src/runtime/sys_windows_386.s | 18 +++++- src/runtime/sys_windows_amd64.s | 18 +++++- src/runtime/syscall_windows_test.go | 39 ++++++++++++ 9 files changed, 220 insertions(+), 72 deletions(-) diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go index cb0f54d8ab..c27cc41dc0 100644 --- a/src/runtime/defs_windows.go +++ b/src/runtime/defs_windows.go @@ -59,6 +59,9 @@ const ( INFINITE = C.INFINITE WAIT_TIMEOUT = C.WAIT_TIMEOUT + + EXCEPTION_CONTINUE_EXECUTION = C.EXCEPTION_CONTINUE_EXECUTION + EXCEPTION_CONTINUE_SEARCH = C.EXCEPTION_CONTINUE_SEARCH ) type SystemInfo C.SYSTEM_INFO diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h index 295e422c6b..67cac0f01e 100644 --- a/src/runtime/defs_windows_386.h +++ b/src/runtime/defs_windows_386.h @@ -32,6 +32,9 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, + + EXCEPTION_CONTINUE_EXECUTION = -0x1, + EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h index 2516c84128..97cdb9ed15 100644 --- a/src/runtime/defs_windows_amd64.h +++ b/src/runtime/defs_windows_amd64.h @@ -32,6 +32,9 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, + + EXCEPTION_CONTINUE_EXECUTION = -0x1, + EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 6337dde2af..7210835503 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -34,6 +34,7 @@ #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" #pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" +#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" #pragma dynimport runtime·Sleep Sleep "kernel32.dll" #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" @@ -65,6 +66,7 @@ extern void *runtime·SetConsoleCtrlHandler; extern void *runtime·SetEvent; extern void *runtime·SetProcessPriorityBoost; extern void *runtime·SetThreadPriority; +extern void *runtime·SetUnhandledExceptionFilter; extern void *runtime·SetWaitableTimer; extern void *runtime·Sleep; extern void *runtime·SuspendThread; @@ -77,7 +79,9 @@ void *runtime·GetQueuedCompletionStatusEx; extern uintptr runtime·externalthreadhandlerp; void runtime·externalthreadhandler(void); -void runtime·sigtramp(void); +void runtime·exceptiontramp(void); +void runtime·firstcontinuetramp(void); +void runtime·lastcontinuetramp(void); #pragma textflag NOSPLIT uintptr @@ -106,12 +110,28 @@ void runtime·osinit(void) { void *kernel32; + void *addVectoredContinueHandler = nil; + + kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp); + runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); + if(kernel32 != nil) + addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); + if(addVectoredContinueHandler == nil) + // use SetUnhandledExceptionFilter if VectoredContinueHandler is unavailable. + // note: SetUnhandledExceptionFilter handler won't be called, if debugging. + runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); + else { + runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); + runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); + } + runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); + runtime·stdcall1(runtime·timeBeginPeriod, 1); + runtime·ncpu = getproccount(); // Windows dynamic priority boosting assumes that a process has different types @@ -120,7 +140,6 @@ runtime·osinit(void) // In such context dynamic priority boosting does nothing but harm, so we turn it off. runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); if(kernel32 != nil) { runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); } @@ -475,10 +494,14 @@ runtime·issigpanic(uint32 code) void runtime·initsig(void) { - // following line keeps sigtramp alive at link stage + // following line keeps these functions alive at link stage // if there's a better way please write it here - void *p = runtime·sigtramp; - USED(p); + void *e = runtime·exceptiontramp; + void *f = runtime·firstcontinuetramp; + void *l = runtime·lastcontinuetramp; + USED(e); + USED(f); + USED(l); } uint32 diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c index e2ae8db277..213582799b 100644 --- a/src/runtime/os_windows_386.c +++ b/src/runtime/os_windows_386.c @@ -24,45 +24,63 @@ runtime·dumpregs(Context *r) runtime·printf("gs %x\n", r->SegGs); } -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (-1) -// or should be made available to other handlers in the chain (0). -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +bool +runtime·isgoexception(ExceptionRecord *info, Context *r) { - bool crash; - uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return 0; + return false; - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; + if(!runtime·issigpanic(info->ExceptionCode)) + return false; - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; - } - r->Eip = (uintptr)runtime·sigpanic; - return -1; + return true; +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +uint32 +runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Eip; + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Eip != 0) { + sp = (uintptr*)r->Esp; + *--sp = r->Eip; + r->Esp = (uintptr)sp; } + r->Eip = (uintptr)runtime·sigpanic; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +uint32 +runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -88,7 +106,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return -1; // not reached + return 0; // not reached } void diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c index 261880d450..b96cf70d1e 100644 --- a/src/runtime/os_windows_amd64.c +++ b/src/runtime/os_windows_amd64.c @@ -32,45 +32,76 @@ runtime·dumpregs(Context *r) runtime·printf("gs %X\n", (uint64)r->SegGs); } -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (-1) -// or should be made available to other handlers in the chain (0). -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +bool +runtime·isgoexception(ExceptionRecord *info, Context *r) { - bool crash; - uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return 0; + return false; - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; + if(!runtime·issigpanic(info->ExceptionCode)) + return false; - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; - } - r->Rip = (uintptr)runtime·sigpanic; - return -1; + return true; +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +uint32 +runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Rip; + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Rip != 0) { + sp = (uintptr*)r->Rsp; + *--sp = r->Rip; + r->Rsp = (uintptr)sp; } + r->Rip = (uintptr)runtime·sigpanic; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// It seems Windows searches ContinueHandler's list even +// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. +// firstcontinuehandler will stop that search, +// if exceptionhandler did the same earlier. +uint32 +runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + USED(gp); + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +uint32 +runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -97,7 +128,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return -1; // not reached + return 0; // not reached } void diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 1bf4d062ac..932fe9dd24 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -73,6 +73,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. +// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL ptrs+0(FP), CX @@ -84,6 +85,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL SI, 20(SP) MOVL DI, 24(SP) + MOVL AX, SI // save handler address + // find g get_tls(DX) CMPL DX, $0 @@ -123,11 +126,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVL 0(CX), BX // ExceptionRecord* MOVL 4(CX), CX // Context* - // call sighandler(ExceptionRecord*, Context*, G*) MOVL BX, 0(SP) MOVL CX, 4(SP) MOVL DX, 8(SP) - CALL runtime·sighandler(SB) + CALL SI // call handler // AX is set to report result back to Windows MOVL 12(SP), AX @@ -149,6 +151,18 @@ done: // RET 4 (return and pop 4 bytes parameters) BYTE $0xC2; WORD $4 RET // unreached; make assembler happy + +TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 + MOVL $runtime·exceptionhandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 + // is never called + INT $3 + +TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 + MOVL $runtime·lastcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) TEXT runtime·ctrlhandler(SB),NOSPLIT,$0 PUSHL $runtime·ctrlhandler1(SB) diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 05750398ea..e6190ce684 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -99,6 +99,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. +// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // CX: PEXCEPTION_POINTERS ExceptionInfo @@ -116,6 +117,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVQ R14, 32(SP) MOVQ R15, 88(SP) + MOVQ AX, R15 // save handler address + // find g get_tls(DX) CMPQ DX, $0 @@ -157,11 +160,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVQ 0(CX), BX // ExceptionRecord* MOVQ 8(CX), CX // Context* - // call sighandler(ExceptionRecord*, Context*, G*) MOVQ BX, 0(SP) MOVQ CX, 8(SP) MOVQ DX, 16(SP) - CALL runtime·sighandler(SB) + CALL R15 // call handler // AX is set to report result back to Windows MOVL 24(SP), AX @@ -187,6 +189,18 @@ done: RET +TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 + MOVQ $runtime·exceptionhandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 + MOVQ $runtime·firstcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 + MOVQ $runtime·lastcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) + TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 MOVQ CX, 16(SP) // spill MOVQ $runtime·ctrlhandler1(SB), CX diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index 9ed016ccc8..ce8a9ec1ba 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -494,3 +494,42 @@ func TestOutputDebugString(t *testing.T) { p := syscall.StringToUTF16Ptr("testing OutputDebugString") d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p))) } + +func TestRaiseException(t *testing.T) { + o := executeTest(t, raiseExceptionSource, nil) + if strings.Contains(o, "RaiseException should not return") { + t.Fatalf("RaiseException did not crash program: %v", o) + } + if !strings.Contains(o, "Exception 0xbad") { + t.Fatalf("No stack trace: %v", o) + } +} + +const raiseExceptionSource = ` +package main +import "syscall" +func main() { + const EXCEPTION_NONCONTINUABLE = 1 + mod := syscall.MustLoadDLL("kernel32.dll") + proc := mod.MustFindProc("RaiseException") + proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0) + println("RaiseException should not return") +} +` + +func TestZeroDivisionException(t *testing.T) { + o := executeTest(t, zeroDivisionExceptionSource, nil) + if !strings.Contains(o, "panic: runtime error: integer divide by zero") { + t.Fatalf("No stack trace: %v", o) + } +} + +const zeroDivisionExceptionSource = ` +package main +func main() { + x := 1 + y := 0 + z := x / y + println(z) +} +` From 64736accdbc187eba6619345754abaaeefdb7238 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Thu, 9 Oct 2014 17:24:34 +1100 Subject: [PATCH 336/430] undo CL 145150043 / 8b3d26697b8d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That was complete failure - builders are broken, but original cl worked fine on my system. I will need access to builders to test this change properly. ««« original CL description runtime: handle all windows exception Fixes #8006. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/145150043 »»» TBR=rsc R=golang-codereviews CC=golang-codereviews https://golang.org/cl/154180043 --- src/runtime/defs_windows.go | 3 - src/runtime/defs_windows_386.h | 3 - src/runtime/defs_windows_amd64.h | 3 - src/runtime/os_windows.c | 35 ++--------- src/runtime/os_windows_386.c | 80 ++++++++++--------------- src/runtime/os_windows_amd64.c | 93 ++++++++++------------------- src/runtime/sys_windows_386.s | 18 +----- src/runtime/sys_windows_amd64.s | 18 +----- src/runtime/syscall_windows_test.go | 39 ------------ 9 files changed, 72 insertions(+), 220 deletions(-) diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go index c27cc41dc0..cb0f54d8ab 100644 --- a/src/runtime/defs_windows.go +++ b/src/runtime/defs_windows.go @@ -59,9 +59,6 @@ const ( INFINITE = C.INFINITE WAIT_TIMEOUT = C.WAIT_TIMEOUT - - EXCEPTION_CONTINUE_EXECUTION = C.EXCEPTION_CONTINUE_EXECUTION - EXCEPTION_CONTINUE_SEARCH = C.EXCEPTION_CONTINUE_SEARCH ) type SystemInfo C.SYSTEM_INFO diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h index 67cac0f01e..295e422c6b 100644 --- a/src/runtime/defs_windows_386.h +++ b/src/runtime/defs_windows_386.h @@ -32,9 +32,6 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, - - EXCEPTION_CONTINUE_EXECUTION = -0x1, - EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h index 97cdb9ed15..2516c84128 100644 --- a/src/runtime/defs_windows_amd64.h +++ b/src/runtime/defs_windows_amd64.h @@ -32,9 +32,6 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, - - EXCEPTION_CONTINUE_EXECUTION = -0x1, - EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 7210835503..6337dde2af 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -34,7 +34,6 @@ #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" #pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" -#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" #pragma dynimport runtime·Sleep Sleep "kernel32.dll" #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" @@ -66,7 +65,6 @@ extern void *runtime·SetConsoleCtrlHandler; extern void *runtime·SetEvent; extern void *runtime·SetProcessPriorityBoost; extern void *runtime·SetThreadPriority; -extern void *runtime·SetUnhandledExceptionFilter; extern void *runtime·SetWaitableTimer; extern void *runtime·Sleep; extern void *runtime·SuspendThread; @@ -79,9 +77,7 @@ void *runtime·GetQueuedCompletionStatusEx; extern uintptr runtime·externalthreadhandlerp; void runtime·externalthreadhandler(void); -void runtime·exceptiontramp(void); -void runtime·firstcontinuetramp(void); -void runtime·lastcontinuetramp(void); +void runtime·sigtramp(void); #pragma textflag NOSPLIT uintptr @@ -110,28 +106,12 @@ void runtime·osinit(void) { void *kernel32; - void *addVectoredContinueHandler = nil; - - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); - if(kernel32 != nil) - addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); - if(addVectoredContinueHandler == nil) - // use SetUnhandledExceptionFilter if VectoredContinueHandler is unavailable. - // note: SetUnhandledExceptionFilter handler won't be called, if debugging. - runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); - else { - runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); - runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); - } - + runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp); runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); - runtime·stdcall1(runtime·timeBeginPeriod, 1); - runtime·ncpu = getproccount(); // Windows dynamic priority boosting assumes that a process has different types @@ -140,6 +120,7 @@ runtime·osinit(void) // In such context dynamic priority boosting does nothing but harm, so we turn it off. runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); + kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); if(kernel32 != nil) { runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); } @@ -494,14 +475,10 @@ runtime·issigpanic(uint32 code) void runtime·initsig(void) { - // following line keeps these functions alive at link stage + // following line keeps sigtramp alive at link stage // if there's a better way please write it here - void *e = runtime·exceptiontramp; - void *f = runtime·firstcontinuetramp; - void *l = runtime·lastcontinuetramp; - USED(e); - USED(f); - USED(l); + void *p = runtime·sigtramp; + USED(p); } uint32 diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c index 213582799b..e2ae8db277 100644 --- a/src/runtime/os_windows_386.c +++ b/src/runtime/os_windows_386.c @@ -24,63 +24,45 @@ runtime·dumpregs(Context *r) runtime·printf("gs %x\n", r->SegGs); } -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (-1) +// or should be made available to other handlers in the chain (0). +uint32 +runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { + bool crash; + uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return false; + return 0; - if(!runtime·issigpanic(info->ExceptionCode)) - return false; + if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Eip; - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; - - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Eip != 0) { + sp = (uintptr*)r->Esp; + *--sp = r->Eip; + r->Esp = (uintptr)sp; + } + r->Eip = (uintptr)runtime·sigpanic; + return -1; } - r->Eip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -106,7 +88,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return 0; // not reached + return -1; // not reached } void diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c index b96cf70d1e..261880d450 100644 --- a/src/runtime/os_windows_amd64.c +++ b/src/runtime/os_windows_amd64.c @@ -32,76 +32,45 @@ runtime·dumpregs(Context *r) runtime·printf("gs %X\n", (uint64)r->SegGs); } -bool -runtime·isgoexception(ExceptionRecord *info, Context *r) +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (-1) +// or should be made available to other handlers in the chain (0). +uint32 +runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) { + bool crash; + uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return false; + return 0; - if(!runtime·issigpanic(info->ExceptionCode)) - return false; + if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Rip; - return true; -} - -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) -// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). -uint32 -runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) -{ - uintptr *sp; - - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; - - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Rip != 0) { + sp = (uintptr*)r->Rsp; + *--sp = r->Rip; + r->Rsp = (uintptr)sp; + } + r->Rip = (uintptr)runtime·sigpanic; + return -1; } - r->Rip = (uintptr)runtime·sigpanic; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// It seems Windows searches ContinueHandler's list even -// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. -// firstcontinuehandler will stop that search, -// if exceptionhandler did the same earlier. -uint32 -runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - USED(gp); - if(!runtime·isgoexception(info, r)) - return EXCEPTION_CONTINUE_SEARCH; - return EXCEPTION_CONTINUE_EXECUTION; -} - -// lastcontinuehandler is reached, because runtime cannot handle -// current exception. lastcontinuehandler will print crash info and exit. -uint32 -runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) -{ - bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -128,7 +97,7 @@ runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return 0; // not reached + return -1; // not reached } void diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 932fe9dd24..1bf4d062ac 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -73,7 +73,6 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. -// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL ptrs+0(FP), CX @@ -85,8 +84,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL SI, 20(SP) MOVL DI, 24(SP) - MOVL AX, SI // save handler address - // find g get_tls(DX) CMPL DX, $0 @@ -126,10 +123,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVL 0(CX), BX // ExceptionRecord* MOVL 4(CX), CX // Context* + // call sighandler(ExceptionRecord*, Context*, G*) MOVL BX, 0(SP) MOVL CX, 4(SP) MOVL DX, 8(SP) - CALL SI // call handler + CALL runtime·sighandler(SB) // AX is set to report result back to Windows MOVL 12(SP), AX @@ -151,18 +149,6 @@ done: // RET 4 (return and pop 4 bytes parameters) BYTE $0xC2; WORD $4 RET // unreached; make assembler happy - -TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 - MOVL $runtime·exceptionhandler(SB), AX - JMP runtime·sigtramp(SB) - -TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 - // is never called - INT $3 - -TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 - MOVL $runtime·lastcontinuehandler(SB), AX - JMP runtime·sigtramp(SB) TEXT runtime·ctrlhandler(SB),NOSPLIT,$0 PUSHL $runtime·ctrlhandler1(SB) diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index e6190ce684..05750398ea 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -99,7 +99,6 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. -// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // CX: PEXCEPTION_POINTERS ExceptionInfo @@ -117,8 +116,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVQ R14, 32(SP) MOVQ R15, 88(SP) - MOVQ AX, R15 // save handler address - // find g get_tls(DX) CMPQ DX, $0 @@ -160,10 +157,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVQ 0(CX), BX // ExceptionRecord* MOVQ 8(CX), CX // Context* + // call sighandler(ExceptionRecord*, Context*, G*) MOVQ BX, 0(SP) MOVQ CX, 8(SP) MOVQ DX, 16(SP) - CALL R15 // call handler + CALL runtime·sighandler(SB) // AX is set to report result back to Windows MOVL 24(SP), AX @@ -189,18 +187,6 @@ done: RET -TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 - MOVQ $runtime·exceptionhandler(SB), AX - JMP runtime·sigtramp(SB) - -TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 - MOVQ $runtime·firstcontinuehandler(SB), AX - JMP runtime·sigtramp(SB) - -TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 - MOVQ $runtime·lastcontinuehandler(SB), AX - JMP runtime·sigtramp(SB) - TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 MOVQ CX, 16(SP) // spill MOVQ $runtime·ctrlhandler1(SB), CX diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index ce8a9ec1ba..9ed016ccc8 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -494,42 +494,3 @@ func TestOutputDebugString(t *testing.T) { p := syscall.StringToUTF16Ptr("testing OutputDebugString") d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p))) } - -func TestRaiseException(t *testing.T) { - o := executeTest(t, raiseExceptionSource, nil) - if strings.Contains(o, "RaiseException should not return") { - t.Fatalf("RaiseException did not crash program: %v", o) - } - if !strings.Contains(o, "Exception 0xbad") { - t.Fatalf("No stack trace: %v", o) - } -} - -const raiseExceptionSource = ` -package main -import "syscall" -func main() { - const EXCEPTION_NONCONTINUABLE = 1 - mod := syscall.MustLoadDLL("kernel32.dll") - proc := mod.MustFindProc("RaiseException") - proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0) - println("RaiseException should not return") -} -` - -func TestZeroDivisionException(t *testing.T) { - o := executeTest(t, zeroDivisionExceptionSource, nil) - if !strings.Contains(o, "panic: runtime error: integer divide by zero") { - t.Fatalf("No stack trace: %v", o) - } -} - -const zeroDivisionExceptionSource = ` -package main -func main() { - x := 1 - y := 0 - z := x / y - println(z) -} -` From e6295210b9abef03d350f5117df228fb21093f84 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 9 Oct 2014 11:12:03 +0200 Subject: [PATCH 337/430] net/rpc: skip TestGobError on Plan 9 LGTM=bradfitz R=rsc, bradfitz CC=aram, golang-codereviews https://golang.org/cl/154140043 --- src/net/rpc/client_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go index d116d2acc9..fb838eb34f 100644 --- a/src/net/rpc/client_test.go +++ b/src/net/rpc/client_test.go @@ -52,6 +52,9 @@ func (s *S) Recv(nul *struct{}, reply *R) error { } func TestGobError(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping test; see http://golang.org/issue/8908") + } defer func() { err := recover() if err == nil { From 9be9861c91aa42fc8cea8a9c902af6873b96b3b9 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 9 Oct 2014 11:21:21 +0200 Subject: [PATCH 338/430] net/rpc: fix build LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/151620043 --- src/net/rpc/client_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go index fb838eb34f..5dd111b299 100644 --- a/src/net/rpc/client_test.go +++ b/src/net/rpc/client_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "net" + "runtime" "strings" "testing" ) From e3727df55001478b97afd3d5ec9eea6f78cfbda1 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 9 Oct 2014 15:00:23 +0200 Subject: [PATCH 339/430] C: add Hana Kim (Google CLA) LGTM=crawshaw R=golang-codereviews, crawshaw CC=golang-codereviews, iant https://golang.org/cl/150690043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a44e4be2e8..a24178b528 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -256,6 +256,7 @@ Gustav Paul Gustavo Franco Gustavo Niemeyer Gwenael Treguier +Hana Kim Han-Wen Nienhuys Harley Laue Hector Chu From f1c0899e6f1219921200d66f56c22807156096c1 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 9 Oct 2014 17:05:38 +0400 Subject: [PATCH 340/430] runtime: add comment to mgc0.h Missed that comment in CL 153990043. LGTM=khr R=khr CC=golang-codereviews https://golang.org/cl/156010043 --- src/runtime/mgc0.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h index 10f24d009f..64f8189143 100644 --- a/src/runtime/mgc0.h +++ b/src/runtime/mgc0.h @@ -42,6 +42,8 @@ enum { BitsMask = (1< Date: Thu, 9 Oct 2014 14:38:45 -0700 Subject: [PATCH 341/430] debug/elf: add comments explaining applyRelocations for amd64/arm64 LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/155190043 --- src/debug/elf/file.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index c908e7a889..de8a3a24fe 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -564,6 +564,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { continue } + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + switch t { case R_X86_64_64: if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { @@ -646,6 +650,10 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { continue } + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + switch t { case R_AARCH64_ABS64: if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { From 3114bd6f97492461d2027a49fee9f7fce3742b75 Mon Sep 17 00:00:00 2001 From: Ron Hashimoto Date: Fri, 10 Oct 2014 09:21:32 +1100 Subject: [PATCH 342/430] net: disable SIO_UDP_CONNRESET behavior on windows. Fixes #5834. LGTM=alex.brainman R=golang-codereviews, bradfitz, alex.brainman, mikioh.mikioh, in60jp, iant CC=golang-codereviews https://golang.org/cl/149510043 --- src/net/fd_windows.go | 12 ++++++++++++ src/net/udp_test.go | 36 +++++++++++++++++++++++++++++++++++ src/syscall/ztypes_windows.go | 1 + 3 files changed, 49 insertions(+) diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go index 6d69e06249..f3a534a1de 100644 --- a/src/net/fd_windows.go +++ b/src/net/fd_windows.go @@ -294,6 +294,18 @@ func (fd *netFD) init() error { fd.skipSyncNotif = true } } + // Disable SIO_UDP_CONNRESET behavior. + // http://support.microsoft.com/kb/263823 + switch fd.net { + case "udp", "udp4", "udp6": + ret := uint32(0) + flag := uint32(0) + size := uint32(unsafe.Sizeof(flag)) + err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) + if err != nil { + return os.NewSyscallError("WSAIoctl", err) + } + } fd.rop.mode = 'r' fd.wop.mode = 'w' fd.rop.fd = fd diff --git a/src/net/udp_test.go b/src/net/udp_test.go index e1778779cf..a102acf6c5 100644 --- a/src/net/udp_test.go +++ b/src/net/udp_test.go @@ -9,6 +9,7 @@ import ( "runtime" "strings" "testing" + "time" ) func TestResolveUDPAddr(t *testing.T) { @@ -34,6 +35,41 @@ func TestResolveUDPAddr(t *testing.T) { } } +func TestReadFromUDP(t *testing.T) { + ra, err := ResolveUDPAddr("udp", "127.0.0.1:7") + if err != nil { + t.Fatal(err) + } + + la, err := ResolveUDPAddr("udp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + + c, err := ListenUDP("udp", la) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + _, err = c.WriteToUDP([]byte("a"), ra) + if err != nil { + t.Fatal(err) + } + + err = c.SetDeadline(time.Now().Add(100 * time.Millisecond)) + if err != nil { + t.Fatal(err) + } + b := make([]byte, 1) + _, _, err = c.ReadFromUDP(b) + if err == nil { + t.Fatal("ReadFromUDP should fail") + } else if !isTimeout(err) { + t.Fatal(err) + } +} + func TestWriteToUDP(t *testing.T) { switch runtime.GOOS { case "plan9": diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go index 1363da01a8..4c8a99ab94 100644 --- a/src/syscall/ztypes_windows.go +++ b/src/syscall/ztypes_windows.go @@ -547,6 +547,7 @@ const ( IOC_WS2 = 0x08000000 SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6 SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4 + SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 From eeb2211a5b88ae0774fbfd5bccc1de329e7663f7 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 10 Oct 2014 09:46:41 +1100 Subject: [PATCH 343/430] net: skip new TestReadFromUDP on nacl and plan9 (fixes build) TBR=0intro R=golang-codereviews CC=golang-codereviews https://golang.org/cl/157820043 --- src/net/udp_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/net/udp_test.go b/src/net/udp_test.go index a102acf6c5..aa5751557f 100644 --- a/src/net/udp_test.go +++ b/src/net/udp_test.go @@ -36,6 +36,11 @@ func TestResolveUDPAddr(t *testing.T) { } func TestReadFromUDP(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("skipping test on %q", runtime.GOOS) + } + ra, err := ResolveUDPAddr("udp", "127.0.0.1:7") if err != nil { t.Fatal(err) From 1fd042c9aa84cc20f02974c69202df919cf1ff00 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Thu, 9 Oct 2014 17:37:40 -0700 Subject: [PATCH 344/430] encoding/asn1: fix explicitly tagged Times. https://golang.org/cl/153770043/ tried to fix the case where a implicitly tagged Time, that happened to have the same tag as GENERALIZEDTIME, shouldn't be parsed as a GENERALIZEDTIME. It did so, mistakenly, by testing whether params.tag != nil. But explicitly tagged values also have a non-nil tag and there the inner tag actually does encode the type of the value. This change instead tests whether the tag class is UNIVERSAL before assuming that the tag contains type information. LGTM=iant R=iant CC=golang-codereviews https://golang.org/cl/152380044 --- src/encoding/asn1/asn1.go | 4 +-- src/encoding/asn1/asn1_test.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go index 3aeb3dcc4b..8b3d1b3412 100644 --- a/src/encoding/asn1/asn1.go +++ b/src/encoding/asn1/asn1.go @@ -640,7 +640,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam // when it sees a string, so if we see a different string type on the // wire, we change the universal type to match. if universalTag == tagPrintableString { - if params.tag == nil { + if t.class == classUniversal { switch t.tag { case tagIA5String, tagGeneralString, tagT61String, tagUTF8String: universalTag = t.tag @@ -652,7 +652,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam // Special case for time: UTCTime and GeneralizedTime both map to the // Go type time.Time. - if universalTag == tagUTCTime && params.tag == nil && t.tag == tagGeneralizedTime { + if universalTag == tagUTCTime && t.tag == tagGeneralizedTime && t.class == classUniversal { universalTag = tagGeneralizedTime } diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go index b94d59d369..4e864d08ac 100644 --- a/src/encoding/asn1/asn1_test.go +++ b/src/encoding/asn1/asn1_test.go @@ -817,3 +817,51 @@ func TestStringSlice(t *testing.T) { } } } + +type explicitTaggedTimeTest struct { + Time time.Time `asn1:"explicit,tag:0"` +} + +var explicitTaggedTimeTestData = []struct { + in []byte + out explicitTaggedTimeTest +}{ + {[]byte{0x30, 0x11, 0xa0, 0xf, 0x17, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'}, + explicitTaggedTimeTest{time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC)}}, + {[]byte{0x30, 0x17, 0xa0, 0xf, 0x18, 0x13, '2', '0', '1', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '+', '0', '6', '0', '7'}, + explicitTaggedTimeTest{time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}}, +} + +func TestExplicitTaggedTime(t *testing.T) { + // Test that a time.Time will match either tagUTCTime or + // tagGeneralizedTime. + for i, test := range explicitTaggedTimeTestData { + var got explicitTaggedTimeTest + _, err := Unmarshal(test.in, &got) + if err != nil { + t.Errorf("Unmarshal failed at index %d %v", i, err) + } + if !got.Time.Equal(test.out.Time) { + t.Errorf("#%d: got %v, want %v", i, got.Time, test.out.Time) + } + } +} + +type implicitTaggedTimeTest struct { + Time time.Time `asn1:"tag:24"` +} + +func TestImplicitTaggedTime(t *testing.T) { + // An implicitly tagged time value, that happens to have an implicit + // tag equal to a GENERALIZEDTIME, should still be parsed as a UTCTime. + // (There's no "timeType" in fieldParameters to determine what type of + // time should be expected when implicitly tagged.) + der := []byte{0x30, 0x0f, 0x80 | 24, 0xd, '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'} + var result implicitTaggedTimeTest + if _, err := Unmarshal(der, &result); err != nil { + t.Fatalf("Error while parsing: %s", err) + } + if expected := time.Date(1991, 05, 06, 16, 45, 40, 0, time.UTC); !result.Time.Equal(expected) { + t.Errorf("Wrong result. Got %v, want %v", result.Time, expected) + } +} From c689abd56c05c34922f6390ac835719c4a48065a Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Fri, 10 Oct 2014 13:12:32 +1100 Subject: [PATCH 345/430] net: link skipped TestReadFromUDP to the issue LGTM=minux R=bradfitz, minux CC=golang-codereviews https://golang.org/cl/154220043 --- src/net/udp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/udp_test.go b/src/net/udp_test.go index aa5751557f..125bbca6c4 100644 --- a/src/net/udp_test.go +++ b/src/net/udp_test.go @@ -38,7 +38,7 @@ func TestResolveUDPAddr(t *testing.T) { func TestReadFromUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS) } ra, err := ResolveUDPAddr("udp", "127.0.0.1:7") From 8fe5ef40525d23012282a83a06a441863daa6bdb Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Fri, 10 Oct 2014 20:30:24 -0400 Subject: [PATCH 346/430] cmd/ld: fix off-by-one error when emitting symbol names I diffed the output of `nm -n gofmt' before and after this change, and verified that all changes are correct and all corrupted symbol names are fixed. Fixes #8906. LGTM=iant, cookieo9 R=golang-codereviews, iant, cookieo9 CC=golang-codereviews https://golang.org/cl/159750043 --- src/cmd/ld/macho.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 61306bb7ca..fe7e10e466 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -590,8 +590,7 @@ machosymtab(void) if(strstr(s->extname, "·") == nil) { addstring(symstr, s->extname); } else { - p = s->extname; - while (*p++ != '\0') { + for(p = s->extname; *p; p++) { if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) { adduint8(ctxt, symstr, '.'); p++; From d0ee959ab74f39734ae99fdd3e50bea08b52625d Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sat, 11 Oct 2014 21:34:10 +1100 Subject: [PATCH 347/430] cmd/ld: correct pe section names if longer then 8 chars gcc 4.9.1 generates pe sections with names longer then 8 charters. From IMAGE_SECTION_HEADER definition: Name An 8-byte, null-padded UTF-8 string. There is no terminating null character if the string is exactly eight characters long. For longer names, this member contains a forward slash (/) followed by an ASCII representation of a decimal number that is an offset into the string table. Our current pe object file reader does not read string table when section names starts with /. Do that, so (issue 8811 example) c:\go\path\src\isssue8811>go build # isssue8811 isssue8811/glfw(.text): isssue8811/glfw(/76): not defined isssue8811/glfw(.text): undefined: isssue8811/glfw(/76) becomes c:\go\path\src\isssue8811>go build # isssue8811 isssue8811/glfw(.text): isssue8811/glfw(.rdata$.refptr._glfwInitialized): not defined isssue8811/glfw(.text): undefined: isssue8811/glfw(.rdata$.refptr._glfwInitialized) Small progress to Update #8811 LGTM=iant, jfrederich R=golang-codereviews, iant, jfrederich CC=golang-codereviews https://golang.org/cl/154210044 --- src/cmd/ld/ldpe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index 1b05916148..9257c243c9 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -179,6 +179,15 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0); if(Bread(f, obj->snames, l) != l) goto bad; + // rewrite section names if they start with / + for(i=0; i < obj->fh.NumberOfSections; i++) { + if(obj->sect[i].name == nil) + continue; + if(obj->sect[i].name[0] != '/') + continue; + l = atoi(obj->sect[i].name + 1); + obj->sect[i].name = (char*)&obj->snames[l]; + } // read symbols obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); obj->npesym = obj->fh.NumberOfSymbols; From d704bb0dc907d32ca827e97bf506794d809ebce8 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sat, 11 Oct 2014 22:01:04 +1100 Subject: [PATCH 348/430] cmd/ld: do not assume that only pe section names start with '.' Our current pe object reader assumes that every symbol starting with '.' is section. It appeared to be true, until now gcc 4.9.1 generates some symbols with '.' at the front. Change that logic to check other symbol fields in addition to checking for '.'. I am not an expert here, but it seems reasonable to me. Added test, but it is only good, if tested with gcc 4.9.1. Otherwise the test PASSes regardless. Fixes #8811. Fixes #8856. LGTM=jfrederich, iant, stephen.gutekanst R=golang-codereviews, jfrederich, stephen.gutekanst, iant CC=alex.brainman, golang-codereviews https://golang.org/cl/152410043 --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue8811.c | 8 ++++++++ misc/cgo/test/issue8811.go | 22 ++++++++++++++++++++++ src/cmd/ld/ldpe.c | 17 ++++++++++++----- 4 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 misc/cgo/test/issue8811.c create mode 100644 misc/cgo/test/issue8811.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 05deb4197c..3b289ba7b5 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -59,6 +59,7 @@ func Test8092(t *testing.T) { test8092(t) } func Test7978(t *testing.T) { test7978(t) } func Test8694(t *testing.T) { test8694(t) } func Test8517(t *testing.T) { test8517(t) } +func Test8811(t *testing.T) { test8811(t) } func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) } func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) } diff --git a/misc/cgo/test/issue8811.c b/misc/cgo/test/issue8811.c new file mode 100644 index 0000000000..584bb39342 --- /dev/null +++ b/misc/cgo/test/issue8811.c @@ -0,0 +1,8 @@ +// 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. + +int issue8811Initialized = 0; + +void issue8811Init() { +} diff --git a/misc/cgo/test/issue8811.go b/misc/cgo/test/issue8811.go new file mode 100644 index 0000000000..2e217d9356 --- /dev/null +++ b/misc/cgo/test/issue8811.go @@ -0,0 +1,22 @@ +// 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 cgotest + +/* +extern int issue8811Initialized; +extern void issue8811Init(); + +void issue8811Execute() { + if(!issue8811Initialized) + issue8811Init(); +} +*/ +import "C" + +import "testing" + +func test8811(t *testing.T) { + C.issue8811Execute() +} diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index 9257c243c9..4f5e51f2f1 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -128,6 +128,7 @@ struct PeObj { }; static int map(PeObj *obj, PeSect *sect); +static int issect(PeSym *s); static int readsym(PeObj *obj, int i, PeSym **sym); void @@ -318,8 +319,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) // ld -r could generate multiple section symbols for the // same section but with different values, we have to take // that into account - if (obj->pesym[symindex].name[0] == '.') - rp->add += obj->pesym[symindex].value; + if(issect(&obj->pesym[symindex])) + rp->add += obj->pesym[symindex].value; } qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); @@ -327,12 +328,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) s->r = r; s->nr = rsect->sh.NumberOfRelocations; } - + // enter sub-symbols into symbol table. for(i=0; inpesym; i++) { if(obj->pesym[i].name == 0) continue; - if(obj->pesym[i].name[0] == '.') //skip section + if(issect(&obj->pesym[i])) continue; if(obj->pesym[i].sectnum > 0) { sect = &obj->sect[obj->pesym[i].sectnum-1]; @@ -430,6 +431,12 @@ map(PeObj *obj, PeSect *sect) return 0; } +static int +issect(PeSym *s) +{ + return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.'; +} + static int readsym(PeObj *obj, int i, PeSym **y) { @@ -445,7 +452,7 @@ readsym(PeObj *obj, int i, PeSym **y) sym = &obj->pesym[i]; *y = sym; - if(sym->name[0] == '.') // .section + if(issect(sym)) name = obj->sect[sym->sectnum-1].sym->name; else { name = sym->name; From 7c74850d764665aedcef8831cf028bea93f35178 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 12 Oct 2014 11:41:55 -0700 Subject: [PATCH 349/430] go1.4: add note about change to bufio.SplitFunc at EOF CC=golang-codereviews https://golang.org/cl/159800044 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 6d5f845789..833d331cb0 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -20,6 +20,7 @@ cmd/go: compile and link all _test.go files during 'go test', even in packages w cmd/go: (via go/build): a GOOS prefix acts as a tag only if preceded by an underscore. this is a breaking change. (CL 147690043) asm: make textflag.h available outside of cmd/ld (CL 128050043) +bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) crypto/tls: support programmatic selection of server certificates (CL 107400043) fmt: print type *map[T]T as &map[k:v] (CL 154870043) From 3cf9acccae4686ebb1dbaece4056eca58b8392b2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 13 Oct 2014 10:01:34 -0700 Subject: [PATCH 350/430] reflect: generated unrolled GC bitmask directly The code for a generated type is already generating an unrolled GC bitmask. Rather than unrolling the the source type bitmasks and copying them, just generate the required bitmask directly. Don't mark it as an unrolled GC program, since there is no need to do so. Fixes #8917. LGTM=rsc R=dvyukov, rsc CC=golang-codereviews https://golang.org/cl/156930044 --- src/reflect/all_test.go | 6 +++++ src/reflect/type.go | 56 +++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index f0cd6a4128..6bdc9be9dd 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4018,3 +4018,9 @@ func TestInvalid(t *testing.T) { t.Errorf("field elem: IsValid=%v, Kind=%v, want false, Invalid", v.IsValid(), v.Kind()) } } + +// Issue 8917. +func TestLargeGCProg(t *testing.T) { + fv := ValueOf(func([256]*byte) {}) + fv.Call([]Value{ValueOf([256]*byte{})}) +} diff --git a/src/reflect/type.go b/src/reflect/type.go index a36c0ba604..821b60412e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1514,20 +1514,36 @@ func (gc *gcProg) appendProg(t *rtype) { gc.size += t.size return } - nptr := t.size / unsafe.Sizeof(uintptr(0)) - var prog []byte - if t.kind&kindGCProg != 0 { - // Ensure that the runtime has unrolled GC program. - // TODO(rsc): Do not allocate. - unsafe_New(t) - // The program is stored in t.gc[0], skip unroll flag. - prog = (*[1 << 30]byte)(unsafe.Pointer(t.gc[0]))[1:] - } else { - // The mask is linked directly in t.gc. - prog = (*[2 * ptrSize]byte)(unsafe.Pointer(t.gc[0]))[:] - } - for i := uintptr(0); i < nptr; i++ { - gc.appendWord(extractGCWord(prog, i)) + switch t.Kind() { + default: + panic("reflect: non-pointer type marked as having pointers") + case Ptr, UnsafePointer, Chan, Func, Map: + gc.appendWord(bitsPointer) + case Slice: + gc.appendWord(bitsPointer) + gc.appendWord(bitsScalar) + gc.appendWord(bitsScalar) + case String: + gc.appendWord(bitsPointer) + gc.appendWord(bitsScalar) + case Array: + c := t.Len() + e := t.Elem().common() + for i := 0; i < c; i++ { + gc.appendProg(e) + } + case Interface: + gc.appendWord(bitsMultiWord) + if t.NumMethod() == 0 { + gc.appendWord(bitsEface) + } else { + gc.appendWord(bitsIface) + } + case Struct: + c := t.NumField() + for i := 0; i < c; i++ { + gc.appendProg(t.Field(i).Type.common()) + } } } @@ -1562,7 +1578,6 @@ func (gc *gcProg) finalize() unsafe.Pointer { gc.appendWord(extractGCWord(gc.gc, i)) } } - gc.gc = append([]byte{1}, gc.gc...) // prepend unroll flag return unsafe.Pointer(&gc.gc[0]) } @@ -1574,9 +1589,14 @@ func (gc *gcProg) align(a uintptr) { gc.size = align(gc.size, a) } +// These constants must stay in sync with ../runtime/mgc0.h. const ( - bitsScalar = 1 - bitsPointer = 2 + bitsScalar = 1 + bitsPointer = 2 + bitsMultiWord = 3 + + bitsIface = 2 + bitsEface = 3 ) // Make sure these routines stay in sync with ../../runtime/hashmap.go! @@ -1619,7 +1639,6 @@ func bucketOf(ktyp, etyp *rtype) *rtype { b := new(rtype) b.size = gc.size b.gc[0] = gc.finalize() - b.kind |= kindGCProg s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" b.string = &s return b @@ -1821,7 +1840,6 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin x := new(rtype) x.size = gc.size x.gc[0] = gc.finalize() - x.kind |= kindGCProg var s string if rcvr != nil { s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")" From 968153d0632ad138440780d6041cc5a5b50a1fa3 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 13 Oct 2014 10:27:51 -0700 Subject: [PATCH 351/430] net/rpc: fix mutex comment Fixes #8086. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/153420044 --- src/net/rpc/client.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/net/rpc/client.go b/src/net/rpc/client.go index 21f79b0684..d0c4a69214 100644 --- a/src/net/rpc/client.go +++ b/src/net/rpc/client.go @@ -41,10 +41,10 @@ type Call struct { type Client struct { codec ClientCodec - sending sync.Mutex + reqMutex sync.Mutex // protects following + request Request mutex sync.Mutex // protects following - request Request seq uint64 pending map[uint64]*Call closing bool // user has called Close @@ -69,8 +69,8 @@ type ClientCodec interface { } func (client *Client) send(call *Call) { - client.sending.Lock() - defer client.sending.Unlock() + client.reqMutex.Lock() + defer client.reqMutex.Unlock() // Register this call. client.mutex.Lock() @@ -146,7 +146,7 @@ func (client *Client) input() { } } // Terminate pending calls. - client.sending.Lock() + client.reqMutex.Lock() client.mutex.Lock() client.shutdown = true closing := client.closing @@ -162,7 +162,7 @@ func (client *Client) input() { call.done() } client.mutex.Unlock() - client.sending.Unlock() + client.reqMutex.Unlock() if debugLog && err != io.EOF && !closing { log.Println("rpc: client protocol error:", err) } From b9fc8d8cbde61d18997886602e975ff04f2547e1 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 13 Oct 2014 20:39:46 +0200 Subject: [PATCH 352/430] os: handle 'no parent' error as IsNotExist on Plan 9 This error is returned by lib9p when removing a file without parent. It should fix TestRemoveAllRace when running on ramfs. LGTM=bradfitz, aram R=rsc, bradfitz, aram CC=golang-codereviews, mischief https://golang.org/cl/153410044 --- src/os/error_plan9.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/os/error_plan9.go b/src/os/error_plan9.go index 45cd747923..001cdfcf2e 100644 --- a/src/os/error_plan9.go +++ b/src/os/error_plan9.go @@ -25,7 +25,8 @@ func isNotExist(err error) bool { case *LinkError: err = pe.Err } - return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || contains(err.Error(), "has been removed") + return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || + contains(err.Error(), "has been removed") || contains(err.Error(), "no parent") } func isPermission(err error) bool { From d83e43ccc6bd453cb1c85b83e37560c7bc420963 Mon Sep 17 00:00:00 2001 From: Chris Manghane Date: Mon, 13 Oct 2014 12:33:45 -0700 Subject: [PATCH 353/430] test: add test for gccgo-specific issue 8079 LGTM=gri R=gri CC=golang-codereviews, iant https://golang.org/cl/159850044 --- test/fixedbugs/issue8079.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 test/fixedbugs/issue8079.go diff --git a/test/fixedbugs/issue8079.go b/test/fixedbugs/issue8079.go new file mode 100644 index 0000000000..994999bf6f --- /dev/null +++ b/test/fixedbugs/issue8079.go @@ -0,0 +1,11 @@ +// compile + +// 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. + +// Issue 8079: gccgo crashes when compiling interface with blank type name. + +package p + +type _ interface{} From 73711533210a3ddc85e092eb06c1373277b65e99 Mon Sep 17 00:00:00 2001 From: Casey Marshall Date: Mon, 13 Oct 2014 12:41:14 -0700 Subject: [PATCH 354/430] math/big: Fixes issue 8920 (*Rat).SetString checks for denominator. LGTM=gri R=golang-codereviews, gri CC=golang-codereviews https://golang.org/cl/159760043 --- src/math/big/rat.go | 3 +++ src/math/big/rat_test.go | 1 + 2 files changed, 4 insertions(+) diff --git a/src/math/big/rat.go b/src/math/big/rat.go index 0bcec30252..c5339fe443 100644 --- a/src/math/big/rat.go +++ b/src/math/big/rat.go @@ -552,6 +552,9 @@ func (z *Rat) SetString(s string) (*Rat, bool) { if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil { return nil, false } + if len(z.b.abs) == 0 { + return nil, false + } return z.norm(), true } diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go index 598eac8cc7..5dbbb3510f 100644 --- a/src/math/big/rat_test.go +++ b/src/math/big/rat_test.go @@ -89,6 +89,7 @@ var setStringTests = []struct { {"53/70893980658822810696", "53/70893980658822810696", true}, {"106/141787961317645621392", "53/70893980658822810696", true}, {"204211327800791583.81095", "4084226556015831676219/20000", true}, + {in: "1/0", ok: false}, } func TestRatSetString(t *testing.T) { From 64bed3f55fdf3628e0bfe75079a8f5f845aa7bb2 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Mon, 13 Oct 2014 18:35:53 -0700 Subject: [PATCH 355/430] crypto/x509: continue to recognise MaxPathLen of zero as "no value". In [1] the behaviour of encoding/asn1 with respect to marshaling optional integers was changed. Previously, a zero valued integer would be omitted when marshaling. After the change, if a default value was set then the integer would only be omitted if it was the default value. This changed the behaviour of crypto/x509 because Certificate.MaxPathLen has a default value of -1 and thus zero valued MaxPathLens would no longer be omitted when marshaling. This is arguably a bug-fix -- a value of zero for MaxPathLen is valid and meaningful and now could be expressed. However it broke users (including Docker) who were not setting MaxPathLen at all. This change again causes a zero-valued MaxPathLen to be omitted and introduces a ZeroMathPathLen member that indicates that, yes, one really does want a zero. This is ugly, but we value not breaking users. [1] https://code.google.com/p/go/source/detail?r=4218b3544610e8d9771b89126553177e32687adf LGTM=rsc R=rsc CC=golang-codereviews, golang-dev https://golang.org/cl/153420045 --- src/crypto/x509/x509.go | 15 ++++++++- src/crypto/x509/x509_test.go | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 6e57e913ac..69a62e57d2 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -494,6 +494,11 @@ type Certificate struct { BasicConstraintsValid bool // if true then the next two fields are valid. IsCA bool MaxPathLen int + // MaxPathLenZero indicates that BasicConstraintsValid==true and + // MaxPathLen==0 should be interpreted as an actual maximum path length + // of zero. Otherwise, that combination is interpreted as MaxPathLen + // not being set. + MaxPathLenZero bool SubjectKeyId []byte AuthorityKeyId []byte @@ -913,6 +918,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.BasicConstraintsValid = true out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen + out.MaxPathLenZero = out.MaxPathLen == 0 continue } case 17: @@ -1227,8 +1233,15 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { } if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) { + // Leaving MaxPathLen as zero indicates that no maximum path + // length is desired, unless MaxPathLenZero is set. A value of + // -1 causes encoding/asn1 to omit the value as desired. + maxPathLen := template.MaxPathLen + if maxPathLen == 0 && !template.MaxPathLenZero { + maxPathLen = -1 + } ret[n].Id = oidExtensionBasicConstraints - ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen}) + ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen}) ret[n].Critical = true if err != nil { return diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index abe86216f9..4f5173fb5d 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -953,6 +953,69 @@ func TestParseCertificateRequest(t *testing.T) { } } +func TestMaxPathLen(t *testing.T) { + block, _ := pem.Decode([]byte(pemPrivateKey)) + rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + t.Fatalf("Failed to parse private key: %s", err) + } + + template := &Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "Σ Acme Co", + }, + NotBefore: time.Unix(1000, 0), + NotAfter: time.Unix(100000, 0), + + BasicConstraintsValid: true, + IsCA: true, + } + + serialiseAndParse := func(template *Certificate) *Certificate { + derBytes, err := CreateCertificate(rand.Reader, template, template, &rsaPriv.PublicKey, rsaPriv) + if err != nil { + t.Fatalf("failed to create certificate: %s", err) + return nil + } + + cert, err := ParseCertificate(derBytes) + if err != nil { + t.Fatalf("failed to parse certificate: %s", err) + return nil + } + + return cert + } + + cert1 := serialiseAndParse(template) + if m := cert1.MaxPathLen; m != -1 { + t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m) + } + if cert1.MaxPathLenZero { + t.Errorf("Omitting MaxPathLen resulted in MaxPathLenZero") + } + + template.MaxPathLen = 1 + cert2 := serialiseAndParse(template) + if m := cert2.MaxPathLen; m != 1 { + t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m) + } + if cert2.MaxPathLenZero { + t.Errorf("Setting MaxPathLen resulted in MaxPathLenZero") + } + + template.MaxPathLen = 0 + template.MaxPathLenZero = true + cert3 := serialiseAndParse(template) + if m := cert3.MaxPathLen; m != 0 { + t.Errorf("Setting MaxPathLenZero didn't work, got %d", m) + } + if !cert3.MaxPathLenZero { + t.Errorf("Setting MaxPathLen to zero didn't result in MaxPathLenZero") + } +} + // This CSR was generated with OpenSSL: // openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf // From 9dc6764d3c780cf302a8a7521d27e61102d701fc Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 14 Oct 2014 09:22:47 -0700 Subject: [PATCH 356/430] runtime: a few optimizations of scanblock. Lowers gc pause time by 5-10% on test/bench/garbage LGTM=rsc, dvyukov R=rsc, dvyukov CC=golang-codereviews https://golang.org/cl/157810043 --- src/runtime/mgc0.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 0de7b1bf4a..05cabe7085 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -215,8 +215,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) for(i = 0; i < nelem(scanbuf); i++) { b = scanbuf[scanbufpos]; scanbuf[scanbufpos++] = nil; - if(scanbufpos == nelem(scanbuf)) - scanbufpos = 0; + scanbufpos %= nelem(scanbuf); if(b != nil) { n = arena_used - b; // scan until bitBoundary or BitsDead ptrmask = nil; // use GC bitmap for pointer info @@ -267,10 +266,13 @@ scanblock(byte *b, uintptr n, byte *ptrmask) break; // Consult GC bitmap. bits = *ptrbitp; - if((((uintptr)b+i)%(PtrSize*wordsPerBitmapByte)) != 0) { - ptrbitp--; - bits >>= gcBits; - } + + if(wordsPerBitmapByte != 2) + runtime·throw("alg doesn't work for wordsPerBitmapByte != 2"); + j = ((uintptr)b+i)/PtrSize & 1; + ptrbitp -= j; + bits >>= gcBits*j; + if((bits&bitBoundary) != 0 && i != 0) break; // reached beginning of the next object bits = (bits>>2)&BitsMask; @@ -293,10 +295,9 @@ scanblock(byte *b, uintptr n, byte *ptrmask) // Find the next pair of bits. if(ptrmask == nil) { bits = *ptrbitp; - if((((uintptr)b+i)%(PtrSize*wordsPerBitmapByte)) == 0) { - ptrbitp--; - bits >>= gcBits; - } + j = ((uintptr)b+i+PtrSize)/PtrSize & 1; + ptrbitp -= j; + bits >>= gcBits*j; bits = (bits>>2)&BitsMask; } else bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask; @@ -328,12 +329,13 @@ scanblock(byte *b, uintptr n, byte *ptrmask) // Check if it points into heap. if(obj == nil) continue; - if((uintptr)obj < PhysPageSize) { - s = nil; - goto badobj; - } - if(obj < arena_start || obj >= arena_used) + if(obj < arena_start || obj >= arena_used) { + if((uintptr)obj < PhysPageSize) { + s = nil; + goto badobj; + } continue; + } // Mark the object. obj = (byte*)((uintptr)obj & ~(PtrSize-1)); off = (uintptr*)obj - (uintptr*)arena_start; @@ -442,8 +444,7 @@ scanblock(byte *b, uintptr n, byte *ptrmask) PREFETCH(obj); p = scanbuf[scanbufpos]; scanbuf[scanbufpos++] = obj; - if(scanbufpos == nelem(scanbuf)) - scanbufpos = 0; + scanbufpos %= nelem(scanbuf); if(p == nil) continue; From 3511454e1307e1919fe6e0ce12262c147d189f98 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Oct 2014 14:58:25 -0400 Subject: [PATCH 357/430] cmd/gc: fix 'make' in cmd/gc directory Right now, go tool 6g -A fails complaining about 'any' type. TBR=r CC=golang-codereviews https://golang.org/cl/156200044 --- src/cmd/gc/pgen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 50c03788e8..39028e3f88 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -182,6 +182,8 @@ compile(Node *fn) yyerror("missing function body", fn); goto ret; } + if(debug['A']) + goto ret; emitptrargsmap(); goto ret; } From a3416cf5cd06857c16fd2d1e665955f0b05248dd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Oct 2014 16:31:09 -0400 Subject: [PATCH 358/430] cmd/gc: add 2-, 3-, 4-word write barrier specializations Assignments of 2-, 3-, and 4-word values were handled by individual MOV instructions (and for scalars still are). But if there are pointers involved, those assignments now go through the write barrier routine. Before this CL, they went to writebarrierfat, which calls memmove. Memmove is too much overhead for these small amounts of data. Instead, call writebarrierfat{2,3,4}, which are specialized for the specific amount of data being copied. Today the write barrier does not care which words are pointers, so size alone is enough to distinguish the cases. If we keep these distinctions in Go 1.5 we will need to expand them for all the pointer-vs-scalar possibilities, so the current 3 functions will become 3+7+15 = 25, still not a large burden (we deleted more morestack functions than that when we dropped segmented stacks). BenchmarkBinaryTree17 3250972583 3123910344 -3.91% BenchmarkFannkuch11 3067605223 2964737839 -3.35% BenchmarkFmtFprintfEmpty 101 96.0 -4.95% BenchmarkFmtFprintfString 267 235 -11.99% BenchmarkFmtFprintfInt 261 253 -3.07% BenchmarkFmtFprintfIntInt 444 402 -9.46% BenchmarkFmtFprintfPrefixedInt 374 346 -7.49% BenchmarkFmtFprintfFloat 472 449 -4.87% BenchmarkFmtManyArgs 1537 1476 -3.97% BenchmarkGobDecode 13986528 12432985 -11.11% BenchmarkGobEncode 13120323 12537420 -4.44% BenchmarkGzip 451925758 437500578 -3.19% BenchmarkGunzip 113267612 110053644 -2.84% BenchmarkHTTPClientServer 103151 77100 -25.26% BenchmarkJSONEncode 25002733 23435278 -6.27% BenchmarkJSONDecode 94213717 82568789 -12.36% BenchmarkMandelbrot200 4804246 4713070 -1.90% BenchmarkGoParse 4646114 4379456 -5.74% BenchmarkRegexpMatchEasy0_32 163 158 -3.07% BenchmarkRegexpMatchEasy0_1K 433 391 -9.70% BenchmarkRegexpMatchEasy1_32 154 138 -10.39% BenchmarkRegexpMatchEasy1_1K 1481 1132 -23.57% BenchmarkRegexpMatchMedium_32 282 270 -4.26% BenchmarkRegexpMatchMedium_1K 92421 86149 -6.79% BenchmarkRegexpMatchHard_32 5209 4718 -9.43% BenchmarkRegexpMatchHard_1K 158141 147921 -6.46% BenchmarkRevcomp 699818791 642222464 -8.23% BenchmarkTemplate 132402383 108269713 -18.23% BenchmarkTimeParse 509 478 -6.09% BenchmarkTimeFormat 462 456 -1.30% LGTM=r R=r CC=golang-codereviews https://golang.org/cl/156200043 --- src/cmd/gc/builtin.c | 5 ++++- src/cmd/gc/runtime.go | 3 +++ src/cmd/gc/walk.c | 32 ++++++++++++++++++++++---------- src/runtime/mgc0.go | 21 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index ee1ac1da42..17f80ebba4 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -84,9 +84,12 @@ char *runtimeimport = "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" "func @\"\".closechan (@\"\".hchan·1 any)\n" "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, @\"\".src·2 any)\n" "func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index fa927a58ac..6ee5e2e364 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -112,6 +112,9 @@ func writebarrierptr(dst *any, src any) func writebarrierstring(dst *any, src any) func writebarrierslice(dst *any, src any) func writebarrieriface(dst *any, src any) +func writebarrierfat2(dst *any, src any) +func writebarrierfat3(dst *any, src any) +func writebarrierfat4(dst *any, src any) func writebarrierfat(typ *byte, dst *any, src *any) func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 713348c0c0..5b5385d50c 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2040,21 +2040,32 @@ static Node* applywritebarrier(Node *n, NodeList **init) { Node *l, *r; + Type *t; if(n->left && n->right && needwritebarrier(n->left, n->right)) { + t = n->left->type; l = nod(OADDR, n->left, N); l->etype = 1; // addr does not escape - if(n->left->type->width == widthptr) { - n = mkcall1(writebarrierfn("writebarrierptr", n->left->type, n->right->type), T, init, + if(t->width == widthptr) { + n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init, l, n->right); - } else if(n->left->type->etype == TSTRING) { - n = mkcall1(writebarrierfn("writebarrierstring", n->left->type, n->right->type), T, init, + } else if(t->etype == TSTRING) { + n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init, l, n->right); - } else if(isslice(n->left->type)) { - n = mkcall1(writebarrierfn("writebarrierslice", n->left->type, n->right->type), T, init, + } else if(isslice(t)) { + n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init, l, n->right); - } else if(isinter(n->left->type)) { - n = mkcall1(writebarrierfn("writebarrieriface", n->left->type, n->right->type), T, init, + } else if(isinter(t)) { + n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init, + l, n->right); + } else if(t->width == 2*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init, + l, n->right); + } else if(t->width == 3*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init, + l, n->right); + } else if(t->width == 4*widthptr) { + n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init, l, n->right); } else { r = n->right; @@ -2062,8 +2073,9 @@ applywritebarrier(Node *n, NodeList **init) r = r->left; r = nod(OADDR, r, N); r->etype = 1; // addr does not escape - n = mkcall1(writebarrierfn("writebarrierfat", n->left->type, r->left->type), T, init, - typename(n->left->type), l, r); + //warnl(n->lineno, "writebarrierfat %T %N", t, r); + n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init, + typename(t), l, r); } } return n; diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 0e17599c2a..3152b1fe1a 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -109,6 +109,27 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) { dst[1] = src[1] } +//go:nosplit +func writebarrierfat2(dst *[2]uintptr, src [2]uintptr) { + dst[0] = src[0] + dst[1] = src[1] +} + +//go:nosplit +func writebarrierfat3(dst *[3]uintptr, src [3]uintptr) { + dst[0] = src[0] + dst[1] = src[1] + dst[2] = src[2] +} + +//go:nosplit +func writebarrierfat4(dst *[4]uintptr, src [4]uintptr) { + dst[0] = src[0] + dst[1] = src[1] + dst[2] = src[2] + dst[3] = src[3] +} + //go:nosplit func writebarrierfat(typ *_type, dst, src unsafe.Pointer) { memmove(dst, src, typ.size) From 96d1e4ab5938d263457a9c18fdf6fdf0581c6ec6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 14 Oct 2014 14:09:56 -0700 Subject: [PATCH 359/430] math/big: Allow non-prime modulus for ModInverse The inverse is defined whenever the element and the modulus are relatively prime. The code already handles this situation, but the spec does not. Test that it does indeed work. Fixes #8875 LGTM=agl R=agl CC=golang-codereviews https://golang.org/cl/155010043 --- src/math/big/int.go | 15 ++++++++------- src/math/big/int_test.go | 36 ++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/math/big/int.go b/src/math/big/int.go index fc53719d71..d22e39e7c9 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -752,15 +752,16 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int { return z } -// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where -// p is a prime) and returns z. -func (z *Int) ModInverse(g, p *Int) *Int { +// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ +// and returns z. If g and n are not relatively prime, the result is undefined. +func (z *Int) ModInverse(g, n *Int) *Int { var d Int - d.GCD(z, nil, g, p) - // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking - // that modulo p results in g*x = 1, therefore x is the inverse element. + d.GCD(z, nil, g, n) + // x and y are such that g*x + n*y = d. Since g and n are + // relatively prime, d = 1. Taking that modulo n results in + // g*x = 1, therefore x is the inverse element. if z.neg { - z.Add(z, p) + z.Add(z, n) } return z } diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go index ec05fbb1c0..6070cf325d 100644 --- a/src/math/big/int_test.go +++ b/src/math/big/int_test.go @@ -1448,24 +1448,40 @@ func TestNot(t *testing.T) { var modInverseTests = []struct { element string - prime string + modulus string }{ - {"1", "7"}, - {"1", "13"}, + {"1234567", "458948883992"}, {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"}, } func TestModInverse(t *testing.T) { - var element, prime Int + var element, modulus, gcd, inverse Int one := NewInt(1) for i, test := range modInverseTests { (&element).SetString(test.element, 10) - (&prime).SetString(test.prime, 10) - inverse := new(Int).ModInverse(&element, &prime) - inverse.Mul(inverse, &element) - inverse.Mod(inverse, &prime) - if inverse.Cmp(one) != 0 { - t.Errorf("#%d: failed (e·e^(-1)=%s)", i, inverse) + (&modulus).SetString(test.modulus, 10) + (&inverse).ModInverse(&element, &modulus) + (&inverse).Mul(&inverse, &element) + (&inverse).Mod(&inverse, &modulus) + if (&inverse).Cmp(one) != 0 { + t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse) + } + } + // exhaustive test for small values + for n := 2; n < 100; n++ { + (&modulus).SetInt64(int64(n)) + for x := 1; x < n; x++ { + (&element).SetInt64(int64(x)) + (&gcd).GCD(nil, nil, &element, &modulus) + if (&gcd).Cmp(one) != 0 { + continue + } + (&inverse).ModInverse(&element, &modulus) + (&inverse).Mul(&inverse, &element) + (&inverse).Mod(&inverse, &modulus) + if (&inverse).Cmp(one) != 0 { + t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse) + } } } } From e9ecd4aec51f06cb0834fe3bbd8c4b88d5fd94b5 Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Wed, 15 Oct 2014 11:11:11 +1100 Subject: [PATCH 360/430] runtime: handle all windows exception (second attempt) includes undo of 22318cd31d7d and also: - always use SetUnhandledExceptionFilter on windows-386; - crash when receive EXCEPTION_BREAKPOINT in exception handler. Fixes #8006. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/155360043 --- src/runtime/defs_windows.go | 4 ++ src/runtime/defs_windows_386.h | 4 ++ src/runtime/defs_windows_amd64.h | 4 ++ src/runtime/os_windows.c | 38 ++++++++++-- src/runtime/os_windows_386.c | 80 +++++++++++++++---------- src/runtime/os_windows_amd64.c | 93 +++++++++++++++++++---------- src/runtime/sys_windows_386.s | 18 +++++- src/runtime/sys_windows_amd64.s | 18 +++++- src/runtime/syscall_windows_test.go | 39 ++++++++++++ 9 files changed, 226 insertions(+), 72 deletions(-) diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go index cb0f54d8ab..7ce6797414 100644 --- a/src/runtime/defs_windows.go +++ b/src/runtime/defs_windows.go @@ -49,6 +49,7 @@ const ( CONTEXT_FULL = C.CONTEXT_FULL EXCEPTION_ACCESS_VIOLATION = C.STATUS_ACCESS_VIOLATION + EXCEPTION_BREAKPOINT = C.STATUS_BREAKPOINT EXCEPTION_FLT_DENORMAL_OPERAND = C.STATUS_FLOAT_DENORMAL_OPERAND EXCEPTION_FLT_DIVIDE_BY_ZERO = C.STATUS_FLOAT_DIVIDE_BY_ZERO EXCEPTION_FLT_INEXACT_RESULT = C.STATUS_FLOAT_INEXACT_RESULT @@ -59,6 +60,9 @@ const ( INFINITE = C.INFINITE WAIT_TIMEOUT = C.WAIT_TIMEOUT + + EXCEPTION_CONTINUE_EXECUTION = C.EXCEPTION_CONTINUE_EXECUTION + EXCEPTION_CONTINUE_SEARCH = C.EXCEPTION_CONTINUE_SEARCH ) type SystemInfo C.SYSTEM_INFO diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h index 295e422c6b..2317c04f65 100644 --- a/src/runtime/defs_windows_386.h +++ b/src/runtime/defs_windows_386.h @@ -22,6 +22,7 @@ enum { CONTEXT_FULL = 0x10007, EXCEPTION_ACCESS_VIOLATION = 0xc0000005, + EXCEPTION_BREAKPOINT = 0x80000003, EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d, EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e, EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f, @@ -32,6 +33,9 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, + + EXCEPTION_CONTINUE_EXECUTION = -0x1, + EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h index 2516c84128..7f37a7a8c3 100644 --- a/src/runtime/defs_windows_amd64.h +++ b/src/runtime/defs_windows_amd64.h @@ -22,6 +22,7 @@ enum { CONTEXT_FULL = 0x10000b, EXCEPTION_ACCESS_VIOLATION = 0xc0000005, + EXCEPTION_BREAKPOINT = 0x80000003, EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d, EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e, EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f, @@ -32,6 +33,9 @@ enum { INFINITE = 0xffffffff, WAIT_TIMEOUT = 0x102, + + EXCEPTION_CONTINUE_EXECUTION = -0x1, + EXCEPTION_CONTINUE_SEARCH = 0x0, }; typedef struct SystemInfo SystemInfo; diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c index 6337dde2af..b8b8eda5f3 100644 --- a/src/runtime/os_windows.c +++ b/src/runtime/os_windows.c @@ -34,6 +34,7 @@ #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" #pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll" #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll" +#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll" #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll" #pragma dynimport runtime·Sleep Sleep "kernel32.dll" #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll" @@ -65,6 +66,7 @@ extern void *runtime·SetConsoleCtrlHandler; extern void *runtime·SetEvent; extern void *runtime·SetProcessPriorityBoost; extern void *runtime·SetThreadPriority; +extern void *runtime·SetUnhandledExceptionFilter; extern void *runtime·SetWaitableTimer; extern void *runtime·Sleep; extern void *runtime·SuspendThread; @@ -77,7 +79,9 @@ void *runtime·GetQueuedCompletionStatusEx; extern uintptr runtime·externalthreadhandlerp; void runtime·externalthreadhandler(void); -void runtime·sigtramp(void); +void runtime·exceptiontramp(void); +void runtime·firstcontinuetramp(void); +void runtime·lastcontinuetramp(void); #pragma textflag NOSPLIT uintptr @@ -106,12 +110,30 @@ void runtime·osinit(void) { void *kernel32; + void *addVectoredContinueHandler; + + kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler; - runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·sigtramp); + runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp); + addVectoredContinueHandler = nil; + if(kernel32 != nil) + addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler"); + if(addVectoredContinueHandler == nil || sizeof(void*) == 4) { + // use SetUnhandledExceptionFilter for windows-386 or + // if VectoredContinueHandler is unavailable. + // note: SetUnhandledExceptionFilter handler won't be called, if debugging. + runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp); + } else { + runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp); + runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp); + } + runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1); + runtime·stdcall1(runtime·timeBeginPeriod, 1); + runtime·ncpu = getproccount(); // Windows dynamic priority boosting assumes that a process has different types @@ -120,7 +142,6 @@ runtime·osinit(void) // In such context dynamic priority boosting does nothing but harm, so we turn it off. runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1); - kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll"); if(kernel32 != nil) { runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx"); } @@ -467,6 +488,7 @@ runtime·issigpanic(uint32 code) case EXCEPTION_FLT_INEXACT_RESULT: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_BREAKPOINT: return 1; } return 0; @@ -475,10 +497,14 @@ runtime·issigpanic(uint32 code) void runtime·initsig(void) { - // following line keeps sigtramp alive at link stage + // following line keeps these functions alive at link stage // if there's a better way please write it here - void *p = runtime·sigtramp; - USED(p); + void *e = runtime·exceptiontramp; + void *f = runtime·firstcontinuetramp; + void *l = runtime·lastcontinuetramp; + USED(e); + USED(f); + USED(l); } uint32 diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c index e2ae8db277..213582799b 100644 --- a/src/runtime/os_windows_386.c +++ b/src/runtime/os_windows_386.c @@ -24,45 +24,63 @@ runtime·dumpregs(Context *r) runtime·printf("gs %x\n", r->SegGs); } -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (-1) -// or should be made available to other handlers in the chain (0). -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +bool +runtime·isgoexception(ExceptionRecord *info, Context *r) { - bool crash; - uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip) - return 0; + return false; - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Eip; + if(!runtime·issigpanic(info->ExceptionCode)) + return false; - // Only push runtime·sigpanic if r->eip != 0. - // If r->eip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Eip != 0) { - sp = (uintptr*)r->Esp; - *--sp = r->Eip; - r->Esp = (uintptr)sp; - } - r->Eip = (uintptr)runtime·sigpanic; - return -1; + return true; +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +uint32 +runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Eip; + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Eip != 0) { + sp = (uintptr*)r->Esp; + *--sp = r->Eip; + r->Esp = (uintptr)sp; } + r->Eip = (uintptr)runtime·sigpanic; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +uint32 +runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -88,7 +106,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return -1; // not reached + return 0; // not reached } void diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c index 261880d450..b96cf70d1e 100644 --- a/src/runtime/os_windows_amd64.c +++ b/src/runtime/os_windows_amd64.c @@ -32,45 +32,76 @@ runtime·dumpregs(Context *r) runtime·printf("gs %X\n", (uint64)r->SegGs); } -// Called by sigtramp from Windows VEH handler. -// Return value signals whether the exception has been handled (-1) -// or should be made available to other handlers in the chain (0). -uint32 -runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) +bool +runtime·isgoexception(ExceptionRecord *info, Context *r) { - bool crash; - uintptr *sp; extern byte runtime·text[], runtime·etext[]; // Only handle exception if executing instructions in Go binary // (not Windows library code). if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip) - return 0; + return false; - if(gp != nil && runtime·issigpanic(info->ExceptionCode)) { - // Make it look like a call to the signal func. - // Have to pass arguments out of band since - // augmenting the stack frame would break - // the unwinding code. - gp->sig = info->ExceptionCode; - gp->sigcode0 = info->ExceptionInformation[0]; - gp->sigcode1 = info->ExceptionInformation[1]; - gp->sigpc = r->Rip; + if(!runtime·issigpanic(info->ExceptionCode)) + return false; - // Only push runtime·sigpanic if r->rip != 0. - // If r->rip == 0, probably panicked because of a - // call to a nil func. Not pushing that onto sp will - // make the trace look like a call to runtime·sigpanic instead. - // (Otherwise the trace will end at runtime·sigpanic and we - // won't get to see who faulted.) - if(r->Rip != 0) { - sp = (uintptr*)r->Rsp; - *--sp = r->Rip; - r->Rsp = (uintptr)sp; - } - r->Rip = (uintptr)runtime·sigpanic; - return -1; + return true; +} + +// Called by sigtramp from Windows VEH handler. +// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION) +// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH). +uint32 +runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp) +{ + uintptr *sp; + + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Rip; + + // Only push runtime·sigpanic if r->rip != 0. + // If r->rip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Rip != 0) { + sp = (uintptr*)r->Rsp; + *--sp = r->Rip; + r->Rsp = (uintptr)sp; } + r->Rip = (uintptr)runtime·sigpanic; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// It seems Windows searches ContinueHandler's list even +// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION. +// firstcontinuehandler will stop that search, +// if exceptionhandler did the same earlier. +uint32 +runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + USED(gp); + if(!runtime·isgoexception(info, r)) + return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_CONTINUE_EXECUTION; +} + +// lastcontinuehandler is reached, because runtime cannot handle +// current exception. lastcontinuehandler will print crash info and exit. +uint32 +runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp) +{ + bool crash; if(runtime·panicking) // traceback already printed runtime·exit(2); @@ -97,7 +128,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp) runtime·crash(); runtime·exit(2); - return -1; // not reached + return 0; // not reached } void diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s index 1bf4d062ac..932fe9dd24 100644 --- a/src/runtime/sys_windows_386.s +++ b/src/runtime/sys_windows_386.s @@ -73,6 +73,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. +// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL ptrs+0(FP), CX @@ -84,6 +85,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVL SI, 20(SP) MOVL DI, 24(SP) + MOVL AX, SI // save handler address + // find g get_tls(DX) CMPL DX, $0 @@ -123,11 +126,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVL 0(CX), BX // ExceptionRecord* MOVL 4(CX), CX // Context* - // call sighandler(ExceptionRecord*, Context*, G*) MOVL BX, 0(SP) MOVL CX, 4(SP) MOVL DX, 8(SP) - CALL runtime·sighandler(SB) + CALL SI // call handler // AX is set to report result back to Windows MOVL 12(SP), AX @@ -149,6 +151,18 @@ done: // RET 4 (return and pop 4 bytes parameters) BYTE $0xC2; WORD $4 RET // unreached; make assembler happy + +TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 + MOVL $runtime·exceptionhandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 + // is never called + INT $3 + +TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 + MOVL $runtime·lastcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) TEXT runtime·ctrlhandler(SB),NOSPLIT,$0 PUSHL $runtime·ctrlhandler1(SB) diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 05750398ea..e6190ce684 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -99,6 +99,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0 // Called by Windows as a Vectored Exception Handler (VEH). // First argument is pointer to struct containing // exception record and context pointers. +// Handler function is stored in AX. // Return 0 for 'not handled', -1 for handled. TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 // CX: PEXCEPTION_POINTERS ExceptionInfo @@ -116,6 +117,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 MOVQ R14, 32(SP) MOVQ R15, 88(SP) + MOVQ AX, R15 // save handler address + // find g get_tls(DX) CMPQ DX, $0 @@ -157,11 +160,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0 sigtramp_g0: MOVQ 0(CX), BX // ExceptionRecord* MOVQ 8(CX), CX // Context* - // call sighandler(ExceptionRecord*, Context*, G*) MOVQ BX, 0(SP) MOVQ CX, 8(SP) MOVQ DX, 16(SP) - CALL runtime·sighandler(SB) + CALL R15 // call handler // AX is set to report result back to Windows MOVL 24(SP), AX @@ -187,6 +189,18 @@ done: RET +TEXT runtime·exceptiontramp(SB),NOSPLIT,$0 + MOVQ $runtime·exceptionhandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0 + MOVQ $runtime·firstcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) + +TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0 + MOVQ $runtime·lastcontinuehandler(SB), AX + JMP runtime·sigtramp(SB) + TEXT runtime·ctrlhandler(SB),NOSPLIT,$8 MOVQ CX, 16(SP) // spill MOVQ $runtime·ctrlhandler1(SB), CX diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index 9ed016ccc8..ce8a9ec1ba 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -494,3 +494,42 @@ func TestOutputDebugString(t *testing.T) { p := syscall.StringToUTF16Ptr("testing OutputDebugString") d.Proc("OutputDebugStringW").Call(uintptr(unsafe.Pointer(p))) } + +func TestRaiseException(t *testing.T) { + o := executeTest(t, raiseExceptionSource, nil) + if strings.Contains(o, "RaiseException should not return") { + t.Fatalf("RaiseException did not crash program: %v", o) + } + if !strings.Contains(o, "Exception 0xbad") { + t.Fatalf("No stack trace: %v", o) + } +} + +const raiseExceptionSource = ` +package main +import "syscall" +func main() { + const EXCEPTION_NONCONTINUABLE = 1 + mod := syscall.MustLoadDLL("kernel32.dll") + proc := mod.MustFindProc("RaiseException") + proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0) + println("RaiseException should not return") +} +` + +func TestZeroDivisionException(t *testing.T) { + o := executeTest(t, zeroDivisionExceptionSource, nil) + if !strings.Contains(o, "panic: runtime error: integer divide by zero") { + t.Fatalf("No stack trace: %v", o) + } +} + +const zeroDivisionExceptionSource = ` +package main +func main() { + x := 1 + y := 0 + z := x / y + println(z) +} +` From fe8f799ef7b0124ff0a50f5ec590a70ad20d6ef2 Mon Sep 17 00:00:00 2001 From: Chris Manghane Date: Tue, 14 Oct 2014 19:12:10 -0700 Subject: [PATCH 361/430] cmd/gc: check for initialization cycles in method values Fixes #7960. LGTM=rsc R=rsc CC=golang-codereviews, gri https://golang.org/cl/159800045 --- src/cmd/gc/sinit.c | 2 +- test/fixedbugs/issue6703a.go | 16 ++++++++++++++++ test/fixedbugs/issue6703b.go | 16 ++++++++++++++++ test/fixedbugs/issue6703c.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703d.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703e.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703f.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703g.go | 20 ++++++++++++++++++++ test/fixedbugs/issue6703h.go | 20 ++++++++++++++++++++ test/fixedbugs/issue6703i.go | 20 ++++++++++++++++++++ test/fixedbugs/issue6703j.go | 20 ++++++++++++++++++++ test/fixedbugs/issue6703k.go | 21 +++++++++++++++++++++ test/fixedbugs/issue6703l.go | 21 +++++++++++++++++++++ test/fixedbugs/issue6703m.go | 25 +++++++++++++++++++++++++ test/fixedbugs/issue6703n.go | 25 +++++++++++++++++++++++++ test/fixedbugs/issue6703o.go | 23 +++++++++++++++++++++++ test/fixedbugs/issue6703p.go | 23 +++++++++++++++++++++++ test/fixedbugs/issue6703q.go | 28 ++++++++++++++++++++++++++++ test/fixedbugs/issue6703r.go | 28 ++++++++++++++++++++++++++++ test/fixedbugs/issue6703s.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703t.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703u.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703v.go | 18 ++++++++++++++++++ test/fixedbugs/issue6703w.go | 21 +++++++++++++++++++++ test/fixedbugs/issue6703x.go | 21 +++++++++++++++++++++ test/fixedbugs/issue6703y.go | 23 +++++++++++++++++++++++ test/fixedbugs/issue6703z.go | 23 +++++++++++++++++++++++ 27 files changed, 539 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue6703a.go create mode 100644 test/fixedbugs/issue6703b.go create mode 100644 test/fixedbugs/issue6703c.go create mode 100644 test/fixedbugs/issue6703d.go create mode 100644 test/fixedbugs/issue6703e.go create mode 100644 test/fixedbugs/issue6703f.go create mode 100644 test/fixedbugs/issue6703g.go create mode 100644 test/fixedbugs/issue6703h.go create mode 100644 test/fixedbugs/issue6703i.go create mode 100644 test/fixedbugs/issue6703j.go create mode 100644 test/fixedbugs/issue6703k.go create mode 100644 test/fixedbugs/issue6703l.go create mode 100644 test/fixedbugs/issue6703m.go create mode 100644 test/fixedbugs/issue6703n.go create mode 100644 test/fixedbugs/issue6703o.go create mode 100644 test/fixedbugs/issue6703p.go create mode 100644 test/fixedbugs/issue6703q.go create mode 100644 test/fixedbugs/issue6703r.go create mode 100644 test/fixedbugs/issue6703s.go create mode 100644 test/fixedbugs/issue6703t.go create mode 100644 test/fixedbugs/issue6703u.go create mode 100644 test/fixedbugs/issue6703v.go create mode 100644 test/fixedbugs/issue6703w.go create mode 100644 test/fixedbugs/issue6703x.go create mode 100644 test/fixedbugs/issue6703y.go create mode 100644 test/fixedbugs/issue6703z.go diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 508747e5a0..f050026d9d 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -207,7 +207,7 @@ init2(Node *n, NodeList **out) if(n->op == OCLOSURE) init2list(n->closure->nbody, out); - if(n->op == ODOTMETH) + if(n->op == ODOTMETH || n->op == OCALLPART) init2(n->type->nname, out); } diff --git a/test/fixedbugs/issue6703a.go b/test/fixedbugs/issue6703a.go new file mode 100644 index 0000000000..d4c008f836 --- /dev/null +++ b/test/fixedbugs/issue6703a.go @@ -0,0 +1,16 @@ +// errorcheck + +// 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. + +// Check for cycles in a function value. + +package funcvalue + +func fx() int { + _ = x + return 0 +} + +var x = fx // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703b.go b/test/fixedbugs/issue6703b.go new file mode 100644 index 0000000000..326b5839a7 --- /dev/null +++ b/test/fixedbugs/issue6703b.go @@ -0,0 +1,16 @@ +// errorcheck + +// 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. + +// Check for cycles in a function call. + +package funccall + +func fx() int { + _ = x + return 0 +} + +var x = fx() // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703c.go b/test/fixedbugs/issue6703c.go new file mode 100644 index 0000000000..4735764758 --- /dev/null +++ b/test/fixedbugs/issue6703c.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in a method expression. + +package methexpr + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var x = T.m // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703d.go b/test/fixedbugs/issue6703d.go new file mode 100644 index 0000000000..0a1952f78b --- /dev/null +++ b/test/fixedbugs/issue6703d.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in a method expression call. + +package methexprcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var x = T.m(0) // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703e.go b/test/fixedbugs/issue6703e.go new file mode 100644 index 0000000000..416066e858 --- /dev/null +++ b/test/fixedbugs/issue6703e.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in the method value of a value literal. + +package litmethvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var x = T(0).m // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703f.go b/test/fixedbugs/issue6703f.go new file mode 100644 index 0000000000..30238297b5 --- /dev/null +++ b/test/fixedbugs/issue6703f.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in the method call of a value literal. + +package litmethcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var x = T(0).m() // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703g.go b/test/fixedbugs/issue6703g.go new file mode 100644 index 0000000000..002b5a6368 --- /dev/null +++ b/test/fixedbugs/issue6703g.go @@ -0,0 +1,20 @@ +// errorcheck + +// 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. + +// Check for cycles in an embedded method expression. + +package embedmethexpr + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var x = E.m // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703h.go b/test/fixedbugs/issue6703h.go new file mode 100644 index 0000000000..234ccb365c --- /dev/null +++ b/test/fixedbugs/issue6703h.go @@ -0,0 +1,20 @@ +// errorcheck + +// 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. + +// Check for cycles when calling an embedded method expression. + +package embedmethexprcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var x = E.m(E{0}) // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703i.go b/test/fixedbugs/issue6703i.go new file mode 100644 index 0000000000..78b4d49804 --- /dev/null +++ b/test/fixedbugs/issue6703i.go @@ -0,0 +1,20 @@ +// errorcheck + +// 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. + +// Check for cycles in an embedded struct literal's method value. + +package embedlitmethvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var x = E{}.m // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703j.go b/test/fixedbugs/issue6703j.go new file mode 100644 index 0000000000..a7f63f7483 --- /dev/null +++ b/test/fixedbugs/issue6703j.go @@ -0,0 +1,20 @@ +// errorcheck + +// 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. + +// Check for cycles in an embedded struct literal's method call. + +package embedlitmethcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var x = E{}.m() // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703k.go b/test/fixedbugs/issue6703k.go new file mode 100644 index 0000000000..19c61078ca --- /dev/null +++ b/test/fixedbugs/issue6703k.go @@ -0,0 +1,21 @@ +// errorcheck + +// 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. + +// Check for cycles in a method value. + +package methvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var ( + t T + x = t.m // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703l.go b/test/fixedbugs/issue6703l.go new file mode 100644 index 0000000000..3f4ca31478 --- /dev/null +++ b/test/fixedbugs/issue6703l.go @@ -0,0 +1,21 @@ +// errorcheck + +// 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. + +// Check for cycles in a method call. + +package methcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +var ( + t T + x = t.m() // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703m.go b/test/fixedbugs/issue6703m.go new file mode 100644 index 0000000000..d80959cdc6 --- /dev/null +++ b/test/fixedbugs/issue6703m.go @@ -0,0 +1,25 @@ +// errorcheck + +// 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. + +// Check for cycles in the method value of a value returned from a function call. + +package funcmethvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +func f() T { + return T(0) +} + +var ( + t T + x = f().m // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703n.go b/test/fixedbugs/issue6703n.go new file mode 100644 index 0000000000..2c623f2197 --- /dev/null +++ b/test/fixedbugs/issue6703n.go @@ -0,0 +1,25 @@ +// errorcheck + +// 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. + +// Check for cycles in the method call of a value returned from a function call. + +package funcmethcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +func f() T { + return T(0) +} + +var ( + t T + x = f().m() // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703o.go b/test/fixedbugs/issue6703o.go new file mode 100644 index 0000000000..efc8947373 --- /dev/null +++ b/test/fixedbugs/issue6703o.go @@ -0,0 +1,23 @@ +// errorcheck + +// 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. + +// Check for cycles in an embedded struct's method value. + +package embedmethvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var ( + e E + x = e.m // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703p.go b/test/fixedbugs/issue6703p.go new file mode 100644 index 0000000000..dad88f6345 --- /dev/null +++ b/test/fixedbugs/issue6703p.go @@ -0,0 +1,23 @@ +// errorcheck + +// 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. + +// Check for cycles in an embedded struct's method call. + +package embedmethcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +type E struct{ T } + +var ( + e E + x = e.m() // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703q.go b/test/fixedbugs/issue6703q.go new file mode 100644 index 0000000000..7bd748aaa2 --- /dev/null +++ b/test/fixedbugs/issue6703q.go @@ -0,0 +1,28 @@ +// errorcheck + +// 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. + +// Check for cycles in the method value of an embedded struct returned +// from a function call. + +package funcembedmethvalue + +type T int + +func (T) m() int { + _ = x + return 0 +} + +func g() E { + return E{0} +} + +type E struct{ T } + +var ( + e E + x = g().m // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703r.go b/test/fixedbugs/issue6703r.go new file mode 100644 index 0000000000..6698462417 --- /dev/null +++ b/test/fixedbugs/issue6703r.go @@ -0,0 +1,28 @@ +// errorcheck + +// 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. + +// Check for cycles in the method call of an embedded struct returned +// from a function call. + +package funcembedmethcall + +type T int + +func (T) m() int { + _ = x + return 0 +} + +func g() E { + return E{0} +} + +type E struct{ T } + +var ( + e E + x = g().m() // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703s.go b/test/fixedbugs/issue6703s.go new file mode 100644 index 0000000000..6aa28483ac --- /dev/null +++ b/test/fixedbugs/issue6703s.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in a pointer method expression. + +package ptrmethexpr + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var x = (*T).pm // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703t.go b/test/fixedbugs/issue6703t.go new file mode 100644 index 0000000000..bad65ad161 --- /dev/null +++ b/test/fixedbugs/issue6703t.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in the call of a pointer method expression. + +package ptrmethexprcall + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var x = (*T).pm(nil) // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703u.go b/test/fixedbugs/issue6703u.go new file mode 100644 index 0000000000..b6813b7712 --- /dev/null +++ b/test/fixedbugs/issue6703u.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in a pointer literal's method value. + +package ptrlitmethvalue + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var x = (*T)(nil).pm // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703v.go b/test/fixedbugs/issue6703v.go new file mode 100644 index 0000000000..a1b3711bb2 --- /dev/null +++ b/test/fixedbugs/issue6703v.go @@ -0,0 +1,18 @@ +// errorcheck + +// 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. + +// Check for cycles in a pointer literal's method call. + +package ptrlitmethcall + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var x = (*T)(nil).pm() // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703w.go b/test/fixedbugs/issue6703w.go new file mode 100644 index 0000000000..d4733debac --- /dev/null +++ b/test/fixedbugs/issue6703w.go @@ -0,0 +1,21 @@ +// errorcheck + +// 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. + +// Check for cycles in a pointer value's method value. + +package ptrmethvalue + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var ( + p *T + x = p.pm // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703x.go b/test/fixedbugs/issue6703x.go new file mode 100644 index 0000000000..8008b8c379 --- /dev/null +++ b/test/fixedbugs/issue6703x.go @@ -0,0 +1,21 @@ +// errorcheck + +// 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. + +// Check for cycles in a pointer value's method call. + +package ptrmethcall + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +var ( + p *T + x = p.pm() // ERROR "initialization loop|depends upon itself" +) diff --git a/test/fixedbugs/issue6703y.go b/test/fixedbugs/issue6703y.go new file mode 100644 index 0000000000..ac4526dda8 --- /dev/null +++ b/test/fixedbugs/issue6703y.go @@ -0,0 +1,23 @@ +// errorcheck + +// 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. + +// Check for cycles in the method value of a pointer value returned +// from a function call. + +package funcptrmethvalue + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +func pf() *T { + return nil +} + +var x = pf().pm // ERROR "initialization loop|depends upon itself" diff --git a/test/fixedbugs/issue6703z.go b/test/fixedbugs/issue6703z.go new file mode 100644 index 0000000000..d4c17e13ae --- /dev/null +++ b/test/fixedbugs/issue6703z.go @@ -0,0 +1,23 @@ +// errorcheck + +// 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. + +// Check for cycles in the method call of a pointer value returned +// from a function call. + +package funcptrmethcall + +type T int + +func (*T) pm() int { + _ = x + return 0 +} + +func pf() *T { + return nil +} + +var x = pf().pm() // ERROR "initialization loop|depends upon itself" From ae250ab227311aab7fd8dff22ae05592abd13bde Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 14 Oct 2014 20:03:35 -0700 Subject: [PATCH 362/430] encoding/gob: make encoding structs a little faster FieldByIndex never returns an invalid Value, so the validity test can be avoided if the field is not indirect. BenchmarkGobEncode 12768642 12424022 -2.70% BenchmarkGobEncode 60.11 61.78 1.03x LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/158890045 --- src/encoding/gob/encode.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index b7bf8b0022..04a85410c6 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -281,15 +281,16 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle field := value.FieldByIndex(instr.index) if instr.indir > 0 { field = encIndirect(field, instr.indir) - } - if !valid(field) { - continue + // TODO: Is field guaranteed valid? If so we could avoid this check. + if !valid(field) { + continue + } } instr.op(instr, state, field) } } -// encodeArray encodes the array whose 0th element is at p. +// encodeArray encodes an array. func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) { state := enc.newEncoderState(b) defer enc.freeEncoderState(state) @@ -300,6 +301,7 @@ func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elem := value.Index(i) if elemIndir > 0 { elem = encIndirect(elem, elemIndir) + // TODO: Is elem guaranteed valid? If so we could avoid this check. if !valid(elem) { errorf("encodeArray: nil element") } From ff6d0a4df44b24b71df1cfbd29534f54a4b2de17 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Oct 2014 23:24:32 -0400 Subject: [PATCH 363/430] cmd/gc, runtime: fix race, nacl for writebarrier changes The racewalk code was not updated for the new write barriers. Make it more future-proof. The new write barrier code assumed that +1 pointer would be aligned properly for any type that might follow, but that's not true on 32-bit systems where some types are 64-bit aligned. The only system like that today is nacl/amd64p32. Insert a dummy pointer so that the ambiguously typed value is at +2 pointers, which is always max-aligned. LGTM=r R=r CC=golang-codereviews, iant, khr https://golang.org/cl/158890046 --- src/cmd/gc/builtin.c | 6 +++--- src/cmd/gc/racewalk.c | 7 +------ src/cmd/gc/runtime.go | 10 +++++++--- src/cmd/gc/walk.c | 6 +++--- src/runtime/mgc0.go | 6 +++--- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 17f80ebba4..5fbb4f0cf3 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -87,9 +87,9 @@ char *runtimeimport = "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, @\"\".src·2 any)\n" + "func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" + "func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" + "func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" "func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c index cb98ca2471..c9e27fe560 100644 --- a/src/cmd/gc/racewalk.c +++ b/src/cmd/gc/racewalk.c @@ -210,12 +210,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip) case OCALLFUNC: // Instrument dst argument of runtime.writebarrier* calls // as we do not instrument runtime code. - if(n->left->sym != S && n->left->sym->pkg == runtimepkg && - (strcmp(n->left->sym->name, "writebarrierptr") == 0 || - strcmp(n->left->sym->name, "writebarrierstring") == 0 || - strcmp(n->left->sym->name, "writebarrierslice") == 0 || - strcmp(n->left->sym->name, "writebarrieriface") == 0 || - strcmp(n->left->sym->name, "writebarrierfat") == 0)) { + if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) { // Find the dst argument. // The list can be reordered, so it's not necessary just the first or the second element. for(l = n->list; l; l = l->next) { diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 6ee5e2e364..86afe67f17 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -112,9 +112,13 @@ func writebarrierptr(dst *any, src any) func writebarrierstring(dst *any, src any) func writebarrierslice(dst *any, src any) func writebarrieriface(dst *any, src any) -func writebarrierfat2(dst *any, src any) -func writebarrierfat3(dst *any, src any) -func writebarrierfat4(dst *any, src any) + +// The unused *byte argument makes sure that src is 2-pointer-aligned, +// which is the maximum alignment on NaCl amd64p32 +// (and possibly on 32-bit systems if we start 64-bit aligning uint64s). +func writebarrierfat2(dst *any, _ *byte, src any) +func writebarrierfat3(dst *any, _ *byte, src any) +func writebarrierfat4(dst *any, _ *byte, src any) func writebarrierfat(typ *byte, dst *any, src *any) func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 5b5385d50c..241d7d74ad 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2060,13 +2060,13 @@ applywritebarrier(Node *n, NodeList **init) l, n->right); } else if(t->width == 2*widthptr) { n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init, - l, n->right); + l, nodnil(), n->right); } else if(t->width == 3*widthptr) { n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init, - l, n->right); + l, nodnil(), n->right); } else if(t->width == 4*widthptr) { n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init, - l, n->right); + l, nodnil(), n->right); } else { r = n->right; while(r->op == OCONVNOP) diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go index 3152b1fe1a..3a7204b54f 100644 --- a/src/runtime/mgc0.go +++ b/src/runtime/mgc0.go @@ -110,20 +110,20 @@ func writebarrieriface(dst *[2]uintptr, src [2]uintptr) { } //go:nosplit -func writebarrierfat2(dst *[2]uintptr, src [2]uintptr) { +func writebarrierfat2(dst *[2]uintptr, _ *byte, src [2]uintptr) { dst[0] = src[0] dst[1] = src[1] } //go:nosplit -func writebarrierfat3(dst *[3]uintptr, src [3]uintptr) { +func writebarrierfat3(dst *[3]uintptr, _ *byte, src [3]uintptr) { dst[0] = src[0] dst[1] = src[1] dst[2] = src[2] } //go:nosplit -func writebarrierfat4(dst *[4]uintptr, src [4]uintptr) { +func writebarrierfat4(dst *[4]uintptr, _ *byte, src [4]uintptr) { dst[0] = src[0] dst[1] = src[1] dst[2] = src[2] From 4f80b50e235dd6e7637cf1b15f450d5c50d5ba9f Mon Sep 17 00:00:00 2001 From: Jens Frederich Date: Tue, 14 Oct 2014 23:24:58 -0400 Subject: [PATCH 364/430] go/build: Return MultiplePackageError on importing a dir containing multiple packages When the Import function in go/build encounters a directory without any buildable Go source files, it returns a handy NoGoError. Now if, instead it encounters multiple Go source files from multiple packages, it returns a handy MultiplePackageError. A new test for NoGoError and MultiplePackageError is also provided. Fixes #8286. LGTM=adg, rsc R=bradfitz, rsc, adg CC=golang-codereviews https://golang.org/cl/155050043 --- src/go/build/build.go | 15 ++++++++++++++- src/go/build/build_test.go | 14 ++++++++++++++ src/go/build/testdata/empty/dummy | 0 src/go/build/testdata/multi/file.go | 5 +++++ src/go/build/testdata/multi/file_appengine.go | 5 +++++ 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/go/build/testdata/empty/dummy create mode 100644 src/go/build/testdata/multi/file.go create mode 100644 src/go/build/testdata/multi/file_appengine.go diff --git a/src/go/build/build.go b/src/go/build/build.go index 3ac7980833..7a51cf3c06 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -417,6 +417,19 @@ func (e *NoGoError) Error() string { return "no buildable Go source files in " + e.Dir } +// MultiplePackageError describes a directory containing +// multiple buildable Go source files for multiple packages. +type MultiplePackageError struct { + Dir string // directory containing files + Packages []string // package names found + Files []string // corresponding files: Files[i] declares package Packages[i] +} + +func (e *MultiplePackageError) Error() string { + // Error string limited to two entries for compatibility. + return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir) +} + func nameExt(name string) string { i := strings.LastIndex(name, ".") if i < 0 { @@ -675,7 +688,7 @@ Found: p.Name = pkg firstFile = name } else if pkg != p.Name { - return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir) + return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}} } if pf.Doc != nil && p.Doc == "" { p.Doc = doc.Synopsis(pf.Doc.Text()) diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go index 23ce89b4bd..43d09cbd14 100644 --- a/src/go/build/build_test.go +++ b/src/go/build/build_test.go @@ -85,6 +85,20 @@ func TestEmptyImport(t *testing.T) { } } +func TestEmptyFolderImport(t *testing.T) { + _, err := Import(".", "testdata/empty", 0) + if _, ok := err.(*NoGoError); !ok { + t.Fatal(`Import("testdata/empty") did not return NoGoError.`) + } +} + +func TestMultiplePackageImport(t *testing.T) { + _, err := Import(".", "testdata/multi", 0) + if _, ok := err.(*MultiplePackageError); !ok { + t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`) + } +} + func TestLocalDirectory(t *testing.T) { cwd, err := os.Getwd() if err != nil { diff --git a/src/go/build/testdata/empty/dummy b/src/go/build/testdata/empty/dummy new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/go/build/testdata/multi/file.go b/src/go/build/testdata/multi/file.go new file mode 100644 index 0000000000..ee946eb2a2 --- /dev/null +++ b/src/go/build/testdata/multi/file.go @@ -0,0 +1,5 @@ +// Test data - not compiled. + +package main + +func main() {} diff --git a/src/go/build/testdata/multi/file_appengine.go b/src/go/build/testdata/multi/file_appengine.go new file mode 100644 index 0000000000..4ea31e7031 --- /dev/null +++ b/src/go/build/testdata/multi/file_appengine.go @@ -0,0 +1,5 @@ +// Test data - not compiled. + +package test_package + +func init() {} From 5e6bd29c2c522bf55d12bdd2c63c7a06b761617e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 14 Oct 2014 23:25:12 -0400 Subject: [PATCH 365/430] liblink: require DATA lines to be ordered by offset, with no overlap The assembler could give a better error, but this one is good enough for now. Fixes #8880. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/153610043 --- include/link.h | 2 ++ src/cmd/5a/lex.c | 1 + src/cmd/6a/lex.c | 1 + src/cmd/8a/lex.c | 1 + src/liblink/data.c | 2 ++ 5 files changed, 7 insertions(+) diff --git a/include/link.h b/include/link.h index 845f9338d9..05e117c87e 100644 --- a/include/link.h +++ b/include/link.h @@ -373,6 +373,7 @@ struct Link char* trimpath; char* goroot; char* goroot_final; + int32 enforce_data_order; // for use by assembler // hash table of all symbols LSym* hash[LINKHASH]; @@ -542,6 +543,7 @@ vlong adduint8(Link *ctxt, LSym *s, uint8 v); vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid); void mangle(char *file); void savedata(Link *ctxt, LSym *s, Prog *p, char *pn); +void savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order); vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t); vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add); vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v); diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c index 84a17d1557..9c69709479 100644 --- a/src/cmd/5a/lex.c +++ b/src/cmd/5a/lex.c @@ -85,6 +85,7 @@ main(int argc, char *argv[]) ctxt = linknew(&linkarm); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit5(); fmtinstall('L', Lconv); diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c index b50e1622e2..8973d69743 100644 --- a/src/cmd/6a/lex.c +++ b/src/cmd/6a/lex.c @@ -101,6 +101,7 @@ main(int argc, char *argv[]) ctxt = linknew(thelinkarch); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit6(); fmtinstall('L', Lconv); diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c index 807e48cb50..6ce6a18abe 100644 --- a/src/cmd/8a/lex.c +++ b/src/cmd/8a/lex.c @@ -90,6 +90,7 @@ main(int argc, char *argv[]) ctxt = linknew(&link386); ctxt->diag = yyerror; ctxt->bso = &bstdout; + ctxt->enforce_data_order = 1; Binit(&bstdout, 1, OWRITE); listinit8(); fmtinstall('L', Lconv); diff --git a/src/liblink/data.c b/src/liblink/data.c index 4504f4171e..e5efa2eb2d 100644 --- a/src/liblink/data.c +++ b/src/liblink/data.c @@ -83,6 +83,8 @@ savedata(Link *ctxt, LSym *s, Prog *p, char *pn) siz = ctxt->arch->datasize(p); if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100) mangle(pn); + if(ctxt->enforce_data_order && off < s->np) + ctxt->diag("data out of order (already have %d)\n%P", p); symgrow(ctxt, s, off+siz); if(p->to.type == ctxt->arch->D_FCONST) { From a681749ab5b0f7dcb8aff4123e6e8a002e2b5d91 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 15 Oct 2014 06:20:55 -0700 Subject: [PATCH 366/430] crypto/x509: correct field name in comment Fixes #8936. LGTM=bradfitz R=agl, bradfitz CC=golang-codereviews https://golang.org/cl/152590043 --- src/crypto/x509/x509.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 69a62e57d2..7a37b98e31 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1670,7 +1670,7 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} // CreateCertificateRequest creates a new certificate based on a template. The // following members of template are used: Subject, Attributes, -// SignatureAlgorithm, Extension, DNSNames, EmailAddresses, and IPAddresses. +// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. // The private key is the private key of the signer. // // The returned slice is the certificate request in DER encoding. From 9d51cd0fee3cf8bf779ba23a34b7fb2ec311cfe1 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 15 Oct 2014 17:51:12 +0200 Subject: [PATCH 367/430] net/http: don't reuse a server connection after any Write errors Fixes #8534 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/149340044 --- src/net/http/serve_test.go | 97 ++++++++++++++++++++++++++++++++++++++ src/net/http/server.go | 32 +++++++++++-- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 702bffdc13..bb44ac8537 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -2659,6 +2659,103 @@ func TestCloseWrite(t *testing.T) { } } +// This verifies that a handler can Flush and then Hijack. +// +// An similar test crashed once during development, but it was only +// testing this tangentially and temporarily until another TODO was +// fixed. +// +// So add an explicit test for this. +func TestServerFlushAndHijack(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + io.WriteString(w, "Hello, ") + w.(Flusher).Flush() + conn, buf, _ := w.(Hijacker).Hijack() + buf.WriteString("6\r\nworld!\r\n0\r\n\r\n") + if err := buf.Flush(); err != nil { + t.Error(err) + } + if err := conn.Close(); err != nil { + t.Error(err) + } + })) + defer ts.Close() + res, err := Get(ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + all, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if want := "Hello, world!"; string(all) != want { + t.Errorf("Got %q; want %q", all, want) + } +} + +// golang.org/issue/8534 -- the Server shouldn't reuse a connection +// for keep-alive after it's seen any Write error (e.g. a timeout) on +// that net.Conn. +// +// To test, verify we don't timeout or see fewer unique client +// addresses (== unique connections) than requests. +func TestServerKeepAliveAfterWriteError(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode") + } + defer afterTest(t) + const numReq = 3 + addrc := make(chan string, numReq) + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + addrc <- r.RemoteAddr + time.Sleep(500 * time.Millisecond) + w.(Flusher).Flush() + })) + ts.Config.WriteTimeout = 250 * time.Millisecond + ts.Start() + defer ts.Close() + + errc := make(chan error, numReq) + go func() { + defer close(errc) + for i := 0; i < numReq; i++ { + res, err := Get(ts.URL) + if res != nil { + res.Body.Close() + } + errc <- err + } + }() + + timeout := time.NewTimer(numReq * 2 * time.Second) // 4x overkill + defer timeout.Stop() + addrSeen := map[string]bool{} + numOkay := 0 + for { + select { + case v := <-addrc: + addrSeen[v] = true + case err, ok := <-errc: + if !ok { + if len(addrSeen) != numReq { + t.Errorf("saw %d unique client addresses; want %d", len(addrSeen), numReq) + } + if numOkay != 0 { + t.Errorf("got %d successful client requests; want 0", numOkay) + } + return + } + if err == nil { + numOkay++ + } + case <-timeout.C: + t.Fatal("timeout waiting for requests to complete") + } + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() diff --git a/src/net/http/server.go b/src/net/http/server.go index b5959f7321..008d5aa7a7 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -114,6 +114,8 @@ type conn struct { remoteAddr string // network address of remote side server *Server // the Server on which the connection arrived rwc net.Conn // i/o connection + w io.Writer // checkConnErrorWriter's copy of wrc, not zeroed on Hijack + werr error // any errors writing to w sr liveSwitchReader // where the LimitReader reads from; usually the rwc lr *io.LimitedReader // io.LimitReader(sr) buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc @@ -432,13 +434,14 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) { c.remoteAddr = rwc.RemoteAddr().String() c.server = srv c.rwc = rwc + c.w = rwc if debugServerConnections { c.rwc = newLoggingConn("server", c.rwc) } c.sr = liveSwitchReader{r: c.rwc} c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader) br := newBufioReader(c.lr) - bw := newBufioWriterSize(c.rwc, 4<<10) + bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) c.buf = bufio.NewReadWriter(br, bw) return c, nil } @@ -956,8 +959,10 @@ func (w *response) bodyAllowed() bool { // 2. (*response).w, a *bufio.Writer of bufferBeforeChunkingSize bytes // 3. chunkWriter.Writer (whose writeHeader finalizes Content-Length/Type) // and which writes the chunk headers, if needed. -// 4. conn.buf, a bufio.Writer of default (4kB) bytes -// 5. the rwc, the net.Conn. +// 4. conn.buf, a bufio.Writer of default (4kB) bytes, writing to -> +// 5. checkConnErrorWriter{c}, which notes any non-nil error on Write +// and populates c.werr with it if so. but otherwise writes to: +// 6. the rwc, the net.Conn. // // TODO(bradfitz): short-circuit some of the buffering when the // initial header contains both a Content-Type and Content-Length. @@ -1027,6 +1032,12 @@ func (w *response) finishRequest() { // Did not write enough. Avoid getting out of sync. w.closeAfterReply = true } + + // There was some error writing to the underlying connection + // during the request, so don't re-use this conn. + if w.conn.werr != nil { + w.closeAfterReply = true + } } func (w *response) Flush() { @@ -2068,3 +2079,18 @@ func (c *loggingConn) Close() (err error) { log.Printf("%s.Close() = %v", c.name, err) return } + +// checkConnErrorWriter writes to c.rwc and records any write errors to c.werr. +// It only contains one field (and a pointer field at that), so it +// fits in an interface value without an extra allocation. +type checkConnErrorWriter struct { + c *conn +} + +func (w checkConnErrorWriter) Write(p []byte) (n int, err error) { + n, err = w.c.w.Write(p) // c.w == c.rwc, except after a hijack, when rwc is nil. + if err != nil && w.c.werr == nil { + w.c.werr = err + } + return +} From 42c3130780327299cb8a89f30b8e5c3d6b96d2c2 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 15 Oct 2014 17:51:30 +0200 Subject: [PATCH 368/430] net/http: don't send implicit gzip Accept-Encoding on Range requests The http package by default adds "Accept-Encoding: gzip" to outgoing requests, unless it's a bad idea, or the user requested otherwise. Only when the http package adds its own implicit Accept-Encoding header does the http package also transparently un-gzip the response. If the user requested part of a document (e.g. bytes 40 to 50), it appears that Github/Varnish send: range(gzip(content), 40, 50) And not: gzip(range(content, 40, 50)) The RFC 2616 set of replacements (with the purpose of clarifying ambiguities since 1999) has an RFC about Range requests (http://tools.ietf.org/html/rfc7233) but does not mention the interaction with encodings. Regardless of whether range(gzip(content)) or gzip(range(content)) is correct, this change prevents the Go package from asking for gzip in requests if we're also asking for Range, avoiding the issue. If the user cared, they can do it themselves. But Go transparently un-gzipping a fragment of gzip is never useful. Fixes #8923 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/155420044 --- src/net/http/response_test.go | 28 ++++++++++++++++++++++++++++ src/net/http/transport.go | 11 +++++++++-- src/net/http/transport_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go index 2dd0fad11d..06e940d9ab 100644 --- a/src/net/http/response_test.go +++ b/src/net/http/response_test.go @@ -377,6 +377,34 @@ some body`, "Body here\n", }, + + // 206 Partial Content. golang.org/issue/8923 + { + "HTTP/1.1 206 Partial Content\r\n" + + "Content-Type: text/plain; charset=utf-8\r\n" + + "Accept-Ranges: bytes\r\n" + + "Content-Range: bytes 0-5/1862\r\n" + + "Content-Length: 6\r\n\r\n" + + "foobar", + + Response{ + Status: "206 Partial Content", + StatusCode: 206, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq("GET"), + Header: Header{ + "Accept-Ranges": []string{"bytes"}, + "Content-Length": []string{"6"}, + "Content-Type": []string{"text/plain; charset=utf-8"}, + "Content-Range": []string{"bytes 0-5/1862"}, + }, + ContentLength: 6, + }, + + "foobar", + }, } func TestReadResponse(t *testing.T) { diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 70e574fc86..782f7cd395 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1040,11 +1040,14 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err } // Ask for a compressed version if the caller didn't set their - // own value for Accept-Encoding. We only attempted to + // own value for Accept-Encoding. We only attempt to // uncompress the gzip stream if we were the layer that // requested it. requestedGzip := false - if !pc.t.DisableCompression && req.Header.Get("Accept-Encoding") == "" && req.Method != "HEAD" { + if !pc.t.DisableCompression && + req.Header.Get("Accept-Encoding") == "" && + req.Header.Get("Range") == "" && + req.Method != "HEAD" { // Request gzip only, not deflate. Deflate is ambiguous and // not as universally supported anyway. // See: http://www.gzip.org/zlib/zlib_faq.html#faq38 @@ -1053,6 +1056,10 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err // due to a bug in nginx: // http://trac.nginx.org/nginx/ticket/358 // http://golang.org/issue/5522 + // + // We don't request gzip if the request is for a range, since + // auto-decoding a portion of a gzipped document will just fail + // anyway. See http://golang.org/issue/8923 requestedGzip = true req.extraHeaders().Set("Accept-Encoding", "gzip") } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 66fcc3c7d4..defa633708 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -2216,6 +2216,39 @@ func TestTransportCloseIdleConnsThenReturn(t *testing.T) { wantIdle("after final put", 1) } +// This tests that an client requesting a content range won't also +// implicitly ask for gzip support. If they want that, they need to do it +// on their own. +// golang.org/issue/8923 +func TestTransportRangeAndGzip(t *testing.T) { + defer afterTest(t) + reqc := make(chan *Request, 1) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + reqc <- r + })) + defer ts.Close() + + req, _ := NewRequest("GET", ts.URL, nil) + req.Header.Set("Range", "bytes=7-11") + res, err := DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + + select { + case r := <-reqc: + if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { + t.Error("Transport advertised gzip support in the Accept header") + } + if r.Header.Get("Range") == "" { + t.Error("no Range in request") + } + case <-time.After(10 * time.Second): + t.Fatal("timeout") + } + res.Body.Close() +} + func wantBody(res *http.Response, err error, want string) error { if err != nil { return err From db4dad7fd7f8d95ffb0c8e07de150015172d5853 Mon Sep 17 00:00:00 2001 From: Chris Manghane Date: Wed, 15 Oct 2014 09:55:13 -0700 Subject: [PATCH 369/430] cmd/gc: blank methods are not permitted in interface types Fixes #6606. LGTM=rsc R=rsc CC=golang-codereviews, gri https://golang.org/cl/156210044 --- src/cmd/gc/dcl.c | 3 +++ test/interface/explicit.go | 4 ++-- test/interface/fail.go | 14 -------------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index cc010d901c..dfcf47520a 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -558,6 +558,9 @@ ifacedcl(Node *n) if(n->op != ODCLFIELD || n->right == N) fatal("ifacedcl"); + if(isblank(n->left)) + yyerror("methods must have a unique non-blank name"); + dclcontext = PPARAM; markdcl(); funcdepth++; diff --git a/test/interface/explicit.go b/test/interface/explicit.go index 36fa1a4224..b10d02f248 100644 --- a/test/interface/explicit.go +++ b/test/interface/explicit.go @@ -83,12 +83,12 @@ var m4 = M(jj) // ERROR "invalid|wrong type for M method" type B1 interface { - _() + _() // ERROR "methods must have a unique non-blank name" } type B2 interface { M() - _() + _() // ERROR "methods must have a unique non-blank name" } type T2 struct{} diff --git a/test/interface/fail.go b/test/interface/fail.go index 81eb6cb3c1..d40a151383 100644 --- a/test/interface/fail.go +++ b/test/interface/fail.go @@ -14,7 +14,6 @@ type I interface { func main() { shouldPanic(p1) - shouldPanic(p2) } func p1() { @@ -30,19 +29,6 @@ type S struct{} func (s *S) _() {} -type B interface { - _() -} - -func p2() { - var s *S - var b B - var e interface{} - e = s - b = e.(B) - _ = b -} - func shouldPanic(f func()) { defer func() { if recover() == nil { From 05c4b69f848a2de7acc604285d18e995f646adfc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 13:09:59 -0400 Subject: [PATCH 370/430] os/exec: document that Stdin goroutine must finish in Wait Fixes #7990. LGTM=iant, bradfitz R=bradfitz, iant, robryk CC=golang-codereviews https://golang.org/cl/156220043 --- src/os/exec/exec.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go index 4aded41716..72b4905d56 100644 --- a/src/os/exec/exec.go +++ b/src/os/exec/exec.go @@ -55,8 +55,15 @@ type Cmd struct { // calling process's current directory. Dir string - // Stdin specifies the process's standard input. If Stdin is - // nil, the process reads from the null device (os.DevNull). + // Stdin specifies the process's standard input. + // If Stdin is nil, the process reads from the null device (os.DevNull). + // If Stdin is an *os.File, the process's standard input is connected + // directly to that file. + // Otherwise, during the execution of the command a separate + // goroutine reads from Stdin and delivers that data to the command + // over a pipe. In this case, Wait does not complete until the goroutine + // stops copying, either because it has reached the end of Stdin + // (EOF or a read error) or because writing to the pipe returned an error. Stdin io.Reader // Stdout and Stderr specify the process's standard output and error. From 5318a1b5b12d2836b23eb6b706f96f0247f2144a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 13:10:14 -0400 Subject: [PATCH 371/430] database/sql: add Drivers, returning list of registered drivers Fixes #7969. LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/158950043 --- src/database/sql/fakedb_test.go | 22 ++++++++++++++++++++++ src/database/sql/sql.go | 11 +++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go index c7db0dd77b..171c322d49 100644 --- a/src/database/sql/fakedb_test.go +++ b/src/database/sql/fakedb_test.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "log" + "sort" "strconv" "strings" "sync" @@ -126,6 +127,27 @@ func init() { Register("test", fdriver) } +func contains(list []string, y string) bool { + for _, x := range list { + if x == y { + return true + } + } + return false +} + +type Dummy struct { + driver.Driver +} + +func TestDrivers(t *testing.T) { + Register("invalid", Dummy{}) + all := Drivers() + if len(all) < 2 || !sort.StringsAreSorted(all) || !contains(all, "test") || !contains(all, "invalid") { + t.Fatalf("Drivers = %v, want sorted list with at least [invalid, test]", all) + } +} + // Supports dsn forms: // // ; (only currently supported option is `badConn`, diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 731b7a7f79..ad9179cf7d 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -18,6 +18,7 @@ import ( "fmt" "io" "runtime" + "sort" "sync" ) @@ -36,6 +37,16 @@ func Register(name string, driver driver.Driver) { drivers[name] = driver } +// Drivers returns a sorted list of the names of the registered drivers. +func Drivers() []string { + var list []string + for name := range drivers { + list = append(list, name) + } + sort.Strings(list) + return list +} + // RawBytes is a byte slice that holds a reference to memory owned by // the database itself. After a Scan into a RawBytes, the slice is only // valid until the next call to Next, Scan, or Close. From cb6f5ac0b0239b6041267d3e9898390f57fc9eb1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 13:12:16 -0400 Subject: [PATCH 372/430] runtime: remove hand-generated ptr bitmaps for reflectcall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A Go prototype can be used instead now, and the compiler will do a better job than we will doing it by hand. (We got it wrong in amd64p32, causing the current build breakage.) The auto-prototype-matching only applies to functions without an explicit package path, so the TEXT lines for reflectcall and callXX are s/runtime·/·/. LGTM=khr R=khr CC=golang-codereviews, iant, r https://golang.org/cl/153600043 --- src/runtime/asm_386.s | 72 +++++++++++++++-------------------- src/runtime/asm_amd64.s | 72 +++++++++++++++-------------------- src/runtime/asm_amd64p32.s | 77 ++++++++++++++++---------------------- src/runtime/asm_arm.s | 70 ++++++++++++++-------------------- src/runtime/stubs.go | 30 +++++++++++++++ 5 files changed, 151 insertions(+), 170 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index c401741ef9..b0ed2d8ceb 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -353,7 +353,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0 JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 +TEXT ·reflectcall(SB), NOSPLIT, $0-16 MOVL argsize+8(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) @@ -385,21 +385,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 MOVL $runtime·badreflectcall(SB), AX JMP AX -// Argument map for the callXX frames. Each has one stack map. -DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_reflectcall<>+0x04(SB)/4, $8 // 4 words -DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6)) -GLOBL gcargs_reflectcall<>(SB),RODATA,$12 - -// callXX frames have no locals -DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_reflectcall<>(SB),RODATA,$8 - #define CALLFN(NAME,MAXSIZE) \ -TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \ - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\ +TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ + NO_LOCAL_POINTERS; \ /* copy arguments to stack */ \ MOVL argptr+4(FP), SI; \ MOVL argsize+8(FP), CX; \ @@ -421,33 +409,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ REP;MOVSB; \ RET -CALLFN(runtime·call16, 16) -CALLFN(runtime·call32, 32) -CALLFN(runtime·call64, 64) -CALLFN(runtime·call128, 128) -CALLFN(runtime·call256, 256) -CALLFN(runtime·call512, 512) -CALLFN(runtime·call1024, 1024) -CALLFN(runtime·call2048, 2048) -CALLFN(runtime·call4096, 4096) -CALLFN(runtime·call8192, 8192) -CALLFN(runtime·call16384, 16384) -CALLFN(runtime·call32768, 32768) -CALLFN(runtime·call65536, 65536) -CALLFN(runtime·call131072, 131072) -CALLFN(runtime·call262144, 262144) -CALLFN(runtime·call524288, 524288) -CALLFN(runtime·call1048576, 1048576) -CALLFN(runtime·call2097152, 2097152) -CALLFN(runtime·call4194304, 4194304) -CALLFN(runtime·call8388608, 8388608) -CALLFN(runtime·call16777216, 16777216) -CALLFN(runtime·call33554432, 33554432) -CALLFN(runtime·call67108864, 67108864) -CALLFN(runtime·call134217728, 134217728) -CALLFN(runtime·call268435456, 268435456) -CALLFN(runtime·call536870912, 536870912) -CALLFN(runtime·call1073741824, 1073741824) +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) // bool cas(int32 *val, int32 old, int32 new) // Atomically: diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index e21270d8cc..2ee3312086 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -339,11 +339,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 #define DISPATCH(NAME,MAXSIZE) \ CMPQ CX, $MAXSIZE; \ JA 3(PC); \ - MOVQ $NAME(SB), AX; \ + MOVQ $NAME(SB), AX; \ JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT runtime·reflectcall(SB), NOSPLIT, $0-24 +TEXT ·reflectcall(SB), NOSPLIT, $0-24 MOVLQZX argsize+16(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) @@ -375,21 +375,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-24 MOVQ $runtime·badreflectcall(SB), AX JMP AX -// Argument map for the callXX frames. Each has one stack map. -DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 words -DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)) -GLOBL gcargs_reflectcall<>(SB),RODATA,$12 - -// callXX frames have no locals -DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_reflectcall<>(SB),RODATA,$8 - #define CALLFN(NAME,MAXSIZE) \ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \ - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \ - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\ + NO_LOCAL_POINTERS; \ /* copy arguments to stack */ \ MOVQ argptr+8(FP), SI; \ MOVLQZX argsize+16(FP), CX; \ @@ -410,33 +398,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \ REP;MOVSB; \ RET -CALLFN(runtime·call16, 16) -CALLFN(runtime·call32, 32) -CALLFN(runtime·call64, 64) -CALLFN(runtime·call128, 128) -CALLFN(runtime·call256, 256) -CALLFN(runtime·call512, 512) -CALLFN(runtime·call1024, 1024) -CALLFN(runtime·call2048, 2048) -CALLFN(runtime·call4096, 4096) -CALLFN(runtime·call8192, 8192) -CALLFN(runtime·call16384, 16384) -CALLFN(runtime·call32768, 32768) -CALLFN(runtime·call65536, 65536) -CALLFN(runtime·call131072, 131072) -CALLFN(runtime·call262144, 262144) -CALLFN(runtime·call524288, 524288) -CALLFN(runtime·call1048576, 1048576) -CALLFN(runtime·call2097152, 2097152) -CALLFN(runtime·call4194304, 4194304) -CALLFN(runtime·call8388608, 8388608) -CALLFN(runtime·call16777216, 16777216) -CALLFN(runtime·call33554432, 33554432) -CALLFN(runtime·call67108864, 67108864) -CALLFN(runtime·call134217728, 134217728) -CALLFN(runtime·call268435456, 268435456) -CALLFN(runtime·call536870912, 536870912) -CALLFN(runtime·call1073741824, 1073741824) +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) // bool cas(int32 *val, int32 old, int32 new) // Atomically: diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index c2bc91a3f5..e27f67e1ee 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -310,11 +310,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0 #define DISPATCH(NAME,MAXSIZE) \ CMPL CX, $MAXSIZE; \ JA 3(PC); \ - MOVL $NAME(SB), AX; \ + MOVL $NAME(SB), AX; \ JMP AX // Note: can't just "JMP NAME(SB)" - bad inlining results. -TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 +TEXT ·reflectcall(SB), NOSPLIT, $0-16 MOVLQZX argsize+8(FP), CX DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) @@ -346,22 +346,9 @@ TEXT runtime·reflectcall(SB), NOSPLIT, $0-16 MOVL $runtime·badreflectcall(SB), AX JMP AX -// Argument map for the callXX frames. Each has one stack map. -DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_reflectcall<>+0x04(SB)/4, $10 // 5 words -DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6)) -DATA gcargs_reflectcall<>+0x09(SB)/1, $(const_BitsPointer) -GLOBL gcargs_reflectcall<>(SB),RODATA,$12 - -// callXX frames have no locals -DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_reflectcall<>(SB),RODATA,$8 - #define CALLFN(NAME,MAXSIZE) \ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \ - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\ + NO_LOCAL_POINTERS; \ /* copy arguments to stack */ \ MOVL argptr+4(FP), SI; \ MOVL argsize+8(FP), CX; \ @@ -369,8 +356,8 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ REP;MOVSB; \ /* call function */ \ MOVL f+0(FP), DX; \ - MOVL (DX), AX; \ - CALL AX; \ + MOVL (DX), AX; \ + CALL AX; \ /* copy return values back */ \ MOVL argptr+4(FP), DI; \ MOVL argsize+8(FP), CX; \ @@ -382,33 +369,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ REP;MOVSB; \ RET -CALLFN(runtime·call16, 16) -CALLFN(runtime·call32, 32) -CALLFN(runtime·call64, 64) -CALLFN(runtime·call128, 128) -CALLFN(runtime·call256, 256) -CALLFN(runtime·call512, 512) -CALLFN(runtime·call1024, 1024) -CALLFN(runtime·call2048, 2048) -CALLFN(runtime·call4096, 4096) -CALLFN(runtime·call8192, 8192) -CALLFN(runtime·call16384, 16384) -CALLFN(runtime·call32768, 32768) -CALLFN(runtime·call65536, 65536) -CALLFN(runtime·call131072, 131072) -CALLFN(runtime·call262144, 262144) -CALLFN(runtime·call524288, 524288) -CALLFN(runtime·call1048576, 1048576) -CALLFN(runtime·call2097152, 2097152) -CALLFN(runtime·call4194304, 4194304) -CALLFN(runtime·call8388608, 8388608) -CALLFN(runtime·call16777216, 16777216) -CALLFN(runtime·call33554432, 33554432) -CALLFN(runtime·call67108864, 67108864) -CALLFN(runtime·call134217728, 134217728) -CALLFN(runtime·call268435456, 268435456) -CALLFN(runtime·call536870912, 536870912) -CALLFN(runtime·call1073741824, 1073741824) +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) // bool cas(int32 *val, int32 old, int32 new) // Atomically: diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index a1535aeec3..b21441488a 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -343,7 +343,7 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0 MOVW $NAME(SB), R1; \ B (R1) -TEXT runtime·reflectcall(SB),NOSPLIT,$-4-16 +TEXT ·reflectcall(SB),NOSPLIT,$-4-16 MOVW argsize+8(FP), R0 DISPATCH(runtime·call16, 16) DISPATCH(runtime·call32, 32) @@ -375,21 +375,9 @@ TEXT runtime·reflectcall(SB),NOSPLIT,$-4-16 MOVW $runtime·badreflectcall(SB), R1 B (R1) -// Argument map for the callXX frames. Each has one stack map. -DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gcargs_reflectcall<>+0x04(SB)/4, $8 // 4 words -DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6)) -GLOBL gcargs_reflectcall<>(SB),RODATA,$12 - -// callXX frames have no locals -DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap -DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals -GLOBL gclocals_reflectcall<>(SB),RODATA,$8 - #define CALLFN(NAME,MAXSIZE) \ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ - FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \ - FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\ + NO_LOCAL_POINTERS; \ /* copy arguments to stack */ \ MOVW argptr+4(FP), R0; \ MOVW argsize+8(FP), R2; \ @@ -420,33 +408,33 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \ SUB $1, R2, R2; \ B -5(PC) \ -CALLFN(runtime·call16, 16) -CALLFN(runtime·call32, 32) -CALLFN(runtime·call64, 64) -CALLFN(runtime·call128, 128) -CALLFN(runtime·call256, 256) -CALLFN(runtime·call512, 512) -CALLFN(runtime·call1024, 1024) -CALLFN(runtime·call2048, 2048) -CALLFN(runtime·call4096, 4096) -CALLFN(runtime·call8192, 8192) -CALLFN(runtime·call16384, 16384) -CALLFN(runtime·call32768, 32768) -CALLFN(runtime·call65536, 65536) -CALLFN(runtime·call131072, 131072) -CALLFN(runtime·call262144, 262144) -CALLFN(runtime·call524288, 524288) -CALLFN(runtime·call1048576, 1048576) -CALLFN(runtime·call2097152, 2097152) -CALLFN(runtime·call4194304, 4194304) -CALLFN(runtime·call8388608, 8388608) -CALLFN(runtime·call16777216, 16777216) -CALLFN(runtime·call33554432, 33554432) -CALLFN(runtime·call67108864, 67108864) -CALLFN(runtime·call134217728, 134217728) -CALLFN(runtime·call268435456, 268435456) -CALLFN(runtime·call536870912, 536870912) -CALLFN(runtime·call1073741824, 1073741824) +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) // void jmpdefer(fn, sp); // called from deferreturn. diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index c6a9cf9f54..6561094ff1 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -252,3 +252,33 @@ func return0() // thunk to call time.now. func timenow() (sec int64, nsec int32) + +// in asm_*.s +// not called directly; definitions here supply type information for traceback. +func call16(fn, arg unsafe.Pointer, n, retoffset uint32) +func call32(fn, arg unsafe.Pointer, n, retoffset uint32) +func call64(fn, arg unsafe.Pointer, n, retoffset uint32) +func call128(fn, arg unsafe.Pointer, n, retoffset uint32) +func call256(fn, arg unsafe.Pointer, n, retoffset uint32) +func call512(fn, arg unsafe.Pointer, n, retoffset uint32) +func call1024(fn, arg unsafe.Pointer, n, retoffset uint32) +func call2048(fn, arg unsafe.Pointer, n, retoffset uint32) +func call4096(fn, arg unsafe.Pointer, n, retoffset uint32) +func call8192(fn, arg unsafe.Pointer, n, retoffset uint32) +func call16384(fn, arg unsafe.Pointer, n, retoffset uint32) +func call32768(fn, arg unsafe.Pointer, n, retoffset uint32) +func call65536(fn, arg unsafe.Pointer, n, retoffset uint32) +func call131072(fn, arg unsafe.Pointer, n, retoffset uint32) +func call262144(fn, arg unsafe.Pointer, n, retoffset uint32) +func call524288(fn, arg unsafe.Pointer, n, retoffset uint32) +func call1048576(fn, arg unsafe.Pointer, n, retoffset uint32) +func call2097152(fn, arg unsafe.Pointer, n, retoffset uint32) +func call4194304(fn, arg unsafe.Pointer, n, retoffset uint32) +func call8388608(fn, arg unsafe.Pointer, n, retoffset uint32) +func call16777216(fn, arg unsafe.Pointer, n, retoffset uint32) +func call33554432(fn, arg unsafe.Pointer, n, retoffset uint32) +func call67108864(fn, arg unsafe.Pointer, n, retoffset uint32) +func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32) +func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32) +func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32) +func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32) From 94950afdf8d94fd4ff3fba7e84bf4ce4b16854d0 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 13:33:00 -0400 Subject: [PATCH 373/430] reflect: add fast path for FieldByIndex with len(index) = 1 LGTM=r R=r CC=golang-codereviews https://golang.org/cl/152640043 --- src/reflect/value.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reflect/value.go b/src/reflect/value.go index 9c65ee2703..8c320f11b0 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -857,6 +857,9 @@ func (v Value) Field(i int) Value { // FieldByIndex returns the nested field corresponding to index. // It panics if v's Kind is not struct. func (v Value) FieldByIndex(index []int) Value { + if len(index) == 1 { + return v.Field(index[0]) + } v.mustBe(Struct) for i, x := range index { if i > 0 { From a1616d4a3271e54d119221c2d263949fae1d4509 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 14:24:18 -0400 Subject: [PATCH 374/430] reflect: shorten value to 3 words scalar is no longer needed, now that interfaces always hold pointers. Comparing best of 5 with TurboBoost turned off, on a 2012 Retina MacBook Pro Core i5. Still not completely confident in these numbers, but the gob and template improvements seem real. benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 3819892491 3803008185 -0.44% BenchmarkFannkuch11 3623876405 3611776426 -0.33% BenchmarkFmtFprintfEmpty 119 118 -0.84% BenchmarkFmtFprintfString 294 292 -0.68% BenchmarkFmtFprintfInt 310 304 -1.94% BenchmarkFmtFprintfIntInt 513 507 -1.17% BenchmarkFmtFprintfPrefixedInt 427 426 -0.23% BenchmarkFmtFprintfFloat 562 554 -1.42% BenchmarkFmtManyArgs 1873 1832 -2.19% BenchmarkGobDecode 15824504 14746565 -6.81% BenchmarkGobEncode 14347378 14208743 -0.97% BenchmarkGzip 537229271 537973492 +0.14% BenchmarkGunzip 134996775 135406149 +0.30% BenchmarkHTTPClientServer 119065 116937 -1.79% BenchmarkJSONEncode 29134359 28928099 -0.71% BenchmarkJSONDecode 106867289 105770161 -1.03% BenchmarkMandelbrot200 5798475 5791433 -0.12% BenchmarkGoParse 5299169 5379201 +1.51% BenchmarkRegexpMatchEasy0_32 195 195 +0.00% BenchmarkRegexpMatchEasy0_1K 477 477 +0.00% BenchmarkRegexpMatchEasy1_32 170 170 +0.00% BenchmarkRegexpMatchEasy1_1K 1412 1397 -1.06% BenchmarkRegexpMatchMedium_32 336 337 +0.30% BenchmarkRegexpMatchMedium_1K 109025 108977 -0.04% BenchmarkRegexpMatchHard_32 5854 5856 +0.03% BenchmarkRegexpMatchHard_1K 184914 184748 -0.09% BenchmarkRevcomp 829233526 836598734 +0.89% BenchmarkTemplate 142055312 137016166 -3.55% BenchmarkTimeParse 598 597 -0.17% BenchmarkTimeFormat 564 568 +0.71% Fixes #7425. LGTM=r R=golang-codereviews, r CC=golang-codereviews, iant, khr https://golang.org/cl/158890043 --- src/reflect/makefunc.go | 6 +- src/reflect/type.go | 10 +- src/reflect/value.go | 365 +++++++++------------------------------- 3 files changed, 91 insertions(+), 290 deletions(-) diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go index bdb8c21d76..1072c7fabe 100644 --- a/src/reflect/makefunc.go +++ b/src/reflect/makefunc.go @@ -60,7 +60,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn} - return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift} + return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift} } // makeFuncStub is an assembly function that is the code half of @@ -92,7 +92,7 @@ func makeMethodValue(op string, v Value) Value { // Ignoring the flagMethod bit, v describes the receiver, not the method type. fl := v.flag & (flagRO | flagAddr | flagIndir) fl |= flag(v.typ.Kind()) << flagKindShift - rcvr := Value{v.typ, v.ptr, v.scalar, fl} + rcvr := Value{v.typ, v.ptr, fl} // v.Type returns the actual type of the method value. funcType := v.Type().(*rtype) @@ -118,7 +118,7 @@ func makeMethodValue(op string, v Value) Value { // but we want Interface() and other operations to fail early. methodReceiver(op, fv.rcvr, fv.method) - return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<> (field.offset * 8) } - return Value{typ, ptr, scalar, fl} + return Value{typ, ptr, fl} } // FieldByIndex returns the nested field corresponding to index. @@ -904,15 +798,9 @@ func (v Value) Float() float64 { k := v.kind() switch k { case Float32: - if v.flag&flagIndir != 0 { - return float64(*(*float32)(v.ptr)) - } - return float64(*(*float32)(unsafe.Pointer(&v.scalar))) + return float64(*(*float32)(v.ptr)) case Float64: - if v.flag&flagIndir != 0 { - return *(*float64)(v.ptr) - } - return *(*float64)(unsafe.Pointer(&v.scalar)) + return *(*float64)(v.ptr) } panic(&ValueError{"reflect.Value.Float", k}) } @@ -935,12 +823,10 @@ func (v Value) Index(i int) Value { offset := uintptr(i) * typ.size var val unsafe.Pointer - var scalar uintptr - switch { - case fl&flagIndir != 0: + if fl&flagIndir != 0 { // Indirect. Just bump pointer. val = unsafe.Pointer(uintptr(v.ptr) + offset) - case typ.pointers(): + } else { if offset != 0 { // This is an array stored inline in an interface value. // And the array element type has pointers. @@ -951,14 +837,8 @@ func (v Value) Index(i int) Value { panic("reflect: internal error: unexpected array index") } val = v.ptr - case bigEndian: - // Direct. Discard leading bytes. - scalar = v.scalar << (offset * 8) - default: - // Direct. Discard leading bytes. - scalar = v.scalar >> (offset * 8) } - return Value{typ, val, scalar, fl} + return Value{typ, val, fl} case Slice: // Element flag same as Elem of Ptr. @@ -972,7 +852,7 @@ func (v Value) Index(i int) Value { typ := tt.elem fl |= flag(typ.Kind()) << flagKindShift val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size) - return Value{typ, val, 0, fl} + return Value{typ, val, fl} case String: fl := v.flag&flagRO | flag(Uint8< cap { @@ -1708,7 +1565,7 @@ func (v Value) Slice(i, j int) Value { } fl := v.flag&flagRO | flagIndir | flag(Slice)< interface @@ -2618,7 +2419,7 @@ func cvtT2I(v Value, typ Type) Value { } else { ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target)) } - return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)< interface From 9aefdc802890f49fd402592d9f6b447b9c5a82af Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 14:33:52 -0400 Subject: [PATCH 375/430] cmd/gc: do not copy via temporary for writebarrierfat{2,3,4} The general writebarrierfat needs a temporary for src, because we need to pass the address of the temporary to the writebarrierfat routine. But the new fixed-size ones pass the value directly and don't need to introduce the temporary. Magnifies some of the effect of the custom write barrier change. Comparing best of 5 with TurboBoost turned off, on a 2012 Retina MacBook Pro Core i5. Still not completely confident in these numbers, but the fmt, regexp, and revcomp improvements seem real. benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 3942965521 3929654940 -0.34% BenchmarkFannkuch11 3707543350 3699566011 -0.22% BenchmarkFmtFprintfEmpty 119 119 +0.00% BenchmarkFmtFprintfString 295 296 +0.34% BenchmarkFmtFprintfInt 313 314 +0.32% BenchmarkFmtFprintfIntInt 517 484 -6.38% BenchmarkFmtFprintfPrefixedInt 439 429 -2.28% BenchmarkFmtFprintfFloat 571 569 -0.35% BenchmarkFmtManyArgs 1899 1820 -4.16% BenchmarkGobDecode 15507208 15325649 -1.17% BenchmarkGobEncode 14811710 14715434 -0.65% BenchmarkGzip 561144467 549624323 -2.05% BenchmarkGunzip 137377667 137691087 +0.23% BenchmarkHTTPClientServer 126632 124717 -1.51% BenchmarkJSONEncode 29944112 29526629 -1.39% BenchmarkJSONDecode 108954913 107339551 -1.48% BenchmarkMandelbrot200 5828755 5821659 -0.12% BenchmarkGoParse 5577437 5521895 -1.00% BenchmarkRegexpMatchEasy0_32 198 193 -2.53% BenchmarkRegexpMatchEasy0_1K 486 469 -3.50% BenchmarkRegexpMatchEasy1_32 175 167 -4.57% BenchmarkRegexpMatchEasy1_1K 1450 1419 -2.14% BenchmarkRegexpMatchMedium_32 344 338 -1.74% BenchmarkRegexpMatchMedium_1K 112088 109855 -1.99% BenchmarkRegexpMatchHard_32 6078 6003 -1.23% BenchmarkRegexpMatchHard_1K 191166 187499 -1.92% BenchmarkRevcomp 854870445 799012851 -6.53% BenchmarkTemplate 141572691 141508105 -0.05% BenchmarkTimeParse 604 603 -0.17% BenchmarkTimeFormat 579 560 -3.28% LGTM=r R=r CC=golang-codereviews https://golang.org/cl/155450043 --- src/cmd/gc/order.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 3027ed27d4..76820fde7f 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -438,6 +438,9 @@ ordercall(Node *n, Order *order) // cases they are also typically registerizable, so not much harm done. // And this only applies to the multiple-assignment form. // We could do a more precise analysis if needed, like in walk.c. +// +// Ordermapassign also inserts these temporaries if needed for +// calling writebarrierfat with a pointer to n->right. static void ordermapassign(Node *n, Order *order) { @@ -451,7 +454,8 @@ ordermapassign(Node *n, Order *order) case OAS: order->out = list(order->out, n); - if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > widthptr)) && !isaddrokay(n->right)) { + // We call writebarrierfat only for values > 4 pointers long. See walk.c. + if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) { m = n->left; n->left = ordertemp(m->type, order, 0); a = nod(OAS, m, n->left); From 343d113610d22dfcb79442c2ef2e9701b741e451 Mon Sep 17 00:00:00 2001 From: Chris Manghane Date: Wed, 15 Oct 2014 13:13:37 -0700 Subject: [PATCH 376/430] cmd/go: add '_go_' suffix to go files compiled by gccgo to avoid naming conflicts Fixes #8828. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/154410043 --- misc/cgo/test/issue8828.go | 16 ++++++++++++++++ misc/cgo/test/issue8828/issue8828.c | 7 +++++++ misc/cgo/test/issue8828/trivial.go | 8 ++++++++ src/cmd/go/build.go | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 misc/cgo/test/issue8828.go create mode 100644 misc/cgo/test/issue8828/issue8828.c create mode 100644 misc/cgo/test/issue8828/trivial.go diff --git a/misc/cgo/test/issue8828.go b/misc/cgo/test/issue8828.go new file mode 100644 index 0000000000..304797c929 --- /dev/null +++ b/misc/cgo/test/issue8828.go @@ -0,0 +1,16 @@ +// compile + +// 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. + +// Issue 8828: compiling a file with -compiler=gccgo fails if a .c file +// has the same name as compiled directory. + +package cgotest + +import "./issue8828" + +func p() { + issue8828.Bar() +} diff --git a/misc/cgo/test/issue8828/issue8828.c b/misc/cgo/test/issue8828/issue8828.c new file mode 100644 index 0000000000..2950f87cfb --- /dev/null +++ b/misc/cgo/test/issue8828/issue8828.c @@ -0,0 +1,7 @@ +// 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. + +void foo() +{ +} diff --git a/misc/cgo/test/issue8828/trivial.go b/misc/cgo/test/issue8828/trivial.go new file mode 100644 index 0000000000..e7b9a4e573 --- /dev/null +++ b/misc/cgo/test/issue8828/trivial.go @@ -0,0 +1,8 @@ +package issue8828 + +//void foo(); +import "C" + +func Bar() { + C.foo() +} diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 9c7b42650a..49b84709e2 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1852,7 +1852,7 @@ func (gccgoToolchain) linker() string { } func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { - out := p.Name + ".o" + out := "_go_.o" ofile = obj + out gcargs := []string{"-g"} gcargs = append(gcargs, b.gccArchArgs()...) From 2dcb613878d51724e31c45cbbe8cd3e28e4f8f80 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Thu, 16 Oct 2014 09:13:50 +1100 Subject: [PATCH 377/430] unicode/utf8: fix docs for DecodeRune(empty) and friends. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/157080043 --- src/unicode/utf8/utf8.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/unicode/utf8/utf8.go b/src/unicode/utf8/utf8.go index 253295ad35..9ac37184d6 100644 --- a/src/unicode/utf8/utf8.go +++ b/src/unicode/utf8/utf8.go @@ -211,8 +211,11 @@ func FullRuneInString(s string) bool { return !short } -// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes. -// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8. +// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and +// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// the encoding is invalid, it returns (RuneError, 1). Both are impossible +// results for correct UTF-8. +// // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. @@ -221,8 +224,10 @@ func DecodeRune(p []byte) (r rune, size int) { return } -// DecodeRuneInString is like DecodeRune but its input is a string. -// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8. +// DecodeRuneInString is like DecodeRune but its input is a string. If s is +// empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it +// returns (RuneError, 1). Both are impossible results for correct UTF-8. +// // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. @@ -231,8 +236,11 @@ func DecodeRuneInString(s string) (r rune, size int) { return } -// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and its width in bytes. -// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8. +// DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and +// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// the encoding is invalid, it returns (RuneError, 1). Both are impossible +// results for correct UTF-8. +// // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. @@ -268,8 +276,10 @@ func DecodeLastRune(p []byte) (r rune, size int) { return r, size } -// DecodeLastRuneInString is like DecodeLastRune but its input is a string. -// If the encoding is invalid, it returns (RuneError, 1), an impossible result for correct UTF-8. +// DecodeLastRuneInString is like DecodeLastRune but its input is a string. If +// s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, +// it returns (RuneError, 1). Both are impossible results for correct UTF-8. +// // An encoding is invalid if it is incorrect UTF-8, encodes a rune that is // out of range, or is not the shortest possible UTF-8 encoding for the // value. No other validation is performed. From 3c40ee0fe08f95147af9cf7099041f1a4642653d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 15 Oct 2014 19:33:15 -0400 Subject: [PATCH 378/430] cmd/gc: simplify compiled code for explicit zeroing Among other things, *x = T{} does not need a write barrier. The changes here avoid an unnecessary copy even when no pointers are involved, so it may have larger effects. In 6g and 8g, avoid manually repeated STOSQ in favor of writing explicit MOVs, under the theory that the MOVs should have fewer dependencies and pipeline better. Benchmarks compare best of 5 on a 2012 MacBook Pro Core i5 with TurboBoost disabled. Most improvements can be explained by the changes in this CL. The effect in Revcomp is real but harder to explain: none of the instructions in the inner loop changed. I suspect loop alignment but really have no idea. benchmark old new delta BenchmarkBinaryTree17 3809027371 3819907076 +0.29% BenchmarkFannkuch11 3607547556 3686983012 +2.20% BenchmarkFmtFprintfEmpty 118 103 -12.71% BenchmarkFmtFprintfString 289 277 -4.15% BenchmarkFmtFprintfInt 304 290 -4.61% BenchmarkFmtFprintfIntInt 507 458 -9.66% BenchmarkFmtFprintfPrefixedInt 425 408 -4.00% BenchmarkFmtFprintfFloat 555 555 +0.00% BenchmarkFmtManyArgs 1835 1733 -5.56% BenchmarkGobDecode 14738209 14639331 -0.67% BenchmarkGobEncode 14239039 13703571 -3.76% BenchmarkGzip 538211054 538701315 +0.09% BenchmarkGunzip 135430877 134818459 -0.45% BenchmarkHTTPClientServer 116488 116618 +0.11% BenchmarkJSONEncode 28923406 29294334 +1.28% BenchmarkJSONDecode 105779820 104289543 -1.41% BenchmarkMandelbrot200 5791758 5771964 -0.34% BenchmarkGoParse 5376642 5310943 -1.22% BenchmarkRegexpMatchEasy0_32 195 190 -2.56% BenchmarkRegexpMatchEasy0_1K 477 455 -4.61% BenchmarkRegexpMatchEasy1_32 170 165 -2.94% BenchmarkRegexpMatchEasy1_1K 1410 1394 -1.13% BenchmarkRegexpMatchMedium_32 336 329 -2.08% BenchmarkRegexpMatchMedium_1K 108979 106328 -2.43% BenchmarkRegexpMatchHard_32 5854 5821 -0.56% BenchmarkRegexpMatchHard_1K 185089 182838 -1.22% BenchmarkRevcomp 834920364 780202624 -6.55% BenchmarkTemplate 137046937 129728756 -5.34% BenchmarkTimeParse 600 594 -1.00% BenchmarkTimeFormat 559 539 -3.58% LGTM=r R=r CC=golang-codereviews, iant, khr, rlh https://golang.org/cl/157910047 --- src/cmd/6g/ggen.c | 40 ++++++++++++++++++++++++++++++++++------ src/cmd/8g/ggen.c | 28 +++++++++++++++++++++++++++- src/cmd/gc/gen.c | 2 +- src/cmd/gc/go.h | 1 + src/cmd/gc/mparith2.c | 4 ++-- src/cmd/gc/sinit.c | 4 +--- src/cmd/gc/walk.c | 11 ++++++++--- 7 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index 987473ccab..363620769d 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -1102,26 +1102,54 @@ clearfat(Node *nl) c = w % 8; // bytes q = w / 8; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSQ. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSQ loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + agenr(nl, &n1, N); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVQ, &z, &n1); + n1.xoffset += 8; + } + if(c >= 4) { + nodconst(&z, types[TUINT32], 0); + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + c -= 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + savex(D_DI, &n1, &oldn1, N, types[tptr]); agen(nl, &n1); savex(D_AX, &ax, &oldax, N, types[tptr]); gconreg(AMOVL, 0, D_AX); - if(q > 128 || (q >= 4 && nacl)) { + if(q > 128 || nacl) { gconreg(movptr, q, D_CX); gins(AREP, N, N); // repeat gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - } else if(q >= 4) { + } else { p = gins(ADUFFZERO, N, N); p->to.type = D_ADDR; p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s p->to.offset = 2*(128-q); - } else - while(q > 0) { - gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - q--; } z = ax; diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 7c986cc645..6333a60bb8 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -157,7 +157,7 @@ void clearfat(Node *nl) { uint32 w, c, q; - Node n1; + Node n1, z; Prog *p; /* clear a fat object */ @@ -172,6 +172,32 @@ clearfat(Node *nl) c = w % 4; // bytes q = w / 4; // quads + if(q < 4) { + // Write sequence of MOV 0, off(base) instead of using STOSL. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSL loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + regalloc(&n1, types[tptr], N); + agen(nl, &n1); + n1.op = OINDREG; + nodconst(&z, types[TUINT64], 0); + while(q-- > 0) { + n1.type = z.type; + gins(AMOVL, &z, &n1); + n1.xoffset += 4; + } + nodconst(&z, types[TUINT8], 0); + while(c-- > 0) { + n1.type = z.type; + gins(AMOVB, &z, &n1); + n1.xoffset++; + } + regfree(&n1); + return; + } + nodreg(&n1, types[tptr], D_DI); agen(nl, &n1); gconreg(AMOVL, 0, D_AX); diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index eb9eacca8f..a7db833a1a 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -731,7 +731,7 @@ cgen_as(Node *nl, Node *nr) return; } - if(nr == N || isnil(nr)) { + if(nr == N || iszero(nr)) { // externals and heaps should already be clear if(nr == N) { if(nl->class == PEXTERN) diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 8178f7272f..475754145b 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -1374,6 +1374,7 @@ int isnilinter(Type *t); int isptrto(Type *t, int et); int isslice(Type *t); int istype(Type *t, int et); +int iszero(Node *n); void linehist(char *file, int32 off, int relative); NodeList* list(NodeList *l, Node *n); NodeList* list1(Node *n); diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index 5cf98c62c6..fd9f591cea 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -656,7 +656,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) } static int -iszero(Mpint *a) +mpiszero(Mpint *a) { long *a1; int i; @@ -687,7 +687,7 @@ mpdivfract(Mpint *a, Mpint *b) for(j=0; jexpr = n; } -static int +int iszero(Node *n) { NodeList *l; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 241d7d74ad..7f2748c668 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1390,7 +1390,12 @@ walkexpr(Node **np, NodeList **init) case OMAPLIT: case OSTRUCTLIT: case OPTRLIT: - // XXX TODO do we need to clear var? + // NOTE(rsc): Race detector cannot handle seeing + // a STRUCTLIT or ARRAYLIT representing a zero value, + // so make a temporary for those always in race mode. + // Otherwise, leave zero values in place. + if(iszero(n) && !flag_race) + goto ret; var = temp(n->type); anylit(0, n, var, init); n = var; @@ -2009,8 +2014,8 @@ needwritebarrier(Node *l, Node *r) if(isstack(l)) return 0; - // No write barrier for zeroing. - if(r == N) + // No write barrier for implicit or explicit zeroing. + if(r == N || iszero(r)) return 0; // No write barrier for initialization to constant. From e5624edc7e011b71237ba4713878b4b6ae0cab87 Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 15 Oct 2014 17:54:04 -0700 Subject: [PATCH 379/430] crypto/tls: support TLS_FALLBACK_SCSV as a server. A new attack on CBC padding in SSLv3 was released yesterday[1]. Go only supports SSLv3 as a server, not as a client. An easy fix is to change the default minimum version to TLS 1.0 but that seems a little much this late in the 1.4 process as it may break some things. Thus this patch adds server support for TLS_FALLBACK_SCSV[2] -- a mechanism for solving the fallback problem overall. Chrome has implemented this since February and Google has urged others to do so in light of yesterday's news. With this change, clients can indicate that they are doing a fallback connection and Go servers will be able to correctly reject them. [1] http://googleonlinesecurity.blogspot.com/2014/10/this-poodle-bites-exploiting-ssl-30.html [2] https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/157090043 --- src/crypto/tls/alert.go | 2 ++ src/crypto/tls/cipher_suites.go | 5 ++++ src/crypto/tls/handshake_server.go | 12 +++++++++ src/crypto/tls/handshake_server_test.go | 27 +++++++++++++++++-- .../tls/testdata/Server-TLSv11-FallbackSCSV | 17 ++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV diff --git a/src/crypto/tls/alert.go b/src/crypto/tls/alert.go index 0856311e4c..3de4834d3f 100644 --- a/src/crypto/tls/alert.go +++ b/src/crypto/tls/alert.go @@ -35,6 +35,7 @@ const ( alertProtocolVersion alert = 70 alertInsufficientSecurity alert = 71 alertInternalError alert = 80 + alertInappropriateFallback alert = 86 alertUserCanceled alert = 90 alertNoRenegotiation alert = 100 ) @@ -60,6 +61,7 @@ var alertText = map[alert]string{ alertProtocolVersion: "protocol version not supported", alertInsufficientSecurity: "insufficient security level", alertInternalError: "internal error", + alertInappropriateFallback: "inappropriate fallback", alertUserCanceled: "user canceled", alertNoRenegotiation: "no renegotiation", } diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go index 39a51459d2..226e06d68d 100644 --- a/src/crypto/tls/cipher_suites.go +++ b/src/crypto/tls/cipher_suites.go @@ -267,4 +267,9 @@ const ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b + + // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator + // that the client is doing version fallback. See + // https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. + TLS_FALLBACK_SCSV uint16 = 0x5600 ) diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 520675dfb5..0d907656c6 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -224,6 +224,18 @@ Curves: return false, errors.New("tls: no cipher suite supported by both client and server") } + // See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00. + for _, id := range hs.clientHello.cipherSuites { + if id == TLS_FALLBACK_SCSV { + // The client is doing a fallback connection. + if hs.clientHello.vers < c.config.MaxVersion { + c.sendAlert(alertInappropriateFallback) + return false, errors.New("tls: client using inppropriate protocol fallback") + } + break + } + } + return false, nil } diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 580fbc0bfb..0338af457e 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -260,6 +260,9 @@ type serverTest struct { // expectAlert, if true, indicates that a fatal alert should be returned // when handshaking with the server. expectAlert bool + // expectHandshakeErrorIncluding, when not empty, contains a string + // that must be a substring of the error resulting from the handshake. + expectHandshakeErrorIncluding string // validate, if not nil, is a function that will be called with the // ConnectionState of the resulting connection. It returns false if the // ConnectionState is unacceptable. @@ -362,9 +365,17 @@ func (test *serverTest) run(t *testing.T, write bool) { server := Server(serverConn, config) connStateChan := make(chan ConnectionState, 1) go func() { - if _, err := server.Write([]byte("hello, world\n")); err != nil { + var err error + if _, err = server.Write([]byte("hello, world\n")); err != nil { t.Logf("Error from Server.Write: %s", err) } + if len(test.expectHandshakeErrorIncluding) > 0 { + if err == nil { + t.Errorf("Error expected, but no error returned") + } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) { + t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s) + } + } server.Close() serverConn.Close() connStateChan <- server.ConnectionState() @@ -429,7 +440,9 @@ func (test *serverTest) run(t *testing.T, write bool) { recordingConn.Close() if len(recordingConn.flows) < 3 { childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout) - t.Fatalf("Handshake failed") + if len(test.expectHandshakeErrorIncluding) == 0 { + t.Fatalf("Handshake failed") + } } recordingConn.WriteTo(out) fmt.Printf("Wrote %s\n", path) @@ -702,6 +715,16 @@ func TestResumptionDisabled(t *testing.T) { // file for ResumeDisabled does not include a resumption handshake. } +func TestFallbackSCSV(t *testing.T) { + test := &serverTest{ + name: "FallbackSCSV", + // OpenSSL 1.0.1j is needed for the -fallback_scsv option. + command: []string{"openssl", "s_client", "-fallback_scsv"}, + expectHandshakeErrorIncluding: "inppropriate protocol fallback", + } + runServerTestTLS11(t, test) +} + // cert.pem and key.pem were generated with generate_cert.go // Thus, they have no ExtKeyUsage fields and trigger an error // when verification is turned on. diff --git a/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV new file mode 100644 index 0000000000..2d8dfbc3b4 --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV @@ -0,0 +1,17 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 d4 01 00 00 d0 03 02 74 2d da 6d 98 |...........t-.m.| +00000010 ad 3e a5 ec 90 ea d1 5b f0 e0 a7 45 33 d9 5e 8d |.>.....[...E3.^.| +00000020 0f 1d 01 16 6d 00 31 65 ed 50 88 00 00 5e c0 14 |....m.1e.P...^..| +00000030 c0 0a 00 39 00 38 00 88 00 87 c0 0f c0 05 00 35 |...9.8.........5| +00000040 00 84 c0 13 c0 09 00 33 00 32 00 9a 00 99 00 45 |.......3.2.....E| +00000050 00 44 c0 0e c0 04 00 2f 00 96 00 41 00 07 c0 11 |.D...../...A....| +00000060 c0 07 c0 0c c0 02 00 05 00 04 c0 12 c0 08 00 16 |................| +00000070 00 13 c0 0d c0 03 00 0a 00 15 00 12 00 09 00 14 |................| +00000080 00 11 00 08 00 06 00 03 00 ff 56 00 01 00 00 49 |..........V....I| +00000090 00 0b 00 04 03 00 01 02 00 0a 00 34 00 32 00 0e |...........4.2..| +000000a0 00 0d 00 19 00 0b 00 0c 00 18 00 09 00 0a 00 16 |................| +000000b0 00 17 00 08 00 06 00 07 00 14 00 15 00 04 00 05 |................| +000000c0 00 12 00 13 00 01 00 02 00 03 00 0f 00 10 00 11 |................| +000000d0 00 23 00 00 00 0f 00 01 01 |.#.......| +>>> Flow 2 (server to client) +00000000 15 03 02 00 02 02 56 |......V| From 1552e62d70374f86627d7b845ee6effb38a2aebc Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 16 Oct 2014 12:43:17 -0400 Subject: [PATCH 380/430] cmd/gc: elide write barrier for x = x[0:y] and x = append(x, ...) Both of these forms can avoid writing to the base pointer in x (in the slice, always, and in the append, most of the time). For Go 1.5, will need to change the compilation of x = x[0:y] to avoid writing to the base pointer, so that the elision is safe, and will need to change the compilation of x = append(x, ...) to write to the base pointer (through a barrier) only when growing the underlying array, so that the general elision is safe. For Go 1.4, elide the write barrier always, a change that should have equivalent performance characteristics but is much simpler and therefore safer. benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 3910526122 3918802545 +0.21% BenchmarkFannkuch11 3747650699 3732600693 -0.40% BenchmarkFmtFprintfEmpty 106 98.7 -6.89% BenchmarkFmtFprintfString 280 269 -3.93% BenchmarkFmtFprintfInt 296 282 -4.73% BenchmarkFmtFprintfIntInt 467 470 +0.64% BenchmarkFmtFprintfPrefixedInt 418 398 -4.78% BenchmarkFmtFprintfFloat 574 535 -6.79% BenchmarkFmtManyArgs 1768 1818 +2.83% BenchmarkGobDecode 14916799 14925182 +0.06% BenchmarkGobEncode 14110076 13358298 -5.33% BenchmarkGzip 546609795 542630402 -0.73% BenchmarkGunzip 136270657 136496277 +0.17% BenchmarkHTTPClientServer 126574 125245 -1.05% BenchmarkJSONEncode 30006238 27862354 -7.14% BenchmarkJSONDecode 106020889 102664600 -3.17% BenchmarkMandelbrot200 5793550 5818320 +0.43% BenchmarkGoParse 5437608 5463962 +0.48% BenchmarkRegexpMatchEasy0_32 192 179 -6.77% BenchmarkRegexpMatchEasy0_1K 462 460 -0.43% BenchmarkRegexpMatchEasy1_32 168 153 -8.93% BenchmarkRegexpMatchEasy1_1K 1420 1280 -9.86% BenchmarkRegexpMatchMedium_32 338 286 -15.38% BenchmarkRegexpMatchMedium_1K 107435 98027 -8.76% BenchmarkRegexpMatchHard_32 5941 4846 -18.43% BenchmarkRegexpMatchHard_1K 185965 153830 -17.28% BenchmarkRevcomp 795497458 798447829 +0.37% BenchmarkTemplate 132091559 134938425 +2.16% BenchmarkTimeParse 604 608 +0.66% BenchmarkTimeFormat 551 548 -0.54% LGTM=r R=r, dave CC=golang-codereviews, iant, khr, rlh https://golang.org/cl/159960043 --- src/cmd/gc/go.h | 1 + src/cmd/gc/typecheck.c | 50 ++++++++++++++++++++++++++++++++++++++++++ src/cmd/gc/walk.c | 24 +++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 475754145b..965a0550d3 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -283,6 +283,7 @@ struct Node uchar addrtaken; // address taken, even if not moved to heap uchar dupok; // duplicate definitions ok (for func) uchar wrapper; // is method wrapper (for func) + uchar reslice; // this is a reslice x = x[0:y] or x = append(x, ...) schar likely; // likeliness of if statement uchar hasbreak; // has break statement uchar needzero; // if it contains pointers, needs to be zeroed on function entry diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index ff49fe6f92..2ad8ab5bff 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -2814,6 +2814,33 @@ checkassignlist(NodeList *l) checkassign(l->n); } +// Check whether l and r are the same side effect-free expression, +// so that it is safe to reuse one instead of computing both. +static int +samesafeexpr(Node *l, Node *r) +{ + if(l->op != r->op || !eqtype(l->type, r->type)) + return 0; + + switch(l->op) { + case ONAME: + case OCLOSUREVAR: + return l == r; + + case ODOT: + case ODOTPTR: + return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left); + + case OIND: + return samesafeexpr(l->left, r->left); + + case OINDEX: + return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right); + } + + return 0; +} + /* * type check assignment. * if this assignment is the definition of a var on the left side, @@ -2851,6 +2878,29 @@ typecheckas(Node *n) n->typecheck = 1; if(n->left->typecheck == 0) typecheck(&n->left, Erv | Easgn); + + // Recognize slices being updated in place, for better code generation later. + // Don't rewrite if using race detector, to avoid needing to teach race detector + // about this optimization. + if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) { + switch(n->right->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + // For x = x[0:y], x can be updated in place, without touching pointer. + if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left))) + n->right->reslice = 1; + break; + + case OAPPEND: + // For x = append(x, ...), x can be updated in place when there is capacity, + // without touching the pointer; otherwise the emitted code to growslice + // can take care of updating the pointer, and only in that case. + if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n)) + n->right->reslice = 1; + break; + } + } } static void diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 7f2748c668..7649728d37 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -1499,7 +1499,7 @@ fncall(Node *l, Type *rt) if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; - r.op = 0; + memset(&r, 0, sizeof r); if(needwritebarrier(l, &r)) return 1; if(eqtype(l->type, rt)) @@ -2036,6 +2036,28 @@ needwritebarrier(Node *l, Node *r) if(r->op == OADDR && isglobal(r->left)) return 0; + // No write barrier for reslice: x = x[0:y] or x = append(x, ...). + // Both are compiled to modify x directly. + // In the case of append, a write barrier may still be needed + // if the underlying array grows, but the append code can + // generate the write barrier directly in that case. + // (It does not yet, but the cost of the write barrier will be + // small compared to the cost of the allocation.) + if(r->reslice) { + switch(r->op) { + case OSLICE: + case OSLICE3: + case OSLICESTR: + case OAPPEND: + break; + default: + dump("bad reslice-l", l); + dump("bad reslice-r", r); + break; + } + return 0; + } + // Otherwise, be conservative and use write barrier. return 1; } From 8f47c837fd4f550c5b3f25f3725c7101c281e363 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Thu, 16 Oct 2014 22:11:26 +0400 Subject: [PATCH 381/430] runtime: fix memory profiler There are 3 issues: 1. Skip argument of callers is off by 3, so that all allocations are deep inside of memory profiler. 2. Memory profiling statistics are not updated after runtime.GC. 3. Testing package does not update memory profiling statistics before capturing the profile. Also add an end-to-end test. Fixes #8867. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/148710043 --- src/runtime/mgc0.c | 3 +- src/runtime/mprof.go | 2 +- src/runtime/pprof/mprof_test.go | 146 ++++++++++++++++++++++++++++++++ src/testing/testing.go | 1 + 4 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/runtime/pprof/mprof_test.go diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c index 05cabe7085..2ff64aaa30 100644 --- a/src/runtime/mgc0.c +++ b/src/runtime/mgc0.c @@ -1507,7 +1507,6 @@ gc(struct gc_args *args) runtime·sweep.spanidx = 0; runtime·unlock(&runtime·mheap.lock); - // Temporary disable concurrent sweep, because we see failures on builders. if(ConcurrentSweep && !args->eagersweep) { runtime·lock(&runtime·gclock); if(runtime·sweep.g == nil) @@ -1521,6 +1520,8 @@ gc(struct gc_args *args) // Sweep all spans eagerly. while(runtime·sweepone() != -1) runtime·sweep.npausesweep++; + // Do an additional mProf_GC, because all 'free' events are now real as well. + runtime·mProf_GC(); } runtime·mProf_GC(); diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index 89e9915236..f4676fad6e 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -234,7 +234,7 @@ func mProf_GC() { // Called by malloc to record a profiled block. func mProf_Malloc(p unsafe.Pointer, size uintptr) { var stk [maxStack]uintptr - nstk := callers(1, &stk[0], len(stk)) + nstk := callers(4, &stk[0], len(stk)) lock(&proflock) b := stkbucket(memProfile, size, stk[:nstk], true) mp := b.mp() diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go new file mode 100644 index 0000000000..1880b9a707 --- /dev/null +++ b/src/runtime/pprof/mprof_test.go @@ -0,0 +1,146 @@ +// 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 pprof_test + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "runtime" + . "runtime/pprof" + "testing" + "unsafe" +) + +var memSink interface{} + +func allocateTransient1M() { + for i := 0; i < 1024; i++ { + memSink = &struct{ x [1024]byte }{} + } +} + +func allocateTransient2M() { + // prevent inlining + if memSink == nil { + panic("bad") + } + memSink = make([]byte, 2<<20) +} + +type Obj32 struct { + link *Obj32 + pad [32 - unsafe.Sizeof(uintptr(0))]byte +} + +var persistentMemSink *Obj32 + +func allocatePersistent1K() { + for i := 0; i < 32; i++ { + // Can't use slice because that will introduce implicit allocations. + obj := &Obj32{link: persistentMemSink} + persistentMemSink = obj + } +} + +var memoryProfilerRun = 0 + +func TestMemoryProfiler(t *testing.T) { + // Create temp file for the profile. + f, err := ioutil.TempFile("", "memprof") + if err != nil { + t.Fatalf("failed to create temp file: %v", err) + } + defer func() { + f.Close() + os.Remove(f.Name()) + }() + + // Disable sampling, otherwise it's difficult to assert anything. + oldRate := runtime.MemProfileRate + runtime.MemProfileRate = 1 + defer func() { + runtime.MemProfileRate = oldRate + }() + // Allocate a meg to ensure that mcache.next_sample is updated to 1. + for i := 0; i < 1024; i++ { + memSink = make([]byte, 1024) + } + + // Do the interesting allocations. + allocateTransient1M() + allocateTransient2M() + allocatePersistent1K() + memSink = nil + + runtime.GC() // materialize stats + if err := WriteHeapProfile(f); err != nil { + t.Fatalf("failed to write heap profile: %v", err) + } + f.Close() + + memoryProfilerRun++ + checkMemProfile(t, f.Name(), []string{"--alloc_space", "--show_bytes", "--lines"}, []string{ + fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient1M .*mprof_test.go:25`, 1<<20*memoryProfilerRun), + fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient2M .*mprof_test.go:34`, 2<<20*memoryProfilerRun), + fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), + }, []string{}) + + checkMemProfile(t, f.Name(), []string{"--inuse_space", "--show_bytes", "--lines"}, []string{ + fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), + }, []string{ + "allocateTransient1M", + "allocateTransient2M", + }) +} + +func checkMemProfile(t *testing.T, file string, addArgs []string, what []string, whatnot []string) { + args := []string{"tool", "pprof", "--text"} + args = append(args, addArgs...) + args = append(args, os.Args[0], file) + out, err := exec.Command("go", args...).CombinedOutput() + if err != nil { + t.Fatalf("failed to execute pprof: %v\n%v\n", err, string(out)) + } + + matched := make(map[*regexp.Regexp]bool) + for _, s := range what { + matched[regexp.MustCompile(s)] = false + } + var not []*regexp.Regexp + for _, s := range whatnot { + not = append(not, regexp.MustCompile(s)) + } + + s := bufio.NewScanner(bytes.NewReader(out)) + for s.Scan() { + ln := s.Text() + for re := range matched { + if re.MatchString(ln) { + if matched[re] { + t.Errorf("entry '%s' is matched twice", re.String()) + } + matched[re] = true + } + } + for _, re := range not { + if re.MatchString(ln) { + t.Errorf("entry '%s' is matched, but must not", re.String()) + } + } + } + for re, ok := range matched { + if !ok { + t.Errorf("entry '%s' is not matched", re.String()) + } + } + if t.Failed() { + t.Logf("profile:\n%v", string(out)) + } +} diff --git a/src/testing/testing.go b/src/testing/testing.go index f91d860a94..e54a3b8ce4 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -620,6 +620,7 @@ func after() { fmt.Fprintf(os.Stderr, "testing: %s\n", err) os.Exit(2) } + runtime.GC() // materialize all statistics if err = pprof.WriteHeapProfile(f); err != nil { fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err) os.Exit(2) From 7ed8723d49f93b0b983a0a89504a03e455e07537 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 16 Oct 2014 14:44:55 -0400 Subject: [PATCH 382/430] runtime: make pprof a little nicer Update #8942 This does not fully address issue 8942 but it does make the profiles much more useful, until that issue can be fixed completely. LGTM=dvyukov R=r, dvyukov CC=golang-codereviews https://golang.org/cl/159990043 --- src/runtime/proc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 1426790f40..332121e903 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2436,7 +2436,7 @@ extern byte runtime·etext[]; void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) { - int32 n; + int32 n, off; bool traceback; // Do not use global m in this function, use mp instead. // On windows one m is sending reports about all the g's, so m means a wrong thing. @@ -2530,9 +2530,20 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes)) traceback = false; + off = 0; + if(gp == mp->g0 && mp->curg != nil) { + stk[0] = (uintptr)pc; + off = 1; + gp = mp->curg; + pc = (uint8*)gp->sched.pc; + sp = (uint8*)gp->sched.sp; + lr = 0; + traceback = true; + } + n = 0; if(traceback) - n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, false); + n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk+off, nelem(stk)-off, nil, nil, false); if(!traceback || n <= 0) { // Normal traceback is impossible or has failed. // See if it falls into several common cases. From 25f79b9dbeb13d5a6a66290848999de2425ad691 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 16 Oct 2014 14:58:11 -0400 Subject: [PATCH 383/430] runtime/pprof: disable new memory test It cannot run 'go tool pprof'. There is no guarantee that's installed. It needs to build a temporary pprof binary and run that. It also needs to skip the test on systems that can't build and run binaries, namely android and nacl. See src/cmd/nm/nm_test.go's TestNM for a template. Update #8867 Status: Accepted TBR=dvyukov CC=golang-codereviews https://golang.org/cl/153710043 --- src/runtime/malloc.go | 2 ++ src/runtime/pprof/mprof_test.go | 1 + 2 files changed, 3 insertions(+) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 9b4264f2b3..876a2ddaa7 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -40,6 +40,8 @@ type pageID uintptr // base address for all 0-byte allocations var zerobase uintptr +//go:nowritebarrier + // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go index 1880b9a707..76ac02f2b7 100644 --- a/src/runtime/pprof/mprof_test.go +++ b/src/runtime/pprof/mprof_test.go @@ -52,6 +52,7 @@ func allocatePersistent1K() { var memoryProfilerRun = 0 func TestMemoryProfiler(t *testing.T) { + t.Skip("broken test - see issue 8867") // Create temp file for the profile. f, err := ioutil.TempFile("", "memprof") if err != nil { From 70896a78fab1c486af505f9d04f65e29c8a45d0a Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 16 Oct 2014 22:30:14 +0200 Subject: [PATCH 384/430] syscall: don't cache environment variables on Plan 9 Fixes #8849. LGTM=bradfitz, aram R=bradfitz, rsc, aram CC=golang-codereviews https://golang.org/cl/158970045 --- src/syscall/env_plan9.go | 97 +++++++--------------------------------- 1 file changed, 15 insertions(+), 82 deletions(-) diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go index 9345079052..9ea36c886a 100644 --- a/src/syscall/env_plan9.go +++ b/src/syscall/env_plan9.go @@ -8,28 +8,9 @@ package syscall import ( "errors" - "sync" ) var ( - // envOnce guards copyenv, which populates env, envi and envs. - envOnce sync.Once - - // envLock guards env, envi and envs. - envLock sync.RWMutex - - // env maps from an environment variable to its value. - // TODO: remove this? golang.org/issue/8849 - env = make(map[string]string) - - // envi maps from an environment variable to its index in envs. - // TODO: remove this? golang.org/issue/8849 - envi = make(map[string]int) - - // envs contains elements of env in the form "key=value". - // empty strings mean deleted. - envs []string - errZeroLengthKey = errors.New("zero length key") errShortWrite = errors.New("i/o count too small") ) @@ -70,47 +51,14 @@ func writeenv(key, value string) error { return nil } -func copyenv() { - fd, err := Open("/env", O_RDONLY) - if err != nil { - return - } - defer Close(fd) - files, err := readdirnames(fd) - if err != nil { - return - } - envs = make([]string, len(files)) - i := 0 - for _, key := range files { - v, err := readenv(key) - if err != nil { - continue - } - env[key] = v - envs[i] = key + "=" + v - envi[key] = i - i++ - } -} - func Getenv(key string) (value string, found bool) { if len(key) == 0 { return "", false } - - envLock.RLock() - defer envLock.RUnlock() - - if v, ok := env[key]; ok { - return v, true - } v, err := readenv(key) if err != nil { return "", false } - env[key] = v - envs = append(envs, key+"="+v) return v, true } @@ -118,27 +66,14 @@ func Setenv(key, value string) error { if len(key) == 0 { return errZeroLengthKey } - - envLock.Lock() - defer envLock.Unlock() - err := writeenv(key, value) if err != nil { return err } - env[key] = value - envs = append(envs, key+"="+value) - envi[key] = len(envs) - 1 return nil } func Clearenv() { - envLock.Lock() - defer envLock.Unlock() - - env = make(map[string]string) - envi = make(map[string]int) - envs = []string{} RawSyscall(SYS_RFORK, RFCENVG, 0, 0) } @@ -146,30 +81,28 @@ func Unsetenv(key string) error { if len(key) == 0 { return errZeroLengthKey } - - envLock.Lock() - defer envLock.Unlock() - Remove("/env/" + key) - - if i, ok := envi[key]; ok { - delete(env, key) - delete(envi, key) - envs[i] = "" - } return nil } func Environ() []string { - envLock.RLock() - defer envLock.RUnlock() + fd, err := Open("/env", O_RDONLY) + if err != nil { + return nil + } + defer Close(fd) + files, err := readdirnames(fd) + if err != nil { + return nil + } + ret := make([]string, 0, len(files)) - envOnce.Do(copyenv) - ret := make([]string, 0, len(envs)) - for _, pair := range envs { - if pair != "" { - ret = append(ret, pair) + for _, key := range files { + v, err := readenv(key) + if err != nil { + continue } + ret = append(ret, key+"="+v) } return ret } From 68521aa6a8d8c6d8a136858f9be8d6b067498462 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 16 Oct 2014 13:55:32 -0700 Subject: [PATCH 385/430] CONTRIBUTORS: add Damien Neil LGTM=r R=r CC=golang-codereviews https://golang.org/cl/159920044 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a24178b528..d4686215c3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -160,6 +160,7 @@ Corey Thomasson Cosmos Nicolaou Cristian Staretu Damian Gryski +Damien Neil Dan Callahan Dan Peterson Dan Sinclair From 4e1d1965435046192267a6a03dd14773517b28b5 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 16 Oct 2014 13:58:32 -0700 Subject: [PATCH 386/430] reflect: fix struct size calculation to include terminal padding LGTM=r R=r CC=golang-codereviews https://golang.org/cl/160920045 --- src/reflect/all_test.go | 20 ++++++++++++++++++++ src/reflect/type.go | 1 + 2 files changed, 21 insertions(+) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 6bdc9be9dd..40eae0364c 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -2678,6 +2678,26 @@ func TestFuncArg(t *testing.T) { } } +func TestStructArg(t *testing.T) { + type padded struct { + B string + C int32 + } + var ( + gotA padded + gotB uint32 + wantA = padded{"3", 4} + wantB = uint32(5) + ) + f := func(a padded, b uint32) { + gotA, gotB = a, b + } + ValueOf(f).Call([]Value{ValueOf(wantA), ValueOf(wantB)}) + if gotA != wantA || gotB != wantB { + t.Errorf("function called with (%v, %v), want (%v, %v)", gotA, gotB, wantA, wantB) + } +} + var tagGetTests = []struct { Tag StructTag Key string diff --git a/src/reflect/type.go b/src/reflect/type.go index b92d524c3b..4ba1d4fccf 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1544,6 +1544,7 @@ func (gc *gcProg) appendProg(t *rtype) { for i := 0; i < c; i++ { gc.appendProg(t.Field(i).Type.common()) } + gc.align(uintptr(t.align)) } } From 6962c15cec9d77c4402ba0c5a76709d4caf7e78f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 16 Oct 2014 15:08:49 -0700 Subject: [PATCH 387/430] spec: define "variable" Fixes #8496. LGTM=rsc, r, iant R=r, rsc, iant, ken CC=golang-codereviews https://golang.org/cl/148580043 --- doc/go_spec.html | 103 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index 7fa02e4192..97effeaa4a 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -647,6 +647,65 @@ of evaluating constant expressions.

    +

    Variables

    + +

    +A variable is a storage location for holding a value. +The set of permissible values is determined by the +variable's type. +

    + +

    +A variable declaration +or, for function parameters and results, the signature +of a function declaration +or function literal reserves +storage for a named variable. + +Calling the built-in function new +or taking the address of a composite literal +allocates storage for a variable at run time. +Such an anonymous variable is referred to via a (possibly implicit) +pointer indirection. +

    + +

    +Structured variables of array, slice, +and struct types have elements and fields that may +be addressed individually. Each such element +acts like a variable. +

    + +

    +The static type (or just type) of a variable is the +type given in its declaration, the type provided in the +new call or composite literal, or the type of +an element of a structured variable. +Variables of interface type also have a distinct dynamic type, +which is the concrete type of the value assigned to the variable at run time +(unless the value is the predeclared identifier nil, +which has no type). +The dynamic type may vary during execution but values stored in interface +variables are always assignable +to the static type of the variable. +

    + +
    +var x interface{}  // x is nil and has static type interface{}
    +var v *T           // v has value nil, static type *T
    +x = 42             // x has value 42 and dynamic type int
    +x = v              // x has value (*T)(nil) and dynamic type *T
    +
    + +

    +A variable's value is retrieved by referring to the variable in an +expression; it is the most recent value +assigned to the variable. +If a variable has not yet been assigned a value, its value is the +zero value for its type. +

    + +

    Types

    @@ -672,17 +731,6 @@ interface, slice, map, and channel types—may be constructed using type literals.

    -

    -The static type (or just type) of a variable is the -type defined by its declaration. Variables of interface type -also have a distinct dynamic type, which -is the actual type of the value stored in the variable at run time. -The dynamic type may vary during execution but is always -assignable -to the static type of the interface variable. For non-interface -types, the dynamic type is always the static type. -

    -

    Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, @@ -1038,7 +1086,7 @@ struct {

    Pointer types

    -A pointer type denotes the set of all pointers to variables of a given +A pointer type denotes the set of all pointers to variables of a given type, called the base type of the pointer. The value of an uninitialized pointer is nil.

    @@ -1461,7 +1509,7 @@ is different from []string.

    Assignability

    -A value x is assignable to a variable of type T +A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:

    @@ -2266,7 +2314,8 @@ For array and slice literals the following rules apply:

    Taking the address of a composite literal -generates a pointer to a unique instance of the literal's value. +generates a pointer to a unique variable initialized +with the literal's value.

     var pointer *Point3D = &Point3D{y: 1000}
    @@ -3628,7 +3677,7 @@ then the evaluation of &x does too.
     
     

    For an operand x of pointer type *T, the pointer -indirection *x denotes the value of type T pointed +indirection *x denotes the variable of type T pointed to by x. If x is nil, an attempt to evaluate *x will cause a run-time panic. @@ -5405,9 +5454,11 @@ var z complex128

    Allocation

    -The built-in function new takes a type T and -returns a value of type *T. -The memory is initialized as described in the section on +The built-in function new takes a type T, +allocates storage for a variable of that type +at run time, and returns a value of type *T +pointing to it. +The variable is initialized as described in the section on initial values.

    @@ -5425,10 +5476,10 @@ new(S)

    -dynamically allocates memory for a variable of type S, +allocates storage for a variable of type S, initializes it (a=0, b=0.0), and returns a value of type *S containing the address -of the memory. +of the location.

    Making slices, maps and channels

    @@ -5895,10 +5946,12 @@ func main() {

    The zero value

    -When memory is allocated to store a value, either through a declaration -or a call of make or new, -and no explicit initialization is provided, the memory is -given a default initialization. Each element of such a value is +When storage is allocated for a variable, +either through a declaration or a call of new, or when +a new value is created, either through a composite literal or a call +of make, +and no explicit initialization is provided, the variable or value is +given a default value. Each element of such a variable or value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. From 1ba977ccca9c6434e96c39a3099ba8100edb1a88 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 17 Oct 2014 10:11:03 -0400 Subject: [PATCH 388/430] undo CL 159990043 / 421fadcef39a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dmitriy believes this broke Windows. It looks like build.golang.org stopped before that, but it's worth a shot. ««« original CL description runtime: make pprof a little nicer Update #8942 This does not fully address issue 8942 but it does make the profiles much more useful, until that issue can be fixed completely. LGTM=dvyukov R=r, dvyukov CC=golang-codereviews https://golang.org/cl/159990043 »»» TBR=dvyukov CC=golang-codereviews https://golang.org/cl/160030043 --- src/runtime/proc.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/runtime/proc.c b/src/runtime/proc.c index 332121e903..1426790f40 100644 --- a/src/runtime/proc.c +++ b/src/runtime/proc.c @@ -2436,7 +2436,7 @@ extern byte runtime·etext[]; void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) { - int32 n, off; + int32 n; bool traceback; // Do not use global m in this function, use mp instead. // On windows one m is sending reports about all the g's, so m means a wrong thing. @@ -2530,20 +2530,9 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes)) traceback = false; - off = 0; - if(gp == mp->g0 && mp->curg != nil) { - stk[0] = (uintptr)pc; - off = 1; - gp = mp->curg; - pc = (uint8*)gp->sched.pc; - sp = (uint8*)gp->sched.sp; - lr = 0; - traceback = true; - } - n = 0; if(traceback) - n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk+off, nelem(stk)-off, nil, nil, false); + n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, false); if(!traceback || n <= 0) { // Normal traceback is impossible or has failed. // See if it falls into several common cases. From ae933b04e6da9b72ec1affd9375edfa728b79d20 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 17 Oct 2014 16:39:42 +0200 Subject: [PATCH 389/430] CONTRIBUTORS: add James Robinson (Google CLA) LGTM=iant R=golang-codereviews, iant CC=dvyukov, golang-codereviews, jamesr, nigeltao https://golang.org/cl/155530043 --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d4686215c3..b73bce09fc 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -281,6 +281,7 @@ James Fysh James Gray James Meneghello James P. Cooper +James Robinson James Toy James Tucker James Whitehead From 58e357ef160da1d89c68130c83e7a383d8480b16 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 17 Oct 2014 11:03:55 -0400 Subject: [PATCH 390/430] runtime: remove comment that leaked into CL 153710043 This doesn't actually do anything. Maybe it will some day, but maybe not. TBR=r CC=golang-codereviews https://golang.org/cl/155490043 --- src/runtime/malloc.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 876a2ddaa7..9b4264f2b3 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -40,8 +40,6 @@ type pageID uintptr // base address for all 0-byte allocations var zerobase uintptr -//go:nowritebarrier - // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. From fb173c41850c9ad049098be657c923589329fab8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 17 Oct 2014 11:23:15 -0400 Subject: [PATCH 391/430] runtime/pprof: fix test gogo called from GC is okay for the same reasons that gogo called from System or ExternalCode is okay. All three are fake stack traces. Fixes #8408. LGTM=dvyukov, r R=r, dvyukov CC=golang-codereviews https://golang.org/cl/152580043 --- src/runtime/pprof/pprof_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index edd471a0c9..8677cb30c5 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -249,7 +249,7 @@ func TestGoroutineSwitch(t *testing.T) { // exists to record a PC without a traceback. Those are okay. if len(stk) == 2 { f := runtime.FuncForPC(stk[1]) - if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode") { + if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") { return } } From 5e713062b42110b9f7ccd1c326fab0e42b5b8c35 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 17 Oct 2014 09:00:07 -0700 Subject: [PATCH 392/430] encoding/gob: speed up encoding of arrays and slices We borrow a trick from the fmt package and avoid reflection to walk the elements when possible. We could push further with unsafe (and we may) but this is a good start. Decode can benefit similarly; it will be done separately. Use go generate (engen.go) to produce the helper functions (enc_helpers.go). benchmark old ns/op new ns/op delta BenchmarkEndToEndPipe 6593 6482 -1.68% BenchmarkEndToEndByteBuffer 3662 3684 +0.60% BenchmarkEndToEndSliceByteBuffer 350306 351693 +0.40% BenchmarkComplex128Slice 96347 80045 -16.92% BenchmarkInt32Slice 42484 26008 -38.78% BenchmarkFloat64Slice 51143 36265 -29.09% BenchmarkStringSlice 53402 35077 -34.32% LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/156310043 --- src/encoding/gob/enc_helpers.go | 414 ++++++++++++++++++++++++++++++++ src/encoding/gob/encgen.go | 218 +++++++++++++++++ src/encoding/gob/encode.go | 15 +- src/encoding/gob/timing_test.go | 64 +++++ 4 files changed, 708 insertions(+), 3 deletions(-) create mode 100644 src/encoding/gob/enc_helpers.go create mode 100644 src/encoding/gob/encgen.go diff --git a/src/encoding/gob/enc_helpers.go b/src/encoding/gob/enc_helpers.go new file mode 100644 index 0000000000..1e6f307184 --- /dev/null +++ b/src/encoding/gob/enc_helpers.go @@ -0,0 +1,414 @@ +// Created by encgen --output enc_helpers.go; DO NOT EDIT + +// 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 gob + +import ( + "reflect" +) + +var arrayHelper = map[reflect.Kind]encHelper{ + reflect.Bool: encBoolArray, + reflect.Complex64: encComplex64Array, + reflect.Complex128: encComplex128Array, + reflect.Float32: encFloat32Array, + reflect.Float64: encFloat64Array, + reflect.Int: encIntArray, + reflect.Int16: encInt16Array, + reflect.Int32: encInt32Array, + reflect.Int64: encInt64Array, + reflect.Int8: encInt8Array, + reflect.String: encStringArray, + reflect.Uint: encUintArray, + reflect.Uint16: encUint16Array, + reflect.Uint32: encUint32Array, + reflect.Uint64: encUint64Array, + reflect.Uintptr: encUintptrArray, +} + +var sliceHelper = map[reflect.Kind]encHelper{ + reflect.Bool: encBoolSlice, + reflect.Complex64: encComplex64Slice, + reflect.Complex128: encComplex128Slice, + reflect.Float32: encFloat32Slice, + reflect.Float64: encFloat64Slice, + reflect.Int: encIntSlice, + reflect.Int16: encInt16Slice, + reflect.Int32: encInt32Slice, + reflect.Int64: encInt64Slice, + reflect.Int8: encInt8Slice, + reflect.String: encStringSlice, + reflect.Uint: encUintSlice, + reflect.Uint16: encUint16Slice, + reflect.Uint32: encUint32Slice, + reflect.Uint64: encUint64Slice, + reflect.Uintptr: encUintptrSlice, +} + +func encBoolArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encBoolSlice(state, v.Slice(0, v.Len())) +} + +func encBoolSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]bool) + if !ok { + // It is kind bool but not type bool. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != false || state.sendZero { + if x { + state.encodeUint(1) + } else { + state.encodeUint(0) + } + } + } + return true +} + +func encComplex64Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encComplex64Slice(state, v.Slice(0, v.Len())) +} + +func encComplex64Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]complex64) + if !ok { + // It is kind complex64 but not type complex64. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0+0i || state.sendZero { + rpart := floatBits(float64(real(x))) + ipart := floatBits(float64(imag(x))) + state.encodeUint(rpart) + state.encodeUint(ipart) + } + } + return true +} + +func encComplex128Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encComplex128Slice(state, v.Slice(0, v.Len())) +} + +func encComplex128Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]complex128) + if !ok { + // It is kind complex128 but not type complex128. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0+0i || state.sendZero { + rpart := floatBits(real(x)) + ipart := floatBits(imag(x)) + state.encodeUint(rpart) + state.encodeUint(ipart) + } + } + return true +} + +func encFloat32Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encFloat32Slice(state, v.Slice(0, v.Len())) +} + +func encFloat32Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]float32) + if !ok { + // It is kind float32 but not type float32. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + bits := floatBits(float64(x)) + state.encodeUint(bits) + } + } + return true +} + +func encFloat64Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encFloat64Slice(state, v.Slice(0, v.Len())) +} + +func encFloat64Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]float64) + if !ok { + // It is kind float64 but not type float64. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + bits := floatBits(x) + state.encodeUint(bits) + } + } + return true +} + +func encIntArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encIntSlice(state, v.Slice(0, v.Len())) +} + +func encIntSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]int) + if !ok { + // It is kind int but not type int. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeInt(int64(x)) + } + } + return true +} + +func encInt16Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encInt16Slice(state, v.Slice(0, v.Len())) +} + +func encInt16Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]int16) + if !ok { + // It is kind int16 but not type int16. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeInt(int64(x)) + } + } + return true +} + +func encInt32Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encInt32Slice(state, v.Slice(0, v.Len())) +} + +func encInt32Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]int32) + if !ok { + // It is kind int32 but not type int32. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeInt(int64(x)) + } + } + return true +} + +func encInt64Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encInt64Slice(state, v.Slice(0, v.Len())) +} + +func encInt64Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]int64) + if !ok { + // It is kind int64 but not type int64. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeInt(x) + } + } + return true +} + +func encInt8Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encInt8Slice(state, v.Slice(0, v.Len())) +} + +func encInt8Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]int8) + if !ok { + // It is kind int8 but not type int8. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeInt(int64(x)) + } + } + return true +} + +func encStringArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encStringSlice(state, v.Slice(0, v.Len())) +} + +func encStringSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]string) + if !ok { + // It is kind string but not type string. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != "" || state.sendZero { + state.encodeUint(uint64(len(x))) + state.b.WriteString(x) + } + } + return true +} + +func encUintArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encUintSlice(state, v.Slice(0, v.Len())) +} + +func encUintSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]uint) + if !ok { + // It is kind uint but not type uint. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeUint(uint64(x)) + } + } + return true +} + +func encUint16Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encUint16Slice(state, v.Slice(0, v.Len())) +} + +func encUint16Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]uint16) + if !ok { + // It is kind uint16 but not type uint16. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeUint(uint64(x)) + } + } + return true +} + +func encUint32Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encUint32Slice(state, v.Slice(0, v.Len())) +} + +func encUint32Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]uint32) + if !ok { + // It is kind uint32 but not type uint32. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeUint(uint64(x)) + } + } + return true +} + +func encUint64Array(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encUint64Slice(state, v.Slice(0, v.Len())) +} + +func encUint64Slice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]uint64) + if !ok { + // It is kind uint64 but not type uint64. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeUint(x) + } + } + return true +} + +func encUintptrArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return encUintptrSlice(state, v.Slice(0, v.Len())) +} + +func encUintptrSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]uintptr) + if !ok { + // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != 0 || state.sendZero { + state.encodeUint(uint64(x)) + } + } + return true +} diff --git a/src/encoding/gob/encgen.go b/src/encoding/gob/encgen.go new file mode 100644 index 0000000000..fa500e3dab --- /dev/null +++ b/src/encoding/gob/encgen.go @@ -0,0 +1,218 @@ +// Copyright 2009 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. + +// +build ignore + +// encgen writes the helper functions for encoding. Intended to be +// used with go generate; see the invocation in encode.go. + +// TODO: We could do more by being unsafe. Add a -unsafe flag? + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "log" + "os" +) + +var output = flag.String("output", "enc_helpers.go", "file name to write") + +type Type struct { + lower string + upper string + zero string + encoder string +} + +var types = []Type{ + { + "bool", + "Bool", + "false", + `if x { + state.encodeUint(1) + } else { + state.encodeUint(0) + }`, + }, + { + "complex64", + "Complex64", + "0+0i", + `rpart := floatBits(float64(real(x))) + ipart := floatBits(float64(imag(x))) + state.encodeUint(rpart) + state.encodeUint(ipart)`, + }, + { + "complex128", + "Complex128", + "0+0i", + `rpart := floatBits(real(x)) + ipart := floatBits(imag(x)) + state.encodeUint(rpart) + state.encodeUint(ipart)`, + }, + { + "float32", + "Float32", + "0", + `bits := floatBits(float64(x)) + state.encodeUint(bits)`, + }, + { + "float64", + "Float64", + "0", + `bits := floatBits(x) + state.encodeUint(bits)`, + }, + { + "int", + "Int", + "0", + `state.encodeInt(int64(x))`, + }, + { + "int16", + "Int16", + "0", + `state.encodeInt(int64(x))`, + }, + { + "int32", + "Int32", + "0", + `state.encodeInt(int64(x))`, + }, + { + "int64", + "Int64", + "0", + `state.encodeInt(x)`, + }, + { + "int8", + "Int8", + "0", + `state.encodeInt(int64(x))`, + }, + { + "string", + "String", + `""`, + `state.encodeUint(uint64(len(x))) + state.b.WriteString(x)`, + }, + { + "uint", + "Uint", + "0", + `state.encodeUint(uint64(x))`, + }, + { + "uint16", + "Uint16", + "0", + `state.encodeUint(uint64(x))`, + }, + { + "uint32", + "Uint32", + "0", + `state.encodeUint(uint64(x))`, + }, + { + "uint64", + "Uint64", + "0", + `state.encodeUint(x)`, + }, + { + "uintptr", + "Uintptr", + "0", + `state.encodeUint(uint64(x))`, + }, + // uint8 Handled separately. +} + +func main() { + log.SetFlags(0) + log.SetPrefix("helpergen: ") + flag.Parse() + if flag.NArg() != 0 { + log.Fatal("usage: encgen [--output filename]") + } + var b bytes.Buffer + fmt.Fprintf(&b, "// Created by encgen --output %s; DO NOT EDIT\n", *output) + fmt.Fprint(&b, header) + printMaps(&b, "array", "Array") + fmt.Fprint(&b, "\n") + printMaps(&b, "slice", "Slice") + for _, t := range types { + fmt.Fprintf(&b, arrayHelper, t.lower, t.upper) + fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.zero, t.encoder) + } + source, err := format.Source(b.Bytes()) + if err != nil { + log.Fatal("source format error:", err) + } + fd, err := os.Create(*output) + _, err = fd.Write(source) + if err != nil { + log.Fatal(err) + } +} + +func printMaps(b *bytes.Buffer, lowerClass, upperClass string) { + fmt.Fprintf(b, "var %sHelper = map[reflect.Kind]encHelper{\n", lowerClass) + for _, t := range types { + fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass) + } + fmt.Fprintf(b, "}\n") +} + +const header = ` +// 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 gob + +import ( + "reflect" +) + +` + +const arrayHelper = ` +func enc%[2]sArray(state *encoderState, v reflect.Value) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return enc%[2]sSlice(state, v.Slice(0, v.Len())) +} +` + +const sliceHelper = ` +func enc%[2]sSlice(state *encoderState, v reflect.Value) bool { + slice, ok := v.Interface().([]%[1]s) + if !ok { + // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely. + return false + } + for _, x := range slice { + if x != %[3]s || state.sendZero { + %[4]s + } + } + return true +} +` diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index 04a85410c6..3b8d0b4271 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run encgen.go -output enc_helpers.go + package gob import ( @@ -13,6 +15,8 @@ import ( const uint64Size = 8 +type encHelper func(state *encoderState, v reflect.Value) bool + // encoderState is the global execution state of an instance of the encoder. // Field numbers are delta encoded and always increase. The field // number is initialized to -1 so 0 comes out as delta(1). A delta of @@ -291,12 +295,15 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle } // encodeArray encodes an array. -func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) { +func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) { state := enc.newEncoderState(b) defer enc.freeEncoderState(state) state.fieldnum = -1 state.sendZero = true state.encodeUint(uint64(length)) + if helper != nil && helper(state, value) { + return + } for i := 0; i < length; i++ { elem := value.Index(i) if elemIndir > 0 { @@ -501,19 +508,21 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[ } // Slices have a header; we decode it to find the underlying array. elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) + helper := sliceHelper[t.Elem().Kind()] op = func(i *encInstr, state *encoderState, slice reflect.Value) { if !state.sendZero && slice.Len() == 0 { return } state.update(i) - state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len()) + state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len(), helper) } case reflect.Array: // True arrays have size in the type. elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) + helper := arrayHelper[t.Elem().Kind()] op = func(i *encInstr, state *encoderState, array reflect.Value) { state.update(i) - state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len()) + state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper) } case reflect.Map: keyOp, keyIndir := encOpFor(t.Key(), inProgress, building) diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go index ec55c4d63d..abfe936e83 100644 --- a/src/encoding/gob/timing_test.go +++ b/src/encoding/gob/timing_test.go @@ -131,3 +131,67 @@ func TestCountDecodeMallocs(t *testing.T) { t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs) } } + +func BenchmarkComplex128Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]complex128, 1000) + for i := range a { + a[i] = 1.2 + 3.4i + } + for i := 0; i < b.N; i++ { + buf.Reset() + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkInt32Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]int32, 1000) + for i := range a { + a[i] = 1234 + } + for i := 0; i < b.N; i++ { + buf.Reset() + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkFloat64Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]float64, 1000) + for i := range a { + a[i] = 1.23e4 + } + for i := 0; i < b.N; i++ { + buf.Reset() + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkStringSlice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]string, 1000) + for i := range a { + a[i] = "now is the time" + } + for i := 0; i < b.N; i++ { + buf.Reset() + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + } +} From 0d81b72e1bf5518b503dbefd0764bfa7e47dcecf Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 17 Oct 2014 12:54:31 -0400 Subject: [PATCH 393/430] reflect: a few microoptimizations Replace i < 0 || i >= x with uint(i) >= uint(x). Shorten a few other code sequences. Move the kind bits to the bottom of the flag word, to avoid shifts. LGTM=r R=r, bradfitz CC=golang-codereviews https://golang.org/cl/159020043 --- src/reflect/makefunc.go | 6 +- src/reflect/type.go | 2 +- src/reflect/value.go | 205 +++++++++++++++++----------------------- 3 files changed, 91 insertions(+), 122 deletions(-) diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go index 1072c7fabe..d89f7f6811 100644 --- a/src/reflect/makefunc.go +++ b/src/reflect/makefunc.go @@ -60,7 +60,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn} - return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift} + return Value{t, unsafe.Pointer(impl), flag(Func)} } // makeFuncStub is an assembly function that is the code half of @@ -91,7 +91,7 @@ func makeMethodValue(op string, v Value) Value { // Ignoring the flagMethod bit, v describes the receiver, not the method type. fl := v.flag & (flagRO | flagAddr | flagIndir) - fl |= flag(v.typ.Kind()) << flagKindShift + fl |= flag(v.typ.Kind()) rcvr := Value{v.typ, v.ptr, fl} // v.Type returns the actual type of the method value. @@ -118,7 +118,7 @@ func makeMethodValue(op string, v Value) Value { // but we want Interface() and other operations to fail early. methodReceiver(op, fv.rcvr, fv.method) - return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<> flagKindShift) & flagKindMask) + return Kind(f & flagKindMask) } // pointer returns the underlying pointer represented by v. @@ -107,14 +106,14 @@ func packEface(v Value) interface{} { memmove(c, ptr, t.size) ptr = c } - e.word = iword(ptr) + e.word = ptr case v.flag&flagIndir != 0: // Value is indirect, but interface is direct. We need // to load the data at v.ptr into the interface data word. - e.word = iword(*(*unsafe.Pointer)(v.ptr)) + e.word = *(*unsafe.Pointer)(v.ptr) default: // Value is direct, and so is the interface. - e.word = iword(v.ptr) + e.word = v.ptr } // Now, fill in the type portion. We're very careful here not // to have any operation between the e.word and e.typ assignments @@ -132,7 +131,7 @@ func unpackEface(i interface{}) Value { if t == nil { return Value{} } - f := flag(t.Kind()) << flagKindShift + f := flag(t.Kind()) if ifaceIndir(t) { f |= flagIndir } @@ -165,20 +164,10 @@ func methodName() string { return f.Name() } -// An iword is the word that would be stored in an -// interface to represent a given value v. Specifically, if v is -// bigger than a pointer, its word is a pointer to v's data. -// Otherwise, its word holds the data stored -// in its leading bytes (so is not a pointer). -// This type is very dangerous for the garbage collector because -// it must be treated conservatively. We try to never expose it -// to the GC here so that GC remains precise. -type iword unsafe.Pointer - // emptyInterface is the header for an interface{} value. type emptyInterface struct { typ *rtype - word iword + word unsafe.Pointer } // nonEmptyInterface is the header for a interface value with methods. @@ -192,7 +181,7 @@ type nonEmptyInterface struct { unused int32 fun [100000]unsafe.Pointer // method table } - word iword + word unsafe.Pointer } // mustBe panics if f's kind is not expected. @@ -202,9 +191,8 @@ type nonEmptyInterface struct { // v.flag.mustBe(Bool), which will only bother to copy the // single important word for the receiver. func (f flag) mustBe(expected Kind) { - k := f.kind() - if k != expected { - panic(&ValueError{methodName(), k}) + if f.kind() != expected { + panic(&ValueError{methodName(), f.kind()}) } } @@ -244,7 +232,7 @@ func (v Value) Addr() Value { if v.flag&flagAddr == 0 { panic("reflect.Value.Addr of unaddressable value") } - return Value{v.typ.ptrTo(), v.ptr, (v.flag & flagRO) | flag(Ptr)<= len(tt.methods) { + if uint(i) >= uint(len(tt.methods)) { panic("reflect: internal error: invalid method index") } m := &tt.methods[i] @@ -554,7 +542,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn } else { rcvrtype = v.typ ut := v.typ.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { + if ut == nil || uint(i) >= uint(len(ut.methods)) { panic("reflect: internal error: invalid method index") } m := &ut.methods[i] @@ -652,7 +640,7 @@ func (v Value) Cap() int { // Slice is always bigger than a word; assume flagIndir. return (*sliceHeader)(v.ptr).Cap } - panic(&ValueError{"reflect.Value.Cap", k}) + panic(&ValueError{"reflect.Value.Cap", v.kind()}) } // Close closes the channel v. @@ -673,7 +661,7 @@ func (v Value) Complex() complex128 { case Complex128: return *(*complex128)(v.ptr) } - panic(&ValueError{"reflect.Value.Complex", k}) + panic(&ValueError{"reflect.Value.Complex", v.kind()}) } // Elem returns the value that the interface v contains @@ -709,42 +697,37 @@ func (v Value) Elem() Value { tt := (*ptrType)(unsafe.Pointer(v.typ)) typ := tt.elem fl := v.flag&flagRO | flagIndir | flagAddr - fl |= flag(typ.Kind() << flagKindShift) + fl |= flag(typ.Kind()) return Value{typ, ptr, fl} } - panic(&ValueError{"reflect.Value.Elem", k}) + panic(&ValueError{"reflect.Value.Elem", v.kind()}) } // Field returns the i'th field of the struct v. // It panics if v's Kind is not Struct or i is out of range. func (v Value) Field(i int) Value { - v.mustBe(Struct) + if v.kind() != Struct { + panic(&ValueError{"reflect.Value.Field", v.kind()}) + } tt := (*structType)(unsafe.Pointer(v.typ)) - if i < 0 || i >= len(tt.fields) { + if uint(i) >= uint(len(tt.fields)) { panic("reflect: Field index out of range") } field := &tt.fields[i] typ := field.typ // Inherit permission bits from v. - fl := v.flag & (flagRO | flagIndir | flagAddr) + fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // Using an unexported field forces flagRO. if field.pkgPath != nil { fl |= flagRO } - fl |= flag(typ.Kind()) << flagKindShift - - var ptr unsafe.Pointer - if fl&flagIndir != 0 { - // Indirect. Just bump pointer. - ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset) - } else { - if field.offset != 0 { - panic("field access of ptr value isn't at offset 0") - } - ptr = v.ptr - } - + // Either flagIndir is set and v.ptr points at struct, + // or flagIndir is not set and v.ptr is the actual struct data. + // In the former case, we want v.ptr + offset. + // In the latter case, we must be have field.offset = 0, + // so v.ptr + field.offset is still okay. + ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset) return Value{typ, ptr, fl} } @@ -785,7 +768,6 @@ func (v Value) FieldByName(name string) Value { // It panics if v's Kind is not struct. // It returns the zero Value if no field was found. func (v Value) FieldByNameFunc(match func(string) bool) Value { - v.mustBe(Struct) if f, ok := v.typ.FieldByNameFunc(match); ok { return v.FieldByIndex(f.Index) } @@ -802,7 +784,7 @@ func (v Value) Float() float64 { case Float64: return *(*float64)(v.ptr) } - panic(&ValueError{"reflect.Value.Float", k}) + panic(&ValueError{"reflect.Value.Float", v.kind()}) } var uint8Type = TypeOf(uint8(0)).(*rtype) @@ -810,60 +792,47 @@ var uint8Type = TypeOf(uint8(0)).(*rtype) // Index returns v's i'th element. // It panics if v's Kind is not Array, Slice, or String or i is out of range. func (v Value) Index(i int) Value { - k := v.kind() - switch k { + switch v.kind() { case Array: tt := (*arrayType)(unsafe.Pointer(v.typ)) - if i < 0 || i > int(tt.len) { + if uint(i) >= uint(tt.len) { panic("reflect: array index out of range") } typ := tt.elem - fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array - fl |= flag(typ.Kind()) << flagKindShift offset := uintptr(i) * typ.size - var val unsafe.Pointer - if fl&flagIndir != 0 { - // Indirect. Just bump pointer. - val = unsafe.Pointer(uintptr(v.ptr) + offset) - } else { - if offset != 0 { - // This is an array stored inline in an interface value. - // And the array element type has pointers. - // Since the inline storage space is only a single word, - // this implies we must be holding an array of length 1 - // with an element type that is a single pointer. - // If the offset is not 0, something has gone wrong. - panic("reflect: internal error: unexpected array index") - } - val = v.ptr - } + // Either flagIndir is set and v.ptr points at array, + // or flagIndir is not set and v.ptr is the actual array data. + // In the former case, we want v.ptr + offset. + // In the latter case, we must be doing Index(0), so offset = 0, + // so v.ptr + offset is still okay. + val := unsafe.Pointer(uintptr(v.ptr) + offset) + fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind()) // bits same as overall array return Value{typ, val, fl} case Slice: // Element flag same as Elem of Ptr. // Addressable, indirect, possibly read-only. - fl := flagAddr | flagIndir | v.flag&flagRO s := (*sliceHeader)(v.ptr) - if i < 0 || i >= s.Len { + if uint(i) >= uint(s.Len) { panic("reflect: slice index out of range") } tt := (*sliceType)(unsafe.Pointer(v.typ)) typ := tt.elem - fl |= flag(typ.Kind()) << flagKindShift val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size) + fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind()) return Value{typ, val, fl} case String: - fl := v.flag&flagRO | flag(Uint8<= s.Len { + if uint(i) >= uint(s.Len) { panic("reflect: string index out of range") } p := unsafe.Pointer(uintptr(s.Data) + uintptr(i)) + fl := v.flag&flagRO | flag(Uint8) | flagIndir return Value{uint8Type, p, fl} } - panic(&ValueError{"reflect.Value.Index", k}) + panic(&ValueError{"reflect.Value.Index", v.kind()}) } // Int returns v's underlying value, as an int64. @@ -883,7 +852,7 @@ func (v Value) Int() int64 { case Int64: return int64(*(*int64)(p)) } - panic(&ValueError{"reflect.Value.Int", k}) + panic(&ValueError{"reflect.Value.Int", v.kind()}) } // CanInterface returns true if Interface can be used without panicking. @@ -970,7 +939,7 @@ func (v Value) IsNil() bool { // Both are always bigger than a word; assume flagIndir. return *(*unsafe.Pointer)(v.ptr) == nil } - panic(&ValueError{"reflect.Value.IsNil", k}) + panic(&ValueError{"reflect.Value.IsNil", v.kind()}) } // IsValid returns true if v represents a value. @@ -1007,7 +976,7 @@ func (v Value) Len() int { // String is bigger than a word; assume flagIndir. return (*stringHeader)(v.ptr).Len } - panic(&ValueError{"reflect.Value.Len", k}) + panic(&ValueError{"reflect.Value.Len", v.kind()}) } // MapIndex returns the value associated with key in the map v. @@ -1039,7 +1008,7 @@ func (v Value) MapIndex(key Value) Value { } typ := tt.elem fl := (v.flag | key.flag) & flagRO - fl |= flag(typ.Kind()) << flagKindShift + fl |= flag(typ.Kind()) if ifaceIndir(typ) { // Copy result so future changes to the map // won't change the underlying value. @@ -1060,7 +1029,7 @@ func (v Value) MapKeys() []Value { tt := (*mapType)(unsafe.Pointer(v.typ)) keyType := tt.key - fl := v.flag&flagRO | flag(keyType.Kind())<= v.typ.NumMethod() { + if v.flag&flagMethod != 0 || uint(i) >= uint(v.typ.NumMethod()) { panic("reflect: Method index out of range") } if v.typ.Kind() == Interface && v.IsNil() { panic("reflect: Method on nil interface value") } fl := v.flag & (flagRO | flagIndir) - fl |= flag(Func) << flagKindShift + fl |= flag(Func) fl |= flag(i)<> (64 - bitSize) return x != trunc } - panic(&ValueError{"reflect.Value.OverflowInt", k}) + panic(&ValueError{"reflect.Value.OverflowInt", v.kind()}) } // OverflowUint returns true if the uint64 x cannot be represented by v's type. @@ -1206,7 +1175,7 @@ func (v Value) OverflowUint(x uint64) bool { trunc := (x << (64 - bitSize)) >> (64 - bitSize) return x != trunc } - panic(&ValueError{"reflect.Value.OverflowUint", k}) + panic(&ValueError{"reflect.Value.OverflowUint", v.kind()}) } // Pointer returns v's value as a uintptr. @@ -1251,7 +1220,7 @@ func (v Value) Pointer() uintptr { case Slice: return (*SliceHeader)(v.ptr).Data } - panic(&ValueError{"reflect.Value.Pointer", k}) + panic(&ValueError{"reflect.Value.Pointer", v.kind()}) } // Recv receives and returns a value from the channel v. @@ -1273,7 +1242,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) { panic("reflect: recv on send-only channel") } t := tt.elem - val = Value{t, nil, flag(t.Kind()) << flagKindShift} + val = Value{t, nil, flag(t.Kind())} var p unsafe.Pointer if ifaceIndir(t) { p = unsafe_New(t) @@ -1370,7 +1339,7 @@ func (v Value) SetComplex(x complex128) { v.mustBeAssignable() switch k := v.kind(); k { default: - panic(&ValueError{"reflect.Value.SetComplex", k}) + panic(&ValueError{"reflect.Value.SetComplex", v.kind()}) case Complex64: *(*complex64)(v.ptr) = complex64(x) case Complex128: @@ -1384,7 +1353,7 @@ func (v Value) SetFloat(x float64) { v.mustBeAssignable() switch k := v.kind(); k { default: - panic(&ValueError{"reflect.Value.SetFloat", k}) + panic(&ValueError{"reflect.Value.SetFloat", v.kind()}) case Float32: *(*float32)(v.ptr) = float32(x) case Float64: @@ -1398,7 +1367,7 @@ func (v Value) SetInt(x int64) { v.mustBeAssignable() switch k := v.kind(); k { default: - panic(&ValueError{"reflect.Value.SetInt", k}) + panic(&ValueError{"reflect.Value.SetInt", v.kind()}) case Int: *(*int)(v.ptr) = int(x) case Int8: @@ -1419,7 +1388,7 @@ func (v Value) SetLen(n int) { v.mustBeAssignable() v.mustBe(Slice) s := (*sliceHeader)(v.ptr) - if n < 0 || n > int(s.Cap) { + if uint(n) > uint(s.Cap) { panic("reflect: slice length out of range in SetLen") } s.Len = n @@ -1477,7 +1446,7 @@ func (v Value) SetUint(x uint64) { v.mustBeAssignable() switch k := v.kind(); k { default: - panic(&ValueError{"reflect.Value.SetUint", k}) + panic(&ValueError{"reflect.Value.SetUint", v.kind()}) case Uint: *(*uint)(v.ptr) = uint(x) case Uint8: @@ -1520,7 +1489,7 @@ func (v Value) Slice(i, j int) Value { ) switch kind := v.kind(); kind { default: - panic(&ValueError{"reflect.Value.Slice", kind}) + panic(&ValueError{"reflect.Value.Slice", v.kind()}) case Array: if v.flag&flagAddr == 0 { @@ -1564,7 +1533,7 @@ func (v Value) Slice(i, j int) Value { s.Data = base } - fl := v.flag&flagRO | flagIndir | flag(Slice)<= len(tt.methods) { + if uint(i) >= uint(len(tt.methods)) { panic("reflect: internal error: invalid method index") } m := &tt.methods[i] @@ -1682,7 +1651,7 @@ func (v Value) Type() Type { } // Method on concrete type. ut := v.typ.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { + if ut == nil || uint(i) >= uint(len(ut.methods)) { panic("reflect: internal error: invalid method index") } m := &ut.methods[i] @@ -1708,7 +1677,7 @@ func (v Value) Uint() uint64 { case Uintptr: return uint64(*(*uintptr)(p)) } - panic(&ValueError{"reflect.Value.Uint", k}) + panic(&ValueError{"reflect.Value.Uint", v.kind()}) } // UnsafeAddr returns a pointer to v's data. @@ -1998,7 +1967,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ)) t := tt.elem p := runcases[chosen].val - fl := flag(t.Kind()) << flagKindShift + fl := flag(t.Kind()) if ifaceIndir(t) { recv = Value{t, p, fl | flagIndir} } else { @@ -2033,7 +2002,7 @@ func MakeSlice(typ Type, len, cap int) Value { } s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap} - return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)< interface From cfafa9f4cb1a20c4a9490d5bd8e561e650562f54 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 17 Oct 2014 13:10:42 -0400 Subject: [PATCH 394/430] cmd/gc: don't use static init to initialize small structs, fields Better to avoid the memory loads and just use immediate constants. This especially applies to zeroing, which was being done by copying zeros from elsewhere in the binary, even if the value was going to be completely initialized with non-zero values. The zero writes were optimized away but the zero loads from the data segment were not. LGTM=r R=r, bradfitz, dvyukov CC=golang-codereviews https://golang.org/cl/152700045 --- src/cmd/gc/sinit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 2a811513c9..8ad7ae7abb 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -1067,7 +1067,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) if(t->etype != TSTRUCT) fatal("anylit: not struct"); - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1090,7 +1090,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < structcount(t)) { + if(simplename(var) || count(n->list) < structcount(t)) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); @@ -1107,7 +1107,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) break; } - if(simplename(var)) { + if(simplename(var) && count(n->list) > 4) { if(ctxt == 0) { // lay out static data @@ -1130,7 +1130,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) } // initialize of not completely specified - if(count(n->list) < t->bound) { + if(simplename(var) || count(n->list) < t->bound) { a = nod(OAS, var, N); typecheck(&a, Etop); walkexpr(&a, init); From f4de59e234bfa7fb2a3a86764f390b09d4249a9b Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 17 Oct 2014 21:28:47 +0400 Subject: [PATCH 395/430] runtime/pprof: fix memory profiler test Don't use cmd/pprof as it is not necessary installed and does not work on nacl and plan9. Instead just look at the raw profile. LGTM=crawshaw, rsc R=golang-codereviews, crawshaw, 0intro, rsc CC=golang-codereviews https://golang.org/cl/159010043 --- src/runtime/pprof/mprof_test.go | 88 ++++++++------------------------- 1 file changed, 20 insertions(+), 68 deletions(-) diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go index 76ac02f2b7..ebf53dd66b 100644 --- a/src/runtime/pprof/mprof_test.go +++ b/src/runtime/pprof/mprof_test.go @@ -5,12 +5,8 @@ package pprof_test import ( - "bufio" "bytes" "fmt" - "io/ioutil" - "os" - "os/exec" "regexp" "runtime" . "runtime/pprof" @@ -52,23 +48,13 @@ func allocatePersistent1K() { var memoryProfilerRun = 0 func TestMemoryProfiler(t *testing.T) { - t.Skip("broken test - see issue 8867") - // Create temp file for the profile. - f, err := ioutil.TempFile("", "memprof") - if err != nil { - t.Fatalf("failed to create temp file: %v", err) - } - defer func() { - f.Close() - os.Remove(f.Name()) - }() - // Disable sampling, otherwise it's difficult to assert anything. oldRate := runtime.MemProfileRate runtime.MemProfileRate = 1 defer func() { runtime.MemProfileRate = oldRate }() + // Allocate a meg to ensure that mcache.next_sample is updated to 1. for i := 0; i < 1024; i++ { memSink = make([]byte, 1024) @@ -81,67 +67,33 @@ func TestMemoryProfiler(t *testing.T) { memSink = nil runtime.GC() // materialize stats - if err := WriteHeapProfile(f); err != nil { + var buf bytes.Buffer + if err := Lookup("heap").WriteTo(&buf, 1); err != nil { t.Fatalf("failed to write heap profile: %v", err) } - f.Close() memoryProfilerRun++ - checkMemProfile(t, f.Name(), []string{"--alloc_space", "--show_bytes", "--lines"}, []string{ - fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient1M .*mprof_test.go:25`, 1<<20*memoryProfilerRun), - fmt.Sprintf(`%v .* runtime/pprof_test\.allocateTransient2M .*mprof_test.go:34`, 2<<20*memoryProfilerRun), - fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), - }, []string{}) - checkMemProfile(t, f.Name(), []string{"--inuse_space", "--show_bytes", "--lines"}, []string{ - fmt.Sprintf(`%v .* runtime/pprof_test\.allocatePersistent1K .*mprof_test.go:47`, 1<<10*memoryProfilerRun), - }, []string{ - "allocateTransient1M", - "allocateTransient2M", - }) -} + tests := []string{ + fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocatePersistent1K\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:43 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:66 +`, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun), -func checkMemProfile(t *testing.T, file string, addArgs []string, what []string, whatnot []string) { - args := []string{"tool", "pprof", "--text"} - args = append(args, addArgs...) - args = append(args, os.Args[0], file) - out, err := exec.Command("go", args...).CombinedOutput() - if err != nil { - t.Fatalf("failed to execute pprof: %v\n%v\n", err, string(out)) + fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocateTransient1M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:21 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:64 +`, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun), + + fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ +# 0x[0-9,a-f]+ runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:30 +# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:65 +`, memoryProfilerRun, (2<<20)*memoryProfilerRun), } - matched := make(map[*regexp.Regexp]bool) - for _, s := range what { - matched[regexp.MustCompile(s)] = false - } - var not []*regexp.Regexp - for _, s := range whatnot { - not = append(not, regexp.MustCompile(s)) - } - - s := bufio.NewScanner(bytes.NewReader(out)) - for s.Scan() { - ln := s.Text() - for re := range matched { - if re.MatchString(ln) { - if matched[re] { - t.Errorf("entry '%s' is matched twice", re.String()) - } - matched[re] = true - } + for _, test := range tests { + if !regexp.MustCompile(test).Match(buf.Bytes()) { + t.Fatalf("The entry did not match:\n%v\n\nProfile:\n%v\n", test, buf.String()) } - for _, re := range not { - if re.MatchString(ln) { - t.Errorf("entry '%s' is matched, but must not", re.String()) - } - } - } - for re, ok := range matched { - if !ok { - t.Errorf("entry '%s' is not matched", re.String()) - } - } - if t.Failed() { - t.Logf("profile:\n%v", string(out)) } } From 9965e4022030f56fc241be8934d5e6b95ac84900 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 17 Oct 2014 12:37:41 -0700 Subject: [PATCH 396/430] encoding/gob: custom array/slice decoders Use go generate to write better loops for decoding arrays, just as we did for encoding. It doesn't help as much, relatively speaking, but it's still noticeable. benchmark old ns/op new ns/op delta BenchmarkDecodeComplex128Slice 202348 184529 -8.81% BenchmarkDecodeFloat64Slice 135800 120979 -10.91% BenchmarkDecodeInt32Slice 121200 105149 -13.24% BenchmarkDecodeStringSlice 288129 278214 -3.44% LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/154420044 --- src/encoding/gob/dec_helpers.go | 468 ++++++++++++++++++++++++++++++++ src/encoding/gob/decgen.go | 240 ++++++++++++++++ src/encoding/gob/decode.go | 33 ++- src/encoding/gob/enc_helpers.go | 4 +- src/encoding/gob/encgen.go | 10 +- src/encoding/gob/encode.go | 4 +- src/encoding/gob/timing_test.go | 170 ++++++++++-- 7 files changed, 887 insertions(+), 42 deletions(-) create mode 100644 src/encoding/gob/dec_helpers.go create mode 100644 src/encoding/gob/decgen.go diff --git a/src/encoding/gob/dec_helpers.go b/src/encoding/gob/dec_helpers.go new file mode 100644 index 0000000000..ae59ef0ac7 --- /dev/null +++ b/src/encoding/gob/dec_helpers.go @@ -0,0 +1,468 @@ +// Created by decgen --output dec_helpers.go; DO NOT EDIT + +// 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 gob + +import ( + "math" + "reflect" +) + +var decArrayHelper = map[reflect.Kind]decHelper{ + reflect.Bool: decBoolArray, + reflect.Complex64: decComplex64Array, + reflect.Complex128: decComplex128Array, + reflect.Float32: decFloat32Array, + reflect.Float64: decFloat64Array, + reflect.Int: decIntArray, + reflect.Int16: decInt16Array, + reflect.Int32: decInt32Array, + reflect.Int64: decInt64Array, + reflect.Int8: decInt8Array, + reflect.String: decStringArray, + reflect.Uint: decUintArray, + reflect.Uint16: decUint16Array, + reflect.Uint32: decUint32Array, + reflect.Uint64: decUint64Array, + reflect.Uintptr: decUintptrArray, +} + +var decSliceHelper = map[reflect.Kind]decHelper{ + reflect.Bool: decBoolSlice, + reflect.Complex64: decComplex64Slice, + reflect.Complex128: decComplex128Slice, + reflect.Float32: decFloat32Slice, + reflect.Float64: decFloat64Slice, + reflect.Int: decIntSlice, + reflect.Int16: decInt16Slice, + reflect.Int32: decInt32Slice, + reflect.Int64: decInt64Slice, + reflect.Int8: decInt8Slice, + reflect.String: decStringSlice, + reflect.Uint: decUintSlice, + reflect.Uint16: decUint16Slice, + reflect.Uint32: decUint32Slice, + reflect.Uint64: decUint64Slice, + reflect.Uintptr: decUintptrSlice, +} + +func decBoolArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decBoolSlice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decBoolSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]bool) + if !ok { + // It is kind bool but not type bool. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding bool array or slice: length exceeds input size (%!d(string=Bool) elements)", length) + } + slice[i] = state.decodeUint() != 0 + } + return true +} + +func decComplex64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decComplex64Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decComplex64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]complex64) + if !ok { + // It is kind complex64 but not type complex64. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding complex64 array or slice: length exceeds input size (%!d(string=Complex64) elements)", length) + } + real := float32FromBits(state.decodeUint(), ovfl) + imag := float32FromBits(state.decodeUint(), ovfl) + slice[i] = complex(float32(real), float32(imag)) + } + return true +} + +func decComplex128Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decComplex128Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decComplex128Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]complex128) + if !ok { + // It is kind complex128 but not type complex128. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding complex128 array or slice: length exceeds input size (%!d(string=Complex128) elements)", length) + } + real := float64FromBits(state.decodeUint()) + imag := float64FromBits(state.decodeUint()) + slice[i] = complex(real, imag) + } + return true +} + +func decFloat32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decFloat32Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decFloat32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]float32) + if !ok { + // It is kind float32 but not type float32. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding float32 array or slice: length exceeds input size (%!d(string=Float32) elements)", length) + } + slice[i] = float32(float32FromBits(state.decodeUint(), ovfl)) + } + return true +} + +func decFloat64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decFloat64Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decFloat64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]float64) + if !ok { + // It is kind float64 but not type float64. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding float64 array or slice: length exceeds input size (%!d(string=Float64) elements)", length) + } + slice[i] = float64FromBits(state.decodeUint()) + } + return true +} + +func decIntArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decIntSlice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decIntSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]int) + if !ok { + // It is kind int but not type int. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding int array or slice: length exceeds input size (%!d(string=Int) elements)", length) + } + x := state.decodeInt() + // MinInt and MaxInt + if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x { + error_(ovfl) + } + slice[i] = int(x) + } + return true +} + +func decInt16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decInt16Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decInt16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]int16) + if !ok { + // It is kind int16 but not type int16. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding int16 array or slice: length exceeds input size (%!d(string=Int16) elements)", length) + } + x := state.decodeInt() + if x < math.MinInt16 || math.MaxInt16 < x { + error_(ovfl) + } + slice[i] = int16(x) + } + return true +} + +func decInt32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decInt32Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decInt32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]int32) + if !ok { + // It is kind int32 but not type int32. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding int32 array or slice: length exceeds input size (%!d(string=Int32) elements)", length) + } + x := state.decodeInt() + if x < math.MinInt32 || math.MaxInt32 < x { + error_(ovfl) + } + slice[i] = int32(x) + } + return true +} + +func decInt64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decInt64Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decInt64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]int64) + if !ok { + // It is kind int64 but not type int64. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding int64 array or slice: length exceeds input size (%!d(string=Int64) elements)", length) + } + slice[i] = state.decodeInt() + } + return true +} + +func decInt8Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decInt8Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decInt8Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]int8) + if !ok { + // It is kind int8 but not type int8. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding int8 array or slice: length exceeds input size (%!d(string=Int8) elements)", length) + } + x := state.decodeInt() + if x < math.MinInt8 || math.MaxInt8 < x { + error_(ovfl) + } + slice[i] = int8(x) + } + return true +} + +func decStringArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decStringSlice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]string) + if !ok { + // It is kind string but not type string. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding string array or slice: length exceeds input size (%!d(string=String) elements)", length) + } + u := state.decodeUint() + n := int(u) + if n < 0 || uint64(n) != u || n > state.b.Len() { + errorf("length of string exceeds input size (%d bytes)", u) + } + if n > state.b.Len() { + errorf("string data too long for buffer: %d", n) + } + // Read the data. + data := make([]byte, n) + if _, err := state.b.Read(data); err != nil { + errorf("error decoding string: %s", err) + } + slice[i] = string(data) + } + return true +} + +func decUintArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decUintSlice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decUintSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]uint) + if !ok { + // It is kind uint but not type uint. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding uint array or slice: length exceeds input size (%!d(string=Uint) elements)", length) + } + x := state.decodeUint() + /*TODO if math.MaxUint32 < x { + error_(ovfl) + }*/ + slice[i] = uint(x) + } + return true +} + +func decUint16Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decUint16Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decUint16Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]uint16) + if !ok { + // It is kind uint16 but not type uint16. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding uint16 array or slice: length exceeds input size (%!d(string=Uint16) elements)", length) + } + x := state.decodeUint() + if math.MaxUint16 < x { + error_(ovfl) + } + slice[i] = uint16(x) + } + return true +} + +func decUint32Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decUint32Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decUint32Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]uint32) + if !ok { + // It is kind uint32 but not type uint32. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding uint32 array or slice: length exceeds input size (%!d(string=Uint32) elements)", length) + } + x := state.decodeUint() + if math.MaxUint32 < x { + error_(ovfl) + } + slice[i] = uint32(x) + } + return true +} + +func decUint64Array(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decUint64Slice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decUint64Slice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]uint64) + if !ok { + // It is kind uint64 but not type uint64. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding uint64 array or slice: length exceeds input size (%!d(string=Uint64) elements)", length) + } + slice[i] = state.decodeUint() + } + return true +} + +func decUintptrArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return decUintptrSlice(state, v.Slice(0, v.Len()), length, ovfl) +} + +func decUintptrSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]uintptr) + if !ok { + // It is kind uintptr but not type uintptr. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding uintptr array or slice: length exceeds input size (%!d(string=Uintptr) elements)", length) + } + x := state.decodeUint() + if uint64(^uintptr(0)) < x { + error_(ovfl) + } + slice[i] = uintptr(x) + } + return true +} diff --git a/src/encoding/gob/decgen.go b/src/encoding/gob/decgen.go new file mode 100644 index 0000000000..1cd1fb0433 --- /dev/null +++ b/src/encoding/gob/decgen.go @@ -0,0 +1,240 @@ +// Copyright 2009 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. + +// +build ignore + +// encgen writes the helper functions for encoding. Intended to be +// used with go generate; see the invocation in encode.go. + +// TODO: We could do more by being unsafe. Add a -unsafe flag? + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "log" + "os" +) + +var output = flag.String("output", "dec_helpers.go", "file name to write") + +type Type struct { + lower string + upper string + decoder string +} + +var types = []Type{ + { + "bool", + "Bool", + `slice[i] = state.decodeUint() != 0`, + }, + { + "complex64", + "Complex64", + `real := float32FromBits(state.decodeUint(), ovfl) + imag := float32FromBits(state.decodeUint(), ovfl) + slice[i] = complex(float32(real), float32(imag))`, + }, + { + "complex128", + "Complex128", + `real := float64FromBits(state.decodeUint()) + imag := float64FromBits(state.decodeUint()) + slice[i] = complex(real, imag)`, + }, + { + "float32", + "Float32", + `slice[i] = float32(float32FromBits(state.decodeUint(), ovfl))`, + }, + { + "float64", + "Float64", + `slice[i] = float64FromBits(state.decodeUint())`, + }, + { + "int", + "Int", + `x := state.decodeInt() + // MinInt and MaxInt + if x < ^int64(^uint(0)>>1) || int64(^uint(0)>>1) < x { + error_(ovfl) + } + slice[i] = int(x)`, + }, + { + "int16", + "Int16", + `x := state.decodeInt() + if x < math.MinInt16 || math.MaxInt16 < x { + error_(ovfl) + } + slice[i] = int16(x)`, + }, + { + "int32", + "Int32", + `x := state.decodeInt() + if x < math.MinInt32 || math.MaxInt32 < x { + error_(ovfl) + } + slice[i] = int32(x)`, + }, + { + "int64", + "Int64", + `slice[i] = state.decodeInt()`, + }, + { + "int8", + "Int8", + `x := state.decodeInt() + if x < math.MinInt8 || math.MaxInt8 < x { + error_(ovfl) + } + slice[i] = int8(x)`, + }, + { + "string", + "String", + `u := state.decodeUint() + n := int(u) + if n < 0 || uint64(n) != u || n > state.b.Len() { + errorf("length of string exceeds input size (%d bytes)", u) + } + if n > state.b.Len() { + errorf("string data too long for buffer: %d", n) + } + // Read the data. + data := make([]byte, n) + if _, err := state.b.Read(data); err != nil { + errorf("error decoding string: %s", err) + } + slice[i] = string(data)`, + }, + { + "uint", + "Uint", + `x := state.decodeUint() + /*TODO if math.MaxUint32 < x { + error_(ovfl) + }*/ + slice[i] = uint(x)`, + }, + { + "uint16", + "Uint16", + `x := state.decodeUint() + if math.MaxUint16 < x { + error_(ovfl) + } + slice[i] = uint16(x)`, + }, + { + "uint32", + "Uint32", + `x := state.decodeUint() + if math.MaxUint32 < x { + error_(ovfl) + } + slice[i] = uint32(x)`, + }, + { + "uint64", + "Uint64", + `slice[i] = state.decodeUint()`, + }, + { + "uintptr", + "Uintptr", + `x := state.decodeUint() + if uint64(^uintptr(0)) < x { + error_(ovfl) + } + slice[i] = uintptr(x)`, + }, + // uint8 Handled separately. +} + +func main() { + log.SetFlags(0) + log.SetPrefix("decgen: ") + flag.Parse() + if flag.NArg() != 0 { + log.Fatal("usage: decgen [--output filename]") + } + var b bytes.Buffer + fmt.Fprintf(&b, "// Created by decgen --output %s; DO NOT EDIT\n", *output) + fmt.Fprint(&b, header) + printMaps(&b, "Array") + fmt.Fprint(&b, "\n") + printMaps(&b, "Slice") + for _, t := range types { + fmt.Fprintf(&b, arrayHelper, t.lower, t.upper) + fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.decoder) + } + source, err := format.Source(b.Bytes()) + if err != nil { + log.Fatal("source format error:", err) + } + fd, err := os.Create(*output) + _, err = fd.Write(source) + if err != nil { + log.Fatal(err) + } +} + +func printMaps(b *bytes.Buffer, upperClass string) { + fmt.Fprintf(b, "var dec%sHelper = map[reflect.Kind]decHelper{\n", upperClass) + for _, t := range types { + fmt.Fprintf(b, "reflect.%s: dec%s%s,\n", t.upper, t.upper, upperClass) + } + fmt.Fprintf(b, "}\n") +} + +const header = ` +// 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 gob + +import ( + "math" + "reflect" +) + +` + +const arrayHelper = ` +func dec%[2]sArray(state *decoderState, v reflect.Value, length int, ovfl error) bool { + // Can only slice if it is addressable. + if !v.CanAddr() { + return false + } + return dec%[2]sSlice(state, v.Slice(0, v.Len()), length, ovfl) +} +` + +const sliceHelper = ` +func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) bool { + slice, ok := v.Interface().([]%[1]s) + if !ok { + // It is kind %[1]s but not type %[1]s. TODO: We can handle this unsafely. + return false + } + for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding %[1]s array or slice: length exceeds input size (%d elements)", length) + } + %[3]s + } + return true +} +` diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index 6a9213fb3c..f44838e4cf 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run decgen.go -output dec_helpers.go + package gob import ( @@ -19,6 +21,8 @@ var ( errRange = errors.New("gob: bad data: field numbers out of bounds") ) +type decHelper func(state *decoderState, v reflect.Value, length int, ovfl error) bool + // decoderState is the execution state of an instance of the decoder. A new state // is created for nested objects. type decoderState struct { @@ -257,7 +261,7 @@ func float64FromBits(u uint64) float64 { // number, and returns it. It's a helper function for float32 and complex64. // It returns a float64 because that's what reflection needs, but its return // value is known to be accurately representable in a float32. -func float32FromBits(i *decInstr, u uint64) float64 { +func float32FromBits(u uint64, ovfl error) float64 { v := float64FromBits(u) av := v if av < 0 { @@ -265,7 +269,7 @@ func float32FromBits(i *decInstr, u uint64) float64 { } // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. if math.MaxFloat32 < av && av <= math.MaxFloat64 { - error_(i.ovfl) + error_(ovfl) } return v } @@ -273,7 +277,7 @@ func float32FromBits(i *decInstr, u uint64) float64 { // decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point // number, and stores it in value. func decFloat32(i *decInstr, state *decoderState, value reflect.Value) { - value.SetFloat(float32FromBits(i, state.decodeUint())) + value.SetFloat(float32FromBits(state.decodeUint(), i.ovfl)) } // decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point @@ -286,8 +290,8 @@ func decFloat64(i *decInstr, state *decoderState, value reflect.Value) { // pair of floating point numbers, and stores them as a complex64 in value. // The real part comes first. func decComplex64(i *decInstr, state *decoderState, value reflect.Value) { - real := float32FromBits(i, state.decodeUint()) - imag := float32FromBits(i, state.decodeUint()) + real := float32FromBits(state.decodeUint(), i.ovfl) + imag := float32FromBits(state.decodeUint(), i.ovfl) value.SetComplex(complex(real, imag)) } @@ -450,7 +454,10 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) { } // decodeArrayHelper does the work for decoding arrays and slices. -func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) { +func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) { + if helper != nil && helper(state, value, length, ovfl) { + return + } instr := &decInstr{elemOp, 0, nil, ovfl} isPtr := value.Type().Elem().Kind() == reflect.Ptr for i := 0; i < length; i++ { @@ -468,11 +475,11 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, // decodeArray decodes an array and stores it in value. // The length is an unsigned integer preceding the elements. Even though the length is redundant // (it's part of the type), it's a useful check and is included in the encoding. -func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) { +func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) { if n := state.decodeUint(); n != uint64(length) { errorf("length mismatch in decodeArray") } - dec.decodeArrayHelper(state, value, elemOp, length, ovfl) + dec.decodeArrayHelper(state, value, elemOp, length, ovfl, helper) } // decodeIntoValue is a helper for map decoding. @@ -534,7 +541,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { // decodeSlice decodes a slice and stores it in value. // Slices are encoded as an unsigned length followed by the elements. -func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error) { +func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error, helper decHelper) { u := state.decodeUint() typ := value.Type() size := uint64(typ.Elem().Size()) @@ -551,7 +558,7 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp } else { value.Set(value.Slice(0, n)) } - dec.decodeArrayHelper(state, value, elemOp, n, ovfl) + dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper) } // ignoreSlice skips over the data for a slice value with no destination. @@ -720,8 +727,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg elemId := dec.wireType[wireId].ArrayT.Elem elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress) ovfl := overflow(name) + helper := decArrayHelper[t.Elem().Kind()] op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl) + state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl, helper) } case reflect.Map: @@ -748,8 +756,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg } elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress) ovfl := overflow(name) + helper := decSliceHelper[t.Elem().Kind()] op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.decodeSlice(state, value, *elemOp, ovfl) + state.dec.decodeSlice(state, value, *elemOp, ovfl, helper) } case reflect.Struct: diff --git a/src/encoding/gob/enc_helpers.go b/src/encoding/gob/enc_helpers.go index 1e6f307184..804e539d84 100644 --- a/src/encoding/gob/enc_helpers.go +++ b/src/encoding/gob/enc_helpers.go @@ -10,7 +10,7 @@ import ( "reflect" ) -var arrayHelper = map[reflect.Kind]encHelper{ +var encArrayHelper = map[reflect.Kind]encHelper{ reflect.Bool: encBoolArray, reflect.Complex64: encComplex64Array, reflect.Complex128: encComplex128Array, @@ -29,7 +29,7 @@ var arrayHelper = map[reflect.Kind]encHelper{ reflect.Uintptr: encUintptrArray, } -var sliceHelper = map[reflect.Kind]encHelper{ +var encSliceHelper = map[reflect.Kind]encHelper{ reflect.Bool: encBoolSlice, reflect.Complex64: encComplex64Slice, reflect.Complex128: encComplex128Slice, diff --git a/src/encoding/gob/encgen.go b/src/encoding/gob/encgen.go index fa500e3dab..efdd928292 100644 --- a/src/encoding/gob/encgen.go +++ b/src/encoding/gob/encgen.go @@ -144,7 +144,7 @@ var types = []Type{ func main() { log.SetFlags(0) - log.SetPrefix("helpergen: ") + log.SetPrefix("encgen: ") flag.Parse() if flag.NArg() != 0 { log.Fatal("usage: encgen [--output filename]") @@ -152,9 +152,9 @@ func main() { var b bytes.Buffer fmt.Fprintf(&b, "// Created by encgen --output %s; DO NOT EDIT\n", *output) fmt.Fprint(&b, header) - printMaps(&b, "array", "Array") + printMaps(&b, "Array") fmt.Fprint(&b, "\n") - printMaps(&b, "slice", "Slice") + printMaps(&b, "Slice") for _, t := range types { fmt.Fprintf(&b, arrayHelper, t.lower, t.upper) fmt.Fprintf(&b, sliceHelper, t.lower, t.upper, t.zero, t.encoder) @@ -170,8 +170,8 @@ func main() { } } -func printMaps(b *bytes.Buffer, lowerClass, upperClass string) { - fmt.Fprintf(b, "var %sHelper = map[reflect.Kind]encHelper{\n", lowerClass) +func printMaps(b *bytes.Buffer, upperClass string) { + fmt.Fprintf(b, "var enc%sHelper = map[reflect.Kind]encHelper{\n", upperClass) for _, t := range types { fmt.Fprintf(b, "reflect.%s: enc%s%s,\n", t.upper, t.upper, upperClass) } diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index 3b8d0b4271..3da848c851 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -508,7 +508,7 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[ } // Slices have a header; we decode it to find the underlying array. elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) - helper := sliceHelper[t.Elem().Kind()] + helper := encSliceHelper[t.Elem().Kind()] op = func(i *encInstr, state *encoderState, slice reflect.Value) { if !state.sendZero && slice.Len() == 0 { return @@ -519,7 +519,7 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[ case reflect.Array: // True arrays have size in the type. elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building) - helper := arrayHelper[t.Elem().Kind()] + helper := encArrayHelper[t.Elem().Kind()] op = func(i *encInstr, state *encoderState, array reflect.Value) { state.update(i) state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper) diff --git a/src/encoding/gob/timing_test.go b/src/encoding/gob/timing_test.go index abfe936e83..940e5ad412 100644 --- a/src/encoding/gob/timing_test.go +++ b/src/encoding/gob/timing_test.go @@ -132,13 +132,14 @@ func TestCountDecodeMallocs(t *testing.T) { } } -func BenchmarkComplex128Slice(b *testing.B) { +func BenchmarkEncodeComplex128Slice(b *testing.B) { var buf bytes.Buffer enc := NewEncoder(&buf) a := make([]complex128, 1000) for i := range a { a[i] = 1.2 + 3.4i } + b.ResetTimer() for i := 0; i < b.N; i++ { buf.Reset() err := enc.Encode(a) @@ -148,29 +149,14 @@ func BenchmarkComplex128Slice(b *testing.B) { } } -func BenchmarkInt32Slice(b *testing.B) { - var buf bytes.Buffer - enc := NewEncoder(&buf) - a := make([]int32, 1000) - for i := range a { - a[i] = 1234 - } - for i := 0; i < b.N; i++ { - buf.Reset() - err := enc.Encode(a) - if err != nil { - b.Fatal(err) - } - } -} - -func BenchmarkFloat64Slice(b *testing.B) { +func BenchmarkEncodeFloat64Slice(b *testing.B) { var buf bytes.Buffer enc := NewEncoder(&buf) a := make([]float64, 1000) for i := range a { a[i] = 1.23e4 } + b.ResetTimer() for i := 0; i < b.N; i++ { buf.Reset() err := enc.Encode(a) @@ -180,13 +166,14 @@ func BenchmarkFloat64Slice(b *testing.B) { } } -func BenchmarkStringSlice(b *testing.B) { +func BenchmarkEncodeInt32Slice(b *testing.B) { var buf bytes.Buffer enc := NewEncoder(&buf) - a := make([]string, 1000) + a := make([]int32, 1000) for i := range a { - a[i] = "now is the time" + a[i] = 1234 } + b.ResetTimer() for i := 0; i < b.N; i++ { buf.Reset() err := enc.Encode(a) @@ -195,3 +182,144 @@ func BenchmarkStringSlice(b *testing.B) { } } } + +func BenchmarkEncodeStringSlice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]string, 1000) + for i := range a { + a[i] = "now is the time" + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + buf.Reset() + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + } +} + +// benchmarkBuf is a read buffer we can reset +type benchmarkBuf struct { + offset int + data []byte +} + +func (b *benchmarkBuf) Read(p []byte) (n int, err error) { + n = copy(p, b.data[b.offset:]) + if n == 0 { + return 0, io.EOF + } + b.offset += n + return +} + +func (b *benchmarkBuf) ReadByte() (c byte, err error) { + if b.offset >= len(b.data) { + return 0, io.EOF + } + c = b.data[b.offset] + b.offset++ + return +} + +func (b *benchmarkBuf) reset() { + b.offset = 0 +} + +func BenchmarkDecodeComplex128Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]complex128, 1000) + for i := range a { + a[i] = 1.2 + 3.4i + } + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + x := make([]complex128, 1000) + bbuf := benchmarkBuf{data: buf.Bytes()} + b.ResetTimer() + for i := 0; i < b.N; i++ { + bbuf.reset() + dec := NewDecoder(&bbuf) + err := dec.Decode(&x) + if err != nil { + b.Fatal(i, err) + } + } +} + +func BenchmarkDecodeFloat64Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]float64, 1000) + for i := range a { + a[i] = 1.23e4 + } + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + x := make([]float64, 1000) + bbuf := benchmarkBuf{data: buf.Bytes()} + b.ResetTimer() + for i := 0; i < b.N; i++ { + bbuf.reset() + dec := NewDecoder(&bbuf) + err := dec.Decode(&x) + if err != nil { + b.Fatal(i, err) + } + } +} + +func BenchmarkDecodeInt32Slice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]int32, 1000) + for i := range a { + a[i] = 1234 + } + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + x := make([]int32, 1000) + bbuf := benchmarkBuf{data: buf.Bytes()} + b.ResetTimer() + for i := 0; i < b.N; i++ { + bbuf.reset() + dec := NewDecoder(&bbuf) + err := dec.Decode(&x) + if err != nil { + b.Fatal(i, err) + } + } +} + +func BenchmarkDecodeStringSlice(b *testing.B) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + a := make([]string, 1000) + for i := range a { + a[i] = "now is the time" + } + err := enc.Encode(a) + if err != nil { + b.Fatal(err) + } + x := make([]string, 1000) + bbuf := benchmarkBuf{data: buf.Bytes()} + b.ResetTimer() + for i := 0; i < b.N; i++ { + bbuf.reset() + dec := NewDecoder(&bbuf) + err := dec.Decode(&x) + if err != nil { + b.Fatal(i, err) + } + } +} From 65dde1ed4b1c71fad6d2b106b779c5191e5f7cd7 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 17 Oct 2014 20:51:15 -0700 Subject: [PATCH 397/430] encoding/gob: use simple append-only buffer for encoding Bytes buffers have more API and are a little slower. Since appending is a key part of the path in encode, using a faster implementation speeds things up measurably. The couple of positive swings are likely garbage-collection related since memory allocation looks different in the benchmark now. I am not concerned by them. benchmark old ns/op new ns/op delta BenchmarkEndToEndPipe 6620 6388 -3.50% BenchmarkEndToEndByteBuffer 3548 3600 +1.47% BenchmarkEndToEndSliceByteBuffer 336678 367980 +9.30% BenchmarkEncodeComplex128Slice 78199 71297 -8.83% BenchmarkEncodeFloat64Slice 37731 32258 -14.51% BenchmarkEncodeInt32Slice 26780 22977 -14.20% BenchmarkEncodeStringSlice 35882 26492 -26.17% BenchmarkDecodeComplex128Slice 194819 185126 -4.98% BenchmarkDecodeFloat64Slice 120538 120102 -0.36% BenchmarkDecodeInt32Slice 106442 107275 +0.78% BenchmarkDecodeStringSlice 272902 269866 -1.11% LGTM=ruiu R=golang-codereviews, ruiu CC=golang-codereviews https://golang.org/cl/160990043 --- src/encoding/gob/codec_test.go | 12 +++--- src/encoding/gob/decoder.go | 2 +- src/encoding/gob/encode.go | 73 +++++++++++++++++++++++----------- src/encoding/gob/encoder.go | 7 ++-- 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go index 4f17a28931..b3749e3528 100644 --- a/src/encoding/gob/codec_test.go +++ b/src/encoding/gob/codec_test.go @@ -53,7 +53,7 @@ func testError(t *testing.T) { // Test basic encode/decode routines for unsigned integers func TestUintCodec(t *testing.T) { defer testError(t) - b := new(bytes.Buffer) + b := new(encBuffer) encState := newEncoderState(b) for _, tt := range encodeT { b.Reset() @@ -62,10 +62,10 @@ func TestUintCodec(t *testing.T) { t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes()) } } - decState := newDecodeState(b) for u := uint64(0); ; u = (u + 1) * 7 { b.Reset() encState.encodeUint(u) + decState := newDecodeState(bytes.NewBuffer(b.Bytes())) v := decState.decodeUint() if u != v { t.Errorf("Encode/Decode: sent %#x received %#x", u, v) @@ -78,10 +78,10 @@ func TestUintCodec(t *testing.T) { func verifyInt(i int64, t *testing.T) { defer testError(t) - var b = new(bytes.Buffer) + var b = new(encBuffer) encState := newEncoderState(b) encState.encodeInt(i) - decState := newDecodeState(b) + decState := newDecodeState(bytes.NewBuffer(b.Bytes())) decState.buf = make([]byte, 8) j := decState.decodeInt() if i != j { @@ -125,7 +125,7 @@ func newDecodeState(buf *bytes.Buffer) *decoderState { return d } -func newEncoderState(b *bytes.Buffer) *encoderState { +func newEncoderState(b *encBuffer) *encoderState { b.Reset() state := &encoderState{enc: nil, b: b} state.fieldnum = -1 @@ -135,7 +135,7 @@ func newEncoderState(b *bytes.Buffer) *encoderState { // Test instruction execution for encoding. // Do not run the machine yet; instead do individual instructions crafted by hand. func TestScalarEncInstructions(t *testing.T) { - var b = new(bytes.Buffer) + var b = new(encBuffer) // bool { diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index dcad7a0e48..fe1494100a 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -212,7 +212,7 @@ func (dec *Decoder) Decode(e interface{}) error { // Otherwise, it stores the value into v. In that case, v must represent // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet()) // If the input is at EOF, DecodeValue returns io.EOF and -// does not modify e. +// does not modify v. func (dec *Decoder) DecodeValue(v reflect.Value) error { if v.IsValid() { if v.Kind() == reflect.Ptr && !v.IsNil() { diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go index 3da848c851..f66279f141 100644 --- a/src/encoding/gob/encode.go +++ b/src/encoding/gob/encode.go @@ -7,7 +7,6 @@ package gob import ( - "bytes" "encoding" "math" "reflect" @@ -23,14 +22,46 @@ type encHelper func(state *encoderState, v reflect.Value) bool // 0 terminates the structure. type encoderState struct { enc *Encoder - b *bytes.Buffer + b *encBuffer sendZero bool // encoding an array element or map key/value pair; send zero values fieldnum int // the last field number written. buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation. next *encoderState // for free list } -func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState { +// encBuffer is an extremely simple, fast implementation of a write-only byte buffer. +// It never returns a non-nil error, but Write returns an error value so it matches io.Writer. +type encBuffer struct { + data []byte + scratch [64]byte +} + +func (e *encBuffer) WriteByte(c byte) { + e.data = append(e.data, c) +} + +func (e *encBuffer) Write(p []byte) (int, error) { + e.data = append(e.data, p...) + return len(p), nil +} + +func (e *encBuffer) WriteString(s string) { + e.data = append(e.data, s...) +} + +func (e *encBuffer) Len() int { + return len(e.data) +} + +func (e *encBuffer) Bytes() []byte { + return e.data +} + +func (e *encBuffer) Reset() { + e.data = e.data[0:0] +} + +func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState { e := enc.freeList if e == nil { e = new(encoderState) @@ -41,6 +72,9 @@ func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState { e.sendZero = false e.fieldnum = 0 e.b = b + if len(b.data) == 0 { + b.data = b.scratch[0:0] + } return e } @@ -57,10 +91,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) { // encodeUint writes an encoded unsigned integer to state.b. func (state *encoderState) encodeUint(x uint64) { if x <= 0x7F { - err := state.b.WriteByte(uint8(x)) - if err != nil { - error_(err) - } + state.b.WriteByte(uint8(x)) return } i := uint64Size @@ -70,10 +101,7 @@ func (state *encoderState) encodeUint(x uint64) { i-- } state.buf[i] = uint8(i - uint64Size) // = loop count, negated - _, err := state.b.Write(state.buf[i : uint64Size+1]) - if err != nil { - error_(err) - } + state.b.Write(state.buf[i : uint64Size+1]) } // encodeInt writes an encoded signed integer to state.w. @@ -251,7 +279,7 @@ func valid(v reflect.Value) bool { } // encodeSingle encodes a single top-level non-struct value. -func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value reflect.Value) { +func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.Value) { state := enc.newEncoderState(b) defer enc.freeEncoderState(state) state.fieldnum = singletonField @@ -268,7 +296,7 @@ func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value refle } // encodeStruct encodes a single struct value. -func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value reflect.Value) { +func (enc *Encoder) encodeStruct(b *encBuffer, engine *encEngine, value reflect.Value) { if !valid(value) { return } @@ -295,7 +323,7 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle } // encodeArray encodes an array. -func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) { +func (enc *Encoder) encodeArray(b *encBuffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) { state := enc.newEncoderState(b) defer enc.freeEncoderState(state) state.fieldnum = -1 @@ -329,7 +357,7 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in } // encodeMap encodes a map as unsigned count followed by key:value pairs. -func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) { +func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) { state := enc.newEncoderState(b) state.fieldnum = -1 state.sendZero = true @@ -347,7 +375,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp e // by the type identifier (which might require defining that type right now), followed // by the concrete value. A nil value gets sent as the empty string for the name, // followed by no value. -func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { +func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) { // Gobs can encode nil interface values but not typed interface // values holding nil pointers, since nil pointers point to no value. elem := iv.Elem() @@ -371,10 +399,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { } // Send the name. state.encodeUint(uint64(len(name))) - _, err := state.b.WriteString(name) - if err != nil { - error_(err) - } + state.b.WriteString(name) // Define the type id if necessary. enc.sendTypeDescriptor(enc.writer(), state, ut) // Send the type id. @@ -382,7 +407,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { // Encode the value into a new buffer. Any nested type definitions // should be written to b, before the encoded value. enc.pushWriter(b) - data := new(bytes.Buffer) + data := new(encBuffer) data.Write(spaceForLength) enc.encode(data, elem, ut) if enc.err != nil { @@ -391,7 +416,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { enc.popWriter() enc.writeMessage(b, data) if enc.err != nil { - error_(err) + error_(enc.err) } enc.freeEncoderState(state) } @@ -433,7 +458,7 @@ func isZero(val reflect.Value) bool { // encGobEncoder encodes a value that implements the GobEncoder interface. // The data is sent as a byte array. -func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflect.Value) { +func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.Value) { // TODO: should we catch panics from the called method? var data []byte @@ -653,7 +678,7 @@ func buildEncEngine(info *typeInfo, ut *userTypeInfo, building map[*typeInfo]boo return enc } -func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) { +func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) { defer catchError(&enc.err) engine := getEncEngine(ut, nil) indir := ut.indir diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go index 4b5dc16c79..a340e47b5e 100644 --- a/src/encoding/gob/encoder.go +++ b/src/encoding/gob/encoder.go @@ -5,7 +5,6 @@ package gob import ( - "bytes" "io" "reflect" "sync" @@ -19,7 +18,7 @@ type Encoder struct { sent map[reflect.Type]typeId // which types we've already sent countState *encoderState // stage for writing counts freeList *encoderState // list of free encoderStates; avoids reallocation - byteBuf bytes.Buffer // buffer for top-level encoderState + byteBuf encBuffer // buffer for top-level encoderState err error } @@ -34,7 +33,7 @@ func NewEncoder(w io.Writer) *Encoder { enc := new(Encoder) enc.w = []io.Writer{w} enc.sent = make(map[reflect.Type]typeId) - enc.countState = enc.newEncoderState(new(bytes.Buffer)) + enc.countState = enc.newEncoderState(new(encBuffer)) return enc } @@ -60,7 +59,7 @@ func (enc *Encoder) setError(err error) { } // writeMessage sends the data item preceded by a unsigned count of its length. -func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) { +func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) { // Space has been reserved for the length at the head of the message. // This is a little dirty: we grab the slice from the bytes.Buffer and massage // it by hand. From 1cd78eedd092c9ec10f1b5c626b8bcd0298e065f Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sat, 18 Oct 2014 11:22:05 -0700 Subject: [PATCH 398/430] text/template: fix bug in pipelined variadics Simple bug in argument processing: The final arg may be the pipeline value, in which case it gets bound to the fixed argument section. The code got that wrong. Easy to fix. Fixes #8950. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/161750043 --- src/text/template/exec.go | 2 +- src/text/template/exec_test.go | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index f6eed662b7..b00e10c7e4 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -546,7 +546,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a argv := make([]reflect.Value, numIn) // Args must be evaluated. Fixed args first. i := 0 - for ; i < numFixed; i++ { + for ; i < numFixed && i < len(args); i++ { argv[i] = s.evalArg(dot, typ.In(i), args[i]) } // Now the ... args. diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index e2cf2d3705..69c213ed24 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -893,6 +893,18 @@ func TestMessageForExecuteEmpty(t *testing.T) { } } +func TestFinalForPrintf(t *testing.T) { + tmpl, err := New("").Parse(`{{"x" | printf}}`) + if err != nil { + t.Fatal(err) + } + var b bytes.Buffer + err = tmpl.Execute(&b, 0) + if err != nil { + t.Fatal(err) + } +} + type cmpTest struct { expr string truth string From e330cc16f477471c11f78a88c8a71a155a9ca8ec Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 18 Oct 2014 21:02:49 -0700 Subject: [PATCH 399/430] runtime: dequeue the correct SudoG select { case <- c: case <- c: } In this case, c.recvq lists two SudoGs which have the same G. So we can't use the G as the key to dequeue the correct SudoG, as that key is ambiguous. Dequeueing the wrong SudoG ends up freeing a SudoG that is still in c.recvq. The fix is to use the actual SudoG pointer as the key. LGTM=dvyukov R=rsc, bradfitz, dvyukov, khr CC=austin, golang-codereviews https://golang.org/cl/159040043 --- src/runtime/chan_test.go | 29 +++++++++++++++++++++++++++++ src/runtime/select.go | 8 ++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go index 01632892ed..e689ceaed1 100644 --- a/src/runtime/chan_test.go +++ b/src/runtime/chan_test.go @@ -482,6 +482,35 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) { <-done } +func TestSelectDuplicateChannel(t *testing.T) { + // This test makes sure we can queue a G on + // the same channel multiple times. + c := make(chan int) + d := make(chan int) + e := make(chan int) + + // goroutine A + go func() { + select { + case <-c: + case <-c: + case <-d: + } + e <- 9 + }() + time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c + + // goroutine B + go func() { + <-c + }() + time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing + + d <- 7 // wake up A, it dequeues itself from c. This operation used to corrupt c.recvq. + <-e // A tells us it's done + c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B) +} + func BenchmarkChanNonblocking(b *testing.B) { myc := make(chan int) b.RunParallel(func(pb *testing.PB) { diff --git a/src/runtime/select.go b/src/runtime/select.go index 9de057b871..efe68c1f5c 100644 --- a/src/runtime/select.go +++ b/src/runtime/select.go @@ -398,9 +398,9 @@ loop: } else { c = k._chan if k.kind == _CaseSend { - c.sendq.dequeueg(gp) + c.sendq.dequeueSudoG(sglist) } else { - c.recvq.dequeueg(gp) + c.recvq.dequeueSudoG(sglist) } } sgnext = sglist.waitlink @@ -628,7 +628,7 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { return } -func (q *waitq) dequeueg(gp *g) { +func (q *waitq) dequeueSudoG(s *sudog) { var prevsgp *sudog l := &q.first for { @@ -636,7 +636,7 @@ func (q *waitq) dequeueg(gp *g) { if sgp == nil { return } - if sgp.g == gp { + if sgp == s { *l = sgp.next if q.last == sgp { q.last = prevsgp From 4c91b1371f1aef77e7ea7683c5c1d357234ca1cd Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 19 Oct 2014 06:44:50 -0700 Subject: [PATCH 400/430] encoding/gob: fix print format in generated decoder helpers Needed a %% to quote a percent in the format. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/156330043 --- src/encoding/gob/dec_helpers.go | 32 ++++++++++++++++---------------- src/encoding/gob/decgen.go | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/encoding/gob/dec_helpers.go b/src/encoding/gob/dec_helpers.go index ae59ef0ac7..a1b67661d8 100644 --- a/src/encoding/gob/dec_helpers.go +++ b/src/encoding/gob/dec_helpers.go @@ -65,7 +65,7 @@ func decBoolSlice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding bool array or slice: length exceeds input size (%!d(string=Bool) elements)", length) + errorf("decoding bool array or slice: length exceeds input size (%d elements)", length) } slice[i] = state.decodeUint() != 0 } @@ -88,7 +88,7 @@ func decComplex64Slice(state *decoderState, v reflect.Value, length int, ovfl er } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding complex64 array or slice: length exceeds input size (%!d(string=Complex64) elements)", length) + errorf("decoding complex64 array or slice: length exceeds input size (%d elements)", length) } real := float32FromBits(state.decodeUint(), ovfl) imag := float32FromBits(state.decodeUint(), ovfl) @@ -113,7 +113,7 @@ func decComplex128Slice(state *decoderState, v reflect.Value, length int, ovfl e } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding complex128 array or slice: length exceeds input size (%!d(string=Complex128) elements)", length) + errorf("decoding complex128 array or slice: length exceeds input size (%d elements)", length) } real := float64FromBits(state.decodeUint()) imag := float64FromBits(state.decodeUint()) @@ -138,7 +138,7 @@ func decFloat32Slice(state *decoderState, v reflect.Value, length int, ovfl erro } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding float32 array or slice: length exceeds input size (%!d(string=Float32) elements)", length) + errorf("decoding float32 array or slice: length exceeds input size (%d elements)", length) } slice[i] = float32(float32FromBits(state.decodeUint(), ovfl)) } @@ -161,7 +161,7 @@ func decFloat64Slice(state *decoderState, v reflect.Value, length int, ovfl erro } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding float64 array or slice: length exceeds input size (%!d(string=Float64) elements)", length) + errorf("decoding float64 array or slice: length exceeds input size (%d elements)", length) } slice[i] = float64FromBits(state.decodeUint()) } @@ -184,7 +184,7 @@ func decIntSlice(state *decoderState, v reflect.Value, length int, ovfl error) b } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding int array or slice: length exceeds input size (%!d(string=Int) elements)", length) + errorf("decoding int array or slice: length exceeds input size (%d elements)", length) } x := state.decodeInt() // MinInt and MaxInt @@ -212,7 +212,7 @@ func decInt16Slice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding int16 array or slice: length exceeds input size (%!d(string=Int16) elements)", length) + errorf("decoding int16 array or slice: length exceeds input size (%d elements)", length) } x := state.decodeInt() if x < math.MinInt16 || math.MaxInt16 < x { @@ -239,7 +239,7 @@ func decInt32Slice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding int32 array or slice: length exceeds input size (%!d(string=Int32) elements)", length) + errorf("decoding int32 array or slice: length exceeds input size (%d elements)", length) } x := state.decodeInt() if x < math.MinInt32 || math.MaxInt32 < x { @@ -266,7 +266,7 @@ func decInt64Slice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding int64 array or slice: length exceeds input size (%!d(string=Int64) elements)", length) + errorf("decoding int64 array or slice: length exceeds input size (%d elements)", length) } slice[i] = state.decodeInt() } @@ -289,7 +289,7 @@ func decInt8Slice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding int8 array or slice: length exceeds input size (%!d(string=Int8) elements)", length) + errorf("decoding int8 array or slice: length exceeds input size (%d elements)", length) } x := state.decodeInt() if x < math.MinInt8 || math.MaxInt8 < x { @@ -316,7 +316,7 @@ func decStringSlice(state *decoderState, v reflect.Value, length int, ovfl error } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding string array or slice: length exceeds input size (%!d(string=String) elements)", length) + errorf("decoding string array or slice: length exceeds input size (%d elements)", length) } u := state.decodeUint() n := int(u) @@ -352,7 +352,7 @@ func decUintSlice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding uint array or slice: length exceeds input size (%!d(string=Uint) elements)", length) + errorf("decoding uint array or slice: length exceeds input size (%d elements)", length) } x := state.decodeUint() /*TODO if math.MaxUint32 < x { @@ -379,7 +379,7 @@ func decUint16Slice(state *decoderState, v reflect.Value, length int, ovfl error } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding uint16 array or slice: length exceeds input size (%!d(string=Uint16) elements)", length) + errorf("decoding uint16 array or slice: length exceeds input size (%d elements)", length) } x := state.decodeUint() if math.MaxUint16 < x { @@ -406,7 +406,7 @@ func decUint32Slice(state *decoderState, v reflect.Value, length int, ovfl error } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding uint32 array or slice: length exceeds input size (%!d(string=Uint32) elements)", length) + errorf("decoding uint32 array or slice: length exceeds input size (%d elements)", length) } x := state.decodeUint() if math.MaxUint32 < x { @@ -433,7 +433,7 @@ func decUint64Slice(state *decoderState, v reflect.Value, length int, ovfl error } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding uint64 array or slice: length exceeds input size (%!d(string=Uint64) elements)", length) + errorf("decoding uint64 array or slice: length exceeds input size (%d elements)", length) } slice[i] = state.decodeUint() } @@ -456,7 +456,7 @@ func decUintptrSlice(state *decoderState, v reflect.Value, length int, ovfl erro } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding uintptr array or slice: length exceeds input size (%!d(string=Uintptr) elements)", length) + errorf("decoding uintptr array or slice: length exceeds input size (%d elements)", length) } x := state.decodeUint() if uint64(^uintptr(0)) < x { diff --git a/src/encoding/gob/decgen.go b/src/encoding/gob/decgen.go index 1cd1fb0433..da41a899ed 100644 --- a/src/encoding/gob/decgen.go +++ b/src/encoding/gob/decgen.go @@ -231,7 +231,7 @@ func dec%[2]sSlice(state *decoderState, v reflect.Value, length int, ovfl error) } for i := 0; i < length; i++ { if state.b.Len() == 0 { - errorf("decoding %[1]s array or slice: length exceeds input size (%d elements)", length) + errorf("decoding %[1]s array or slice: length exceeds input size (%%d elements)", length) } %[3]s } From 3c5fd98918e0c1c22566b19769a0a370b1321737 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 19 Oct 2014 10:28:27 -0700 Subject: [PATCH 401/430] regexp: correct doc comment for ReplaceAllLiteralString Fixes #8959. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/161790043 --- src/regexp/regexp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index 0b8336a04f..b615acdf0e 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -452,7 +452,7 @@ func (re *Regexp) ReplaceAllString(src, repl string) string { return string(b) } -// ReplaceAllStringLiteral returns a copy of src, replacing matches of the Regexp +// ReplaceAllLiteralString returns a copy of src, replacing matches of the Regexp // with the replacement string repl. The replacement repl is substituted directly, // without using Expand. func (re *Regexp) ReplaceAllLiteralString(src, repl string) string { From 8c29633368994eb56f19d9d15f1a3433f5e9306a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 19 Oct 2014 10:33:22 -0700 Subject: [PATCH 402/430] flag: disallow setting flags multiple times This is a day 1 error in the flag package: It did not check that a flag was set at most once on the command line. Because user-defined flags may have more general properties, the check applies only to the standard flag types in this package: bool, string, etc. Fixes #8960. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/156390043 --- src/flag/flag.go | 30 ++++++++++++++++++++++ src/flag/flag_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/flag/flag.go b/src/flag/flag.go index 323e452a83..56860fc9de 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -235,6 +235,9 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() } // If a Value has an IsBoolFlag() bool method returning true, // the command-line parser makes -name equivalent to -name=true // rather than using the next command-line argument. +// +// It is the implementer's responsibility to verify, if required, that the +// flag has been set only once. type Value interface { String() string Set(string) error @@ -270,6 +273,7 @@ type FlagSet struct { parsed bool actual map[string]*Flag formal map[string]*Flag + set map[*Flag]bool args []string // arguments after flags errorHandling ErrorHandling output io.Writer // nil means stderr; use out() accessor @@ -717,6 +721,25 @@ func (f *FlagSet) usage() { } } +// alreadySet reports whether the flag has already been set during parsing. +// Because user-defined flags may legally be set multiple times, it only +// complains about flags defined in this package. +func (f *FlagSet) alreadySet(flag *Flag) bool { + if f.set == nil { + f.set = make(map[*Flag]bool) + } + switch flag.Value.(type) { + case *boolValue, *intValue, *int64Value, *uintValue, *uint64Value, *stringValue, *float64Value, *durationValue: + default: + return false // Not one of ours. + } + if f.set[flag] { + return true + } + f.set[flag] = true + return false +} + // parseOne parses one flag. It reports whether a flag was seen. func (f *FlagSet) parseOne() (bool, error) { if len(f.args) == 0 { @@ -760,6 +783,12 @@ func (f *FlagSet) parseOne() (bool, error) { } return false, f.failf("flag provided but not defined: -%s", name) } + + // has it already been set? + if f.alreadySet(flag) { + return false, f.failf("flag set multiple times: -%s", name) + } + if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg if has_value { if err := fv.Set(value); err != nil { @@ -795,6 +824,7 @@ func (f *FlagSet) parseOne() (bool, error) { // The return value will be ErrHelp if -help or -h were set but not defined. func (f *FlagSet) Parse(arguments []string) error { f.parsed = true + f.set = nil f.args = arguments for { seen, err := f.parseOne() diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 8c88c8c274..80d92a5e71 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -377,3 +377,63 @@ func TestHelp(t *testing.T) { t.Fatal("help was called; should not have been for defined help flag") } } + +// Test that a standard flag can be set only once. Need to verify every flag type. +// User-defined flags can be set multiple times, and this is verified in the tests above. +func TestErrorOnMultipleSettings(t *testing.T) { + check := func(typ string, err error) { + if err == nil { + t.Errorf("%s flag can be set multiple times") + } else if !strings.Contains(err.Error(), "flag set multiple") { + t.Fatalf("expected multiple setting error, got %q", err) + } + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Bool("v", false, "usage") + check("bool", flags.Parse([]string{"-v", "-v"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Int("v", 0, "usage") + check("int", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Int64("v", 0, "usage") + check("int64", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Uint("v", 0, "usage") + check("uint", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Uint64("v", 0, "usage") + check("uint64", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.String("v", "", "usage") + check("string", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Float64("v", 0, "usage") + check("float64", flags.Parse([]string{"-v", "1", "-v", "2"})) + } + { + var flags FlagSet + flags.Init("test", ContinueOnError) + flags.Duration("v", 0, "usage") + check("duration", flags.Parse([]string{"-v", "1s", "-v", "2s"})) + } +} From 18c7fbdfd7a0842ca601231266b6582f957c982b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Sun, 19 Oct 2014 10:33:50 -0700 Subject: [PATCH 403/430] doc/go1.4.txt: flags can now be set at most once CC=golang-codereviews https://golang.org/cl/161820043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index 833d331cb0..df98de5c76 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -23,6 +23,7 @@ asm: make textflag.h available outside of cmd/ld (CL 128050043) bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) crypto/tls: support programmatic selection of server certificates (CL 107400043) +flag: it is now an error to set a flag multiple times (CL 156390043) fmt: print type *map[T]T as &map[k:v] (CL 154870043) encoding/gob: remove unsafe (CL 102680045) misc: deleted editor support; refer to https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins instead (CL 105470043) From 193d09a659c8d0a894fa682a879adb8fac1a4d82 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Mon, 20 Oct 2014 12:58:02 +1100 Subject: [PATCH 404/430] compress/flate: add Reset() to allow reusing large buffers to compress multiple buffers This adds a Reset() to compress/flate's decompressor and plumbs that through to compress/zlib and compress/gzip's Readers so callers can avoid large allocations when performing many inflate operations. In particular this preserves the allocation of the decompressor.hist buffer, which is 32kb and overwritten as needed while inflating. On the benchmark described in issue 6317, produces the following speedup on my 2.3ghz Intel Core i7 MBP with go version devel +6b696a34e0af Sun Aug 03 15:14:59 2014 -0700 darwin/amd64: blocked.text w/out patch vs blocked.text w/ patch: benchmark old ns/op new ns/op delta BenchmarkGunzip 8371577533 7927917687 -5.30% benchmark old allocs new allocs delta BenchmarkGunzip 176818 148519 -16.00% benchmark old bytes new bytes delta BenchmarkGunzip 292184936 12739528 -95.64% flat.text vs blocked.text w/patch: benchmark old ns/op new ns/op delta BenchmarkGunzip 7939447827 7927917687 -0.15% benchmark old allocs new allocs delta BenchmarkGunzip 90702 148519 +63.74% benchmark old bytes new bytes delta BenchmarkGunzip 9959528 12739528 +27.91% Similar speedups to those bradfitz saw in https://golang.org/cl/13416045. Fixes #6317. Fixes #7950. LGTM=nigeltao R=golang-codereviews, bradfitz, dan.kortschak, adg, nigeltao, jamesr CC=golang-codereviews https://golang.org/cl/97140043 --- src/compress/flate/inflate.go | 27 ++++++++++ src/compress/flate/inflate_test.go | 39 +++++++++++++++ src/compress/gzip/gunzip.go | 6 ++- src/compress/zlib/reader.go | 80 ++++++++++++++++++++---------- 4 files changed, 125 insertions(+), 27 deletions(-) create mode 100644 src/compress/flate/inflate_test.go diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go index a7fe94c50c..76519bbf42 100644 --- a/src/compress/flate/inflate.go +++ b/src/compress/flate/inflate.go @@ -56,6 +56,15 @@ func (e *WriteError) Error() string { return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() } +// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to +// to switch to a new underlying Reader. This permits reusing a ReadCloser +// instead of allocating a new one. +type Resetter interface { + // Reset discards any buffered data and resets the Resetter as if it was + // newly initialized with the given reader. + Reset(r io.Reader, dict []byte) error +} + // Note that much of the implementation of huffmanDecoder is also copied // into gen.go (in package main) for the purpose of precomputing the // fixed huffman tables so they can be included statically. @@ -679,12 +688,28 @@ func makeReader(r io.Reader) Reader { return bufio.NewReader(r) } +func (f *decompressor) Reset(r io.Reader, dict []byte) error { + *f = decompressor{ + r: makeReader(r), + bits: f.bits, + codebits: f.codebits, + hist: f.hist, + step: (*decompressor).nextBlock, + } + if dict != nil { + f.setDict(dict) + } + return nil +} + // NewReader returns a new ReadCloser that can be used // to read the uncompressed version of r. // If r does not also implement io.ByteReader, // the decompressor may read more data than necessary from r. // It is the caller's responsibility to call Close on the ReadCloser // when finished reading. +// +// The ReadCloser returned by NewReader also implements Resetter. func NewReader(r io.Reader) io.ReadCloser { var f decompressor f.bits = new([maxLit + maxDist]int) @@ -700,6 +725,8 @@ func NewReader(r io.Reader) io.ReadCloser { // the uncompressed data stream started with the given dictionary, // which has already been read. NewReaderDict is typically used // to read data compressed by NewWriterDict. +// +// The ReadCloser returned by NewReader also implements Resetter. func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { var f decompressor f.r = makeReader(r) diff --git a/src/compress/flate/inflate_test.go b/src/compress/flate/inflate_test.go new file mode 100644 index 0000000000..9f25d30b35 --- /dev/null +++ b/src/compress/flate/inflate_test.go @@ -0,0 +1,39 @@ +// 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 flate + +import ( + "bytes" + "io" + "testing" +) + +func TestReset(t *testing.T) { + ss := []string{ + "lorem ipsum izzle fo rizzle", + "the quick brown fox jumped over", + } + + deflated := make([]bytes.Buffer, 2) + for i, s := range ss { + w, _ := NewWriter(&deflated[i], 1) + w.Write([]byte(s)) + w.Close() + } + + inflated := make([]bytes.Buffer, 2) + + f := NewReader(&deflated[0]) + io.Copy(&inflated[0], f) + f.(Resetter).Reset(&deflated[1], nil) + io.Copy(&inflated[1], f) + f.Close() + + for i, s := range ss { + if s != inflated[i].String() { + t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s) + } + } +} diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go index fc08c7a48c..df1d5aa2be 100644 --- a/src/compress/gzip/gunzip.go +++ b/src/compress/gzip/gunzip.go @@ -208,7 +208,11 @@ func (z *Reader) readHeader(save bool) error { } z.digest.Reset() - z.decompressor = flate.NewReader(z.r) + if z.decompressor == nil { + z.decompressor = flate.NewReader(z.r) + } else { + z.decompressor.(flate.Resetter).Reset(z.r, nil) + } return nil } diff --git a/src/compress/zlib/reader.go b/src/compress/zlib/reader.go index e1191816d6..816f1bf6bd 100644 --- a/src/compress/zlib/reader.go +++ b/src/compress/zlib/reader.go @@ -51,10 +51,21 @@ type reader struct { scratch [4]byte } -// NewReader creates a new io.ReadCloser. -// Reads from the returned io.ReadCloser read and decompress data from r. +// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to +// to switch to a new underlying Reader. This permits reusing a ReadCloser +// instead of allocating a new one. +type Resetter interface { + // Reset discards any buffered data and resets the Resetter as if it was + // newly initialized with the given reader. + Reset(r io.Reader, dict []byte) error +} + +// NewReader creates a new ReadCloser. +// Reads from the returned ReadCloser read and decompress data from r. // The implementation buffers input and may read more data than necessary from r. // It is the caller's responsibility to call Close on the ReadCloser when done. +// +// The ReadCloser returned by NewReader also implements Resetter. func NewReader(r io.Reader) (io.ReadCloser, error) { return NewReaderDict(r, nil) } @@ -62,35 +73,14 @@ func NewReader(r io.Reader) (io.ReadCloser, error) { // NewReaderDict is like NewReader but uses a preset dictionary. // NewReaderDict ignores the dictionary if the compressed data does not refer to it. // If the compressed data refers to a different dictionary, NewReaderDict returns ErrDictionary. +// +// The ReadCloser returned by NewReaderDict also implements Resetter. func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) { z := new(reader) - if fr, ok := r.(flate.Reader); ok { - z.r = fr - } else { - z.r = bufio.NewReader(r) - } - _, err := io.ReadFull(z.r, z.scratch[0:2]) + err := z.Reset(r, dict) if err != nil { return nil, err } - h := uint(z.scratch[0])<<8 | uint(z.scratch[1]) - if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) { - return nil, ErrHeader - } - if z.scratch[1]&0x20 != 0 { - _, err = io.ReadFull(z.r, z.scratch[0:4]) - if err != nil { - return nil, err - } - checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) - if checksum != adler32.Checksum(dict) { - return nil, ErrDictionary - } - z.decompressor = flate.NewReaderDict(z.r, dict) - } else { - z.decompressor = flate.NewReader(z.r) - } - z.digest = adler32.New() return z, nil } @@ -131,3 +121,41 @@ func (z *reader) Close() error { z.err = z.decompressor.Close() return z.err } + +func (z *reader) Reset(r io.Reader, dict []byte) error { + if fr, ok := r.(flate.Reader); ok { + z.r = fr + } else { + z.r = bufio.NewReader(r) + } + _, err := io.ReadFull(z.r, z.scratch[0:2]) + if err != nil { + return err + } + h := uint(z.scratch[0])<<8 | uint(z.scratch[1]) + if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) { + return ErrHeader + } + haveDict := z.scratch[1]&0x20 != 0 + if haveDict { + _, err = io.ReadFull(z.r, z.scratch[0:4]) + if err != nil { + return err + } + checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3]) + if checksum != adler32.Checksum(dict) { + return ErrDictionary + } + } + if z.decompressor == nil { + if haveDict { + z.decompressor = flate.NewReaderDict(z.r, dict) + } else { + z.decompressor = flate.NewReader(z.r) + } + } else { + z.decompressor.(flate.Resetter).Reset(z.r, dict) + } + z.digest = adler32.New() + return nil +} From 8ba47e3d99b0cf1c86e10ece756ece3f9abeba04 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 20 Oct 2014 10:02:25 +0200 Subject: [PATCH 405/430] doc/go1.4.txt: add compress/* Reset note CC=golang-codereviews https://golang.org/cl/156430043 --- doc/go1.4.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.4.txt b/doc/go1.4.txt index df98de5c76..ae52562df9 100644 --- a/doc/go1.4.txt +++ b/doc/go1.4.txt @@ -21,6 +21,7 @@ cmd/go: (via go/build): a GOOS prefix acts as a tag only if preceded by an under asm: make textflag.h available outside of cmd/ld (CL 128050043) bufio: handling of empty tokens at EOF changed, may require scanner change (CL 145390043) +compress/flate, compress/gzip, compress/zlib: Reset support (https://codereview.appspot.com/97140043) crypto/tls: add support for ALPN (RFC 7301) (CL 108710046) crypto/tls: support programmatic selection of server certificates (CL 107400043) flag: it is now an error to set a flag multiple times (CL 156390043) From 63acc48f8794aa51b91d7e482ba9271e54d3f77a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 20 Oct 2014 07:33:08 -0700 Subject: [PATCH 406/430] encoding/gob: add custom decoder buffer for performance As we did with encoding, provide a trivial byte reader for faster decoding. We can also reduce some of the copying by doing the allocation all at once using a slightly different interface from byte buffers. benchmark old ns/op new ns/op delta BenchmarkEndToEndPipe 13368 12902 -3.49% BenchmarkEndToEndByteBuffer 5969 5642 -5.48% BenchmarkEndToEndSliceByteBuffer 479485 470798 -1.81% BenchmarkEncodeComplex128Slice 92367 92201 -0.18% BenchmarkEncodeFloat64Slice 39990 38960 -2.58% BenchmarkEncodeInt32Slice 30510 27938 -8.43% BenchmarkEncodeStringSlice 33753 33365 -1.15% BenchmarkDecodeComplex128Slice 232278 196704 -15.32% BenchmarkDecodeFloat64Slice 150258 128191 -14.69% BenchmarkDecodeInt32Slice 133806 115748 -13.50% BenchmarkDecodeStringSlice 335117 300534 -10.32% LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/154360049 --- src/encoding/gob/codec_test.go | 14 +++++--- src/encoding/gob/decode.go | 63 +++++++++++++++++++++++++++++++--- src/encoding/gob/decoder.go | 40 +++++---------------- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go index b3749e3528..56a7298fa5 100644 --- a/src/encoding/gob/codec_test.go +++ b/src/encoding/gob/codec_test.go @@ -50,6 +50,12 @@ func testError(t *testing.T) { return } +func newDecBuffer(data []byte) *decBuffer { + return &decBuffer{ + data: data, + } +} + // Test basic encode/decode routines for unsigned integers func TestUintCodec(t *testing.T) { defer testError(t) @@ -65,7 +71,7 @@ func TestUintCodec(t *testing.T) { for u := uint64(0); ; u = (u + 1) * 7 { b.Reset() encState.encodeUint(u) - decState := newDecodeState(bytes.NewBuffer(b.Bytes())) + decState := newDecodeState(newDecBuffer(b.Bytes())) v := decState.decodeUint() if u != v { t.Errorf("Encode/Decode: sent %#x received %#x", u, v) @@ -81,7 +87,7 @@ func verifyInt(i int64, t *testing.T) { var b = new(encBuffer) encState := newEncoderState(b) encState.encodeInt(i) - decState := newDecodeState(bytes.NewBuffer(b.Bytes())) + decState := newDecodeState(newDecBuffer(b.Bytes())) decState.buf = make([]byte, 8) j := decState.decodeInt() if i != j { @@ -118,7 +124,7 @@ var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40} // The result of encoding "hello" with field number 7 var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'} -func newDecodeState(buf *bytes.Buffer) *decoderState { +func newDecodeState(buf *decBuffer) *decoderState { d := new(decoderState) d.b = buf d.buf = make([]byte, uint64Size) @@ -328,7 +334,7 @@ func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, val } func newDecodeStateFromData(data []byte) *decoderState { - b := bytes.NewBuffer(data) + b := newDecBuffer(data) state := newDecodeState(b) state.fieldnum = -1 return state diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go index f44838e4cf..a5bef93141 100644 --- a/src/encoding/gob/decode.go +++ b/src/encoding/gob/decode.go @@ -7,7 +7,6 @@ package gob import ( - "bytes" "encoding" "errors" "io" @@ -29,15 +28,71 @@ type decoderState struct { dec *Decoder // The buffer is stored with an extra indirection because it may be replaced // if we load a type during decode (when reading an interface value). - b *bytes.Buffer + b *decBuffer fieldnum int // the last field number read. buf []byte next *decoderState // for free list } +// decBuffer is an extremely simple, fast implementation of a read-only byte buffer. +// It is initialized by calling Size and then copying the data into the slice returned by Bytes(). +type decBuffer struct { + data []byte + offset int // Read offset. +} + +func (d *decBuffer) Read(p []byte) (int, error) { + n := copy(p, d.data[d.offset:]) + if n == 0 && len(p) != 0 { + return 0, io.EOF + } + d.offset += n + return n, nil +} + +func (d *decBuffer) Drop(n int) { + if n > d.Len() { + panic("drop") + } + d.offset += n +} + +// Size grows the buffer to exactly n bytes, so d.Bytes() will +// return a slice of length n. Existing data is first discarded. +func (d *decBuffer) Size(n int) { + d.Reset() + if cap(d.data) < n { + d.data = make([]byte, n) + } else { + d.data = d.data[0:n] + } +} + +func (d *decBuffer) ReadByte() (byte, error) { + if d.offset >= len(d.data) { + return 0, io.EOF + } + c := d.data[d.offset] + d.offset++ + return c, nil +} + +func (d *decBuffer) Len() int { + return len(d.data) - d.offset +} + +func (d *decBuffer) Bytes() []byte { + return d.data[d.offset:] +} + +func (d *decBuffer) Reset() { + d.data = d.data[0:0] + d.offset = 0 +} + // We pass the bytes.Buffer separately for easier testing of the infrastructure // without requiring a full Decoder. -func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState { +func (dec *Decoder) newDecoderState(buf *decBuffer) *decoderState { d := dec.freeList if d == nil { d = new(decoderState) @@ -633,7 +688,7 @@ func (dec *Decoder) ignoreInterface(state *decoderState) { error_(dec.err) } // At this point, the decoder buffer contains a delimited value. Just toss it. - state.b.Next(int(state.decodeUint())) + state.b.Drop(int(state.decodeUint())) } // decodeGobDecoder decodes something implementing the GobDecoder interface. diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go index fe1494100a..c453e9ba39 100644 --- a/src/encoding/gob/decoder.go +++ b/src/encoding/gob/decoder.go @@ -6,7 +6,6 @@ package gob import ( "bufio" - "bytes" "errors" "io" "reflect" @@ -23,13 +22,12 @@ const tooBig = 1 << 30 type Decoder struct { mutex sync.Mutex // each item must be received atomically r io.Reader // source of the data - buf bytes.Buffer // buffer for more efficient i/o from r + buf decBuffer // buffer for more efficient i/o from r wireType map[typeId]*wireType // map from remote ID to local description decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines ignorerCache map[typeId]**decEngine // ditto for ignored objects freeList *decoderState // list of free decoderStates; avoids reallocation countBuf []byte // used for decoding integers while parsing messages - tmp []byte // temporary storage for i/o; saves reallocating err error } @@ -90,37 +88,17 @@ func (dec *Decoder) recvMessage() bool { // readMessage reads the next nbytes bytes from the input. func (dec *Decoder) readMessage(nbytes int) { - // Allocate the dec.tmp buffer, up to 10KB. - const maxBuf = 10 * 1024 - nTmp := nbytes - if nTmp > maxBuf { - nTmp = maxBuf + if dec.buf.Len() != 0 { + // The buffer should always be empty now. + panic("non-empty decoder buffer") } - if cap(dec.tmp) < nTmp { - nAlloc := nTmp + 100 // A little extra for growth. - if nAlloc > maxBuf { - nAlloc = maxBuf - } - dec.tmp = make([]byte, nAlloc) - } - dec.tmp = dec.tmp[:nTmp] - // Read the data - dec.buf.Grow(nbytes) - for nbytes > 0 { - if nbytes < nTmp { - dec.tmp = dec.tmp[:nbytes] + dec.buf.Size(nbytes) + _, dec.err = io.ReadFull(dec.r, dec.buf.Bytes()) + if dec.err != nil { + if dec.err == io.EOF { + dec.err = io.ErrUnexpectedEOF } - var nRead int - nRead, dec.err = io.ReadFull(dec.r, dec.tmp) - if dec.err != nil { - if dec.err == io.EOF { - dec.err = io.ErrUnexpectedEOF - } - return - } - dec.buf.Write(dec.tmp) - nbytes -= nRead } } From 0edafefc36b39dd456d3b6410f81dfcecfef6a3b Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Mon, 20 Oct 2014 15:59:10 +0100 Subject: [PATCH 407/430] cmd/gc: emit code for extern = https://golang.org/cl/152700045/ made it possible for struct literals assigned to globals to use as the RHS. Normally, this is to zero out variables on first use. Because globals are already zero (or their linker initialized value), we just ignored this. Now that can occur from non-initialization code, we need to emit this code. We don't use for initialization of globals any more, so this shouldn't cause any excessive zeroing. Fixes #8961. LGTM=rsc R=golang-codereviews, rsc CC=bradfitz, golang-codereviews https://golang.org/cl/154540044 --- src/cmd/gc/gen.c | 10 +++------- test/fixedbugs/issue8961.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 test/fixedbugs/issue8961.go diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index a7db833a1a..c7c9fcdaff 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -732,13 +732,9 @@ cgen_as(Node *nl, Node *nr) } if(nr == N || iszero(nr)) { - // externals and heaps should already be clear - if(nr == N) { - if(nl->class == PEXTERN) - return; - if(nl->class & PHEAP) - return; - } + // heaps should already be clear + if(nr == N && (nl->class & PHEAP)) + return; tl = nl->type; if(tl == T) diff --git a/test/fixedbugs/issue8961.go b/test/fixedbugs/issue8961.go new file mode 100644 index 0000000000..fbfb7e67f9 --- /dev/null +++ b/test/fixedbugs/issue8961.go @@ -0,0 +1,20 @@ +// 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. + +// Issue 8961. Empty composite literals to small globals were not filled in +package main + +type small struct { a int } +var foo small + +func main() { + foo.a = 1 + foo = small{} + if foo.a != 0 { + println("expected foo.a to be 0, was", foo.a) + panic("composite literal not filled in") + } +} From 3811c4d84aabc544f3431bf7fb59e9c57b183628 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 20 Oct 2014 11:10:00 -0400 Subject: [PATCH 408/430] debug/pe: remove use of unsafe Helps in environments with restricted support for unsafe. LGTM=bradfitz R=r, bradfitz CC=dsymonds, golang-codereviews https://golang.org/cl/156410044 --- src/debug/pe/file.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index ce6f1408fe..28a4bae113 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -13,7 +13,6 @@ import ( "io" "os" "strconv" - "unsafe" ) // A File represents an open PE file. @@ -125,6 +124,11 @@ func (f *File) Close() error { return err } +var ( + sizeofOptionalHeader32 = uintptr(binary.Size(OptionalHeader32{})) + sizeofOptionalHeader64 = uintptr(binary.Size(OptionalHeader64{})) +) + // NewFile creates a new File for accessing a PE binary in an underlying reader. func NewFile(r io.ReaderAt) (*File, error) { f := new(File) @@ -206,7 +210,7 @@ func NewFile(r io.ReaderAt) (*File, error) { var oh32 OptionalHeader32 var oh64 OptionalHeader64 switch uintptr(f.FileHeader.SizeOfOptionalHeader) { - case unsafe.Sizeof(oh32): + case sizeofOptionalHeader32: if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil { return nil, err } @@ -214,7 +218,7 @@ func NewFile(r io.ReaderAt) (*File, error) { return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic) } f.OptionalHeader = &oh32 - case unsafe.Sizeof(oh64): + case sizeofOptionalHeader64: if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil { return nil, err } From 0f022fdd527db88419c1261b11e764a53ea41160 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 20 Oct 2014 08:12:45 -0700 Subject: [PATCH 409/430] regexp/syntax: fix validity testing of zero repeats This is already tested by TestRE2Exhaustive, but the build has not broken because that test is not run when using -test.short. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/155580043 --- src/regexp/syntax/parse.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go index 3dc8ccf503..d579a4069b 100644 --- a/src/regexp/syntax/parse.go +++ b/src/regexp/syntax/parse.go @@ -272,13 +272,18 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( func repeatIsValid(re *Regexp, n int) bool { if re.Op == OpRepeat { m := re.Max + if m == 0 { + return true + } if m < 0 { m = re.Min } if m > n { return false } - n /= m + if m > 0 { + n /= m + } } for _, sub := range re.Sub { if !repeatIsValid(sub, n) { From 22be4bfdbf8100cfff28c4053dcfd35370917993 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 20 Oct 2014 12:16:46 -0400 Subject: [PATCH 410/430] regexp: fix TestOnePassCutoff The stack blowout can no longer happen, but we can still test that too-complex regexps are rejected. Replacement for CL 162770043. LGTM=iant, r R=r, iant CC=bradfitz, golang-codereviews https://golang.org/cl/162860043 --- src/regexp/all_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go index 5fadb67c09..01ea3742a8 100644 --- a/src/regexp/all_test.go +++ b/src/regexp/all_test.go @@ -6,6 +6,7 @@ package regexp import ( "reflect" + "regexp/syntax" "strings" "testing" ) @@ -473,12 +474,19 @@ func TestSplit(t *testing.T) { } } -// This ran out of stack before issue 7608 was fixed. +// Check that one-pass cutoff does trigger. func TestOnePassCutoff(t *testing.T) { - if testing.Short() { - t.Skip("Skipping in short mode") + re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl) + if err != nil { + t.Fatalf("parse: %v", err) + } + p, err := syntax.Compile(re.Simplify()) + if err != nil { + t.Fatalf("compile: %v", err) + } + if compileOnePass(p) != notOnePass { + t.Fatalf("makeOnePass succeeded; wanted notOnePass") } - MustCompile(`^(?:x{1,1000}){1,1000}$`) } func BenchmarkLiteral(b *testing.B) { From 7b9c5ec24b9c5e931544c1437eb7047c74549f58 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 20 Oct 2014 10:43:43 -0700 Subject: [PATCH 411/430] reflect: allocate correct type in assignTo and cvtT2I I came across this while debugging a GC problem in gccgo. There is code in assignTo and cvtT2I that handles assignment to all interface values. It allocates an empty interface even if the real type is a non-empty interface. The fields are then set for a non-empty interface, but the memory is recorded as holding an empty interface. This means that the GC has incorrect information. This is extremely unlikely to fail, because the code in the GC that handles empty interfaces looks like this: obj = nil; typ = eface->type; if(typ != nil) { if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers)) obj = eface->data; In the current runtime the condition is always true--if KindDirectIface is set, then KindNoPointers is clear--and we always want to set obj = eface->data. So the question is what happens when we incorrectly store a non-empty interface value in memory marked as an empty interface. In that case eface->type will not be a *rtype as we expect, but will instead be a pointer to an Itab. We are going to use this pointer to look at a *rtype kind field. The *rtype struct starts out like this: type rtype struct { size uintptr hash uint32 // hash of type; avoids computation in hash tables _ uint8 // unused/padding align uint8 // alignment of variable with this type fieldAlign uint8 // alignment of struct field with this type kind uint8 // enumeration for C An Itab always has at least two pointers, so on a little-endian 64-bit system the kind field will be the high byte of the second pointer. This will normally be zero, so the test of typ->kind will succeed, which is what we want. On a 32-bit system it might be possible to construct a failing case by somehow getting the Itab for an interface with one method to be immediately followed by a word that is all ones. The effect would be that the test would sometimes fail and the GC would not mark obj, leading to an invalid dangling pointer. I have not tried to construct this test. I noticed this in gccgo, where this error is much more likely to cause trouble for a rather random reason: gccgo uses a different layout of rtype, and in gccgo the kind field happens to be the low byte of a pointer, not the high byte. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/155450044 --- src/reflect/value.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/reflect/value.go b/src/reflect/value.go index 55a22350c0..43843e963a 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -406,7 +406,7 @@ func (v Value) call(op string, in []Value) []Value { off = (off + a - 1) &^ (a - 1) n := targ.size addr := unsafe.Pointer(uintptr(args) + off) - v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr)) + v = v.assignTo("reflect.Value.Call", targ, addr) if v.flag&flagIndir != 0 { memmove(addr, v.ptr, n) } else { @@ -1291,9 +1291,9 @@ func (v Value) send(x Value, nb bool) (selected bool) { func (v Value) Set(x Value) { v.mustBeAssignable() x.mustBeExported() // do not let unexported x leak - var target *interface{} + var target unsafe.Pointer if v.kind() == Interface { - target = (*interface{})(v.ptr) + target = v.ptr } x = x.assignTo("reflect.Set", v.typ, target) if x.flag&flagIndir != 0 { @@ -2094,7 +2094,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value { // assignTo returns a value v that can be assigned directly to typ. // It panics if v is not assignable to typ. // For a conversion to an interface type, target is a suggested scratch space to use. -func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { +func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value { if v.flag&flagMethod != 0 { v = makeMethodValue(context, v) } @@ -2110,15 +2110,15 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value { case implements(dst, v.typ): if target == nil { - target = new(interface{}) + target = unsafe_New(dst) } x := valueInterface(v, false) if dst.NumMethod() == 0 { - *target = x + *(*interface{})(target) = x } else { - ifaceE2I(dst, x, unsafe.Pointer(target)) + ifaceE2I(dst, x, target) } - return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)} + return Value{dst, target, flagIndir | flag(Interface)} } // Failed. @@ -2381,14 +2381,14 @@ func cvtDirect(v Value, typ Type) Value { // convertOp: concrete -> interface func cvtT2I(v Value, typ Type) Value { - target := new(interface{}) + target := unsafe_New(typ.common()) x := valueInterface(v, false) if typ.NumMethod() == 0 { - *target = x + *(*interface{})(target) = x } else { - ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target)) + ifaceE2I(typ.(*rtype), x, target) } - return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)} + return Value{typ.common(), target, v.flag&flagRO | flagIndir | flag(Interface)} } // convertOp: interface -> interface From 82a0188c88bd7bb0fbf31f10157b77beb2195594 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 20 Oct 2014 11:10:03 -0700 Subject: [PATCH 412/430] reflect: fix TestAllocations now that interfaces hold only pointers This test was failing but did not break the build because it was not run when -test.short was used. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/157150043 --- src/reflect/all_test.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 40eae0364c..268a9e319f 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -2502,10 +2502,21 @@ func TestAllocations(t *testing.T) { noAlloc(t, 100, func(j int) { var i interface{} var v Value - i = 42 + j + + // We can uncomment this when compiler escape analysis + // is good enough to see that the integer assigned to i + // does not escape and therefore need not be allocated. + // + // i = 42 + j + // v = ValueOf(i) + // if int(v.Int()) != 42+j { + // panic("wrong int") + // } + + i = func(j int) int { return j } v = ValueOf(i) - if int(v.Int()) != 42+j { - panic("wrong int") + if v.Interface().(func(int) int)(j) != j { + panic("wrong result") } }) } From c57cb7867e834136e55e7a2a171e1b7cc7cf34a0 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 20 Oct 2014 13:27:41 -0700 Subject: [PATCH 413/430] cmd/go: set exit status for failing "go generate" run. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/154360048 --- src/cmd/go/generate.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go index 167758207e..4227abbe7c 100644 --- a/src/cmd/go/generate.go +++ b/src/cmd/go/generate.go @@ -169,6 +169,7 @@ func (g *Generator) run() (ok bool) { if e != stop { panic(e) } + setExitStatus(1) } }() g.dir, g.file = filepath.Split(g.path) @@ -267,7 +268,8 @@ Words: var stop = fmt.Errorf("error in generation") // errorf logs an error message prefixed with the file and line number. -// It then exits the program because generation stops at the first error. +// It then exits the program (with exit status 1) because generation stops +// at the first error. func (g *Generator) errorf(format string, args ...interface{}) { fmt.Fprintf(os.Stderr, "%s:%d: %s\n", shortPath(g.path), g.lineNum, fmt.Sprintf(format, args...)) From 9070afb3599ad437ad08e5839653978817818c9a Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 20 Oct 2014 13:28:00 -0700 Subject: [PATCH 414/430] flag: roll back 156390043 (flag setting) Shell scripts depend on the old behavior too often. It's too late to make this change. LGTM=bradfitz R=rsc, bradfitz CC=golang-codereviews https://golang.org/cl/161890044 --- src/flag/flag.go | 29 --------------------- src/flag/flag_test.go | 60 ------------------------------------------- 2 files changed, 89 deletions(-) diff --git a/src/flag/flag.go b/src/flag/flag.go index 56860fc9de..60aef5d806 100644 --- a/src/flag/flag.go +++ b/src/flag/flag.go @@ -235,9 +235,6 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() } // If a Value has an IsBoolFlag() bool method returning true, // the command-line parser makes -name equivalent to -name=true // rather than using the next command-line argument. -// -// It is the implementer's responsibility to verify, if required, that the -// flag has been set only once. type Value interface { String() string Set(string) error @@ -273,7 +270,6 @@ type FlagSet struct { parsed bool actual map[string]*Flag formal map[string]*Flag - set map[*Flag]bool args []string // arguments after flags errorHandling ErrorHandling output io.Writer // nil means stderr; use out() accessor @@ -721,25 +717,6 @@ func (f *FlagSet) usage() { } } -// alreadySet reports whether the flag has already been set during parsing. -// Because user-defined flags may legally be set multiple times, it only -// complains about flags defined in this package. -func (f *FlagSet) alreadySet(flag *Flag) bool { - if f.set == nil { - f.set = make(map[*Flag]bool) - } - switch flag.Value.(type) { - case *boolValue, *intValue, *int64Value, *uintValue, *uint64Value, *stringValue, *float64Value, *durationValue: - default: - return false // Not one of ours. - } - if f.set[flag] { - return true - } - f.set[flag] = true - return false -} - // parseOne parses one flag. It reports whether a flag was seen. func (f *FlagSet) parseOne() (bool, error) { if len(f.args) == 0 { @@ -784,11 +761,6 @@ func (f *FlagSet) parseOne() (bool, error) { return false, f.failf("flag provided but not defined: -%s", name) } - // has it already been set? - if f.alreadySet(flag) { - return false, f.failf("flag set multiple times: -%s", name) - } - if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg if has_value { if err := fv.Set(value); err != nil { @@ -824,7 +796,6 @@ func (f *FlagSet) parseOne() (bool, error) { // The return value will be ErrHelp if -help or -h were set but not defined. func (f *FlagSet) Parse(arguments []string) error { f.parsed = true - f.set = nil f.args = arguments for { seen, err := f.parseOne() diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 80d92a5e71..8c88c8c274 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -377,63 +377,3 @@ func TestHelp(t *testing.T) { t.Fatal("help was called; should not have been for defined help flag") } } - -// Test that a standard flag can be set only once. Need to verify every flag type. -// User-defined flags can be set multiple times, and this is verified in the tests above. -func TestErrorOnMultipleSettings(t *testing.T) { - check := func(typ string, err error) { - if err == nil { - t.Errorf("%s flag can be set multiple times") - } else if !strings.Contains(err.Error(), "flag set multiple") { - t.Fatalf("expected multiple setting error, got %q", err) - } - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Bool("v", false, "usage") - check("bool", flags.Parse([]string{"-v", "-v"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Int("v", 0, "usage") - check("int", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Int64("v", 0, "usage") - check("int64", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Uint("v", 0, "usage") - check("uint", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Uint64("v", 0, "usage") - check("uint64", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.String("v", "", "usage") - check("string", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Float64("v", 0, "usage") - check("float64", flags.Parse([]string{"-v", "1", "-v", "2"})) - } - { - var flags FlagSet - flags.Init("test", ContinueOnError) - flags.Duration("v", 0, "usage") - check("duration", flags.Parse([]string{"-v", "1s", "-v", "2s"})) - } -} From 1946afb6621735d519009107bc98cab0a94d4fb6 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 20 Oct 2014 23:01:32 +0200 Subject: [PATCH 415/430] os/exec: fix number of expected file descriptors on Plan 9 Since CL 104570043 and 112720043, we are using the nsec system call instead of /dev/bintime on Plan 9. LGTM=rsc R=rsc CC=aram, golang-codereviews https://golang.org/cl/155590043 --- src/os/exec/exec_test.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 5fd439b8bb..bc9c00effe 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -258,15 +258,7 @@ var testedAlreadyLeaked = false // basefds returns the number of expected file descriptors // to be present in a process at start. func basefds() uintptr { - n := os.Stderr.Fd() + 1 - - // Go runtime for 32-bit Plan 9 requires that /dev/bintime - // be kept open. - // See ../../runtime/time_plan9_386.c:/^runtime·nanotime - if runtime.GOOS == "plan9" && runtime.GOARCH == "386" { - n++ - } - return n + return os.Stderr.Fd() + 1 } func closeUnexpectedFds(t *testing.T, m string) { From 9d06cfc810692911372b80b7ef0dc080ee1d34d4 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 20 Oct 2014 23:03:03 +0200 Subject: [PATCH 416/430] runtime: handle non-nil-terminated environment strings on Plan 9 Russ Cox pointed out that environment strings are not required to be nil-terminated on Plan 9. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/159130044 --- src/runtime/env_plan9.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go index 76e9867e03..e442c34835 100644 --- a/src/runtime/env_plan9.go +++ b/src/runtime/env_plan9.go @@ -30,7 +30,7 @@ func gogetenv(key string) string { if fd < 0 { return "" } - n := seek(fd, 0, 2) - 1 + n := seek(fd, 0, 2) if n <= 0 { close(fd) return "" @@ -44,6 +44,10 @@ func gogetenv(key string) string { return "" } + if p[r-1] == 0 { + r-- + } + var s string sp := (*_string)(unsafe.Pointer(&s)) sp.str = &p[0] From 3ec8fe45cf4190a55f692f7c6e42936f9d912d36 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 20 Oct 2014 15:48:42 -0700 Subject: [PATCH 417/430] runtime: fix flaky TestBlockProfile test It has been failing periodically on Solaris/x64. Change blockevent so it always records an event if we called SetBlockProfileRate(1), even if the time delta is negative or zero. Hopefully this will fix the test on Solaris. Caveat: I don't actually know what the Solaris problem is, this is just an educated guess. LGTM=dave R=dvyukov, dave CC=golang-codereviews https://golang.org/cl/159150043 --- src/runtime/mprof.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index f4676fad6e..803da56670 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -284,6 +284,8 @@ func SetBlockProfileRate(rate int) { var r int64 if rate <= 0 { r = 0 // disable profiling + } else if rate == 1 { + r = 1 // profile everything } else { // convert ns to cycles, use float64 to prevent overflow during multiplication r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000)) @@ -297,7 +299,7 @@ func SetBlockProfileRate(rate int) { func blockevent(cycles int64, skip int) { if cycles <= 0 { - return + cycles = 1 } rate := int64(atomicload64(&blockprofilerate)) if rate <= 0 || (rate > cycles && int64(fastrand1())%rate > cycles) { From e5383c68544236bbf41628ef8a3460676e0aec2a Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Tue, 21 Oct 2014 10:02:33 +1100 Subject: [PATCH 418/430] debug/pe: use appropriate type for sizeofOptionalHeader32 LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/157220043 --- src/debug/pe/file.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index 28a4bae113..759e5674fd 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -125,8 +125,8 @@ func (f *File) Close() error { } var ( - sizeofOptionalHeader32 = uintptr(binary.Size(OptionalHeader32{})) - sizeofOptionalHeader64 = uintptr(binary.Size(OptionalHeader64{})) + sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{})) + sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{})) ) // NewFile creates a new File for accessing a PE binary in an underlying reader. @@ -209,7 +209,7 @@ func NewFile(r io.ReaderAt) (*File, error) { } var oh32 OptionalHeader32 var oh64 OptionalHeader64 - switch uintptr(f.FileHeader.SizeOfOptionalHeader) { + switch f.FileHeader.SizeOfOptionalHeader { case sizeofOptionalHeader32: if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil { return nil, err From cf9558c8ab9a09cffeea1020e62411338c790b2f Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Mon, 20 Oct 2014 23:28:39 +0000 Subject: [PATCH 419/430] cmd/cgo: disable clang's integrated assembler Fixes #8348. Clang's internal assembler (introduced by default in clang 3.4) understands the .arch directive, but doesn't change the default value of -march. This causes the build to fail when we use BLX (armv5 and above) when clang is compiled for the default armv4t architecture (which appears to be the default on all the distros I've used). This is probably a clang bug, so work around it for the time being by disabling the integrated assembler when compiling the cgo assembly shim. This CL also includes a small change to ldelf.c which was required as clang 3.4 and above generate more weird symtab entries. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/156430044 --- src/cmd/cgo/gcc.go | 8 +++++++- src/cmd/ld/ldelf.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index d77d56c22a..e45839e8a4 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -745,7 +745,13 @@ func (p *Package) gccMachine() []string { case "386": return []string{"-m32"} case "arm": - return []string{"-marm"} // not thumb + args := []string{"-marm"} // not thumb + if strings.Contains(p.gccBaseCmd()[0], "clang") { + // The clang integrated assembler understands the .arch directive + // but does not appear to honor it, so disable it. Issue 8348. + args = append(args, "-no-integrated-as") + } + return args } return nil } diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c index 35f8b49856..b5d0819493 100644 --- a/src/cmd/ld/ldelf.c +++ b/src/cmd/ld/ldelf.c @@ -819,7 +819,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym) } break; case ElfSymBindLocal: - if(!(thechar == '5' && (strcmp(sym->name, "$a") == 0 || strcmp(sym->name, "$d") == 0))) // binutils for arm generate these mapping symbols, ignore these + if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these if(needSym) { // local names and hidden visiblity global names are unique // and should only reference by its index, not name, so we From 70f2f1b4705bfeaaeffa9fd7bf322473b27f2baf Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 20 Oct 2014 22:03:46 -0400 Subject: [PATCH 420/430] compress/gzip: allow stopping at end of first stream Allows parsing some file formats that assign special meaning to which stream data is found in. Will do the same for compress/bzip2 once this is reviewed and submitted. Fixes #6486. LGTM=nigeltao R=nigeltao, dan.kortschak CC=adg, bradfitz, golang-codereviews, r https://golang.org/cl/159120044 --- src/compress/gzip/gunzip.go | 27 +++++++++++++++++++++ src/compress/gzip/gunzip_test.go | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go index df1d5aa2be..72ee55c4fa 100644 --- a/src/compress/gzip/gunzip.go +++ b/src/compress/gzip/gunzip.go @@ -74,6 +74,7 @@ type Reader struct { flg byte buf [512]byte err error + multistream bool } // NewReader creates a new Reader reading the given reader. @@ -83,6 +84,7 @@ type Reader struct { func NewReader(r io.Reader) (*Reader, error) { z := new(Reader) z.r = makeReader(r) + z.multistream = true z.digest = crc32.NewIEEE() if err := z.readHeader(true); err != nil { return nil, err @@ -102,9 +104,30 @@ func (z *Reader) Reset(r io.Reader) error { } z.size = 0 z.err = nil + z.multistream = true return z.readHeader(true) } +// Multistream controls whether the reader supports multistream files. +// +// If enabled (the default), the Reader expects the input to be a sequence +// of individually gzipped data streams, each with its own header and +// trailer, ending at EOF. The effect is that the concatenation of a sequence +// of gzipped files is treated as equivalent to the gzip of the concatenation +// of the sequence. This is standard behavior for gzip readers. +// +// Calling Multistream(false) disables this behavior; disabling the behavior +// can be useful when reading file formats that distinguish individual gzip +// data streams or mix gzip data streams with other data streams. +// In this mode, when the Reader reaches the end of the data stream, +// Read returns io.EOF. If the underlying reader implements io.ByteReader, +// it will be left positioned just after the gzip stream. +// To start the next stream, call z.Reset(r) followed by z.Multistream(false). +// If there is no next stream, z.Reset(r) will return io.EOF. +func (z *Reader) Multistream(ok bool) { + z.multistream = ok +} + // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950). func get4(p []byte) uint32 { return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 @@ -245,6 +268,10 @@ func (z *Reader) Read(p []byte) (n int, err error) { } // File is ok; is there another? + if !z.multistream { + return 0, io.EOF + } + if err = z.readHeader(false); err != nil { z.err = err return diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go index 2471038f53..0636dec9ab 100644 --- a/src/compress/gzip/gunzip_test.go +++ b/src/compress/gzip/gunzip_test.go @@ -9,6 +9,7 @@ import ( "io" "io/ioutil" "os" + "strings" "testing" "time" ) @@ -367,3 +368,43 @@ func TestInitialReset(t *testing.T) { t.Errorf("got %q want %q", s, gunzipTests[1].raw) } } + +func TestMultistreamFalse(t *testing.T) { + // Find concatenation test. + var tt gunzipTest + for _, tt = range gunzipTests { + if strings.HasSuffix(tt.desc, " x2") { + goto Found + } + } + t.Fatal("cannot find hello.txt x2 in gunzip tests") + +Found: + br := bytes.NewReader(tt.gzip) + var r Reader + if err := r.Reset(br); err != nil { + t.Fatalf("first reset: %v", err) + } + + // Expect two streams with "hello world\n", then real EOF. + const hello = "hello world\n" + + r.Multistream(false) + data, err := ioutil.ReadAll(&r) + if string(data) != hello || err != nil { + t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil) + } + + if err := r.Reset(br); err != nil { + t.Fatalf("second reset: %v", err) + } + r.Multistream(false) + data, err = ioutil.ReadAll(&r) + if string(data) != hello || err != nil { + t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil) + } + + if err := r.Reset(br); err != io.EOF { + t.Fatalf("third reset: err=%v, want io.EOF", err) + } +} From 93fcb922570ac3b601f5addbe408866641783dac Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 20 Oct 2014 22:04:12 -0400 Subject: [PATCH 421/430] cmd/gc: disallow call of *T method using **T variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This brings cmd/gc in line with the spec on this question. It might break existing code, but that code was not conformant with the spec. Credit to Rémy for finding the broken code. Fixes #6366. LGTM=r R=golang-codereviews, r CC=adonovan, golang-codereviews, gri https://golang.org/cl/129550043 --- src/cmd/gc/typecheck.c | 7 +++++-- test/fixedbugs/bug371.go | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 2ad8ab5bff..714c662681 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -2127,13 +2127,16 @@ lookdot(Node *n, Type *t, int dostrcmp) n->left = nod(OADDR, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && eqtype(tt->type, rcvr)) { + } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) { n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) { + } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) { yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left); while(tt->etype == tptr) { + // Stop one level early for method with pointer receiver. + if(rcvr->etype == tptr && tt->type->etype != tptr) + break; n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); diff --git a/test/fixedbugs/bug371.go b/test/fixedbugs/bug371.go index 6329e9635a..86c73bf4a8 100644 --- a/test/fixedbugs/bug371.go +++ b/test/fixedbugs/bug371.go @@ -8,10 +8,10 @@ package main -type T struct {} +type T struct{} func (t *T) pm() {} -func (t T) m() {} +func (t T) m() {} func main() { p := &T{} @@ -20,5 +20,5 @@ func main() { q := &p q.m() // ERROR "requires explicit dereference" - q.pm() + q.pm() // ERROR "requires explicit dereference" } From ab4af52a9b3f821a96daa5fcbf86ac1fed4343a3 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 21 Oct 2014 13:26:40 +0200 Subject: [PATCH 422/430] time: panic with a more helpful error on use of invalid Timer Fixes #8721 LGTM=rsc R=r, rsc CC=golang-codereviews https://golang.org/cl/155620045 --- src/time/sleep.go | 6 ++++++ src/time/sleep_test.go | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/time/sleep.go b/src/time/sleep.go index 61660d14ff..e7a2ee2059 100644 --- a/src/time/sleep.go +++ b/src/time/sleep.go @@ -55,6 +55,9 @@ type Timer struct { // Stop does not close the channel, to prevent a read from the channel succeeding // incorrectly. func (t *Timer) Stop() bool { + if t.r.f == nil { + panic("time: Stop called on uninitialized Timer") + } return stopTimer(&t.r) } @@ -78,6 +81,9 @@ func NewTimer(d Duration) *Timer { // It returns true if the timer had been active, false if the timer had // expired or been stopped. func (t *Timer) Reset(d Duration) bool { + if t.r.f == nil { + panic("time: Reset called on uninitialized Timer") + } w := when(d) active := stopTimer(&t.r) t.r.when = w diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go index 2cfb6a59c2..c9b2956b78 100644 --- a/src/time/sleep_test.go +++ b/src/time/sleep_test.go @@ -9,6 +9,7 @@ import ( "fmt" "runtime" "sort" + "strings" "sync" "sync/atomic" "testing" @@ -407,3 +408,23 @@ func TestOverflowRuntimeTimer(t *testing.T) { // the end of CheckRuntimeTimerOverflow in internal_test.go. CheckRuntimeTimerOverflow() } + +func checkZeroPanicString(t *testing.T) { + e := recover() + s, _ := e.(string) + if want := "called on uninitialized Timer"; !strings.Contains(s, want) { + t.Errorf("panic = %v; want substring %q", e, want) + } +} + +func TestZeroTimerResetPanics(t *testing.T) { + defer checkZeroPanicString(t) + var tr Timer + tr.Reset(1) +} + +func TestZeroTimerStopPanics(t *testing.T) { + defer checkZeroPanicString(t) + var tr Timer + tr.Stop() +} From f29bd6c4a4385cd9ad24b4a0da0b66dd4f6644aa Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 21 Oct 2014 10:10:11 -0700 Subject: [PATCH 423/430] cmd/ld: fix addstrdata for big-endian systems LGTM=rsc R=minux, rsc CC=golang-codereviews https://golang.org/cl/158280043 --- src/cmd/ld/data.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 9983a9281c..61847546a3 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -633,9 +633,7 @@ addstrdata(char *name, char *value) s->dupok = 1; reachable = s->reachable; addaddr(ctxt, s, sp); - adduint32(ctxt, s, strlen(value)); - if(PtrSize == 8) - adduint32(ctxt, s, 0); // round struct to pointer width + adduintxx(ctxt, s, strlen(value), PtrSize); // addstring, addaddr, etc., mark the symbols as reachable. // In this case that is not necessarily true, so stick to what From b60d5e12e983e7e48ffab47b15e372bd23fbad98 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 21 Oct 2014 14:46:07 -0700 Subject: [PATCH 424/430] runtime: warn that cputicks() might not be monotonic. Get rid of gocputicks(), it is no longer used. LGTM=bradfitz, dave R=golang-codereviews, bradfitz, dave, minux CC=golang-codereviews https://golang.org/cl/161110044 --- src/runtime/asm_386.s | 6 ------ src/runtime/asm_amd64.s | 7 ------- src/runtime/asm_amd64p32.s | 7 ------- src/runtime/asm_arm.s | 3 --- src/runtime/stubs.go | 4 ++++ 5 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s index b0ed2d8ceb..20d3c47c94 100644 --- a/src/runtime/asm_386.s +++ b/src/runtime/asm_386.s @@ -871,12 +871,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-8 MOVL DX, ret_hi+4(FP) RET -TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 - RDTSC - MOVL AX, ret_lo+0(FP) - MOVL DX, ret_hi+4(FP) - RET - TEXT runtime·ldt0setup(SB),NOSPLIT,$16-0 // set up ldt 7 to point at tls0 // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go. diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 2ee3312086..709834180e 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -855,13 +855,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0 MOVQ AX, ret+0(FP) RET -TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 - RDTSC - SHLQ $32, DX - ADDQ DX, AX - MOVQ AX, ret+0(FP) - RET - // hash function using AES hardware instructions TEXT runtime·aeshash(SB),NOSPLIT,$0-32 MOVQ p+0(FP), AX // ptr to data diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s index e27f67e1ee..28875bc55a 100644 --- a/src/runtime/asm_amd64p32.s +++ b/src/runtime/asm_amd64p32.s @@ -657,13 +657,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0 MOVQ AX, ret+0(FP) RET -TEXT runtime·gocputicks(SB),NOSPLIT,$0-8 - RDTSC - SHLQ $32, DX - ADDQ DX, AX - MOVQ AX, ret+0(FP) - RET - // hash function using AES hardware instructions // For now, our one amd64p32 system (NaCl) does not // support using AES instructions, so have not bothered to diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index b21441488a..621d13187a 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -1275,9 +1275,6 @@ TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4 MOVW R0, ret+0(FP) RET -TEXT runtime·gocputicks(SB),NOSPLIT,$0 - B runtime·cputicks(SB) - TEXT runtime·return0(SB),NOSPLIT,$0 MOVW $0, R0 RET diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 6561094ff1..3419047198 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -180,7 +180,11 @@ func exit(code int32) func breakpoint() func nanotime() int64 func usleep(usec uint32) + +// careful: cputicks is not guaranteed to be monotonic! In particular, we have +// noticed drift between cpus on certain os/arch combinations. See issue 8976. func cputicks() int64 + func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer func munmap(addr unsafe.Pointer, n uintptr) func madvise(addr unsafe.Pointer, n uintptr, flags int32) From 4073be88f426180030971d0b06a7598ec46a0583 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Tue, 21 Oct 2014 23:42:13 +0000 Subject: [PATCH 425/430] undo CL 156430044 / 5d69cad4faaf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partial undo, changes to ldelf.c retained. Some platforms are still not working even with the integrated assembler disabled, will have to find another solution. ««« original CL description cmd/cgo: disable clang's integrated assembler Fixes #8348. Clang's internal assembler (introduced by default in clang 3.4) understands the .arch directive, but doesn't change the default value of -march. This causes the build to fail when we use BLX (armv5 and above) when clang is compiled for the default armv4t architecture (which appears to be the default on all the distros I've used). This is probably a clang bug, so work around it for the time being by disabling the integrated assembler when compiling the cgo assembly shim. This CL also includes a small change to ldelf.c which was required as clang 3.4 and above generate more weird symtab entries. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews https://golang.org/cl/156430044 »»» LGTM=minux R=iant, minux CC=golang-codereviews https://golang.org/cl/162880044 --- src/cmd/cgo/gcc.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index e45839e8a4..d77d56c22a 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -745,13 +745,7 @@ func (p *Package) gccMachine() []string { case "386": return []string{"-m32"} case "arm": - args := []string{"-marm"} // not thumb - if strings.Contains(p.gccBaseCmd()[0], "clang") { - // The clang integrated assembler understands the .arch directive - // but does not appear to honor it, so disable it. Issue 8348. - args = append(args, "-no-integrated-as") - } - return args + return []string{"-marm"} // not thumb } return nil } From 1e30bb027ac6f5d88c40fd9280805bc5f7a0d9be Mon Sep 17 00:00:00 2001 From: Jens Frederich Date: Wed, 22 Oct 2014 10:56:26 +1100 Subject: [PATCH 426/430] misc/makerelease: set version number in Windows installer Set correct version number at Windows installer based on Go's Mercurial tag. Name | Version ------------------------------------------------ Go Programming Language amd64 go1.3.3 | 1.3.3 Go Programming Language amd64 go1.2rc3 | 1.2 Go Programming Language amd64 go1.2beta1 | 1.2 Fixes #8239. LGTM=adg R=adg, c.emil.hessman, alex.brainman CC=golang-codereviews https://golang.org/cl/160950044 --- misc/makerelease/makerelease.go | 19 ++++++++++++++++++- misc/makerelease/windows/installer.wxs | 5 ++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go index 3094856dd4..9b2373307f 100644 --- a/misc/makerelease/makerelease.go +++ b/misc/makerelease/makerelease.go @@ -437,7 +437,8 @@ func (b *Build) Do() error { // Build package. _, err = b.run(work, "candle", "-nologo", - "-dVersion="+version, + "-dGoVersion="+version, + "-dWixGoVersion="+wixVersion(version), "-dArch="+b.Arch, "-dSourceDir=go", installer, appfiles) @@ -471,6 +472,22 @@ func (b *Build) Do() error { return err } +var versionRe = regexp.MustCompile(`^go([0-9]+(\.[0-9]+)*)`) + +// The Microsoft installer requires version format major.minor.build +// (http://msdn.microsoft.com/en-us/library/aa370859%28v=vs.85%29.aspx). +// Where the major and minor field has a maximum value of 255 and build 65535. +// The offical Go version format is goMAJOR.MINOR.PATCH at $GOROOT/VERSION. +// It's based on the Mercurial tag. Remove prefix and suffix to make the +// installer happy. +func wixVersion(v string) string { + m := versionRe.FindStringSubmatch(v) + if m == nil { + return "0.0.0" + } + return m[1] +} + // extras fetches the go.tools, go.blog, and go-tour repositories, // builds them and copies the resulting binaries and static assets // to the new GOROOT. diff --git a/misc/makerelease/windows/installer.wxs b/misc/makerelease/windows/installer.wxs index b170b98dc4..66e0913ba8 100644 --- a/misc/makerelease/windows/installer.wxs +++ b/misc/makerelease/windows/installer.wxs @@ -18,13 +18,12 @@ - Date: Wed, 22 Oct 2014 12:30:15 +1100 Subject: [PATCH 427/430] runtime/cgo: encode BLX directly, fixes one clang build error on arm Fixes #8348. Trying to work around clang's dodgy support for .arch by reverting to the external assembler didn't work out so well. Minux had a much better solution to encode the instructions we need as .word directives which avoids .arch altogether. I've confirmed with gdb that this form produces the expected machine code Dump of assembler code for function crosscall_arm1: 0x00000000 <+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr} 0x00000004 <+4>: mov r4, r0 0x00000008 <+8>: mov r5, r1 0x0000000c <+12>: mov r0, r2 0x00000010 <+16>: blx r5 0x00000014 <+20>: blx r4 0x00000018 <+24>: pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc} There is another compilation failure that blocks building Go with clang on arm # ../misc/cgo/test # _/home/dfc/go/misc/cgo/test /tmp/--407b12.s: Assembler messages: /tmp/--407b12.s:59: Error: selected processor does not support ARM mode `blx r0' clang: error: assembler command failed with exit code 1 (use -v to see invocation) FAIL _/home/dfc/go/misc/cgo/test [build failed] I'll open a new issue for that LGTM=iant R=iant, minux CC=golang-codereviews https://golang.org/cl/158180047 --- src/runtime/cgo/gcc_arm.S | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S index 2e4b3528ba..d5833bfad0 100644 --- a/src/runtime/cgo/gcc_arm.S +++ b/src/runtime/cgo/gcc_arm.S @@ -11,13 +11,6 @@ #define EXT(s) s #endif -/* - * Because the assembler might target an earlier revision of the ISA - * by default, we must explicitly specify the ISA revision to ensure - * BLX is recognized as a valid instruction. - */ -.arch armv5t - /* * void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void *g), void *g) * @@ -31,8 +24,12 @@ EXT(crosscall_arm1): mov r4, r0 mov r5, r1 mov r0, r2 - blx r5 // setg(g) - blx r4 // fn() + + // Because the assembler might target an earlier revision of the ISA + // by default, we encode BLX as a .word. + .word 0xe12fff35 // blx r5 // setg(g) + .word 0xe12fff34 // blx r4 // fn() + pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc} .globl EXT(__stack_chk_fail_local) From ecd1cc173aed7360ce1c9e7454e5b0b548728c18 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 22 Oct 2014 10:51:30 -0400 Subject: [PATCH 428/430] CONTRIBUTORS: add Austin Clements's google.com email (Google CLA) LGTM=bradfitz, austin R=austin CC=bradfitz, golang-codereviews https://golang.org/cl/158330045 --- CONTRIBUTORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b73bce09fc..7679f78742 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -96,7 +96,7 @@ Arvindh Rajesh Tamilmani Asim Shankar Ato Araki Aulus Egnatius Varialus -Austin Clements +Austin Clements Balazs Lecz Ben Eitzen Ben Fried From 18051c086012e3ea279994e987ffe826308f93df Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 22 Oct 2014 08:06:15 -0700 Subject: [PATCH 429/430] test: add more cases to recover.go test16 used to fail with gccgo. The withoutRecoverRecursive test would have failed in some possible implementations. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/151630043 --- test/recover.go | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/test/recover.go b/test/recover.go index 6287d65076..f92c15c1d6 100644 --- a/test/recover.go +++ b/test/recover.go @@ -63,6 +63,7 @@ func main() { test14reflect1() test14reflect2() test15() + test16() } } @@ -114,10 +115,23 @@ func withoutRecover() { mustNotRecover() // because it's a sub-call } +func withoutRecoverRecursive(n int) { + if n == 0 { + withoutRecoverRecursive(1) + } else { + v := recover() + if v != nil { + println("spurious recover (recursive)", v) + die() + } + } +} + func test1() { - defer mustNotRecover() // because mustRecover will squelch it - defer mustRecover(1) // because of panic below - defer withoutRecover() // should be no-op, leaving for mustRecover to find + defer mustNotRecover() // because mustRecover will squelch it + defer mustRecover(1) // because of panic below + defer withoutRecover() // should be no-op, leaving for mustRecover to find + defer withoutRecoverRecursive(0) // ditto panic(1) } @@ -547,3 +561,27 @@ func test15() { defer f() panic(15) } + +func reflectFunc2(args []reflect.Value) (results []reflect.Value) { + // This will call reflectFunc3 + args[0].Interface().(func())() + return nil +} + +func reflectFunc3(args []reflect.Value) (results []reflect.Value) { + if v := recover(); v != nil { + println("spurious recover", v) + die() + } + return nil +} + +func test16() { + defer mustRecover(16) + + f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func())) + f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func()) + defer f2(f3) + + panic(16) +} From af3868f1879c7f8bef1a4ac43cfe1ab1304ad6a4 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Wed, 22 Oct 2014 20:23:49 +0400 Subject: [PATCH 430/430] sync: release Pool memory during second and later GCs Pool memory was only being released during the first GC after the first Put. Put assumes that p.local != nil means p is on the allPools list. poolCleanup (called during each GC) removed each pool from allPools but did not clear p.local, so each pool was cleared by exactly one GC and then never cleared again. This bug was introduced late in the Go 1.3 release cycle. Fixes #8979. LGTM=rsc R=golang-codereviews, bradfitz, r, rsc CC=golang-codereviews, khr https://golang.org/cl/162980043 --- src/sync/pool.go | 2 ++ src/sync/pool_test.go | 54 ++++++++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/sync/pool.go b/src/sync/pool.go index 1f08707cd4..0cf0637024 100644 --- a/src/sync/pool.go +++ b/src/sync/pool.go @@ -200,6 +200,8 @@ func poolCleanup() { } l.shared = nil } + p.local = nil + p.localSize = 0 } allPools = []*Pool{} } diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go index cf5c8bd903..fa1a27beac 100644 --- a/src/sync/pool_test.go +++ b/src/sync/pool_test.go @@ -69,32 +69,44 @@ func TestPoolNew(t *testing.T) { } } -// Test that Pool does not hold pointers to previously cached -// resources +// Test that Pool does not hold pointers to previously cached resources. func TestPoolGC(t *testing.T) { + testPool(t, true) +} + +// Test that Pool releases resources on GC. +func TestPoolRelease(t *testing.T) { + testPool(t, false) +} + +func testPool(t *testing.T, drain bool) { var p Pool - var fin uint32 const N = 100 - for i := 0; i < N; i++ { - v := new(string) - runtime.SetFinalizer(v, func(vv *string) { - atomic.AddUint32(&fin, 1) - }) - p.Put(v) - } - for i := 0; i < N; i++ { - p.Get() - } - for i := 0; i < 5; i++ { - runtime.GC() - time.Sleep(time.Duration(i*100+10) * time.Millisecond) - // 1 pointer can remain on stack or elsewhere - if atomic.LoadUint32(&fin) >= N-1 { - return +loop: + for try := 0; try < 3; try++ { + var fin, fin1 uint32 + for i := 0; i < N; i++ { + v := new(string) + runtime.SetFinalizer(v, func(vv *string) { + atomic.AddUint32(&fin, 1) + }) + p.Put(v) } + if drain { + for i := 0; i < N; i++ { + p.Get() + } + } + for i := 0; i < 5; i++ { + runtime.GC() + time.Sleep(time.Duration(i*100+10) * time.Millisecond) + // 1 pointer can remain on stack or elsewhere + if fin1 = atomic.LoadUint32(&fin); fin1 >= N-1 { + continue loop + } + } + t.Fatalf("only %v out of %v resources are finalized on try %v", fin1, N, try) } - t.Fatalf("only %v out of %v resources are finalized", - atomic.LoadUint32(&fin), N) } func TestPoolStress(t *testing.T) {