summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/5l/noop.c3
-rw-r--r--src/cmd/6l/pass.c13
-rw-r--r--src/cmd/8l/pass.c14
-rw-r--r--src/cmd/api/goapi.go28
-rw-r--r--src/cmd/api/testdata/src/pkg/p1/golden.txt4
-rw-r--r--src/cmd/api/testdata/src/pkg/p1/p1.go6
-rw-r--r--src/cmd/cgo/doc.go13
-rw-r--r--src/cmd/cgo/main.go3
-rw-r--r--src/cmd/cgo/out.go107
-rw-r--r--src/cmd/dist/build.c7
-rw-r--r--src/cmd/fix/go1rename.go90
-rw-r--r--src/cmd/fix/go1rename_test.go130
-rw-r--r--src/cmd/fix/httputil.go63
-rw-r--r--src/cmd/fix/httputil_test.go122
-rw-r--r--src/cmd/gc/Makefile2
-rw-r--r--src/cmd/gc/dcl.c35
-rw-r--r--src/cmd/gc/doc.go2
-rw-r--r--src/cmd/gc/go.h4
-rw-r--r--src/cmd/gc/inl.c2
-rw-r--r--src/cmd/gc/lex.c2
-rw-r--r--src/cmd/gc/obj.c32
-rw-r--r--src/cmd/gc/reflect.c6
-rw-r--r--src/cmd/gc/runtime.go2
-rw-r--r--src/cmd/gc/subr.c28
-rw-r--r--src/cmd/gc/typecheck.c62
-rw-r--r--src/cmd/gc/walk.c14
-rw-r--r--src/cmd/go/bootstrap.go17
-rw-r--r--src/cmd/go/build.go272
-rw-r--r--src/cmd/go/clean.go2
-rw-r--r--src/cmd/go/discovery.go63
-rw-r--r--src/cmd/go/doc.go101
-rw-r--r--src/cmd/go/env.go89
-rw-r--r--src/cmd/go/get.go132
-rw-r--r--src/cmd/go/help.go48
-rw-r--r--src/cmd/go/http.go52
-rw-r--r--src/cmd/go/list.go37
-rw-r--r--src/cmd/go/main.go57
-rw-r--r--src/cmd/go/match_test.go36
-rw-r--r--src/cmd/go/pkg.go93
-rw-r--r--src/cmd/go/run.go9
-rwxr-xr-xsrc/cmd/go/test.bash71
-rw-r--r--src/cmd/go/test.go44
-rw-r--r--src/cmd/go/testflag.go47
-rw-r--r--src/cmd/go/vcs.go185
-rw-r--r--src/cmd/godoc/appinit.go8
-rw-r--r--src/cmd/godoc/codewalk.go14
-rw-r--r--src/cmd/godoc/dirtrees.go43
-rw-r--r--src/cmd/godoc/doc.go45
-rw-r--r--src/cmd/godoc/filesystem.go522
-rw-r--r--src/cmd/godoc/godoc.go376
-rw-r--r--src/cmd/godoc/httpzip.go190
-rw-r--r--src/cmd/godoc/index.go8
-rw-r--r--src/cmd/godoc/main.go223
-rw-r--r--src/cmd/godoc/mapping.go202
-rw-r--r--src/cmd/godoc/parser.go4
-rw-r--r--src/cmd/godoc/template.go182
-rw-r--r--src/cmd/godoc/utils.go79
-rw-r--r--src/cmd/godoc/zip.go35
-rw-r--r--src/cmd/gofmt/gofmt.go12
-rw-r--r--src/cmd/gofmt/long_test.go12
-rw-r--r--src/cmd/ld/doc.go71
-rw-r--r--src/cmd/nm/doc.go3
-rw-r--r--src/cmd/pack/ar.c9
-rw-r--r--src/cmd/vet/doc.go2
-rw-r--r--src/cmd/vet/taglit.go3
-rw-r--r--src/lib9/utf/Makefile14
-rwxr-xr-xsrc/make.bash19
-rw-r--r--src/make.bat40
-rw-r--r--src/pkg/archive/tar/reader.go2
-rw-r--r--src/pkg/archive/tar/writer.go17
-rw-r--r--src/pkg/archive/tar/writer_test.go9
-rw-r--r--src/pkg/archive/zip/reader.go65
-rw-r--r--src/pkg/archive/zip/reader_test.go252
-rw-r--r--src/pkg/archive/zip/struct.go9
-rw-r--r--src/pkg/archive/zip/testdata/crc32-not-streamed.zipbin0 -> 314 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-no-datadesc-sig.zipbin0 -> 330 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-with-datadesc-sig.zipbin0 -> 242 bytes
-rw-r--r--src/pkg/archive/zip/testdata/r.zipbin440 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/writer.go1
-rw-r--r--src/pkg/archive/zip/writer_test.go2
-rw-r--r--src/pkg/crypto/tls/common.go30
-rw-r--r--src/pkg/crypto/tls/handshake_client.go14
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go2
-rw-r--r--src/pkg/crypto/tls/root_test.go37
-rw-r--r--src/pkg/crypto/tls/root_windows.go47
-rw-r--r--src/pkg/crypto/tls/tls.go7
-rw-r--r--src/pkg/crypto/x509/pkcs1.go2
-rw-r--r--src/pkg/crypto/x509/root.go17
-rw-r--r--src/pkg/crypto/x509/root_darwin.go (renamed from src/pkg/crypto/tls/root_darwin.go)17
-rw-r--r--src/pkg/crypto/x509/root_stub.go (renamed from src/pkg/crypto/tls/root_stub.go)9
-rw-r--r--src/pkg/crypto/x509/root_unix.go (renamed from src/pkg/crypto/tls/root_unix.go)18
-rw-r--r--src/pkg/crypto/x509/root_windows.go226
-rw-r--r--src/pkg/crypto/x509/verify.go36
-rw-r--r--src/pkg/crypto/x509/verify_test.go53
-rw-r--r--src/pkg/crypto/x509/x509.go2
-rw-r--r--src/pkg/database/sql/driver/driver.go11
-rw-r--r--src/pkg/database/sql/fakedb_test.go21
-rw-r--r--src/pkg/database/sql/sql.go145
-rw-r--r--src/pkg/database/sql/sql_test.go115
-rw-r--r--src/pkg/encoding/asn1/asn1.go10
-rw-r--r--src/pkg/encoding/asn1/asn1_test.go2
-rw-r--r--src/pkg/encoding/asn1/common.go3
-rw-r--r--src/pkg/encoding/asn1/marshal.go4
-rw-r--r--src/pkg/encoding/asn1/marshal_test.go6
-rw-r--r--src/pkg/encoding/binary/binary.go11
-rw-r--r--src/pkg/encoding/csv/reader.go3
-rw-r--r--src/pkg/encoding/gob/decode.go3
-rw-r--r--src/pkg/encoding/gob/doc.go2
-rw-r--r--src/pkg/encoding/gob/encoder_test.go4
-rw-r--r--src/pkg/encoding/gob/gobencdec_test.go19
-rw-r--r--src/pkg/encoding/json/encode.go5
-rw-r--r--src/pkg/exp/norm/maketables.go4
-rw-r--r--src/pkg/exp/norm/normalize.go2
-rw-r--r--src/pkg/exp/types/universe.go5
-rw-r--r--src/pkg/exp/wingui/Makefile24
-rw-r--r--src/pkg/exp/wingui/gui.go155
-rw-r--r--src/pkg/exp/wingui/winapi.go134
-rw-r--r--src/pkg/exp/wingui/zwinapi.go192
-rw-r--r--src/pkg/expvar/expvar.go41
-rw-r--r--src/pkg/flag/example_test.go83
-rw-r--r--src/pkg/fmt/doc.go6
-rw-r--r--src/pkg/fmt/export_test.go7
-rw-r--r--src/pkg/fmt/fmt_test.go11
-rw-r--r--src/pkg/fmt/format.go19
-rw-r--r--src/pkg/fmt/print.go58
-rw-r--r--src/pkg/fmt/scan.go113
-rw-r--r--src/pkg/fmt/scan_test.go4
-rw-r--r--src/pkg/go/build/Makefile11
-rw-r--r--src/pkg/go/build/build.go85
-rw-r--r--src/pkg/go/build/build_test.go1
-rw-r--r--src/pkg/go/build/deps_test.go424
-rw-r--r--src/pkg/go/build/syslist.go4
-rw-r--r--src/pkg/go/parser/error_test.go166
-rw-r--r--src/pkg/go/parser/parser.go152
-rw-r--r--src/pkg/go/parser/parser_test.go83
-rw-r--r--src/pkg/go/parser/short_test.go75
-rw-r--r--src/pkg/go/parser/testdata/commas.src19
-rw-r--r--src/pkg/go/parser/testdata/issue3106.src46
-rw-r--r--src/pkg/go/printer/example_test.go67
-rw-r--r--src/pkg/go/printer/nodes.go58
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden15
-rw-r--r--src/pkg/go/printer/testdata/declarations.input10
-rw-r--r--src/pkg/go/printer/testdata/statements.golden59
-rw-r--r--src/pkg/go/printer/testdata/statements.input43
-rw-r--r--src/pkg/go/scanner/scanner.go2
-rw-r--r--src/pkg/html/template/clone_test.go33
-rw-r--r--src/pkg/html/template/content.go4
-rw-r--r--src/pkg/html/template/doc.go2
-rw-r--r--src/pkg/html/template/escape.go42
-rw-r--r--src/pkg/html/template/escape_test.go9
-rw-r--r--src/pkg/html/template/template.go34
-rw-r--r--src/pkg/image/draw/draw.go2
-rw-r--r--src/pkg/index/suffixarray/qsufsort.go4
-rw-r--r--src/pkg/io/io.go7
-rw-r--r--src/pkg/io/ioutil/ioutil.go9
-rw-r--r--src/pkg/log/log.go56
-rw-r--r--src/pkg/log/syslog/syslog_windows.go8
-rw-r--r--src/pkg/math/big/nat.go2
-rw-r--r--src/pkg/math/erf.go4
-rw-r--r--src/pkg/net/dial_test.go19
-rw-r--r--src/pkg/net/dnsclient.go20
-rw-r--r--src/pkg/net/dnsmsg.go350
-rw-r--r--src/pkg/net/dnsmsg_test.go13
-rw-r--r--src/pkg/net/fd_linux.go3
-rw-r--r--src/pkg/net/file_test.go112
-rw-r--r--src/pkg/net/http/client_test.go6
-rw-r--r--src/pkg/net/http/request.go6
-rw-r--r--src/pkg/net/http/request_test.go19
-rw-r--r--src/pkg/net/http/server.go2
-rw-r--r--src/pkg/net/http/transport.go2
-rw-r--r--src/pkg/net/http/transport_test.go26
-rw-r--r--src/pkg/net/http/triv.go53
-rw-r--r--src/pkg/net/interface.go2
-rw-r--r--src/pkg/net/interface_linux.go12
-rw-r--r--src/pkg/net/interface_stub.go2
-rw-r--r--src/pkg/net/interface_windows.go2
-rw-r--r--src/pkg/net/iprawsock_posix.go7
-rw-r--r--src/pkg/net/ipsock_posix.go82
-rw-r--r--src/pkg/net/mac.go20
-rw-r--r--src/pkg/net/mac_test.go16
-rw-r--r--src/pkg/net/mail/message.go3
-rw-r--r--src/pkg/net/multicast_test.go8
-rw-r--r--src/pkg/net/net.go17
-rw-r--r--src/pkg/net/net_test.go1
-rw-r--r--src/pkg/net/parse_test.go4
-rw-r--r--src/pkg/net/rpc/client.go3
-rw-r--r--src/pkg/net/server_test.go547
-rw-r--r--src/pkg/net/sock.go4
-rw-r--r--src/pkg/net/sockopt.go3
-rw-r--r--src/pkg/net/sockopt_bsd.go13
-rw-r--r--src/pkg/net/sockopt_linux.go13
-rw-r--r--src/pkg/net/sockopt_windows.go13
-rw-r--r--src/pkg/net/tcpsock_posix.go10
-rw-r--r--src/pkg/net/timeout_test.go51
-rw-r--r--src/pkg/net/udp_test.go4
-rw-r--r--src/pkg/net/udpsock_posix.go7
-rw-r--r--src/pkg/net/unicast_test.go523
-rw-r--r--src/pkg/net/unixsock_posix.go14
-rw-r--r--src/pkg/os/error.go18
-rw-r--r--src/pkg/os/error_plan9.go9
-rw-r--r--src/pkg/os/error_posix.go14
-rw-r--r--src/pkg/os/error_test.go81
-rw-r--r--src/pkg/os/error_windows.go30
-rw-r--r--src/pkg/os/exec/exec.go2
-rw-r--r--src/pkg/os/file_unix.go16
-rw-r--r--src/pkg/os/os_test.go19
-rw-r--r--src/pkg/os/stat_windows.go24
-rw-r--r--src/pkg/os/types.go2
-rw-r--r--src/pkg/path/filepath/match.go24
-rw-r--r--src/pkg/path/filepath/match_test.go38
-rw-r--r--src/pkg/path/filepath/path.go61
-rw-r--r--src/pkg/path/filepath/path_test.go76
-rw-r--r--src/pkg/path/filepath/symlink.go67
-rw-r--r--src/pkg/path/filepath/symlink_windows.go27
-rw-r--r--src/pkg/reflect/type.go44
-rw-r--r--src/pkg/reflect/value.go13
-rw-r--r--src/pkg/runtime/asm_386.s17
-rw-r--r--src/pkg/runtime/asm_amd64.s19
-rw-r--r--src/pkg/runtime/asm_arm.s7
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_386.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_darwin_amd64.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c8
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c8
-rw-r--r--src/pkg/runtime/compiler.go13
-rw-r--r--src/pkg/runtime/debug/stack_test.go21
-rw-r--r--src/pkg/runtime/export_test.go2
-rw-r--r--src/pkg/runtime/goc2c.c750
-rw-r--r--src/pkg/runtime/malloc.goc19
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go5
-rw-r--r--src/pkg/runtime/proc.c17
-rw-r--r--src/pkg/runtime/runtime.c8
-rw-r--r--src/pkg/runtime/runtime.h2
-rw-r--r--src/pkg/runtime/signal_plan9_386.c6
-rw-r--r--src/pkg/runtime/signal_unix.c8
-rw-r--r--src/pkg/runtime/stack.h5
-rw-r--r--src/pkg/runtime/stack_test.go1528
-rw-r--r--src/pkg/runtime/sys_darwin_386.s29
-rw-r--r--src/pkg/runtime/sys_darwin_amd64.s28
-rw-r--r--src/pkg/runtime/sys_freebsd_386.s27
-rw-r--r--src/pkg/runtime/sys_freebsd_amd64.s28
-rw-r--r--src/pkg/runtime/sys_linux_386.s6
-rw-r--r--src/pkg/runtime/sys_linux_amd64.s22
-rw-r--r--src/pkg/runtime/sys_linux_arm.s14
-rw-r--r--src/pkg/runtime/sys_netbsd_386.s23
-rw-r--r--src/pkg/runtime/sys_netbsd_amd64.s24
-rw-r--r--src/pkg/runtime/sys_openbsd_386.s23
-rw-r--r--src/pkg/runtime/sys_openbsd_amd64.s24
-rw-r--r--src/pkg/runtime/sys_windows_386.s48
-rw-r--r--src/pkg/runtime/sys_windows_amd64.s88
-rw-r--r--src/pkg/runtime/thread_darwin.c20
-rw-r--r--src/pkg/runtime/thread_freebsd.c20
-rw-r--r--src/pkg/runtime/thread_linux.c20
-rw-r--r--src/pkg/runtime/thread_netbsd.c20
-rw-r--r--src/pkg/runtime/thread_openbsd.c20
-rw-r--r--src/pkg/runtime/thread_plan9.c20
-rw-r--r--src/pkg/runtime/thread_windows.c21
-rw-r--r--src/pkg/sort/sort.go8
-rw-r--r--src/pkg/strconv/isprint.go521
-rw-r--r--src/pkg/strconv/makeisprint.go162
-rw-r--r--src/pkg/strconv/quote.go181
-rw-r--r--src/pkg/strconv/quote_test.go15
-rw-r--r--src/pkg/strings/example_test.go2
-rw-r--r--src/pkg/sync/atomic/atomic_test.go16
-rwxr-xr-xsrc/pkg/syscall/mkall.sh4
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl10
-rw-r--r--src/pkg/syscall/syscall_linux.go2
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go53
-rw-r--r--src/pkg/syscall/syscall_windows.go8
-rw-r--r--src/pkg/syscall/zerrors_linux_arm.go66
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go60
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go330
-rw-r--r--src/pkg/syscall/zsyscall_windows_amd64.go330
-rw-r--r--src/pkg/syscall/zsysnum_linux_arm.go14
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go6
-rw-r--r--src/pkg/syscall/ztypes_windows.go146
-rw-r--r--src/pkg/testing/testing.go5
-rw-r--r--src/pkg/text/template/exec.go1
-rw-r--r--src/pkg/text/template/exec_test.go4
-rw-r--r--src/pkg/text/template/multi_test.go2
-rw-r--r--src/pkg/text/template/parse/lex.go25
-rw-r--r--src/pkg/text/template/parse/parse.go2
-rw-r--r--src/pkg/text/template/parse/parse_test.go15
-rw-r--r--src/pkg/time/tick_test.go2
-rw-r--r--src/pkg/time/time.go7
-rw-r--r--src/pkg/unicode/utf16/export_test.go11
-rw-r--r--src/pkg/unicode/utf16/utf16.go21
-rw-r--r--src/pkg/unicode/utf16/utf16_test.go10
-rw-r--r--src/pkg/unicode/utf8/utf8.go13
-rw-r--r--src/pkg/unicode/utf8/utf8_test.go21
-rwxr-xr-xsrc/run.bash55
-rw-r--r--src/run.bat31
-rwxr-xr-xsrc/sudo.bash2
292 files changed, 11024 insertions, 4595 deletions
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index eb44344f4..004f9f2fa 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -226,8 +226,7 @@ noops(void)
p->as = AMOVW;
p->scond = C_SCOND_LO;
p->from.type = D_CONST;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- p->from.offset = autosize+160;
+ p->from.offset = autosize;
p->to.type = D_REG;
p->to.reg = 1;
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index 2357a7f77..c9b477627 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -501,10 +501,17 @@ dostkoff(void)
q = p;
}
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ // 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(autoffset+160+textarg > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
+ if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
+ moreconst1 = autoffset;
moreconst2 = textarg;
// 4 varieties varieties (const1==0 cross const2==0)
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index b900a5f79..9034fdf3a 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -527,10 +527,18 @@ dostkoff(void)
p = appendp(p); // save frame size in DX
p->as = AMOVL;
p->to.type = D_DX;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
p->from.type = D_CONST;
- if(autoffset+160+cursym->text->to.offset2 > 4096)
- p->from.offset = (autoffset+160) & ~7LL;
+
+ // 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 + cursym->text->to.offset2 + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
+ p->from.offset = (autoffset+7) & ~7LL;
p = appendp(p); // save arg size in AX
p->as = AMOVL;
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index fe9c862f4..7363f6d82 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -52,6 +52,12 @@ var contexts = []*build.Context{
{GOOS: "windows", GOARCH: "386"},
}
+func init() {
+ for _, c := range contexts {
+ c.Compiler = build.Default.Compiler
+ }
+}
+
func contextName(c *build.Context) string {
s := c.GOOS + "-" + c.GOARCH
if c.CgoEnabled {
@@ -125,7 +131,7 @@ func main() {
if err != nil {
log.Fatalf("Error reading file %s: %v", *checkFile, err)
}
- v1 := strings.Split(string(bs), "\n")
+ v1 := strings.Split(strings.TrimSpace(string(bs)), "\n")
sort.Strings(v1)
v2 := features
take := func(sl *[]string) string {
@@ -133,17 +139,24 @@ func main() {
*sl = (*sl)[1:]
return s
}
+ changes := false
for len(v1) > 0 || len(v2) > 0 {
switch {
case len(v2) == 0 || v1[0] < v2[0]:
fmt.Fprintf(bw, "-%s\n", take(&v1))
+ changes = true
case len(v1) == 0 || v1[0] > v2[0]:
fmt.Fprintf(bw, "+%s\n", take(&v2))
+ changes = true
default:
take(&v1)
take(&v2)
}
}
+ if changes {
+ bw.Flush()
+ os.Exit(1)
+ }
} else {
for _, f := range features {
fmt.Fprintf(bw, "%s\n", f)
@@ -278,7 +291,9 @@ func (w *Walker) WalkPackage(name string) {
}
}
- log.Printf("package %s", name)
+ if *verbose {
+ log.Printf("package %s", name)
+ }
pop := w.pushScope("pkg " + name)
defer pop()
@@ -573,7 +588,14 @@ func (w *Walker) varValueType(vi interface{}) (string, error) {
}
}
// maybe a function call; maybe a conversion. Need to lookup type.
- return "", fmt.Errorf("not a known function %q", w.nodeString(v.Fun))
+ // TODO(bradfitz): this is a hack, but arguably most of this tool is,
+ // until the Go AST has type information.
+ nodeStr := w.nodeString(v.Fun)
+ switch nodeStr {
+ case "string", "[]byte":
+ return nodeStr, nil
+ }
+ return "", fmt.Errorf("not a known function %q", nodeStr)
default:
return "", fmt.Errorf("unknown const value type %T", vi)
}
diff --git a/src/cmd/api/testdata/src/pkg/p1/golden.txt b/src/cmd/api/testdata/src/pkg/p1/golden.txt
index 3a1b3f535..e334e5776 100644
--- a/src/cmd/api/testdata/src/pkg/p1/golden.txt
+++ b/src/cmd/api/testdata/src/pkg/p1/golden.txt
@@ -58,14 +58,16 @@ pkg p1, type T struct
pkg p1, type TPtrExported struct
pkg p1, type TPtrExported struct, embedded *Embedded
pkg p1, type TPtrUnexported struct
+pkg p1, var ByteConv []byte
pkg p1, var ChecksumError error
pkg p1, var SIPtr *SI
pkg p1, var SIPtr2 *SI
pkg p1, var SIVal SI
+pkg p1, var StrConv string
pkg p1, var V string
-pkg p1, var VError Error
pkg p1, var V1 uint64
pkg p1, var V2 p2.Twoer
+pkg p1, var VError Error
pkg p1, var X I
pkg p1, var X int64
pkg p1, var Y int
diff --git a/src/cmd/api/testdata/src/pkg/p1/p1.go b/src/cmd/api/testdata/src/pkg/p1/p1.go
index 9d2afa913..d965bb75e 100644
--- a/src/cmd/api/testdata/src/pkg/p1/p1.go
+++ b/src/cmd/api/testdata/src/pkg/p1/p1.go
@@ -27,6 +27,12 @@ var (
V2 = ptwo.G()
)
+// Variables with conversions:
+var (
+ StrConv = string("foo")
+ ByteConv = []byte("foo")
+)
+
var ChecksumError = ptwo.NewError("gzip checksum error")
const B = 2
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index f6a14ae08..1bb48f44e 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -44,6 +44,11 @@ For example:
// #include <png.h>
import "C"
+The CGO_CFLAGS and CGO_LDFLAGS environment variables are added
+to the flags derived from these directives. Package-specific flags should
+be set using the directives, not the environment variables, so that builds
+work in unmodified environments.
+
Within the Go file, C identifiers or field names that are keywords in Go
can be accessed by prefixing them with an underscore: if x points at a C
struct with a field named "type", x._type accesses the field.
@@ -111,13 +116,13 @@ Not all Go types can be mapped to C types in a useful way.
Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
-The standard package makefile rules in Make.pkg automate the
-process of using cgo. See $GOROOT/misc/cgo/stdio and
-$GOROOT/misc/cgo/gmp for examples.
+The standard package construction rules of the go command
+automate the process of using cgo. See $GOROOT/misc/cgo/stdio
+and $GOROOT/misc/cgo/gmp for examples.
Cgo does not yet work with gccgo.
See "C? Go? Cgo!" for an introduction to using cgo:
-http://blog.golang.org/2011/03/c-go-cgo.html
+http://golang.org/doc/articles/c_go_cgo.html
*/
package documentation
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index a8be7be7d..7449f04c4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -136,6 +136,7 @@ var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C
var objDir = flag.String("objdir", "", "object directory")
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
+var gccgoprefix = flag.String("gccgoprefix", "go", "prefix of symbols generated by gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var goarch, goos string
@@ -147,7 +148,7 @@ func main() {
// cgo -dynimport is essentially a separate helper command
// built into the cgo binary. It scans a gcc-produced executable
// and dumps information about the imported symbols and the
- // imported libraries. The Make.pkg rules for cgo prepare an
+ // imported libraries. The 'go build' rules for cgo prepare an
// appropriate executable and then use its import information
// instead of needing to make the linkers duplicate all the
// specialized knowledge gcc has about where to look for imported
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 4dc0f8454..814250c2e 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -107,7 +107,11 @@ func (p *Package) writeDefs() {
}
}
- p.writeExports(fgo2, fc, fm)
+ if *gccgo {
+ p.writeGccgoExports(fgo2, fc, fm)
+ } else {
+ p.writeExports(fgo2, fc, fm)
+ }
fgo2.Close()
fc.Close()
@@ -280,8 +284,13 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
}
conf.Fprint(fgo2, fset, d)
fmt.Fprintf(fgo2, "{\n")
+ fmt.Fprintf(fgo2, "\tsyscall.SetErrno(0)\n")
fmt.Fprintf(fgo2, "\tr := %s(%s)\n", cname, strings.Join(paramnames, ", "))
- fmt.Fprintf(fgo2, "\treturn r, syscall.GetErrno()\n")
+ fmt.Fprintf(fgo2, "\te := syscall.GetErrno()\n")
+ fmt.Fprintf(fgo2, "\tif e != 0 {\n")
+ fmt.Fprintf(fgo2, "\t\treturn r, e\n")
+ fmt.Fprintf(fgo2, "\t}\n")
+ fmt.Fprintf(fgo2, "\treturn r, nil\n")
fmt.Fprintf(fgo2, "}\n")
// declare the C function.
fmt.Fprintf(fgo2, "//extern %s\n", n.C)
@@ -411,10 +420,20 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i := range n.FuncType.Params {
+ for i, t := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
+ // We know the type params are correct, because
+ // the Go equivalents had good type params.
+ // However, our version of the type omits the magic
+ // words const and volatile, which can provoke
+ // C compiler warnings. Silence them by casting
+ // all pointers to void*. (Eventually that will produce
+ // other warnings.)
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -563,8 +582,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
fmt.Fprintf(fc, "#pragma dynexport %s %s\n", goname, goname)
- fmt.Fprintf(fc, "extern void ·%s();\n", goname)
- fmt.Fprintf(fc, "\nvoid\n")
+ fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+ fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
+ fmt.Fprintf(fc, "void\n")
fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n")
fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
@@ -613,6 +633,83 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
}
}
+// Write out the C header allowing C code to call exported gccgo functions.
+func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+ fgcc := creat(*objDir + "_cgo_export.c")
+ fgcch := creat(*objDir + "_cgo_export.h")
+ _ = fgcc
+
+ fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcch, "%s\n", gccExportHeaderProlog)
+ fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
+
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ gccgoSymbolPrefix := strings.Map(clean, *gccgoprefix)
+
+ for _, exp := range p.ExpFunc {
+ // TODO: support functions with receivers.
+ fn := exp.Func
+ fntype := fn.Type
+
+ if !ast.IsExported(fn.Name.Name) {
+ fatalf("cannot export unexported function %s with gccgo", fn.Name)
+ }
+
+ cdeclBuf := new(bytes.Buffer)
+ resultCount := 0
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) { resultCount++ })
+ switch resultCount {
+ case 0:
+ fmt.Fprintf(cdeclBuf, "void")
+ case 1:
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s", t.C)
+ })
+ default:
+ // Declare a result struct.
+ fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
+ forFieldList(fntype.Results,
+ func(i int, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i)
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName)
+ }
+
+ // The function name.
+ fmt.Fprintf(cdeclBuf, " "+exp.ExpName)
+ gccgoSymbol := fmt.Sprintf("%s.%s.%s", gccgoSymbolPrefix, p.PackageName, exp.Func.Name)
+ fmt.Fprintf(cdeclBuf, " (")
+ // Function parameters.
+ forFieldList(fntype.Params,
+ func(i int, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprintf(cdeclBuf, ", ")
+ }
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i)
+ })
+ fmt.Fprintf(cdeclBuf, ")")
+ cdecl := cdeclBuf.String()
+
+ fmt.Fprintf(fgcch, "extern %s __asm__(\"%s\");\n", cdecl, gccgoSymbol)
+ // Dummy declaration for _cgo_main.c
+ fmt.Fprintf(fm, "%s {}\n", cdecl)
+ }
+}
+
// Call a function for each entry in an ast.FieldList, passing the
// index into the list and the type.
func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) {
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index a40853fad..3936f7621 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -209,7 +209,7 @@ findgoversion(void)
// What are the tags along the current branch?
tag = "";
rev = ".";
- run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "--template", "{tags} + ", nil);
+ run(&b, goroot, CheckExit, "hg", "log", "-b", bstr(&branch), "-r", ".:0", "--template", "{tags} + ", nil);
splitfields(&tags, bstr(&b));
nrev = 0;
for(i=0; i<tags.len; i++) {
@@ -1214,6 +1214,8 @@ clean(void)
vinit(&dir);
for(i=0; i<nelem(cleantab); i++) {
+ if((streq(cleantab[i], "cmd/cov") || streq(cleantab[i], "cmd/prof")) && !isdir(cleantab[i]))
+ continue;
bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
xreaddir(&dir, bstr(&path));
// Remove generated files.
@@ -1351,6 +1353,9 @@ cmdbootstrap(int argc, char **argv)
goversion = findgoversion();
setup();
+ xsetenv("GOROOT", goroot);
+ xsetenv("GOROOT_FINAL", goroot_final);
+
// For the main bootstrap, building for host os/arch.
oldgoos = goos;
oldgoarch = goarch;
diff --git a/src/cmd/fix/go1rename.go b/src/cmd/fix/go1rename.go
index 4b666720b..9266c749c 100644
--- a/src/cmd/fix/go1rename.go
+++ b/src/cmd/fix/go1rename.go
@@ -74,4 +74,94 @@ var go1renameReplace = []rename{
Old: "runtime.Goroutines",
New: "runtime.NumGoroutine",
},
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrPersistEOF",
+ New: "httputil.ErrPersistEOF",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrPipeline",
+ New: "httputil.ErrPipeline",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ErrClosed",
+ New: "httputil.ErrClosed",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ServerConn",
+ New: "httputil.ServerConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ClientConn",
+ New: "httputil.ClientConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewChunkedReader",
+ New: "httputil.NewChunkedReader",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewChunkedWriter",
+ New: "httputil.NewChunkedWriter",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.ReverseProxy",
+ New: "httputil.ReverseProxy",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewSingleHostReverseProxy",
+ New: "httputil.NewSingleHostReverseProxy",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpRequest",
+ New: "httputil.DumpRequest",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpRequestOut",
+ New: "httputil.DumpRequestOut",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.DumpResponse",
+ New: "httputil.DumpResponse",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewClientConn",
+ New: "httputil.NewClientConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewServerConn",
+ New: "httputil.NewServerConn",
+ },
+ {
+ OldImport: "net/http",
+ NewImport: "net/http/httputil",
+ Old: "http.NewProxyClientConn",
+ New: "httputil.NewProxyClientConn",
+ },
}
diff --git a/src/cmd/fix/go1rename_test.go b/src/cmd/fix/go1rename_test.go
index 481ebea8e..90219ba71 100644
--- a/src/cmd/fix/go1rename_test.go
+++ b/src/cmd/fix/go1rename_test.go
@@ -17,6 +17,7 @@ import (
"crypto/aes"
"crypto/des"
"encoding/json"
+ "net/http"
"net/url"
"os"
"runtime"
@@ -34,6 +35,15 @@ var (
_ = os.Exec
_ = runtime.Cgocalls
_ = runtime.Goroutines
+ _ = http.ErrPersistEOF
+ _ = http.ErrPipeline
+ _ = http.ErrClosed
+ _ = http.NewSingleHostReverseProxy
+ _ = http.NewChunkedReader
+ _ = http.NewChunkedWriter
+ _ *http.ReverseProxy
+ _ *http.ClientConn
+ _ *http.ServerConn
)
`,
Out: `package main
@@ -42,6 +52,7 @@ import (
"crypto/aes"
"crypto/cipher"
"encoding/json"
+ "net/http/httputil"
"net/url"
"runtime"
"syscall"
@@ -59,7 +70,126 @@ var (
_ = syscall.Exec
_ = runtime.NumCgoCall
_ = runtime.NumGoroutine
+ _ = httputil.ErrPersistEOF
+ _ = httputil.ErrPipeline
+ _ = httputil.ErrClosed
+ _ = httputil.NewSingleHostReverseProxy
+ _ = httputil.NewChunkedReader
+ _ = httputil.NewChunkedWriter
+ _ *httputil.ReverseProxy
+ _ *httputil.ClientConn
+ _ *httputil.ServerConn
)
`,
},
+ {
+ Name: "httputil.0",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+}
+`,
+ Out: `package main
+
+import "net/http/httputil"
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+}
+`,
+ },
+ {
+ Name: "httputil.1",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+}
+`,
+ Out: `package main
+
+import "net/http/httputil"
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+}
+`,
+ },
+ {
+ Name: "httputil.2",
+ In: `package main
+
+import "net/http"
+
+func f() {
+ http.DumpRequest(nil, false)
+ http.DumpRequestOut(nil, false)
+ http.DumpResponse(nil, false)
+ http.NewChunkedReader(nil)
+ http.NewChunkedWriter(nil)
+ http.NewClientConn(nil, nil)
+ http.NewProxyClientConn(nil, nil)
+ http.NewServerConn(nil, nil)
+ http.NewSingleHostReverseProxy(nil)
+ http.Get("")
+}
+`,
+ Out: `package main
+
+import (
+ "net/http"
+ "net/http/httputil"
+)
+
+func f() {
+ httputil.DumpRequest(nil, false)
+ httputil.DumpRequestOut(nil, false)
+ httputil.DumpResponse(nil, false)
+ httputil.NewChunkedReader(nil)
+ httputil.NewChunkedWriter(nil)
+ httputil.NewClientConn(nil, nil)
+ httputil.NewProxyClientConn(nil, nil)
+ httputil.NewServerConn(nil, nil)
+ httputil.NewSingleHostReverseProxy(nil)
+ http.Get("")
+}
+`,
+ },
}
diff --git a/src/cmd/fix/httputil.go b/src/cmd/fix/httputil.go
deleted file mode 100644
index 86c42e160..000000000
--- a/src/cmd/fix/httputil.go
+++ /dev/null
@@ -1,63 +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.
-
-package main
-
-import "go/ast"
-
-func init() {
- register(httputilFix)
-}
-
-var httputilFix = fix{
- "httputil",
- "2011-11-18",
- httputil,
- `Move some functions in http package into httputil package.
-
-http://codereview.appspot.com/5336049
-`,
-}
-
-var httputilFuncs = []string{
- "DumpRequest",
- "DumpRequestOut",
- "DumpResponse",
- "NewChunkedReader",
- "NewChunkedWriter",
- "NewClientConn",
- "NewProxyClientConn",
- "NewServerConn",
- "NewSingleHostReverseProxy",
-}
-
-func httputil(f *ast.File) bool {
- if imports(f, "net/http/httputil") {
- return false
- }
-
- fixed := false
-
- walk(f, func(n interface{}) {
- // Rename package name.
- if expr, ok := n.(ast.Expr); ok {
- for _, s := range httputilFuncs {
- if isPkgDot(expr, "http", s) {
- if !fixed {
- addImport(f, "net/http/httputil")
- fixed = true
- }
- expr.(*ast.SelectorExpr).X.(*ast.Ident).Name = "httputil"
- }
- }
- }
- })
-
- // Remove the net/http import if no longer needed.
- if fixed && !usesImport(f, "net/http") {
- deleteImport(f, "net/http")
- }
-
- return fixed
-}
diff --git a/src/cmd/fix/httputil_test.go b/src/cmd/fix/httputil_test.go
deleted file mode 100644
index 83e9f6dfb..000000000
--- a/src/cmd/fix/httputil_test.go
+++ /dev/null
@@ -1,122 +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.
-
-package main
-
-func init() {
- addTestCases(httputilTests, httputil)
-}
-
-var httputilTests = []testCase{
- {
- Name: "httputil.0",
- In: `package main
-
-import "net/http"
-
-func f() {
- http.DumpRequest(nil, false)
- http.DumpRequestOut(nil, false)
- http.DumpResponse(nil, false)
- http.NewChunkedReader(nil)
- http.NewChunkedWriter(nil)
- http.NewClientConn(nil, nil)
- http.NewProxyClientConn(nil, nil)
- http.NewServerConn(nil, nil)
- http.NewSingleHostReverseProxy(nil)
-}
-`,
- Out: `package main
-
-import "net/http/httputil"
-
-func f() {
- httputil.DumpRequest(nil, false)
- httputil.DumpRequestOut(nil, false)
- httputil.DumpResponse(nil, false)
- httputil.NewChunkedReader(nil)
- httputil.NewChunkedWriter(nil)
- httputil.NewClientConn(nil, nil)
- httputil.NewProxyClientConn(nil, nil)
- httputil.NewServerConn(nil, nil)
- httputil.NewSingleHostReverseProxy(nil)
-}
-`,
- },
- {
- Name: "httputil.1",
- In: `package main
-
-import "net/http"
-
-func f() {
- http.DumpRequest(nil, false)
- http.DumpRequestOut(nil, false)
- http.DumpResponse(nil, false)
- http.NewChunkedReader(nil)
- http.NewChunkedWriter(nil)
- http.NewClientConn(nil, nil)
- http.NewProxyClientConn(nil, nil)
- http.NewServerConn(nil, nil)
- http.NewSingleHostReverseProxy(nil)
-}
-`,
- Out: `package main
-
-import "net/http/httputil"
-
-func f() {
- httputil.DumpRequest(nil, false)
- httputil.DumpRequestOut(nil, false)
- httputil.DumpResponse(nil, false)
- httputil.NewChunkedReader(nil)
- httputil.NewChunkedWriter(nil)
- httputil.NewClientConn(nil, nil)
- httputil.NewProxyClientConn(nil, nil)
- httputil.NewServerConn(nil, nil)
- httputil.NewSingleHostReverseProxy(nil)
-}
-`,
- },
- {
- Name: "httputil.2",
- In: `package main
-
-import "net/http"
-
-func f() {
- http.DumpRequest(nil, false)
- http.DumpRequestOut(nil, false)
- http.DumpResponse(nil, false)
- http.NewChunkedReader(nil)
- http.NewChunkedWriter(nil)
- http.NewClientConn(nil, nil)
- http.NewProxyClientConn(nil, nil)
- http.NewServerConn(nil, nil)
- http.NewSingleHostReverseProxy(nil)
- http.Get("")
-}
-`,
- Out: `package main
-
-import (
- "net/http"
- "net/http/httputil"
-)
-
-func f() {
- httputil.DumpRequest(nil, false)
- httputil.DumpRequestOut(nil, false)
- httputil.DumpResponse(nil, false)
- httputil.NewChunkedReader(nil)
- httputil.NewChunkedWriter(nil)
- httputil.NewClientConn(nil, nil)
- httputil.NewProxyClientConn(nil, nil)
- httputil.NewServerConn(nil, nil)
- httputil.NewSingleHostReverseProxy(nil)
- http.Get("")
-}
-`,
- },
-}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index df34c05b2..58e25faaf 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -6,7 +6,7 @@ include ../../Make.dist
install: y.tab.h builtin.c
-y.tab.h: go.y
+y.tab.h: go.y go.errors bisonerrors
bison -v -y -d go.y
# make yystate global, yytname mutable
cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 4a0e7430a..4121a45ab 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -1168,21 +1168,22 @@ methodsym(Sym *nsym, Type *t0, int iface)
char *p;
Type *t;
char *suffix;
+ Pkg *spkg;
+ static Pkg *toppkg;
t = t0;
if(t == T)
goto bad;
s = t->sym;
- if(s == S) {
- if(!isptr[t->etype])
- goto bad;
+ if(s == S && isptr[t->etype]) {
t = t->type;
if(t == T)
goto bad;
s = t->sym;
- if(s == S)
- goto bad;
}
+ spkg = nil;
+ if(s != S)
+ spkg = s->pkg;
// if t0 == *t and t0 has a sym,
// we want to see *t, not t0, in the method name.
@@ -1195,11 +1196,23 @@ methodsym(Sym *nsym, Type *t0, int iface)
if(t0->width < types[tptr]->width)
suffix = "·i";
}
- if(t0->sym == S && isptr[t0->etype])
- p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
- else
- p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
- s = pkglookup(p, s->pkg);
+ if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+ } else {
+ if(t0->sym == S && isptr[t0->etype])
+ p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
+ else
+ p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
+ }
+ if(spkg == nil) {
+ if(toppkg == nil)
+ toppkg = mkpkg(strlit("go"));
+ spkg = toppkg;
+ }
+ s = pkglookup(p, spkg);
free(p);
return s;
@@ -1268,7 +1281,7 @@ addmethod(Sym *sf, Type *t, int local)
}
pa = pa->type;
- f = methtype(pa);
+ f = methtype(pa, 1);
if(f == T) {
t = pa;
if(t != T) {
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 5a2977eab..163d3862c 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -26,7 +26,7 @@ package P to read the files of P's dependencies, only the compiled output
of P.
Usage:
- 6g [flags] file...
+ go tool 6g [flags] file...
The specified files must be Go source files and all part of the same package.
Substitute 6g with 8g or 5g where appropriate.
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 753360e46..8c4fff15a 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -1154,7 +1154,7 @@ int cplxsubtype(int et);
int eqtype(Type *t1, Type *t2);
int eqtypenoname(Type *t1, Type *t2);
void errorexit(void);
-void expandmeth(Sym *s, Type *t);
+void expandmeth(Type *t);
void fatal(char *fmt, ...);
void flusherrors(void);
void frame(int context);
@@ -1192,7 +1192,7 @@ NodeList* listtreecopy(NodeList *l);
Sym* lookup(char *name);
void* mal(int32 n);
Type* maptype(Type *key, Type *val);
-Type* methtype(Type *t);
+Type* methtype(Type *t, int mustname);
Pkg* mkpkg(Strlit *path);
Sym* ngotype(Node *n);
int noconv(Type *t1, Type *t2);
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
index 96080cbfa..efce56057 100644
--- a/src/cmd/gc/inl.c
+++ b/src/cmd/gc/inl.c
@@ -182,6 +182,8 @@ ishairy(Node *n, int *budget)
case OCALLFUNC:
case OCALLINTER:
case OCALLMETH:
+ case OPANIC:
+ case ORECOVER:
if(debug['l'] < 4)
return 1;
break;
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 96786b5e6..e71fd3848 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -514,7 +514,7 @@ addidir(char* dir)
static int
islocalname(Strlit *name)
{
- if(!windows && name->len >= 1 && name->s[0] == '/')
+ if(name->len >= 1 && name->s[0] == '/')
return 1;
if(windows && name->len >= 3 &&
yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index aae566dbb..e45b4e0d4 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -126,10 +126,37 @@ outhist(Biobuf *b)
{
Hist *h;
char *p, ds[] = {'c', ':', '/', 0};
+ char *tofree;
+ int n;
+ static int first = 1;
+ static char *goroot, *goroot_final;
+ if(first) {
+ // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
+ first = 0;
+ goroot = getenv("GOROOT");
+ goroot_final = getenv("GOROOT_FINAL");
+ if(goroot == nil)
+ goroot = "";
+ if(goroot_final == nil)
+ goroot_final = goroot;
+ if(strcmp(goroot, goroot_final) == 0) {
+ goroot = nil;
+ goroot_final = nil;
+ }
+ }
+
+ tofree = nil;
for(h = hist; h != H; h = h->link) {
p = h->name;
if(p) {
+ if(goroot != nil) {
+ n = strlen(goroot);
+ if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
+ tofree = smprint("%s%s", goroot_final, p+n);
+ p = tofree;
+ }
+ }
if(windows) {
// if windows variable is set, then, we know already,
// pathname is started with windows drive specifier
@@ -161,9 +188,12 @@ outhist(Biobuf *b)
outzfile(b, p);
}
}
-
}
zhist(b, h->line, h->offset);
+ if(tofree) {
+ free(tofree);
+ tofree = nil;
+ }
}
}
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 0847e9a3f..07b426508 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -144,11 +144,11 @@ methods(Type *t)
Sig *a, *b;
Sym *method;
- // named method type
- mt = methtype(t);
+ // method type
+ mt = methtype(t, 0);
if(mt == T)
return nil;
- expandmeth(mt->sym, mt);
+ expandmeth(mt);
// type stored in interface word
it = t;
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 000b2328f..15a61d9ef 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot. This is not done automatically
+// to update builtin.c. This is not done automatically
// to avoid depending on having a working compiler binary.
// +build ignore
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 6eb7734f0..681c023a0 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -944,7 +944,7 @@ isideal(Type *t)
* return type to hang methods off (r).
*/
Type*
-methtype(Type *t)
+methtype(Type *t, int mustname)
{
if(t == T)
return T;
@@ -959,7 +959,7 @@ methtype(Type *t)
}
// need a type name
- if(t->sym == S)
+ if(t->sym == S && (mustname || t->etype != TSTRUCT))
return T;
// check types
@@ -2101,7 +2101,7 @@ lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
c++;
}
}
- u = methtype(t);
+ u = methtype(t, 0);
if(u != T) {
for(f=u->method; f!=T; f=f->down)
if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
@@ -2251,7 +2251,7 @@ expand0(Type *t, int followptr)
return;
}
- u = methtype(t);
+ u = methtype(t, 0);
if(u != T) {
for(f=u->method; f!=T; f=f->down) {
if(f->sym->flags & SymUniq)
@@ -2301,14 +2301,12 @@ out:
}
void
-expandmeth(Sym *s, Type *t)
+expandmeth(Type *t)
{
Symlink *sl;
Type *f;
int c, d;
- if(s == S)
- return;
if(t == T || t->xmethod != nil)
return;
@@ -3021,9 +3019,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
return 1;
}
- t = methtype(t);
+ t = methtype(t, 0);
if(t != T)
- expandmeth(t->sym, t);
+ expandmeth(t);
for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr, 0);
@@ -3626,23 +3624,23 @@ isbadimport(Strlit *path)
while(*s) {
s += chartorune(&r, s);
if(r == Runeerror) {
- yyerror("import path contains invalid UTF-8 sequence");
+ yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
return 1;
}
if(r < 0x20 || r == 0x7f) {
- yyerror("import path contains control character");
+ yyerror("import path contains control character: \"%Z\"", path);
return 1;
}
if(r == '\\') {
- yyerror("import path contains backslash; use slash");
+ yyerror("import path contains backslash; use slash: \"%Z\"", path);
return 1;
}
if(isspacerune(r)) {
- yyerror("import path contains space character");
+ yyerror("import path contains space character: \"%Z\"", path);
return 1;
}
- if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}~", r)) {
- yyerror("import path contains invalid character '%C'", r);
+ if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
+ yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
return 1;
}
}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 90bd24964..e98d53857 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -190,6 +190,46 @@ typecheck(Node **np, int top)
return n;
}
+/*
+ * does n contain a call or receive operation?
+ */
+static int callrecvlist(NodeList*);
+
+static int
+callrecv(Node *n)
+{
+ if(n == nil)
+ return 0;
+
+ switch(n->op) {
+ case OCALL:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
+ case ORECV:
+ return 1;
+ }
+
+ return callrecv(n->left) ||
+ callrecv(n->right) ||
+ callrecv(n->ntest) ||
+ callrecv(n->nincr) ||
+ callrecvlist(n->ninit) ||
+ callrecvlist(n->nbody) ||
+ callrecvlist(n->nelse) ||
+ callrecvlist(n->list) ||
+ callrecvlist(n->rlist);
+}
+
+static int
+callrecvlist(NodeList *l)
+{
+ for(; l; l=l->next)
+ if(callrecv(l->n))
+ return 1;
+ return 0;
+}
+
static void
typecheck1(Node **np, int top)
{
@@ -995,12 +1035,14 @@ reswitch:
}
break;
case TARRAY:
- if(t->bound >= 0 && l->op == ONAME) {
- r = nod(OXXX, N, N);
- nodconst(r, types[TINT], t->bound);
- r->orig = n;
- n = r;
- }
+ if(t->bound < 0) // slice
+ break;
+ if(callrecv(l)) // has call or receive
+ break;
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], t->bound);
+ r->orig = n;
+ n = r;
break;
}
n->type = types[TINT];
@@ -1664,11 +1706,11 @@ looktypedot(Node *n, Type *t, int dostrcmp)
if(t->sym == S && isptr[t->etype])
tt = t->type;
- f2 = methtype(tt);
+ f2 = methtype(tt, 0);
if(f2 == T)
return 0;
- expandmeth(f2->sym, f2);
+ expandmeth(f2);
f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp);
if(f2 == T)
return 0;
@@ -1712,7 +1754,7 @@ lookdot(Node *n, Type *t, int dostrcmp)
f2 = T;
if(n->left->type == t || n->left->type->sym == S) {
- f2 = methtype(t);
+ f2 = methtype(t, 0);
if(f2 != T) {
// Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots.
@@ -1964,7 +2006,7 @@ keydup(Node *n, Node *hash[], ulong nhash)
b = cmp.val.u.bval;
if(b) {
// too lazy to print the literal
- yyerror("duplicate key in map literal");
+ yyerror("duplicate key %N in map literal", n);
return;
}
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 74298e126..7dfd34a7a 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -646,12 +646,6 @@ walkexpr(Node **np, NodeList **init)
n->ninit = nil;
l = n->list->n;
r = n->list->next->n;
- if(n->right != N) {
- // TODO: Remove once two-element map assigment is gone.
- l = safeexpr(l, init);
- r = safeexpr(r, init);
- safeexpr(n->right, init); // cause side effects from n->right
- }
t = l->type;
n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r);
goto ret;
@@ -2364,6 +2358,12 @@ append(Node *n, NodeList **init)
walkexprlistsafe(n->list, init);
+ // walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+ // and n are name or literal, but those may index the slice we're
+ // modifying here. Fix explicitly.
+ for(l=n->list; l; l=l->next)
+ l->n = cheapexpr(l->n, init);
+
nsrc = n->list->n;
argc = count(n->list) - 1;
if (argc < 1) {
@@ -2520,6 +2520,7 @@ walkcompare(Node **np, NodeList **init)
expr = nodbool(n->op == OEQ);
typecheck(&expr, Erv);
walkexpr(&expr, init);
+ expr->type = n->type;
*np = expr;
return;
}
@@ -2540,6 +2541,7 @@ walkcompare(Node **np, NodeList **init)
expr = nodbool(n->op == OEQ);
typecheck(&expr, Erv);
walkexpr(&expr, init);
+ expr->type = n->type;
*np = expr;
return;
}
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
index bc9a3dbbc..32941404c 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -10,8 +10,21 @@
package main
-import "errors"
+import (
+ "errors"
+ "io"
+)
+
+var errHTTP = errors.New("no http in bootstrap go command")
func httpGET(url string) ([]byte, error) {
- return nil, errors.New("no http in bootstrap go command")
+ return nil, errHTTP
+}
+
+func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
+ return "", nil, errHTTP
+}
+
+func parseMetaGoImports(r io.Reader) (imports []metaImport) {
+ panic("unreachable")
}
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index c330bd5de..16177c127 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -12,6 +12,7 @@ import (
"go/build"
"io"
"io/ioutil"
+ "log"
"os"
"os/exec"
"path"
@@ -20,6 +21,7 @@ import (
"runtime"
"strings"
"sync"
+ "time"
)
var cmdBuild = &Command{
@@ -58,6 +60,8 @@ The build flags are shared by the build, install, run, and test commands:
-x
print the commands.
+ -compiler name
+ name of compiler to use, as in runtime.Compiler (gccgo or gc)
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation
-gcflags 'arg list'
@@ -97,9 +101,42 @@ var buildLdflags []string // -ldflags flag
var buildGccgoflags []string // -gccgoflags flag
var buildContext = build.Default
+var buildToolchain toolchain = noToolchain{}
+
+// buildCompiler implements flag.Var.
+// It implements Set by updating both
+// buildToolchain and buildContext.Compiler.
+type buildCompiler struct{}
+
+func (c buildCompiler) Set(value string) error {
+ switch value {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgcToolchain{}
+ default:
+ return fmt.Errorf("unknown compiler %q", value)
+ }
+ buildContext.Compiler = value
+ return nil
+}
+
+func (c buildCompiler) String() string {
+ return buildContext.Compiler
+}
+
+func init() {
+ switch build.Default.Compiler {
+ case "gc":
+ buildToolchain = gcToolchain{}
+ case "gccgo":
+ buildToolchain = gccgcToolchain{}
+ }
+}
// addBuildFlags adds the flags common to the build and install commands.
func addBuildFlags(cmd *Command) {
+ // NOTE: If you add flags here, also add them to testflag.go.
cmd.Flag.BoolVar(&buildA, "a", false, "")
cmd.Flag.BoolVar(&buildN, "n", false, "")
cmd.Flag.IntVar(&buildP, "p", buildP, "")
@@ -110,6 +147,7 @@ func addBuildFlags(cmd *Command) {
cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
+ cmd.Flag.Var(buildCompiler{}, "compiler", "")
}
type stringsFlag []string
@@ -131,9 +169,7 @@ func runBuild(cmd *Command, args []string) {
if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
_, *buildO = path.Split(pkgs[0].ImportPath)
- if goos == "windows" {
- *buildO += ".exe"
- }
+ *buildO += exeSuffix
}
if *buildO != "" {
@@ -348,6 +384,7 @@ func goFilesPackage(gofiles []string) *Package {
bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
+ pkg.local = true
pkg.load(&stk, bp, err)
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
@@ -355,7 +392,7 @@ func goFilesPackage(gofiles []string) *Package {
if *buildO == "" {
if pkg.Name == "main" {
_, elem := filepath.Split(gofiles[0])
- *buildO = elem[:len(elem)-len(".go")]
+ *buildO = elem[:len(elem)-len(".go")] + exeSuffix
} else {
*buildO = pkg.Name + ".a"
}
@@ -412,7 +449,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
return a
}
// gccgo standard library is "fake" too.
- if _, ok := buildToolchain.(gccgoToolchain); ok {
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
// the target name is needed for cgo.
a.target = p.target
return a
@@ -568,7 +605,12 @@ func (b *builder) do(root *action) {
}
// build is the action for building a single package or command.
-func (b *builder) build(a *action) error {
+func (b *builder) build(a *action) (err error) {
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
+ }
+ }()
if buildN {
// In -n mode, print a banner between packages.
// The banner is five lines so that when changes to
@@ -620,7 +662,7 @@ func (b *builder) build(a *action) error {
}
cgoExe := tool("cgo")
- if a.cgo != nil {
+ if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
outGo, outObj, err := b.cgo(a.p, cgoExe, obj, gccfiles)
@@ -692,6 +734,11 @@ func (b *builder) build(a *action) error {
// http://golang.org/issue/2601
objects = append(objects, cgoObjects...)
+ // Add system object files.
+ for _, syso := range a.p.SysoFiles {
+ objects = append(objects, filepath.Join(a.p.Dir, syso))
+ }
+
// Pack into archive in obj directory
if err := buildToolchain.pack(b, a.p, obj, a.objpkg, objects); err != nil {
return err
@@ -712,7 +759,12 @@ func (b *builder) build(a *action) error {
}
// install is the action for installing a single package or executable.
-func (b *builder) install(a *action) error {
+func (b *builder) install(a *action) (err error) {
+ defer func() {
+ if err != nil && err != errPrintedOutput {
+ err = fmt.Errorf("go install %s: %v", a.p.ImportPath, err)
+ }
+ }()
a1 := a.deps[0]
perm := os.FileMode(0666)
if a1.link {
@@ -767,7 +819,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
for _, a1 := range all {
if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
incMap[dir] = true
- if _, ok := buildToolchain.(gccgoToolchain); ok {
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
dir = filepath.Join(dir, "gccgo")
} else {
dir = filepath.Join(dir, goos+"_"+goarch)
@@ -833,7 +885,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
df.Close()
if err != nil {
os.Remove(dst)
- return err
+ return fmt.Errorf("copying %s to %s: %v", src, dst, err)
}
return nil
}
@@ -888,8 +940,6 @@ func (b *builder) fmtcmd(dir string, format string, args ...interface{}) string
if b.work != "" {
cmd = strings.Replace(cmd, b.work, "$WORK", -1)
}
- cmd = strings.Replace(cmd, gobin, "$GOBIN", -1)
- cmd = strings.Replace(cmd, goroot, "$GOROOT", -1)
return cmd
}
@@ -998,14 +1048,66 @@ func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byt
}
}
- var buf bytes.Buffer
- cmd := exec.Command(cmdline[0], cmdline[1:]...)
- cmd.Stdout = &buf
- cmd.Stderr = &buf
- cmd.Dir = dir
- // TODO: cmd.Env
- err := cmd.Run()
- return buf.Bytes(), err
+ nbusy := 0
+ for {
+ var buf bytes.Buffer
+ cmd := exec.Command(cmdline[0], cmdline[1:]...)
+ cmd.Stdout = &buf
+ cmd.Stderr = &buf
+ cmd.Dir = dir
+ // TODO: cmd.Env
+ err := cmd.Run()
+
+ // cmd.Run will fail on Unix if some other process has the binary
+ // we want to run open for writing. This can happen here because
+ // we build and install the cgo command and then run it.
+ // If another command was kicked off while we were writing the
+ // cgo binary, the child process for that command may be holding
+ // a reference to the fd, keeping us from running exec.
+ //
+ // But, you might reasonably wonder, how can this happen?
+ // The cgo fd, like all our fds, is close-on-exec, so that we need
+ // not worry about other processes inheriting the fd accidentally.
+ // The answer is that running a command is fork and exec.
+ // A child forked while the cgo fd is open inherits that fd.
+ // Until the child has called exec, it holds the fd open and the
+ // kernel will not let us run cgo. Even if the child were to close
+ // the fd explicitly, it would still be open from the time of the fork
+ // until the time of the explicit close, and the race would remain.
+ //
+ // On Unix systems, this results in ETXTBSY, which formats
+ // as "text file busy". Rather than hard-code specific error cases,
+ // we just look for that string. If this happens, sleep a little
+ // and try again. We let this happen three times, with increasing
+ // sleep lengths: 100+200+400 ms = 0.7 seconds.
+ //
+ // An alternate solution might be to split the cmd.Run into
+ // separate cmd.Start and cmd.Wait, and then use an RWLock
+ // to make sure that copyFile only executes when no cmd.Start
+ // call is in progress. However, cmd.Start (really syscall.forkExec)
+ // only guarantees that when it returns, the exec is committed to
+ // happen and succeed. It uses a close-on-exec file descriptor
+ // itself to determine this, so we know that when cmd.Start returns,
+ // at least one close-on-exec file descriptor has been closed.
+ // However, we cannot be sure that all of them have been closed,
+ // so the program might still encounter ETXTBSY even with such
+ // an RWLock. The race window would be smaller, perhaps, but not
+ // guaranteed to be gone.
+ //
+ // Sleeping when we observe the race seems to be the most reliable
+ // option we have.
+ //
+ // http://golang.org/issue/3001
+ //
+ if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
+ time.Sleep(100 * time.Millisecond << uint(nbusy))
+ nbusy++
+ continue
+ }
+
+ return buf.Bytes(), err
+ }
+ panic("unreachable")
}
// mkdir makes the named directory.
@@ -1072,32 +1174,60 @@ type toolchain interface {
linker() string
}
-type goToolchain struct{}
-type gccgoToolchain struct{}
+type noToolchain struct{}
+
+func noCompiler() error {
+ log.Fatalf("unknown compiler %q", buildContext.Compiler)
+ return nil
+}
-var buildToolchain toolchain
+func (noToolchain) compiler() string {
+ noCompiler()
+ return ""
+}
-func init() {
- // TODO(rsc): Decide how to trigger gccgo. Issue 3157.
- if os.Getenv("GC") == "gccgo" {
- buildContext.Gccgo = true
- buildToolchain = gccgoToolchain{}
- } else {
- buildToolchain = goToolchain{}
- }
+func (noToolchain) linker() string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+ return "", noCompiler()
+}
+
+func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+ return noCompiler()
+}
+
+func (noToolchain) pkgpath(basedir string, p *Package) string {
+ noCompiler()
+ return ""
+}
+
+func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+ return noCompiler()
+}
+
+func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+ return noCompiler()
}
// The Go toolchain.
+type gcToolchain struct{}
-func (goToolchain) compiler() string {
+func (gcToolchain) compiler() string {
return tool(archChar + "g")
}
-func (goToolchain) linker() string {
+func (gcToolchain) linker() string {
return tool(archChar + "l")
}
-func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
out := "_go_." + archChar
ofile = obj + out
gcargs := []string{"-p", p.ImportPath}
@@ -1114,17 +1244,17 @@ func (goToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
return ofile, b.run(p.Dir, p.ImportPath, args)
}
-func (goToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
}
-func (goToolchain) pkgpath(basedir string, p *Package) string {
+func (gcToolchain) pkgpath(basedir string, p *Package) string {
end := filepath.FromSlash(p.ImportPath + ".a")
return filepath.Join(basedir, end)
}
-func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
var absOfiles []string
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
@@ -1132,12 +1262,12 @@ func (goToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
return b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)
}
-func (goToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
importArgs := b.includeArgs("-L", allactions)
- return b.run(p.Dir, p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
+ return b.run(".", p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, buildLdflags, mainpkg)
}
-func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
return b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
@@ -1146,27 +1276,24 @@ func (goToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
}
// The Gccgo toolchain.
+type gccgcToolchain struct{}
var gccgoBin, _ = exec.LookPath("gccgo")
-func (gccgoToolchain) compiler() string {
+func (gccgcToolchain) compiler() string {
return gccgoBin
}
-func (gccgoToolchain) linker() string {
+func (gccgcToolchain) linker() string {
return gccgoBin
}
-func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
+func (gccgcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error) {
out := p.Name + ".o"
ofile = obj + out
gcargs := []string{"-g"}
- if p.Name != "main" {
- if p.fake {
- gcargs = append(gcargs, "-fgo-prefix=fake_"+p.ImportPath)
- } else {
- gcargs = append(gcargs, "-fgo-prefix=go_"+p.ImportPath)
- }
+ if prefix := gccgoPrefix(p); prefix != "" {
+ gcargs = append(gcargs, "-fgo-prefix="+gccgoPrefix(p))
}
args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
for _, f := range gofiles {
@@ -1175,19 +1302,19 @@ func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string
return ofile, b.run(p.Dir, p.ImportPath, args)
}
-func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (gccgcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
}
-func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
+func (gccgcToolchain) pkgpath(basedir string, p *Package) string {
end := filepath.FromSlash(p.ImportPath + ".a")
afile := filepath.Join(basedir, end)
// add "lib" to the final element
return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
}
-func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
+func (gccgcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string) error {
var absOfiles []string
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
@@ -1195,7 +1322,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
}
-func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (tools gccgcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
// gccgo needs explicit linking with all package dependencies,
// and all LDFLAGS from cgo dependencies.
afiles := make(map[*Package]string)
@@ -1215,10 +1342,10 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
ldflags = append(ldflags, afile)
}
ldflags = append(ldflags, cgoldflags...)
- return b.run(p.Dir, p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,-)")
+ return b.run(".", p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,-)")
}
-func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+func (gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
@@ -1226,6 +1353,16 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
"-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
}
+func gccgoPrefix(p *Package) string {
+ switch {
+ case p.build.IsCommand() && !p.forceLibrary:
+ return ""
+ case p.fake:
+ return "fake_" + p.ImportPath
+ }
+ return "go_" + p.ImportPath
+}
+
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
cfile = mkAbs(p.Dir, cfile)
@@ -1239,6 +1376,9 @@ func (b *builder) gccld(p *Package, out string, flags []string, obj []string) er
// gccCmd returns a gcc command line prefix
func (b *builder) gccCmd(objdir string) []string {
+ // NOTE: env.go's mkEnv knows that the first three
+ // strings returned are "gcc", "-I", objdir (and cuts them off).
+
// TODO: HOST_CC?
a := []string{"gcc", "-I", objdir, "-g", "-O2"}
@@ -1263,6 +1403,14 @@ func (b *builder) gccCmd(objdir string) []string {
a = append(a, "-pthread")
}
}
+
+ // On OS X, some of the compilers behave as if -fno-common
+ // is always set, and the Mach-O linker in 6l/8l assumes this.
+ // See http://golang.org/issue/3253.
+ if goos == "darwin" {
+ a = append(a, "-fno-common")
+ }
+
return a
}
@@ -1318,11 +1466,17 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
cgoflags := []string{}
// TODO: make cgo not depend on $GOARCH?
+ objExt := archChar
+
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
- if _, ok := buildToolchain.(gccgoToolchain); ok {
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
cgoflags = append(cgoflags, "-gccgo")
+ if prefix := gccgoPrefix(p); prefix != "" {
+ cgoflags = append(cgoflags, "-gccgoprefix="+gccgoPrefix(p))
+ }
+ objExt = "o"
}
if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
@@ -1330,7 +1484,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
outGo = append(outGo, gofiles...)
// cc _cgo_defun.c
- defunObj := obj + "_cgo_defun." + archChar
+ defunObj := obj + "_cgo_defun." + objExt
if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
return nil, nil, err
}
@@ -1361,7 +1515,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
return nil, nil, err
}
- if _, ok := buildToolchain.(gccgoToolchain); ok {
+ if _, ok := buildToolchain.(gccgcToolchain); ok {
// we don't use dynimport when using gccgo.
return outGo, outObj, nil
}
@@ -1373,7 +1527,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
}
// cc _cgo_import.ARCH
- importObj := obj + "_cgo_import." + archChar
+ importObj := obj + "_cgo_import." + objExt
if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
return nil, nil, err
}
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
index 809e0f0e4..773951826 100644
--- a/src/cmd/go/clean.go
+++ b/src/cmd/go/clean.go
@@ -110,7 +110,7 @@ func clean(p *Package) {
}
dirs, err := ioutil.ReadDir(p.Dir)
if err != nil {
- errorf("%v", err)
+ errorf("go clean %s: %v", p.Dir, err)
return
}
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
new file mode 100644
index 000000000..d9f930867
--- /dev/null
+++ b/src/cmd/go/discovery.go
@@ -0,0 +1,63 @@
+// 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.
+
+// +build !cmd_go_bootstrap
+
+// This code is compiled into the real 'go' binary, but it is not
+// compiled into the binary that is built during all.bash, so as
+// to avoid needing to build net (and thus use cgo) during the
+// bootstrap process.
+
+package main
+
+import (
+ "encoding/xml"
+ "io"
+ "strings"
+)
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport) {
+ d := xml.NewDecoder(r)
+ d.Strict = false
+ for {
+ t, err := d.Token()
+ if err != nil {
+ return
+ }
+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+ return
+ }
+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+ return
+ }
+ e, ok := t.(xml.StartElement)
+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+ continue
+ }
+ if attrValue(e.Attr, "name") != "go-import" {
+ continue
+ }
+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+ imports = append(imports, metaImport{
+ Prefix: f[0],
+ VCS: f[1],
+ RepoRoot: f[2],
+ })
+ }
+ }
+ return
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+ for _, a := range attrs {
+ if strings.EqualFold(a.Name.Local, name) {
+ return a.Value
+ }
+ }
+ return ""
+}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 8df57ff38..775f305d2 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -14,6 +14,7 @@ The commands are:
build compile packages and dependencies
clean remove object files
doc run godoc on package sources
+ env print Go environment information
fix run go tool fix on packages
fmt run gofmt on package sources
get download and install packages and dependencies
@@ -76,6 +77,8 @@ The build flags are shared by the build, install, run, and test commands:
-x
print the commands.
+ -compiler name
+ name of compiler to use, as in runtime.Compiler (gccgo or gc)
-gccgoflags 'arg list'
arguments to pass on each gccgo compiler/linker invocation
-gcflags 'arg list'
@@ -153,6 +156,20 @@ To run godoc with specific options, run godoc itself.
See also: go fix, go fmt, go vet.
+Print Go environment information
+
+Usage:
+
+ go env [var ...]
+
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file). If one or more variable
+names is given as arguments, env prints the value of
+each named variable on its own line.
+
+
Run go tool fix on packages
Usage:
@@ -196,7 +213,7 @@ Get downloads and installs the packages named by the import paths,
along with their dependencies.
The -a, -n, -v, -x, and -p flags have the same meaning as in 'go build'
-and 'go install'. See 'go help install'.
+and 'go install'. See 'go help build'.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
@@ -253,21 +270,28 @@ 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
- ImportPath string // import path of package in dir
- Dir string // directory containing package sources
- Version string // version of installed package (TODO)
+ 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, and XTestGoFiles)
- TestGoFiles []string // _test.go source files internal to the package they are testing
- XTestGoFiles []string // _test.go source files external to the package they are testing
- CFiles []string // .c source files
- HFiles []string // .h source files
- SFiles []string // .s source files
- 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"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso object files to add to archive
+
+ // Cgo directives
+ CgoCFLAGS []string // cgo: flags for C compiler
+ CgoLDFLAGS []string // cgo: flags for linker
+ CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
@@ -275,8 +299,13 @@ being passed to the template is:
// Error information
Incomplete bool // this package or a dependency has an error
- Error *PackageError // error loading package
+ Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
+
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
}
The -json flag causes the package data to be printed in JSON format
@@ -479,9 +508,8 @@ An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the
-patterns. For example, encoding/... expands to all packages
-in subdirectories of the encoding tree, while net... expands to
-net and all its subdirectories.
+patterns. As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help remote' for details.
@@ -535,7 +563,12 @@ A few common code hosting sites have special syntax:
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
-For code hosted on other servers, an import path of the form
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
repository.vcs/path
@@ -564,6 +597,42 @@ When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path correponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
New downloaded packages are written to the first directory
listed in the GOPATH environment variable (see 'go help gopath').
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
new file mode 100644
index 000000000..d5b034809
--- /dev/null
+++ b/src/cmd/go/env.go
@@ -0,0 +1,89 @@
+// 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 main
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+)
+
+var cmdEnv = &Command{
+ Run: runEnv,
+ UsageLine: "env [var ...]",
+ Short: "print Go environment information",
+ Long: `
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file). If one or more variable
+names is given as arguments, env prints the value of
+each named variable on its own line.
+ `,
+}
+
+type envVar struct {
+ name, value string
+}
+
+func mkEnv() []envVar {
+ var b builder
+ b.init()
+
+ env := []envVar{
+ {"GOROOT", goroot},
+ {"GOBIN", gobin},
+ {"GOARCH", goarch},
+ {"GOCHAR", archChar},
+ {"GOOS", goos},
+ {"GOEXE", exeSuffix},
+ {"GOHOSTARCH", runtime.GOARCH},
+ {"GOHOSTOS", runtime.GOOS},
+ {"GOTOOLDIR", toolDir},
+ {"GOGCCFLAGS", strings.Join(b.gccCmd(".")[3:], " ")},
+ }
+
+ if buildContext.CgoEnabled {
+ env = append(env, envVar{"CGO_ENABLED", "1"})
+ } else {
+ env = append(env, envVar{"CGO_ENABLED", "0"})
+ }
+
+ return env
+}
+
+func findEnv(env []envVar, name string) string {
+ for _, e := range env {
+ if e.name == name {
+ return e.value
+ }
+ }
+ return ""
+}
+
+func runEnv(cmd *Command, args []string) {
+ env := mkEnv()
+ if len(args) > 0 {
+ for _, name := range args {
+ fmt.Printf("%s\n", findEnv(env, name))
+ }
+ return
+ }
+
+ switch runtime.GOOS {
+ default:
+ for _, e := range env {
+ fmt.Printf("%s=\"%s\"\n", e.name, e.value)
+ }
+ case "plan9":
+ for _, e := range env {
+ fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
+ }
+ case "windows":
+ for _, e := range env {
+ fmt.Printf("set %s=%s\n", e.name, e.value)
+ }
+ }
+}
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index 0ad22adb0..abaf5ffa0 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -8,6 +8,7 @@ package main
import (
"fmt"
+ "go/build"
"os"
"path/filepath"
"runtime"
@@ -23,7 +24,7 @@ Get downloads and installs the packages named by the import paths,
along with their dependencies.
The -a, -n, -v, -x, and -p flags have the same meaning as in 'go build'
-and 'go install'. See 'go help install'.
+and 'go install'. See 'go help build'.
The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.
@@ -57,19 +58,13 @@ func init() {
func runGet(cmd *Command, args []string) {
// Phase 1. Download/update.
- args = importPaths(args)
var stk importStack
- for _, arg := range args {
+ for _, arg := range downloadPaths(args) {
download(arg, &stk)
}
exitIfErrors()
- if *getD {
- // download only
- return
- }
-
- // Phase 2. Install.
+ // Phase 2. Rescan packages and reevaluate args list.
// Code we downloaded and all code that depends on it
// needs to be evicted from the package cache so that
@@ -80,9 +75,48 @@ func runGet(cmd *Command, args []string) {
delete(packageCache, name)
}
+ args = importPaths(args)
+
+ // Phase 3. Install.
+ if *getD {
+ // Download only.
+ // Check delayed until now so that importPaths
+ // has a chance to print errors.
+ return
+ }
+
runInstall(cmd, args)
}
+// downloadPath prepares the list of paths to pass to download.
+// It expands ... patterns that can be expanded. If there is no match
+// for a particular pattern, downloadPaths leaves it in the result list,
+// in the hope that we can figure out the repository from the
+// initial ...-free prefix.
+func downloadPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ var expand []string
+ // Use matchPackagesInFS to avoid printing
+ // warnings. They will be printed by the
+ // eventual call to importPaths instead.
+ if build.IsLocalImport(a) {
+ expand = matchPackagesInFS(a)
+ } else {
+ expand = matchPackages(a)
+ }
+ if len(expand) > 0 {
+ out = append(out, expand...)
+ continue
+ }
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
// downloadCache records the import paths we have already
// considered during the download, to avoid duplicate work when
// there is more than one dependency sequence leading to
@@ -112,38 +146,73 @@ func download(arg string, stk *importStack) {
}
downloadCache[arg] = true
+ pkgs := []*Package{p}
+ wildcardOkay := len(*stk) == 0
+
// Download if the package is missing, or update if we're using -u.
if p.Dir == "" || *getU {
// The actual download.
stk.push(p.ImportPath)
- defer stk.pop()
- if err := downloadPackage(p); err != nil {
+ err := downloadPackage(p)
+ if err != nil {
errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
+ stk.pop()
return
}
- // Reread the package information from the updated files.
- p = reloadPackage(arg, stk)
- if p.Error != nil {
- errorf("%s", p.Error)
- return
+ args := []string{arg}
+ // If the argument has a wildcard in it, re-evaluate the wildcard.
+ // We delay this until after reloadPackage so that the old entry
+ // for p has been replaced in the package cache.
+ if wildcardOkay && strings.Contains(arg, "...") {
+ if build.IsLocalImport(arg) {
+ args = matchPackagesInFS(arg)
+ } else {
+ args = matchPackages(arg)
+ }
}
- }
- if *getFix {
- run(stringList(tool("fix"), relPaths(p.gofiles)))
+ // Clear all relevant package cache entries before
+ // doing any new loads.
+ for _, arg := range args {
+ p := packageCache[arg]
+ if p != nil {
+ delete(packageCache, p.Dir)
+ delete(packageCache, p.ImportPath)
+ }
+ }
- // The imports might have changed, so reload again.
- p = reloadPackage(arg, stk)
- if p.Error != nil {
- errorf("%s", p.Error)
- return
+ pkgs = pkgs[:0]
+ for _, arg := range args {
+ stk.push(arg)
+ p := loadPackage(arg, stk)
+ stk.pop()
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ continue
+ }
+ pkgs = append(pkgs, p)
}
}
- // Process dependencies, now that we know what they are.
- for _, dep := range p.deps {
- download(dep.ImportPath, stk)
+ // Process package, which might now be multiple packages
+ // due to wildcard expansion.
+ for _, p := range pkgs {
+ if *getFix {
+ run(stringList(tool("fix"), relPaths(p.gofiles)))
+
+ // The imports might have changed, so reload again.
+ p = reloadPackage(arg, stk)
+ if p.Error != nil {
+ errorf("%s", p.Error)
+ return
+ }
+ }
+
+ // Process dependencies, now that we know what they are.
+ for _, dep := range p.deps {
+ download(dep.ImportPath, stk)
+ }
}
}
@@ -162,10 +231,11 @@ func downloadPackage(p *Package) error {
} else {
// Analyze the import path to determine the version control system,
// repository, and the import path for the root of the repository.
- vcs, repo, rootPath, err = vcsForImportPath(p.ImportPath)
- }
- if err != nil {
- return err
+ rr, err := repoRootForImportPath(p.ImportPath)
+ if err != nil {
+ return err
+ }
+ vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
}
if p.build.SrcRoot == "" {
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 60654a272..26640d833 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -36,9 +36,8 @@ An import path is a pattern if it includes one or more "..." wildcards,
each of which can match any string, including the empty string and
strings containing slashes. Such a pattern expands to all package
directories found in the GOPATH trees with names matching the
-patterns. For example, encoding/... expands to all packages
-in subdirectories of the encoding tree, while net... expands to
-net and all its subdirectories.
+patterns. As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
An import path can also name a package to be downloaded from
a remote repository. Run 'go help remote' for details.
@@ -96,7 +95,12 @@ A few common code hosting sites have special syntax:
import "launchpad.net/~user/project/branch"
import "launchpad.net/~user/project/branch/sub/directory"
-For code hosted on other servers, an import path of the form
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
repository.vcs/path
@@ -125,6 +129,42 @@ When a version control system supports multiple protocols,
each is tried in turn when downloading. For example, a Git
download tries git://, then https://, then http://.
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+ <meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path correponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+ import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+ https://example.org/pkg/foo?go-get=1 (preferred)
+ http://example.org/pkg/foo?go-get=1 (fallback)
+
+If that page contains the meta tag
+
+ <meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
New downloaded packages are written to the first directory
listed in the GOPATH environment variable (see 'go help gopath').
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 8d9b2a165..6de9a3e1e 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -13,8 +13,11 @@ package main
import (
"fmt"
+ "io"
"io/ioutil"
+ "log"
"net/http"
+ "net/url"
)
// httpGET returns the data from an HTTP GET request for the given URL.
@@ -33,3 +36,52 @@ func httpGET(url string) ([]byte, error) {
}
return b, nil
}
+
+// httpClient is the default HTTP client, but a variable so it can be
+// changed by tests, without modifying http.DefaultClient.
+var httpClient = http.DefaultClient
+
+// httpsOrHTTP returns the body of either the importPath's
+// https resource or, if unavailable, the http resource.
+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
+ fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
+ u, err := url.Parse(scheme + "://" + importPath)
+ if err != nil {
+ return "", nil, err
+ }
+ u.RawQuery = "go-get=1"
+ urlStr = u.String()
+ if buildV {
+ log.Printf("Fetching %s", urlStr)
+ }
+ res, err = httpClient.Get(urlStr)
+ return
+ }
+ closeBody := func(res *http.Response) {
+ if res != nil {
+ res.Body.Close()
+ }
+ }
+ urlStr, res, err := fetch("https")
+ if err != nil || res.StatusCode != 200 {
+ if buildV {
+ if err != nil {
+ log.Printf("https fetch failed.")
+ } else {
+ log.Printf("ignoring https fetch with status code %d", res.StatusCode)
+ }
+ }
+ closeBody(res)
+ urlStr, res, err = fetch("http")
+ }
+ if err != nil {
+ closeBody(res)
+ return "", nil, err
+ }
+ // Note: accepting a non-200 OK here, so people can serve a
+ // meta import in their http 404 page.
+ if buildV {
+ log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode)
+ }
+ return urlStr, res.Body, nil
+}
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index fa3f5d330..edb59aa79 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -30,30 +30,42 @@ 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
- ImportPath string // import path of package in dir
- Dir string // directory containing package sources
- Version string // version of installed package (TODO)
+ 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, and XTestGoFiles)
- TestGoFiles []string // _test.go source files internal to the package they are testing
- XTestGoFiles []string // _test.go source files external to the package they are testing
- CFiles []string // .c source files
- HFiles []string // .h source files
- SFiles []string // .s source files
- 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"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso object files to add to archive
+
+ // Cgo directives
+ CgoCFLAGS []string // cgo: flags for C compiler
+ CgoLDFLAGS []string // cgo: flags for linker
+ CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
Deps []string // all (recursively) imported dependencies
-
+
// Error information
Incomplete bool // this package or a dependency has an error
- Error *PackageError // error loading package
+ Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
+
+ TestGoFiles []string // _test.go files in package
+ TestImports []string // imports from TestGoFiles
+ XTestGoFiles []string // _test.go files outside package
+ XTestImports []string // imports from XTestGoFiles
}
The -json flag causes the package data to be printed in JSON format
@@ -75,6 +87,7 @@ For more about specifying packages, see 'go help packages'.
func init() {
cmdList.Run = runList // break init cycle
+ cmdList.Flag.Var(buildCompiler{}, "compiler", "")
}
var listE = cmdList.Flag.Bool("e", false, "")
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 3a0f7a089..2f8209c86 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -76,6 +76,7 @@ var commands = []*Command{
cmdBuild,
cmdClean,
cmdDoc,
+ cmdEnv,
cmdFix,
cmdFmt,
cmdGet,
@@ -246,8 +247,9 @@ func help(args []string) {
os.Exit(2) // failed at 'go help cmd'
}
-// importPaths returns the import paths to use for the given command line.
-func importPaths(args []string) []string {
+// importPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func importPathsNoDotExpansion(args []string) []string {
if len(args) == 0 {
return []string{"."}
}
@@ -269,13 +271,26 @@ func importPaths(args []string) []string {
} else {
a = path.Clean(a)
}
-
- if build.IsLocalImport(a) && strings.Contains(a, "...") {
- out = append(out, allPackagesInFS(a)...)
+ if a == "all" || a == "std" {
+ out = append(out, allPackages(a)...)
continue
}
- if a == "all" || a == "std" || strings.Contains(a, "...") {
- out = append(out, allPackages(a)...)
+ out = append(out, a)
+ }
+ return out
+}
+
+// importPaths returns the import paths to use for the given command line.
+func importPaths(args []string) []string {
+ args = importPathsNoDotExpansion(args)
+ var out []string
+ for _, a := range args {
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, allPackagesInFS(a)...)
+ } else {
+ out = append(out, allPackages(a)...)
+ }
continue
}
out = append(out, a)
@@ -344,6 +359,10 @@ func runOut(dir string, cmdargs ...interface{}) []byte {
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
+ // Special case: foo/... matches foo too.
+ if strings.HasSuffix(re, `/.*`) {
+ re = re[:len(re)-len(`/.*`)] + `(/.*)?`
+ }
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
@@ -355,6 +374,14 @@ func matchPattern(pattern string) func(name string) bool {
// The pattern is either "all" (all packages), "std" (standard packages)
// or a path including "...".
func allPackages(pattern string) []string {
+ pkgs := matchPackages(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackages(pattern string) []string {
match := func(string) bool { return true }
if pattern != "all" && pattern != "std" {
match = matchPattern(pattern)
@@ -431,10 +458,6 @@ func allPackages(pattern string) []string {
return nil
})
}
-
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
return pkgs
}
@@ -442,6 +465,14 @@ func allPackages(pattern string) []string {
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory. There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
+ pkgs := matchPackagesInFS(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+func matchPackagesInFS(pattern string) []string {
// Find directory to begin the scan.
// Could be smarter but this one optimization
// is enough for now, since ... is usually at the
@@ -481,10 +512,6 @@ func allPackagesInFS(pattern string) []string {
pkgs = append(pkgs, name)
return nil
})
-
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
return pkgs
}
diff --git a/src/cmd/go/match_test.go b/src/cmd/go/match_test.go
new file mode 100644
index 000000000..f058f235a
--- /dev/null
+++ b/src/cmd/go/match_test.go
@@ -0,0 +1,36 @@
+// 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 main
+
+import "testing"
+
+var matchTests = []struct {
+ pattern string
+ path string
+ match bool
+}{
+ {"...", "foo", true},
+ {"net", "net", true},
+ {"net", "net/http", false},
+ {"net/http", "net", false},
+ {"net/http", "net/http", true},
+ {"net...", "netchan", true},
+ {"net...", "net", true},
+ {"net...", "net/http", true},
+ {"net...", "not/http", false},
+ {"net/...", "netchan", false},
+ {"net/...", "net", true},
+ {"net/...", "net/http", true},
+ {"net/...", "not/http", false},
+}
+
+func TestMatchPattern(t *testing.T) {
+ for _, tt := range matchTests {
+ match := matchPattern(tt.pattern)(tt.path)
+ if match != tt.match {
+ t.Errorf("matchPattern(%q)(%q) = %v, want %v", tt.pattern, tt.path, match, tt.match)
+ }
+ }
+}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 3763000c6..44dbd6798 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -17,6 +17,7 @@ import (
"sort"
"strings"
"time"
+ "unicode"
)
// A Package describes a single package found in a directory.
@@ -24,25 +25,23 @@ 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?
- Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
- Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
-
- Root string `json:",omitempty"` // root dir of tree this package belongs to
+ 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
// Source files
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles XTestGoFiles)
- CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
- CFiles []string `json:",omitempty"` // .c source files
- HFiles []string `json:",omitempty"` // .h source files
- SFiles []string `json:",omitempty"` // .s source files
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
+ CFiles []string `json:",omitempty"` // .c source files
+ HFiles []string `json:",omitempty"` // .h source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
@@ -50,8 +49,12 @@ type Package struct {
CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
// Dependency information
- Imports []string `json:",omitempty"` // import paths used by this package
- Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+ Imports []string `json:",omitempty"` // import paths used by this package
+ Deps []string `json:",omitempty"` // all (recursively) imported dependencies
+
+ // Error information
+ Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies?
+ Error *PackageError `json:",omitempty"` // error loading this package (not dependencies)
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
// Test information
@@ -61,16 +64,17 @@ type Package struct {
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
// Unexported fields are not part of the public API.
- build *build.Package
- pkgdir string // overrides build.PkgDir
- imports []*Package
- deps []*Package
- gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
- target string // installed file for this package (may be executable)
- fake bool // synthesized package
- forceBuild bool // this package must be rebuilt
- local bool // imported via local path (./ or ../)
- localPrefix string // interpret ./ and ../ imports relative to this prefix
+ build *build.Package
+ pkgdir string // overrides build.PkgDir
+ imports []*Package
+ deps []*Package
+ gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ target string // installed file for this package (may be executable)
+ fake bool // synthesized package
+ forceBuild bool // this package must be rebuilt
+ forceLibrary bool // this package is a library (even if named "main")
+ local bool // imported via local path (./ or ../)
+ localPrefix string // interpret ./ and ../ imports relative to this prefix
}
func (p *Package) copyBuild(pp *build.Package) {
@@ -89,6 +93,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.CFiles = pp.CFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
+ p.SysoFiles = pp.SysoFiles
p.CgoCFLAGS = pp.CgoCFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
@@ -171,7 +176,16 @@ func reloadPackage(arg string, stk *importStack) *Package {
// a special case, so that all the code to deal with ordinary imports works
// automatically.
func dirToImportPath(dir string) string {
- return pathpkg.Join("_", strings.Replace(filepath.ToSlash(dir), ":", "_", -1))
+ return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
+}
+
+func makeImportValid(r rune) rune {
+ // Should match Go spec, compilers, and ../../pkg/go/parser/parser.go:/isValidImport.
+ const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+ if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+ return '_'
+ }
+ return r
}
// loadImport scans the directory named by path, which must be an import path,
@@ -276,9 +290,8 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to.
- // Now that we've fixed the import path, it's just the import path.
// Synthesized main packages sometimes override this.
- p.localPrefix = p.ImportPath
+ p.localPrefix = dirToImportPath(p.Dir)
if err != nil {
p.Incomplete = true
@@ -340,6 +353,16 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
if p1.local {
+ if !p.local && p.Error == nil {
+ p.Error = &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("local import %q in non-local package", path),
+ }
+ pos := p.build.ImportPos[path]
+ if len(pos) > 0 {
+ p.Error.Pos = pos[0].String()
+ }
+ }
path = p1.ImportPath
importPaths[i] = path
}
@@ -371,7 +394,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
// unsafe is a fake package.
- if p.Standard && p.ImportPath == "unsafe" {
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
p.target = ""
}
@@ -416,7 +439,7 @@ func computeStale(pkgs ...*Package) {
// isStale reports whether package p needs to be rebuilt.
func isStale(p *Package, topRoot map[string]bool) bool {
- if p.Standard && p.ImportPath == "unsafe" {
+ if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
// fake, builtin package
return false
}
@@ -486,7 +509,7 @@ func isStale(p *Package, topRoot map[string]bool) bool {
return false
}
- srcs := stringList(p.GoFiles, p.CFiles, p.HFiles, p.SFiles, p.CgoFiles)
+ srcs := stringList(p.GoFiles, p.CFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles)
for _, src := range srcs {
if olderThan(filepath.Join(p.Dir, src)) {
return true
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index 2976d5c8d..94cd59296 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -26,9 +26,7 @@ See also: go build.
func init() {
cmdRun.Run = runRun // break init loop
- cmdRun.Flag.BoolVar(&buildA, "a", false, "")
- cmdRun.Flag.BoolVar(&buildN, "n", false, "")
- cmdRun.Flag.BoolVar(&buildX, "x", false, "")
+ addBuildFlags(cmdRun)
}
func printStderr(args ...interface{}) (int, error) {
@@ -44,12 +42,15 @@ func runRun(cmd *Command, args []string) {
i++
}
files, cmdArgs := args[:i], args[i:]
+ if len(files) == 0 {
+ fatalf("go run: no go files listed")
+ }
p := goFilesPackage(files)
if p.Error != nil {
fatalf("%s", p.Error)
}
if p.Name != "main" {
- fatalf("cannot run non-main package")
+ fatalf("go run: cannot run non-main package")
}
p.target = "" // must build - not up to date
a1 := b.action(modeBuild, modeBuild, p)
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index daca144ee..541535101 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -22,37 +22,50 @@ do
done
# Test local (./) imports.
-./testgo build -o hello testdata/local/easy.go
-./hello >hello.out
-if ! grep -q '^easysub\.Hello' hello.out; then
- echo "testdata/local/easy.go did not generate expected output"
- cat hello.out
- ok=false
-fi
-
-./testgo build -o hello testdata/local/easysub/main.go
-./hello >hello.out
-if ! grep -q '^easysub\.Hello' hello.out; then
- echo "testdata/local/easysub/main.go did not generate expected output"
- cat hello.out
- ok=false
-fi
-
-./testgo build -o hello testdata/local/hard.go
-./hello >hello.out
-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
- ok=false
-fi
+testlocal() {
+ local="$1"
+ ./testgo build -o hello "testdata/$local/easy.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easy.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ ./testgo build -o hello "testdata/$local/easysub/main.go"
+ ./hello >hello.out
+ if ! grep -q '^easysub\.Hello' hello.out; then
+ echo "testdata/$local/easysub/main.go did not generate expected output"
+ cat hello.out
+ ok=false
+ fi
+
+ ./testgo build -o hello "testdata/$local/hard.go"
+ ./hello >hello.out
+ 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
+ ok=false
+ fi
+
+ rm -f err.out hello.out hello
+
+ # Test that go install x.go fails.
+ if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
+ echo "go install testdata/$local/easy.go succeeded"
+ ok=false
+ fi
+}
-rm -f err.out hello.out hello
+# Test local imports
+testlocal local
-# Test that go install x.go fails.
-if ./testgo install testdata/local/easy.go >/dev/null 2>&1; then
- echo "go install testdata/local/easy.go succeeded"
- ok=false
-fi
+# Test local imports again, with bad characters in the directory name.
+bad='#$%:, &()*;<=>?\^{}'
+rm -rf "testdata/$bad"
+cp -R testdata/local "testdata/$bad"
+testlocal "$bad"
+rm -rf "testdata/$bad"
# Test tests with relative imports.
if ! ./testgo test ./testdata/testimport; then
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 6ca49d10f..870ab190f 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -192,8 +192,6 @@ See the documentation of the testing package for more information.
var (
testC bool // -c flag
testI bool // -i flag
- testP int // -p flag
- testX bool // -x flag
testV bool // -v flag
testFiles []string // -file flag(s) TODO: not respected
testTimeout string // -timeout flag
@@ -241,11 +239,6 @@ func runTest(cmd *Command, args []string) {
testStreamOutput = len(pkgArgs) == 0 || testBench ||
(len(pkgs) <= 1 && testShowPass)
- buildX = testX
- if testP > 0 {
- buildP = testP
- }
-
var b builder
b.init()
@@ -265,6 +258,9 @@ func runTest(cmd *Command, args []string) {
for _, path := range p.TestImports {
deps[path] = true
}
+ for _, path := range p.XTestImports {
+ deps[path] = true
+ }
}
// translate C to runtime/cgo
@@ -450,6 +446,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
ptest.imports = append(append([]*Package{}, p.imports...), imports...)
ptest.pkgdir = testDir
ptest.fake = true
+ ptest.forceLibrary = true
ptest.Stale = true
ptest.build = new(build.Package)
*ptest.build = *p.build
@@ -461,12 +458,6 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
m[k] = append(m[k], v...)
}
ptest.build.ImportPos = m
- computeStale(ptest)
- a := b.action(modeBuild, modeBuild, ptest)
- a.objdir = testDir + string(filepath.Separator)
- a.objpkg = ptestObj
- a.target = ptestObj
- a.link = false
} else {
ptest = p
}
@@ -477,6 +468,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
Name: p.Name + "_test",
ImportPath: p.ImportPath + "_test",
localPrefix: p.localPrefix,
+ Root: p.Root,
Dir: p.Dir,
GoFiles: p.XTestGoFiles,
Imports: p.XTestImports,
@@ -488,11 +480,6 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
fake: true,
Stale: true,
}
- computeStale(pxtest)
- a := b.action(modeBuild, modeBuild, pxtest)
- a.objdir = testDir + string(filepath.Separator)
- a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
- a.target = a.objpkg
}
// Action for building pkg.test.
@@ -501,8 +488,9 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
Dir: testDir,
GoFiles: []string{"_testmain.go"},
ImportPath: "testmain",
+ Root: p.Root,
imports: []*Package{ptest},
- build: &build.Package{},
+ build: &build.Package{Name: "main"},
fake: true,
Stale: true,
}
@@ -523,6 +511,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
pmain.imports = append(pmain.imports, ptesting, pregexp)
computeStale(pmain)
+ if ptest != p {
+ a := b.action(modeBuild, modeBuild, ptest)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = ptestObj
+ a.target = ptestObj
+ a.link = false
+ }
+
+ if pxtest != nil {
+ a := b.action(modeBuild, modeBuild, pxtest)
+ a.objdir = testDir + string(filepath.Separator)
+ a.objpkg = buildToolchain.pkgpath(testDir, pxtest)
+ a.target = a.objpkg
+ }
+
a := b.action(modeBuild, modeBuild, pmain)
a.objdir = testDir + string(filepath.Separator)
a.objpkg = filepath.Join(testDir, "main.a")
@@ -639,6 +642,9 @@ func (b *builder) runTest(a *action) error {
// cleanTest is the action for cleaning up after a test.
func (b *builder) cleanTest(a *action) error {
+ if buildWork {
+ return nil
+ }
run := a.deps[0]
testDir := filepath.Join(b.work, filepath.FromSlash(run.p.ImportPath+"/_test"))
os.RemoveAll(testDir)
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 7c9b7f16d..ecf5bf456 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -47,7 +47,7 @@ func testUsage() {
// testFlagSpec defines a flag we know about.
type testFlagSpec struct {
name string
- isBool bool
+ boolVar *bool
passToTest bool // pass to Test
multiOK bool // OK to have multiple instances
present bool // flag has been seen
@@ -56,11 +56,21 @@ type testFlagSpec struct {
// testFlagDefn is the set of flags we process.
var testFlagDefn = []*testFlagSpec{
// local.
- {name: "c", isBool: true},
+ {name: "c", boolVar: &testC},
{name: "file", multiOK: true},
- {name: "i", isBool: true},
+ {name: "i", boolVar: &testI},
+
+ // build flags.
+ {name: "a", boolVar: &buildA},
+ {name: "n", boolVar: &buildN},
{name: "p"},
- {name: "x", isBool: true},
+ {name: "x", boolVar: &buildX},
+ {name: "work", boolVar: &buildWork},
+ {name: "gcflags"},
+ {name: "ldflags"},
+ {name: "gccgoflags"},
+ {name: "tags"},
+ {name: "compiler"},
// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
{name: "bench", passToTest: true},
@@ -71,9 +81,9 @@ var testFlagDefn = []*testFlagSpec{
{name: "memprofilerate", passToTest: true},
{name: "parallel", passToTest: true},
{name: "run", passToTest: true},
- {name: "short", isBool: true, passToTest: true},
+ {name: "short", boolVar: new(bool), passToTest: true},
{name: "timeout", passToTest: true},
- {name: "v", isBool: true, passToTest: true},
+ {name: "v", boolVar: &testV, passToTest: true},
}
// testFlags processes the command line, grabbing -x and -c, rewriting known flags
@@ -118,16 +128,21 @@ func testFlags(args []string) (packageNames, passToTest []string) {
continue
}
switch f.name {
- case "c":
- setBoolFlag(&testC, value)
- case "i":
- setBoolFlag(&testI, value)
+ // bool flags.
+ case "a", "c", "i", "n", "x", "v", "work":
+ setBoolFlag(f.boolVar, value)
case "p":
- setIntFlag(&testP, value)
- case "x":
- setBoolFlag(&testX, value)
- case "v":
- setBoolFlag(&testV, value)
+ setIntFlag(&buildP, value)
+ case "gcflags":
+ buildGcflags = strings.Fields(value)
+ case "ldflags":
+ buildLdflags = strings.Fields(value)
+ case "gccgoflags":
+ buildGccgoflags = strings.Fields(value)
+ case "tags":
+ buildContext.BuildTags = strings.Fields(value)
+ case "compiler":
+ buildCompiler{}.Set(value)
case "file":
testFiles = append(testFiles, value)
case "bench":
@@ -172,7 +187,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
for _, f = range testFlagDefn {
if name == f.name {
// Booleans are special because they have modes -x, -x=true, -x=false.
- if f.isBool {
+ if f.boolVar != nil {
if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
value = "true"
} else {
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index cf3410242..3634b606c 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -7,7 +7,9 @@ package main
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
+ "log"
"os"
"os/exec"
"path/filepath"
@@ -102,7 +104,7 @@ var vcsGit = &vcsCmd{
tagSyncCmd: "checkout {tag}",
tagSyncDefault: "checkout origin/master",
- scheme: []string{"git", "https", "http"},
+ scheme: []string{"git", "https", "http", "git+ssh"},
pingCmd: "ls-remote {scheme}://{repo}",
}
@@ -121,7 +123,7 @@ var vcsBzr = &vcsCmd{
tagSyncCmd: "update -r {tag}",
tagSyncDefault: "update -r revno:-1",
- scheme: []string{"https", "http", "bzr"},
+ scheme: []string{"https", "http", "bzr", "bzr+ssh"},
pingCmd: "info {scheme}://{repo}",
}
@@ -136,7 +138,7 @@ var vcsSvn = &vcsCmd{
// There is no tag command in subversion.
// The branch information is all in the path names.
- scheme: []string{"https", "http", "svn"},
+ scheme: []string{"https", "http", "svn", "svn+ssh"},
pingCmd: "info {scheme}://{repo}",
}
@@ -302,12 +304,58 @@ func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
return nil, "", fmt.Errorf("directory %q is not using a known version control system", dir)
}
-// vcsForImportPath analyzes importPath to determine the
+// repoRoot represents a version control system, a repo, and a root of
+// where to put it on disk.
+type repoRoot struct {
+ vcs *vcsCmd
+
+ // repo is the repository URL, including scheme
+ repo string
+
+ // root is the import path corresponding to the root of the
+ // repository
+ root string
+}
+
+// repoRootForImportPath analyzes importPath to determine the
// version control system, and code repository to use.
-// On return, repo is the repository URL and root is the
-// import path corresponding to the root of the repository
-// (thus root is a prefix of importPath).
-func vcsForImportPath(importPath string) (vcs *vcsCmd, repo, root string, err error) {
+func repoRootForImportPath(importPath string) (*repoRoot, error) {
+ rr, err := repoRootForImportPathStatic(importPath, "")
+ if err == errUnknownSite {
+ rr, err = repoRootForImportDynamic(importPath)
+
+ // repoRootForImportDynamic returns error detail
+ // that is irrelevant if the user didn't intend to use a
+ // dynamic import in the first place.
+ // Squelch it.
+ if err != nil {
+ if buildV {
+ log.Printf("import %q: %v", importPath, err)
+ }
+ err = fmt.Errorf("unrecognized import path %q", importPath)
+ }
+ }
+
+ if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
+ // Do not allow wildcards in the repo root.
+ rr = nil
+ err = fmt.Errorf("cannot expand ... in %q", importPath)
+ }
+ return rr, err
+}
+
+var errUnknownSite = errors.New("dynamic lookup required to find mapping")
+
+// repoRootForImportPathStatic attempts to map importPath to a
+// repoRoot using the commonly-used VCS hosting sites in vcsPaths
+// (github.com/user/dir), or from a fully-qualified importPath already
+// containing its VCS type (foo.com/repo.git/dir)
+//
+// If scheme is non-empty, that scheme is forced.
+func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
+ if strings.Contains(importPath, "://") {
+ return nil, fmt.Errorf("invalid import path %q", importPath)
+ }
for _, srv := range vcsPaths {
if !strings.HasPrefix(importPath, srv.prefix) {
continue
@@ -315,7 +363,7 @@ func vcsForImportPath(importPath string) (vcs *vcsCmd, repo, root string, err er
m := srv.regexp.FindStringSubmatch(importPath)
if m == nil {
if srv.prefix != "" {
- return nil, "", "", fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
+ return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath)
}
continue
}
@@ -338,24 +386,127 @@ func vcsForImportPath(importPath string) (vcs *vcsCmd, repo, root string, err er
}
if srv.check != nil {
if err := srv.check(match); err != nil {
- return nil, "", "", err
+ return nil, err
}
}
vcs := vcsByCmd(match["vcs"])
if vcs == nil {
- return nil, "", "", fmt.Errorf("unknown version control system %q", match["vcs"])
+ return nil, fmt.Errorf("unknown version control system %q", match["vcs"])
}
if srv.ping {
- for _, scheme := range vcs.scheme {
- if vcs.ping(scheme, match["repo"]) == nil {
- match["repo"] = scheme + "://" + match["repo"]
- break
+ if scheme != "" {
+ match["repo"] = scheme + "://" + match["repo"]
+ } else {
+ for _, scheme := range vcs.scheme {
+ if vcs.ping(scheme, match["repo"]) == nil {
+ match["repo"] = scheme + "://" + match["repo"]
+ break
+ }
}
}
}
- return vcs, match["repo"], match["root"], nil
+ rr := &repoRoot{
+ vcs: vcs,
+ repo: match["repo"],
+ root: match["root"],
+ }
+ return rr, nil
+ }
+ return nil, errUnknownSite
+}
+
+// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
+// statically known by repoRootForImportPathStatic.
+//
+// This handles "vanity import paths" like "name.tld/pkg/foo".
+func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
+ slash := strings.Index(importPath, "/")
+ if slash < 0 {
+ return nil, fmt.Errorf("missing / in import %q", importPath)
+ }
+ urlStr, body, err := httpsOrHTTP(importPath)
+ if err != nil {
+ return nil, fmt.Errorf("http/https fetch for import %q: %v", importPath, err)
+ }
+ defer body.Close()
+ metaImport, err := matchGoImport(parseMetaGoImports(body), importPath)
+ if err != nil {
+ if err != errNoMatch {
+ return nil, fmt.Errorf("parse %s: %v", urlStr, err)
+ }
+ return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
+ }
+ if buildV {
+ log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+ }
+ // If the import was "uni.edu/bob/project", which said the
+ // prefix was "uni.edu" and the RepoRoot was "evilroot.com",
+ // make sure we don't trust Bob and check out evilroot.com to
+ // "uni.edu" yet (possibly overwriting/preempting another
+ // non-evil student). Instead, first verify the root and see
+ // if it matches Bob's claim.
+ if metaImport.Prefix != importPath {
+ if buildV {
+ log.Printf("get %q: verifying non-authoritative meta tag", importPath)
+ }
+ urlStr0 := urlStr
+ urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+ if err != nil {
+ return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
+ }
+ imports := parseMetaGoImports(body)
+ if len(imports) == 0 {
+ return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+ }
+ metaImport2, err := matchGoImport(imports, importPath)
+ if err != nil || metaImport != metaImport2 {
+ return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+ }
+ }
+
+ if !strings.Contains(metaImport.RepoRoot, "://") {
+ return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+ }
+ rr := &repoRoot{
+ vcs: vcsByCmd(metaImport.VCS),
+ repo: metaImport.RepoRoot,
+ root: metaImport.Prefix,
+ }
+ if rr.vcs == nil {
+ return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+ }
+ return rr, nil
+}
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+ Prefix, VCS, RepoRoot string
+}
+
+// errNoMatch is returned from matchGoImport when there's no applicable match.
+var errNoMatch = errors.New("no import match")
+
+// matchGoImport returns the metaImport from imports matching importPath.
+// An error is returned if there are multiple matches.
+// errNoMatch is returned if none match.
+func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
+ match := -1
+ for i, im := range imports {
+ if !strings.HasPrefix(importPath, im.Prefix) {
+ continue
+ }
+ if match != -1 {
+ err = fmt.Errorf("multiple meta tags match import path %q", importPath)
+ return
+ }
+ match = i
+ }
+ if match == -1 {
+ err = errNoMatch
+ return
}
- return nil, "", "", fmt.Errorf("unrecognized import path %q", importPath)
+ return imports[match], nil
}
// expand rewrites s to replace {k} with match[k] for each key k in match.
diff --git a/src/cmd/godoc/appinit.go b/src/cmd/godoc/appinit.go
index e65be4094..4096a4f22 100644
--- a/src/cmd/godoc/appinit.go
+++ b/src/cmd/godoc/appinit.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 ignore
+// +build appengine
package main
@@ -42,8 +42,7 @@ func init() {
log.Fatalf("%s: %s\n", zipfile, err)
}
// rc is never closed (app running forever)
- fs = NewZipFS(rc)
- fsHttp = NewHttpZipFS(rc, *goroot)
+ fs.Bind("/", NewZipFS(rc, zipFilename), *goroot, bindReplace)
// initialize http handlers
readTemplates()
@@ -53,9 +52,6 @@ func init() {
// initialize default directory tree with corresponding timestamp.
initFSTree()
- // initialize directory trees for user-defined file systems (-path flag).
- initDirTrees()
-
// Immediately update metadata.
updateMetadata()
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 018259f7d..f7f51d0a0 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -31,7 +31,7 @@ import (
// Handler for /doc/codewalk/ and below.
func codewalk(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[len("/doc/codewalk/"):]
- abspath := absolutePath(r.URL.Path[1:], *goroot)
+ abspath := r.URL.Path
r.ParseForm()
if f := r.FormValue("fileprint"); f != "" {
@@ -53,7 +53,9 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
}
// Otherwise append .xml and hope to find
- // a codewalk description.
+ // a codewalk description, but before trim
+ // the trailing /.
+ abspath = strings.TrimRight(abspath, "/")
cw, err := loadCodewalk(abspath + ".xml")
if err != nil {
log.Print(err)
@@ -67,7 +69,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
}
b := applyTemplate(codewalkHTML, "codewalk", cw)
- servePage(w, "Codewalk: "+cw.Title, "", "", b)
+ servePage(w, cw.Title, "Codewalk: "+cw.Title, "", "", b)
}
// A Codewalk represents a single codewalk read from an XML file.
@@ -130,7 +132,7 @@ func loadCodewalk(filename string) (*Codewalk, error) {
i = len(st.Src)
}
filename := st.Src[0:i]
- data, err := ReadFile(fs, absolutePath(filename, *goroot))
+ data, err := ReadFile(fs, filename)
if err != nil {
st.Err = err
continue
@@ -198,7 +200,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
}
b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
- servePage(w, "Codewalks", "", "", b)
+ servePage(w, "", "Codewalks", "", "", b)
}
// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
@@ -208,7 +210,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
// of the codewalk pages. It is a separate iframe and does not get
// the usual godoc HTML wrapper.
func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
- abspath := absolutePath(f, *goroot)
+ abspath := f
data, err := ReadFile(fs, abspath)
if err != nil {
log.Print(err)
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
index 1acde99bd..b9b529f87 100644
--- a/src/cmd/godoc/dirtrees.go
+++ b/src/cmd/godoc/dirtrees.go
@@ -13,7 +13,7 @@ import (
"go/token"
"log"
"os"
- "path/filepath"
+ pathpkg "path"
"strings"
)
@@ -35,7 +35,7 @@ func isGoFile(fi os.FileInfo) bool {
name := fi.Name()
return !fi.IsDir() &&
len(name) > 0 && name[0] != '.' && // ignore .files
- filepath.Ext(name) == ".go"
+ pathpkg.Ext(name) == ".go"
}
func isPkgFile(fi os.FileInfo) bool {
@@ -50,12 +50,11 @@ func isPkgDir(fi os.FileInfo) bool {
}
type treeBuilder struct {
- pathFilter func(string) bool
- maxDepth int
+ maxDepth int
}
func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
- if b.pathFilter != nil && !b.pathFilter(path) || name == testdataDirName {
+ if name == testdataDirName {
return nil
}
@@ -70,13 +69,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
}
}
- list, err := fs.ReadDir(path)
- if err != nil {
- // newDirTree is called with a path that should be a package
- // directory; errors here should not happen, but if they do,
- // we want to know about them
- log.Printf("ReadDir(%s): %s", path, err)
- }
+ list, _ := fs.ReadDir(path)
// determine number of subdirectories and if there are package files
ndirs := 0
@@ -92,7 +85,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// though the directory doesn't contain any real package files - was bug)
if synopses[0] == "" {
// no "optimal" package synopsis yet; continue to collect synopses
- file, err := parseFile(fset, filepath.Join(path, d.Name()),
+ file, err := parseFile(fset, pathpkg.Join(path, d.Name()),
parser.ParseComments|parser.PackageClauseOnly)
if err == nil {
hasPkgFiles = true
@@ -126,7 +119,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
for _, d := range list {
if isPkgDir(d) {
name := d.Name()
- dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
+ dd := b.newDirTree(fset, pathpkg.Join(path, name), name, depth+1)
if dd != nil {
dirs[i] = dd
i++
@@ -170,7 +163,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// are assumed to contain package files even if their contents are not known
// (i.e., in this case the tree may contain directories w/o any package files).
//
-func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
+func newDirectory(root string, maxDepth int) *Directory {
// The root could be a symbolic link so use Stat not Lstat.
d, err := fs.Stat(root)
// If we fail here, report detailed error messages; otherwise
@@ -186,7 +179,7 @@ func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Dire
if maxDepth < 0 {
maxDepth = 1e6 // "infinity"
}
- b := treeBuilder{pathFilter, maxDepth}
+ b := treeBuilder{maxDepth}
// the file set provided is only for local parsing, no position
// information escapes and thus we don't need to save the set
return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
@@ -235,10 +228,20 @@ func (dir *Directory) lookupLocal(name string) *Directory {
return nil
}
+func splitPath(p string) []string {
+ if strings.HasPrefix(p, "/") {
+ p = p[1:]
+ }
+ if p == "" {
+ return nil
+ }
+ return strings.Split(p, "/")
+}
+
// lookup looks for the *Directory for a given path, relative to dir.
func (dir *Directory) lookup(path string) *Directory {
- d := strings.Split(dir.Path, string(filepath.Separator))
- p := strings.Split(path, string(filepath.Separator))
+ d := splitPath(dir.Path)
+ p := splitPath(path)
i := 0
for i < len(d) {
if i >= len(p) || d[i] != p[i] {
@@ -311,8 +314,8 @@ func (root *Directory) listing(skipRoot bool) *DirList {
if strings.HasPrefix(d.Path, root.Path) {
path = d.Path[len(root.Path):]
}
- // remove trailing separator if any - path must be relative
- if len(path) > 0 && path[0] == filepath.Separator {
+ // remove leading separator if any - path must be relative
+ if len(path) > 0 && path[0] == '/' {
path = path[1:]
}
p.Path = path
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 15c393cd7..39ecc6e63 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -25,7 +25,7 @@ In command-line mode, the -q flag enables search queries against a godoc running
as a webserver. If no explicit server address is specified with the -server flag,
godoc first tries localhost:6060 and then http://golang.org.
- godoc -q Reader Writer
+ godoc -q Reader
godoc -q math.Sin
godoc -server=:6060 -q sin
@@ -77,27 +77,22 @@ The flags are:
HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
-server=addr
webserver address for command line searches
- -sync="command"
- if this and -sync_minutes are set, run the argument as a
- command every sync_minutes; it is intended to update the
- repository holding the source files.
- -sync_minutes=0
- sync interval in minutes; sync is disabled if <= 0
-templates=""
directory containing alternate template files; if set,
the directory may provide alternative template files
for the files in $GOROOT/lib/godoc
- -filter=""
- filter file containing permitted package directory paths
- -filter_minutes=0
- filter file update interval in minutes; update is disabled if <= 0
+ -url=path
+ print to standard output the data that would be served by
+ an HTTP request for path
-zip=""
zip file providing the file system to serve; disabled if empty
-The -path flag accepts a list of colon-separated paths; unrooted paths are relative
-to the current working directory. Each path is considered as an additional root for
-packages in order of appearance. The last (absolute) path element is the prefix for
-the package path. For instance, given the flag value:
+By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
+Additional directories may be specified via the -path flag which accepts a list
+of colon-separated paths; unrooted paths are relative to the current working
+directory. Each path is considered as an additional root for packages in order
+of appearance. The last (absolute) path element is the prefix for the package
+path. For instance, given the flag value:
path=".:/home/bar:/public"
@@ -108,23 +103,8 @@ as follows:
/home/bar/x -> bar/x
/public/x -> public/x
-Paths provided via -path may point to very large file systems that contain
-non-Go files. Creating the subtree of directories with Go packages may take
-a long amount of time. A file containing newline-separated directory paths
-may be provided with the -filter flag; if it exists, only directories
-on those paths are considered. If -filter_minutes is set, the filter_file is
-updated regularly by walking the entire directory tree.
-
When godoc runs as a web server and -index is set, a search index is maintained.
-The index is created at startup and is automatically updated every time the
--sync command terminates with exit status 0, indicating that files have changed.
-
-If the sync exit status is 1, godoc assumes that it succeeded without errors
-but that no files changed; the index is not updated in this case.
-
-In all other cases, sync is assumed to have failed and godoc backs off running
-sync exponentially (up to 1 day). As soon as sync succeeds again (exit status 0
-or 1), the normal sync rhythm is re-established.
+The index is created at startup.
The index contains both identifier and full text search information (searchable
via regular expressions). The maximum number of full text search results shown
@@ -158,6 +138,7 @@ one may run godoc as follows:
godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
See "Godoc: documenting Go code" for how to write good comments for godoc:
-http://blog.golang.org/2011/03/godoc-documenting-go-code.html
+http://golang.org/doc/articles/godoc_documenting_go_code.html
+
*/
package documentation
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
index 4e48c9e68..09d7b2463 100644
--- a/src/cmd/godoc/filesystem.go
+++ b/src/cmd/godoc/filesystem.go
@@ -12,16 +12,56 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/http"
"os"
+ pathpkg "path"
+ "path/filepath"
+ "sort"
+ "strings"
+ "time"
)
+// fs is the file system that godoc reads from and serves.
+// It is a virtual file system that operates on slash-separated paths,
+// and its root corresponds to the Go distribution root: /src/pkg
+// holds the source tree, and so on. This means that the URLs served by
+// the godoc server are the same as the paths in the virtual file
+// system, which helps keep things simple.
+//
+// New file trees - implementations of FileSystem - can be added to
+// the virtual file system using nameSpace's Bind method.
+// The usual setup is to bind OS(runtime.GOROOT) to the root
+// of the name space and then bind any GOPATH/src directories
+// on top of /src/pkg, so that all sources are in /src/pkg.
+//
+// For more about name spaces, see the nameSpace type's
+// documentation below.
+//
+// The use of this virtual file system means that most code processing
+// paths can assume they are slash-separated and should be using
+// package path (often imported as pathpkg) to manipulate them,
+// even on Windows.
+//
+var fs = nameSpace{} // the underlying file system for godoc
+
+// Setting debugNS = true will enable debugging prints about
+// name space translations.
+const debugNS = false
+
// The FileSystem interface specifies the methods godoc is using
// to access the file system for which it serves documentation.
type FileSystem interface {
- Open(path string) (io.ReadCloser, error)
+ Open(path string) (readSeekCloser, error)
Lstat(path string) (os.FileInfo, error)
Stat(path string) (os.FileInfo, error)
ReadDir(path string) ([]os.FileInfo, error)
+ String() string
+}
+
+type readSeekCloser interface {
+ io.Reader
+ io.Seeker
+ io.Closer
}
// ReadFile reads the file named by path from fs and returns the contents.
@@ -34,16 +74,31 @@ func ReadFile(fs FileSystem, path string) ([]byte, error) {
return ioutil.ReadAll(rc)
}
-// ----------------------------------------------------------------------------
-// OS-specific FileSystem implementation
+// OS returns an implementation of FileSystem reading from the
+// tree rooted at root. Recording a root is convenient everywhere
+// but necessary on Windows, because the slash-separated path
+// passed to Open has no way to specify a drive letter. Using a root
+// lets code refer to OS(`c:\`), OS(`d:\`) and so on.
+func OS(root string) FileSystem {
+ return osFS(root)
+}
+
+type osFS string
-var OS FileSystem = osFS{}
+func (root osFS) String() string { return "os(" + string(root) + ")" }
-// osFS is the OS-specific implementation of FileSystem
-type osFS struct{}
+func (root osFS) resolve(path string) string {
+ // Clean the path so that it cannot possibly begin with ../.
+ // If it did, the result of filepath.Join would be outside the
+ // tree rooted at root. We probably won't ever see a path
+ // with .. in it, but be safe anyway.
+ path = pathpkg.Clean("/" + path)
-func (osFS) Open(path string) (io.ReadCloser, error) {
- f, err := os.Open(path)
+ return filepath.Join(string(root), path)
+}
+
+func (root osFS) Open(path string) (readSeekCloser, error) {
+ f, err := os.Open(root.resolve(path))
if err != nil {
return nil, err
}
@@ -57,14 +112,453 @@ func (osFS) Open(path string) (io.ReadCloser, error) {
return f, nil
}
-func (osFS) Lstat(path string) (os.FileInfo, error) {
- return os.Lstat(path)
+func (root osFS) Lstat(path string) (os.FileInfo, error) {
+ return os.Lstat(root.resolve(path))
+}
+
+func (root osFS) Stat(path string) (os.FileInfo, error) {
+ return os.Stat(root.resolve(path))
+}
+
+func (root osFS) ReadDir(path string) ([]os.FileInfo, error) {
+ return ioutil.ReadDir(root.resolve(path)) // is sorted
+}
+
+// hasPathPrefix returns true if x == y or x == y + "/" + more
+func hasPathPrefix(x, y string) bool {
+ return x == y || strings.HasPrefix(x, y) && (strings.HasSuffix(y, "/") || strings.HasPrefix(x[len(y):], "/"))
+}
+
+// A nameSpace is a file system made up of other file systems
+// mounted at specific locations in the name space.
+//
+// The representation is a map from mount point locations
+// to the list of file systems mounted at that location. A traditional
+// Unix mount table would use a single file system per mount point,
+// but we want to be able to mount multiple file systems on a single
+// mount point and have the system behave as if the union of those
+// file systems were present at the mount point.
+// For example, if the OS file system has a Go installation in
+// c:\Go and additional Go path trees in d:\Work1 and d:\Work2, then
+// this name space creates the view we want for the godoc server:
+//
+// nameSpace{
+// "/": {
+// {old: "/", fs: OS(`c:\Go`), new: "/"},
+// },
+// "/src/pkg": {
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+// },
+// }
+//
+// This is created by executing:
+//
+// ns := nameSpace{}
+// ns.Bind("/", OS(`c:\Go`), "/", bindReplace)
+// ns.Bind("/src/pkg", OS(`d:\Work1`), "/src", bindAfter)
+// ns.Bind("/src/pkg", OS(`d:\Work2`), "/src", bindAfter)
+//
+// A particular mount point entry is a triple (old, fs, new), meaning that to
+// operate on a path beginning with old, replace that prefix (old) with new
+// and then pass that path to the FileSystem implementation fs.
+//
+// Given this name space, a ReadDir of /src/pkg/code will check each prefix
+// of the path for a mount point (first /src/pkg/code, then /src/pkg, then /src,
+// then /), stopping when it finds one. For the above example, /src/pkg/code
+// will find the mount point at /src/pkg:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// ReadDir will when execute these three calls and merge the results:
+//
+// OS(`c:\Go`).ReadDir("/src/pkg/code")
+// OS(`d:\Work1').ReadDir("/src/code")
+// OS(`d:\Work2').ReadDir("/src/code")
+//
+// Note that the "/src/pkg" in "/src/pkg/code" has been replaced by
+// just "/src" in the final two calls.
+//
+// OS is itself an implementation of a file system: it implements
+// OS(`c:\Go`).ReadDir("/src/pkg/code") as ioutil.ReadDir(`c:\Go\src\pkg\code`).
+//
+// Because the new path is evaluated by fs (here OS(root)), another way
+// to read the mount table is to mentally combine fs+new, so that this table:
+//
+// {old: "/src/pkg", fs: OS(`c:\Go`), new: "/src/pkg"},
+// {old: "/src/pkg", fs: OS(`d:\Work1`), new: "/src"},
+// {old: "/src/pkg", fs: OS(`d:\Work2`), new: "/src"},
+//
+// reads as:
+//
+// "/src/pkg" -> c:\Go\src\pkg
+// "/src/pkg" -> d:\Work1\src
+// "/src/pkg" -> d:\Work2\src
+//
+// An invariant (a redundancy) of the name space representation is that
+// ns[mtpt][i].old is always equal to mtpt (in the example, ns["/src/pkg"]'s
+// mount table entries always have old == "/src/pkg"). The 'old' field is
+// useful to callers, because they receive just a []mountedFS and not any
+// other indication of which mount point was found.
+//
+type nameSpace map[string][]mountedFS
+
+// A mountedFS handles requests for path by replacing
+// a prefix 'old' with 'new' and then calling the fs methods.
+type mountedFS struct {
+ old string
+ fs FileSystem
+ new string
+}
+
+// translate translates path for use in m, replacing old with new.
+//
+// mountedFS{"/src/pkg", fs, "/src"}.translate("/src/pkg/code") == "/src/code".
+func (m mountedFS) translate(path string) string {
+ path = pathpkg.Clean("/" + path)
+ if !hasPathPrefix(path, m.old) {
+ panic("translate " + path + " but old=" + m.old)
+ }
+ return pathpkg.Join(m.new, path[len(m.old):])
+}
+
+func (nameSpace) String() string {
+ return "ns"
+}
+
+// Fprint writes a text representation of the name space to w.
+func (ns nameSpace) Fprint(w io.Writer) {
+ fmt.Fprint(w, "name space {\n")
+ var all []string
+ for mtpt := range ns {
+ all = append(all, mtpt)
+ }
+ sort.Strings(all)
+ for _, mtpt := range all {
+ fmt.Fprintf(w, "\t%s:\n", mtpt)
+ for _, m := range ns[mtpt] {
+ fmt.Fprintf(w, "\t\t%s %s\n", m.fs, m.new)
+ }
+ }
+ fmt.Fprint(w, "}\n")
+}
+
+// clean returns a cleaned, rooted path for evaluation.
+// It canonicalizes the path so that we can use string operations
+// to analyze it.
+func (nameSpace) clean(path string) string {
+ return pathpkg.Clean("/" + path)
+}
+
+// Bind causes references to old to redirect to the path new in newfs.
+// If mode is bindReplace, old redirections are discarded.
+// If mode is bindBefore, this redirection takes priority over existing ones,
+// but earlier ones are still consulted for paths that do not exist in newfs.
+// If mode is bindAfter, this redirection happens only after existing ones
+// have been tried and failed.
+
+const (
+ bindReplace = iota
+ bindBefore
+ bindAfter
+)
+
+func (ns nameSpace) Bind(old string, newfs FileSystem, new string, mode int) {
+ old = ns.clean(old)
+ new = ns.clean(new)
+ m := mountedFS{old, newfs, new}
+ var mtpt []mountedFS
+ switch mode {
+ case bindReplace:
+ mtpt = append(mtpt, m)
+ case bindAfter:
+ mtpt = append(mtpt, ns.resolve(old)...)
+ mtpt = append(mtpt, m)
+ case bindBefore:
+ mtpt = append(mtpt, m)
+ mtpt = append(mtpt, ns.resolve(old)...)
+ }
+
+ // Extend m.old, m.new in inherited mount point entries.
+ for i := range mtpt {
+ m := &mtpt[i]
+ if m.old != old {
+ if !hasPathPrefix(old, m.old) {
+ // This should not happen. If it does, panic so
+ // that we can see the call trace that led to it.
+ panic(fmt.Sprintf("invalid Bind: old=%q m={%q, %s, %q}", old, m.old, m.fs.String(), m.new))
+ }
+ suffix := old[len(m.old):]
+ m.old = pathpkg.Join(m.old, suffix)
+ m.new = pathpkg.Join(m.new, suffix)
+ }
+ }
+
+ ns[old] = mtpt
+}
+
+// resolve resolves a path to the list of mountedFS to use for path.
+func (ns nameSpace) resolve(path string) []mountedFS {
+ path = ns.clean(path)
+ for {
+ if m := ns[path]; m != nil {
+ if debugNS {
+ fmt.Printf("resolve %s: %v\n", path, m)
+ }
+ return m
+ }
+ if path == "/" {
+ break
+ }
+ path = pathpkg.Dir(path)
+ }
+ return nil
+}
+
+// Open implements the FileSystem Open method.
+func (ns nameSpace) Open(path string) (readSeekCloser, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ if debugNS {
+ fmt.Printf("tx %s: %v\n", path, m.translate(path))
+ }
+ r, err1 := m.fs.Open(m.translate(path))
+ if err1 == nil {
+ return r, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+// stat implements the FileSystem Stat and Lstat methods.
+func (ns nameSpace) stat(path string, f func(FileSystem, string) (os.FileInfo, error)) (os.FileInfo, error) {
+ var err error
+ for _, m := range ns.resolve(path) {
+ fi, err1 := f(m.fs, m.translate(path))
+ if err1 == nil {
+ return fi, nil
+ }
+ if err == nil {
+ err = err1
+ }
+ }
+ if err == nil {
+ err = &os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist}
+ }
+ return nil, err
+}
+
+func (ns nameSpace) Stat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Stat)
+}
+
+func (ns nameSpace) Lstat(path string) (os.FileInfo, error) {
+ return ns.stat(path, FileSystem.Lstat)
+}
+
+// dirInfo is a trivial implementation of os.FileInfo for a directory.
+type dirInfo string
+
+func (d dirInfo) Name() string { return string(d) }
+func (d dirInfo) Size() int64 { return 0 }
+func (d dirInfo) Mode() os.FileMode { return os.ModeDir | 0555 }
+func (d dirInfo) ModTime() time.Time { return startTime }
+func (d dirInfo) IsDir() bool { return true }
+func (d dirInfo) Sys() interface{} { return nil }
+
+var startTime = time.Now()
+
+// ReadDir implements the FileSystem ReadDir method. It's where most of the magic is.
+// (The rest is in resolve.)
+//
+// Logically, ReadDir must return the union of all the directories that are named
+// by path. In order to avoid misinterpreting Go packages, of all the directories
+// that contain Go source code, we only include the files from the first,
+// but we include subdirectories from all.
+//
+// ReadDir must also return directory entries needed to reach mount points.
+// If the name space looks like the example in the type nameSpace comment,
+// but c:\Go does not have a src/pkg subdirectory, we still want to be able
+// to find that subdirectory, because we've mounted d:\Work1 and d:\Work2
+// there. So if we don't see "src" in the directory listing for c:\Go, we add an
+// entry for it before returning.
+//
+func (ns nameSpace) ReadDir(path string) ([]os.FileInfo, error) {
+ path = ns.clean(path)
+
+ var (
+ haveGo = false
+ haveName = map[string]bool{}
+ all []os.FileInfo
+ err error
+ first []os.FileInfo
+ )
+
+ for _, m := range ns.resolve(path) {
+ dir, err1 := m.fs.ReadDir(m.translate(path))
+ if err1 != nil {
+ if err == nil {
+ err = err1
+ }
+ continue
+ }
+
+ if dir == nil {
+ dir = []os.FileInfo{}
+ }
+
+ if first == nil {
+ first = dir
+ }
+
+ // If we don't yet have Go files in 'all' and this directory
+ // has some, add all the files from this directory.
+ // Otherwise, only add subdirectories.
+ useFiles := false
+ if !haveGo {
+ for _, d := range dir {
+ if strings.HasSuffix(d.Name(), ".go") {
+ useFiles = true
+ haveGo = true
+ break
+ }
+ }
+ }
+
+ for _, d := range dir {
+ name := d.Name()
+ if (d.IsDir() || useFiles) && !haveName[name] {
+ haveName[name] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // We didn't find any directories containing Go files.
+ // If some directory returned successfully, use that.
+ if !haveGo {
+ for _, d := range first {
+ if !haveName[d.Name()] {
+ haveName[d.Name()] = true
+ all = append(all, d)
+ }
+ }
+ }
+
+ // Built union. Add any missing directories needed to reach mount points.
+ for old := range ns {
+ if hasPathPrefix(old, path) && old != path {
+ // Find next element after path in old.
+ elem := old[len(path):]
+ if strings.HasPrefix(elem, "/") {
+ elem = elem[1:]
+ }
+ if i := strings.Index(elem, "/"); i >= 0 {
+ elem = elem[:i]
+ }
+ if !haveName[elem] {
+ haveName[elem] = true
+ all = append(all, dirInfo(elem))
+ }
+ }
+ }
+
+ if len(all) == 0 {
+ return nil, err
+ }
+
+ sort.Sort(byName(all))
+ return all, nil
+}
+
+// byName implements sort.Interface.
+type byName []os.FileInfo
+
+func (f byName) Len() int { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
+
+// An httpFS implements http.FileSystem using a FileSystem.
+type httpFS struct {
+ fs FileSystem
+}
+
+func (h *httpFS) Open(name string) (http.File, error) {
+ fi, err := h.fs.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if fi.IsDir() {
+ return &httpDir{h.fs, name, nil}, nil
+ }
+ f, err := h.fs.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ return &httpFile{h.fs, f, name}, nil
+}
+
+// httpDir implements http.File for a directory in a FileSystem.
+type httpDir struct {
+ fs FileSystem
+ name string
+ pending []os.FileInfo
+}
+
+func (h *httpDir) Close() error { return nil }
+func (h *httpDir) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpDir) Read([]byte) (int, error) {
+ return 0, fmt.Errorf("cannot Read from directory %s", h.name)
+}
+
+func (h *httpDir) Seek(offset int64, whence int) (int64, error) {
+ if offset == 0 && whence == 0 {
+ h.pending = nil
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in directory %s", h.name)
+}
+
+func (h *httpDir) Readdir(count int) ([]os.FileInfo, error) {
+ if h.pending == nil {
+ d, err := h.fs.ReadDir(h.name)
+ if err != nil {
+ return nil, err
+ }
+ if d == nil {
+ d = []os.FileInfo{} // not nil
+ }
+ h.pending = d
+ }
+
+ if len(h.pending) == 0 && count > 0 {
+ return nil, io.EOF
+ }
+ if count <= 0 || count > len(h.pending) {
+ count = len(h.pending)
+ }
+ d := h.pending[:count]
+ h.pending = h.pending[count:]
+ return d, nil
}
-func (osFS) Stat(path string) (os.FileInfo, error) {
- return os.Stat(path)
+// httpFile implements http.File for a file (not directory) in a FileSystem.
+type httpFile struct {
+ fs FileSystem
+ readSeekCloser
+ name string
}
-func (osFS) ReadDir(path string) ([]os.FileInfo, error) {
- return ioutil.ReadDir(path) // is sorted
+func (h *httpFile) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
+func (h *httpFile) Readdir(int) ([]os.FileInfo, error) {
+ return nil, fmt.Errorf("cannot Readdir from file %s", h.name)
}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index e5f7a73d4..26814d2fa 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -20,7 +20,7 @@ import (
"net/http"
"net/url"
"os"
- "path"
+ pathpkg "path"
"path/filepath"
"regexp"
"runtime"
@@ -55,12 +55,9 @@ var (
// file system roots
// TODO(gri) consider the invariant that goroot always end in '/'
- goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
- testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
- pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
- filter = flag.String("filter", "", "filter file containing permitted package directory paths")
- filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
- filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
// layout control
tabwidth = flag.Int("tabwidth", 4, "tab width")
@@ -70,44 +67,42 @@ var (
// search index
indexEnabled = flag.Bool("index", false, "enable search index")
indexFiles = flag.String("index_files", "", "glob pattern specifying index files;"+
- "if not empty, the index is read from these files in sorted order")
+ "if not empty, the index is read from these files in sorted order")
maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
- // file system mapping
- fs FileSystem // the underlying file system for godoc
- fsHttp http.FileSystem // the underlying file system for http
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
- pathFilter RWValue // filter used when building fsMap directory trees
- fsModified RWValue // timestamp of last call to invalidateIndex
- docMetadata RWValue // mapping from paths to *Metadata
+ // file system information
+ fsTree RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now)
+ fsModified RWValue // timestamp of last call to invalidateIndex
+ docMetadata RWValue // mapping from paths to *Metadata
// http handlers
fileServer http.Handler // default file server
- cmdHandler httpHandler
- pkgHandler httpHandler
+ cmdHandler docServer
+ pkgHandler docServer
)
func initHandlers() {
- paths := filepath.SplitList(*pkgPath)
- gorootSrc := filepath.Join(build.Default.GOROOT, "src", "pkg")
- for _, p := range build.Default.SrcDirs() {
- if p != gorootSrc {
- paths = append(paths, p)
+ // Add named directories in -path argument as
+ // subdirectories of src/pkg.
+ for _, p := range filepath.SplitList(*pkgPath) {
+ _, elem := filepath.Split(p)
+ if elem == "" {
+ log.Fatalf("invalid -path argument: %q has no final element", p)
}
+ fs.Bind("/src/pkg/"+elem, OS(p), "/", bindReplace)
}
- fsMap.Init(paths)
- fileServer = http.FileServer(fsHttp)
- cmdHandler = httpHandler{"/cmd/", filepath.Join(*goroot, "src", "cmd"), false}
- pkgHandler = httpHandler{"/pkg/", filepath.Join(*goroot, "src", "pkg"), true}
+ fileServer = http.FileServer(&httpFS{fs})
+ cmdHandler = docServer{"/cmd/", "/src/cmd", false}
+ pkgHandler = docServer{"/pkg/", "/src/pkg", true}
}
func registerPublicHandlers(mux *http.ServeMux) {
mux.Handle(cmdHandler.pattern, &cmdHandler)
mux.Handle(pkgHandler.pattern, &pkgHandler)
mux.HandleFunc("/doc/codewalk/", codewalk)
+ mux.Handle("/doc/play/", fileServer)
mux.HandleFunc("/search", search)
mux.Handle("/robots.txt", fileServer)
mux.HandleFunc("/opensearch.xml", serveSearchDesc)
@@ -115,7 +110,7 @@ func registerPublicHandlers(mux *http.ServeMux) {
}
func initFSTree() {
- dir := newDirectory(filepath.Join(*goroot, *testDir), nil, -1)
+ dir := newDirectory(pathpkg.Join("/", *testDir), -1)
if dir == nil {
log.Println("Warning: FSTree is nil")
return
@@ -125,177 +120,6 @@ func initFSTree() {
}
// ----------------------------------------------------------------------------
-// Directory filters
-
-// isParentOf returns true if p is a parent of (or the same as) q
-// where p and q are directory paths.
-func isParentOf(p, q string) bool {
- n := len(p)
- return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
-}
-
-func setPathFilter(list []string) {
- if len(list) == 0 {
- pathFilter.set(nil)
- return
- }
-
- // len(list) > 0
- pathFilter.set(func(path string) bool {
- // list is sorted in increasing order and for each path all its children are removed
- i := sort.Search(len(list), func(i int) bool { return list[i] > path })
- // Now we have list[i-1] <= path < list[i].
- // Path may be a child of list[i-1] or a parent of list[i].
- return i > 0 && isParentOf(list[i-1], path) || i < len(list) && isParentOf(path, list[i])
- })
-}
-
-func getPathFilter() func(string) bool {
- f, _ := pathFilter.get()
- if f != nil {
- return f.(func(string) bool)
- }
- return nil
-}
-
-// readDirList reads a file containing a newline-separated list
-// of directory paths and returns the list of paths.
-func readDirList(filename string) ([]string, error) {
- contents, err := ReadFile(fs, filename)
- if err != nil {
- return nil, err
- }
- // create a sorted list of valid directory names
- filter := func(path string) bool {
- d, e := fs.Lstat(path)
- if e != nil && err == nil {
- // remember first error and return it from readDirList
- // so we have at least some information if things go bad
- err = e
- }
- return e == nil && isPkgDir(d)
- }
- list := canonicalizePaths(strings.Split(string(contents), "\n"), filter)
- // for each parent path, remove all its children q
- // (requirement for binary search to work when filtering)
- i := 0
- for _, q := range list {
- if i == 0 || !isParentOf(list[i-1], q) {
- list[i] = q
- i++
- }
- }
- return list[0:i], err
-}
-
-// updateMappedDirs computes the directory tree for
-// each user-defined file system mapping. If a filter
-// is provided, it is used to filter directories.
-//
-func updateMappedDirs(filter func(string) bool) {
- if !fsMap.IsEmpty() {
- fsMap.Iterate(func(path string, value *RWValue) bool {
- value.set(newDirectory(path, filter, -1))
- return true
- })
- invalidateIndex()
- }
-}
-
-func updateFilterFile() {
- updateMappedDirs(nil) // no filter for accuracy
-
- // collect directory tree leaf node paths
- var buf bytes.Buffer
- fsMap.Iterate(func(_ string, value *RWValue) bool {
- v, _ := value.get()
- if v != nil && v.(*Directory) != nil {
- v.(*Directory).writeLeafs(&buf)
- }
- return true
- })
-
- // update filter file
- if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
- log.Printf("writeFileAtomically(%s): %s", *filter, err)
- filterDelay.backoff(24 * time.Hour) // back off exponentially, but try at least once a day
- } else {
- filterDelay.set(*filterMin) // revert to regular filter update schedule
- }
-}
-
-func initDirTrees() {
- // setup initial path filter
- if *filter != "" {
- list, err := readDirList(*filter)
- if err != nil {
- log.Printf("readDirList(%s): %s", *filter, err)
- }
- if *verbose || len(list) == 0 {
- log.Printf("found %d directory paths in file %s", len(list), *filter)
- }
- setPathFilter(list)
- }
-
- go updateMappedDirs(getPathFilter()) // use filter for speed
-
- // start filter update goroutine, if enabled.
- if *filter != "" && *filterMin > 0 {
- filterDelay.set(time.Duration(*filterMin) * time.Minute) // initial filter update delay
- go func() {
- for {
- if *verbose {
- log.Printf("start update of %s", *filter)
- }
- updateFilterFile()
- delay, _ := filterDelay.get()
- dt := delay.(time.Duration)
- if *verbose {
- log.Printf("next filter update in %s", dt)
- }
- time.Sleep(dt)
- }
- }()
- }
-}
-
-// ----------------------------------------------------------------------------
-// Path mapping
-
-// Absolute paths are file system paths (backslash-separated on Windows),
-// but relative paths are always slash-separated.
-
-func absolutePath(relpath, defaultRoot string) string {
- abspath := fsMap.ToAbsolute(relpath)
- if abspath == "" {
- // no user-defined mapping found; use default mapping
- abspath = filepath.Join(defaultRoot, filepath.FromSlash(relpath))
- }
- return abspath
-}
-
-func relativeURL(abspath string) string {
- relpath := fsMap.ToRelative(abspath)
- if relpath == "" {
- // prefix must end in a path separator
- prefix := *goroot
- if len(prefix) > 0 && prefix[len(prefix)-1] != filepath.Separator {
- prefix += string(filepath.Separator)
- }
- if strings.HasPrefix(abspath, prefix) {
- // no user-defined mapping found; use default mapping
- relpath = filepath.ToSlash(abspath[len(prefix):])
- }
- }
- // Only if path is an invalid absolute path is relpath == ""
- // at this point. This should never happen since absolute paths
- // are only created via godoc for files that do exist. However,
- // it is ok to return ""; it will simply provide a link to the
- // top of the pkg or src directories.
- return relpath
-}
-
-// ----------------------------------------------------------------------------
// Tab conversion
var spaces = []byte(" ") // 32 spaces seems like a good number
@@ -391,7 +215,7 @@ func writeNode(w io.Writer, fset *token.FileSet, x interface{}) {
}
func filenameFunc(path string) string {
- _, localname := filepath.Split(path)
+ _, localname := pathpkg.Split(path)
return localname
}
@@ -581,7 +405,7 @@ func splitExampleName(s string) (name, suffix string) {
}
func pkgLinkFunc(path string) string {
- relpath := relativeURL(path)
+ relpath := path[1:]
// because of the irregular mapping under goroot
// we need to correct certain relative paths
if strings.HasPrefix(relpath, "src/pkg/") {
@@ -597,7 +421,7 @@ func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
if p := node.Pos(); p.IsValid() {
pos := fset.Position(p)
- relpath = relativeURL(pos.Filename)
+ relpath = pos.Filename
line = pos.Line
low = pos.Offset
}
@@ -626,6 +450,10 @@ func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
return buf.String()
}
+func srcLinkFunc(s string) string {
+ return pathpkg.Clean("/" + s)
+}
+
// fmap describes the template functions installed with all godoc templates.
// Convention: template function names ending in "_html" or "_url" produce
// HTML- or URL-escaped strings; all other function results may
@@ -652,7 +480,7 @@ var fmap = template.FuncMap{
// support for URL attributes
"pkgLink": pkgLinkFunc,
- "srcLink": relativeURL,
+ "srcLink": srcLinkFunc,
"posLink_url": posLink_urlFunc,
// formatting of Examples
@@ -662,10 +490,10 @@ var fmap = template.FuncMap{
}
func readTemplate(name string) *template.Template {
- path := filepath.Join(*goroot, "lib", "godoc", name)
+ path := "lib/godoc/" + name
if *templateDir != "" {
defaultpath := path
- path = filepath.Join(*templateDir, name)
+ path = pathpkg.Join(*templateDir, name)
if _, err := fs.Stat(path); err != nil {
log.Print("readTemplate:", err)
path = defaultpath
@@ -718,20 +546,23 @@ func readTemplates() {
// ----------------------------------------------------------------------------
// Generic HTML wrapper
-func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
+func servePage(w http.ResponseWriter, tabtitle, title, subtitle, query string, content []byte) {
+ if tabtitle == "" {
+ tabtitle = title
+ }
d := struct {
+ Tabtitle string
Title string
Subtitle string
- PkgRoots []string
SearchBox bool
Query string
Version string
Menu []byte
Content []byte
}{
+ tabtitle,
title,
subtitle,
- fsMap.PrefixList(),
*indexEnabled,
query,
runtime.Version(),
@@ -780,6 +611,23 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
log.Printf("decoding metadata %s: %v", relpath, err)
}
+ // evaluate as template if indicated
+ if meta.Template {
+ tmpl, err := template.New("main").Funcs(templateFuncs).Parse(string(src))
+ if err != nil {
+ log.Printf("parsing template %s: %v", relpath, err)
+ serveError(w, r, relpath, err)
+ return
+ }
+ var buf bytes.Buffer
+ if err := tmpl.Execute(&buf, nil); err != nil {
+ log.Printf("executing template %s: %v", relpath, err)
+ serveError(w, r, relpath, err)
+ return
+ }
+ src = buf.Bytes()
+ }
+
// if it's the language spec, add tags to EBNF productions
if strings.HasSuffix(abspath, "go_spec.html") {
var buf bytes.Buffer
@@ -787,7 +635,7 @@ func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath strin
src = buf.Bytes()
}
- servePage(w, meta.Title, meta.Subtitle, "", src)
+ servePage(w, "", meta.Title, meta.Subtitle, "", src)
}
func applyTemplate(t *template.Template, name string, data interface{}) []byte {
@@ -799,7 +647,7 @@ func applyTemplate(t *template.Template, name string, data interface{}) []byte {
}
func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
- canonical := path.Clean(r.URL.Path)
+ canonical := pathpkg.Clean(r.URL.Path)
if !strings.HasSuffix("/", canonical) {
canonical += "/"
}
@@ -820,10 +668,10 @@ func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, tit
var buf bytes.Buffer
buf.WriteString("<pre>")
- FormatText(&buf, src, 1, filepath.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+ FormatText(&buf, src, 1, pathpkg.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
buf.WriteString("</pre>")
- servePage(w, title+" "+relpath, "", "", buf.Bytes())
+ servePage(w, relpath, title+" "+relpath, "", "", buf.Bytes())
}
func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
@@ -833,13 +681,12 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str
list, err := fs.ReadDir(abspath)
if err != nil {
- log.Printf("ReadDir: %s", err)
serveError(w, r, relpath, err)
return
}
contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
- servePage(w, "Directory "+relpath, "", "", contents)
+ servePage(w, relpath, "Directory "+relpath, "", "", contents)
}
func serveFile(w http.ResponseWriter, r *http.Request) {
@@ -856,10 +703,10 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
relpath = m.filePath
}
+ abspath := relpath
relpath = relpath[1:] // strip leading slash
- abspath := absolutePath(relpath, *goroot)
- switch path.Ext(relpath) {
+ switch pathpkg.Ext(relpath) {
case ".html":
if strings.HasSuffix(relpath, "/index.html") {
// We'll show index.html for the directory.
@@ -886,8 +733,8 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
if redirect(w, r) {
return
}
- if index := filepath.Join(abspath, "index.html"); isTextFile(index) {
- serveHTMLDoc(w, r, index, relativeURL(index))
+ if index := pathpkg.Join(abspath, "index.html"); isTextFile(index) {
+ serveHTMLDoc(w, r, index, index)
return
}
serveDirectory(w, r, abspath, relpath)
@@ -992,7 +839,7 @@ func (info *PageInfo) IsEmpty() bool {
return info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil
}
-type httpHandler struct {
+type docServer struct {
pattern string // url pattern; e.g. "/pkg/"
fsRoot string // file system root to which the pattern is mapped
isPkg bool // true if this handler serves real package documentation (as opposed to command documentation)
@@ -1029,7 +876,7 @@ func inList(name string, list []string) bool {
// directories, PageInfo.Dirs is nil. If a directory read error occurred,
// PageInfo.Err is set to the respective error but the error is not logged.
//
-func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
+func (h *docServer) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
var pkgFiles []string
// If we're showing the default package, restrict to the ones
@@ -1043,7 +890,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// to choose, set ctxt.GOOS and ctxt.GOARCH before
// calling ctxt.ScanDir.
ctxt := build.Default
- ctxt.IsAbsPath = path.IsAbs
+ ctxt.IsAbsPath = pathpkg.IsAbs
ctxt.ReadDir = fsReadDir
ctxt.OpenFile = fsOpenFile
dir, err := ctxt.ImportDir(abspath, 0)
@@ -1091,13 +938,13 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// the package with dirname, and the 3rd choice is a package
// that is not called "main" if there is exactly one such
// package. Otherwise, don't select a package.
- dirpath, dirname := filepath.Split(abspath)
+ dirpath, dirname := pathpkg.Split(abspath)
// If the dirname is "go" we might be in a sub-directory for
// .go files - use the outer directory name instead for better
// results.
if dirname == "go" {
- _, dirname = filepath.Split(filepath.Clean(dirpath))
+ _, dirname = pathpkg.Split(pathpkg.Clean(dirpath))
}
var choice3 *ast.Package
@@ -1161,7 +1008,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
if mode&allMethods != 0 {
m |= doc.AllMethods
}
- pdoc = doc.New(pkg, path.Clean(relpath), m) // no trailing '/' in importpath
+ pdoc = doc.New(pkg, pathpkg.Clean(relpath), m) // no trailing '/' in importpath
} else {
// show source code
// TODO(gri) Consider eliminating export filtering in this mode,
@@ -1184,34 +1031,11 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
timestamp = ts
}
if dir == nil {
- // the path may refer to a user-specified file system mapped
- // via fsMap; lookup that mapping and corresponding RWValue
- // if any
- var v *RWValue
- fsMap.Iterate(func(path string, value *RWValue) bool {
- if isParentOf(path, abspath) {
- // mapping found
- v = value
- return false
- }
- return true
- })
- if v != nil {
- // found a RWValue associated with a user-specified file
- // system; a non-nil RWValue stores a (possibly out-of-date)
- // directory tree for that file system
- if tree, ts := v.get(); tree != nil && tree.(*Directory) != nil {
- dir = tree.(*Directory).lookup(abspath)
- timestamp = ts
- }
- }
- }
- if dir == nil {
// no directory tree present (too early after startup or
// command-line mode); compute one level for this page
// note: cannot use path filter here because in general
// it doesn't contain the fsTree path
- dir = newDirectory(abspath, nil, 1)
+ dir = newDirectory(abspath, 1)
timestamp = time.Now()
}
@@ -1230,13 +1054,13 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
}
}
-func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if redirect(w, r) {
return
}
- relpath := path.Clean(r.URL.Path[len(h.pattern):])
- abspath := absolutePath(relpath, h.fsRoot)
+ relpath := pathpkg.Clean(r.URL.Path[len(h.pattern):])
+ abspath := pathpkg.Join(h.fsRoot, relpath)
mode := getPageInfoMode(r)
if relpath == builtinPkgPath {
mode = noFiltering
@@ -1254,30 +1078,41 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
- var title, subtitle string
+ var tabtitle, title, subtitle string
switch {
case info.PAst != nil:
- title = "Package " + info.PAst.Name.Name
+ tabtitle = info.PAst.Name.Name
+ title = "Package " + tabtitle
case info.PDoc != nil:
- switch {
- case info.IsPkg:
- title = "Package " + info.PDoc.Name
- case info.PDoc.Name == fakePkgName:
+ if info.PDoc.Name == fakePkgName {
// assume that the directory name is the command name
- _, pkgname := path.Split(relpath)
- title = "Command " + pkgname
- default:
- title = "Command " + info.PDoc.Name
+ _, tabtitle = pathpkg.Split(relpath)
+ } else {
+ tabtitle = info.PDoc.Name
+ }
+ if info.IsPkg {
+ title = "Package " + tabtitle
+ } else {
+ title = "Command " + tabtitle
}
default:
- title = "Directory " + relativeURL(info.Dirname)
+ tabtitle = info.Dirname
+ title = "Directory " + tabtitle
if *showTimestamps {
subtitle = "Last update: " + info.DirTime.String()
}
}
+ // special cases for top-level package/command directories
+ switch tabtitle {
+ case "/src/pkg":
+ tabtitle = "Packages"
+ case "/src/cmd":
+ tabtitle = "Commands"
+ }
+
contents := applyTemplate(packageHTML, "packageHTML", info)
- servePage(w, title, subtitle, "", contents)
+ servePage(w, tabtitle, title, subtitle, "", contents)
}
// ----------------------------------------------------------------------------
@@ -1367,7 +1202,7 @@ func search(w http.ResponseWriter, r *http.Request) {
}
contents := applyTemplate(searchHTML, "searchHTML", result)
- servePage(w, title, "", query, contents)
+ servePage(w, query, title, "", query, contents)
}
// ----------------------------------------------------------------------------
@@ -1376,6 +1211,7 @@ func search(w http.ResponseWriter, r *http.Request) {
type Metadata struct {
Title string
Subtitle string
+ Template bool // execute as template
Path string // canonical path for this page
filePath string // filesystem path relative to goroot
}
@@ -1414,7 +1250,7 @@ func updateMetadata() {
return
}
for _, fi := range fis {
- name := filepath.Join(dir, fi.Name())
+ name := pathpkg.Join(dir, fi.Name())
if fi.IsDir() {
scan(name) // recurse
continue
@@ -1434,7 +1270,7 @@ func updateMetadata() {
continue
}
// Store relative filesystem path in Metadata.
- meta.filePath = filepath.Join("/", name[len(*goroot):])
+ meta.filePath = name
if meta.Path == "" {
// If no Path, canonical path is actual path.
meta.Path = meta.filePath
@@ -1444,7 +1280,7 @@ func updateMetadata() {
metadata[meta.filePath] = &meta
}
}
- scan(filepath.Join(*goroot, "doc"))
+ scan("/doc")
docMetadata.set(metadata)
}
@@ -1519,13 +1355,9 @@ func feedDirnames(root *RWValue, c chan<- string) {
// of all the file systems under godoc's observation.
//
func fsDirnames() <-chan string {
- c := make(chan string, 256) // asynchronous for fewer context switches
+ c := make(chan string, 256) // buffered for fewer context switches
go func() {
feedDirnames(&fsTree, c)
- fsMap.Iterate(func(_ string, root *RWValue) bool {
- feedDirnames(root, c)
- return true
- })
close(c)
}()
return c
diff --git a/src/cmd/godoc/httpzip.go b/src/cmd/godoc/httpzip.go
deleted file mode 100644
index 12e99646d..000000000
--- a/src/cmd/godoc/httpzip.go
+++ /dev/null
@@ -1,190 +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.
-
-// This file provides an implementation of the http.FileSystem
-// interface based on the contents of a .zip file.
-//
-// Assumptions:
-//
-// - The file paths stored in the zip file must use a slash ('/') as path
-// separator; and they must be relative (i.e., they must not start with
-// a '/' - this is usually the case if the file was created w/o special
-// options).
-// - The zip file system treats the file paths found in the zip internally
-// like absolute paths w/o a leading '/'; i.e., the paths are considered
-// relative to the root of the file system.
-// - All path arguments to file system methods are considered relative to
-// the root specified with NewHttpZipFS (even if the paths start with a '/').
-
-// TODO(gri) Should define a commonly used FileSystem API that is the same
-// for http and godoc. Then we only need one zip-file based file
-// system implementation.
-
-package main
-
-import (
- "archive/zip"
- "fmt"
- "io"
- "net/http"
- "os"
- "path"
- "sort"
- "strings"
- "time"
-)
-
-type fileInfo struct {
- name string
- mode os.FileMode
- size int64
- mtime time.Time
-}
-
-func (fi *fileInfo) Name() string { return fi.name }
-func (fi *fileInfo) Mode() os.FileMode { return fi.mode }
-func (fi *fileInfo) Size() int64 { return fi.size }
-func (fi *fileInfo) ModTime() time.Time { return fi.mtime }
-func (fi *fileInfo) IsDir() bool { return fi.mode.IsDir() }
-func (fi *fileInfo) Sys() interface{} { return nil }
-
-// httpZipFile is the zip-file based implementation of http.File
-type httpZipFile struct {
- path string // absolute path within zip FS without leading '/'
- info os.FileInfo
- io.ReadCloser // nil for directory
- list zipList
-}
-
-func (f *httpZipFile) Close() error {
- if !f.info.IsDir() {
- return f.ReadCloser.Close()
- }
- f.list = nil
- return nil
-}
-
-func (f *httpZipFile) Stat() (os.FileInfo, error) {
- return f.info, nil
-}
-
-func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, error) {
- var list []os.FileInfo
- dirname := f.path + "/"
- prevname := ""
- for i, e := range f.list {
- if count == 0 {
- f.list = f.list[i:]
- break
- }
- if !strings.HasPrefix(e.Name, dirname) {
- f.list = nil
- break // not in the same directory anymore
- }
- name := e.Name[len(dirname):] // local name
- var mode os.FileMode
- var size int64
- var mtime time.Time
- if i := strings.IndexRune(name, '/'); i >= 0 {
- // We infer directories from files in subdirectories.
- // If we have x/y, return a directory entry for x.
- name = name[0:i] // keep local directory name only
- mode = os.ModeDir
- // no size or mtime for directories
- } else {
- mode = 0
- size = int64(e.UncompressedSize)
- mtime = e.ModTime()
- }
- // If we have x/y and x/z, don't return two directory entries for x.
- // TODO(gri): It should be possible to do this more efficiently
- // by determining the (fs.list) range of local directory entries
- // (via two binary searches).
- if name != prevname {
- list = append(list, &fileInfo{
- name,
- mode,
- size,
- mtime,
- })
- prevname = name
- count--
- }
- }
-
- if count >= 0 && len(list) == 0 {
- return nil, io.EOF
- }
-
- return list, nil
-}
-
-func (f *httpZipFile) Seek(offset int64, whence int) (int64, error) {
- return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.info.Name())
-}
-
-// httpZipFS is the zip-file based implementation of http.FileSystem
-type httpZipFS struct {
- *zip.ReadCloser
- list zipList
- root string
-}
-
-func (fs *httpZipFS) Open(name string) (http.File, error) {
- // fs.root does not start with '/'.
- path := path.Join(fs.root, name) // path is clean
- index, exact := fs.list.lookup(path)
- if index < 0 || !strings.HasPrefix(path, fs.root) {
- // file not found or not under root
- return nil, fmt.Errorf("file not found: %s", name)
- }
-
- if exact {
- // exact match found - must be a file
- f := fs.list[index]
- rc, err := f.Open()
- if err != nil {
- return nil, err
- }
- return &httpZipFile{
- path,
- &fileInfo{
- name,
- 0,
- int64(f.UncompressedSize),
- f.ModTime(),
- },
- rc,
- nil,
- }, nil
- }
-
- // not an exact match - must be a directory
- return &httpZipFile{
- path,
- &fileInfo{
- name,
- os.ModeDir,
- 0, // no size for directory
- time.Time{}, // no mtime for directory
- },
- nil,
- fs.list[index:],
- }, nil
-}
-
-func (fs *httpZipFS) Close() error {
- fs.list = nil
- return fs.ReadCloser.Close()
-}
-
-// NewHttpZipFS creates a new http.FileSystem based on the contents of
-// the zip file rc restricted to the directory tree specified by root;
-// root must be an absolute path.
-func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
- list := make(zipList, len(rc.File))
- copy(list, rc.File) // sort a copy of rc.File
- sort.Sort(list)
- return &httpZipFS{rc, list, zipPath(root)}
-}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 6c36e6f4f..1bef79693 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -48,7 +48,7 @@ import (
"index/suffixarray"
"io"
"os"
- "path/filepath"
+ pathpkg "path"
"regexp"
"sort"
"strings"
@@ -248,7 +248,7 @@ type File struct {
// Path returns the file path of f.
func (f *File) Path() string {
- return filepath.Join(f.Pak.Path, f.Name)
+ return pathpkg.Join(f.Pak.Path, f.Name)
}
// A Spot describes a single occurrence of a word.
@@ -695,7 +695,7 @@ var whitelisted = map[string]bool{
// of "permitted" files for indexing. The filename must
// be the directory-local name of the file.
func isWhitelisted(filename string) bool {
- key := filepath.Ext(filename)
+ key := pathpkg.Ext(filename)
if key == "" {
// file has no extension - use entire filename
key = filename
@@ -708,7 +708,7 @@ func (x *Indexer) visitFile(dirname string, f os.FileInfo, fulltextIndex bool) {
return
}
- filename := filepath.Join(dirname, f.Name())
+ filename := pathpkg.Join(dirname, f.Name())
goFile := false
switch {
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 5f4210539..23f712ab3 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -38,13 +38,13 @@ import (
"log"
"net/http"
_ "net/http/pprof" // to serve /debug/pprof/*
+ "net/url"
"os"
- "path"
+ pathpkg "path"
"path/filepath"
"regexp"
"runtime"
"strings"
- "time"
)
const defaultAddr = ":6060" // default webserver address
@@ -57,11 +57,6 @@ var (
// file-based index
writeIndex = flag.Bool("write_index", false, "write index to a file; the file name must be specified with -index_files")
- // periodic sync
- syncCmd = flag.String("sync", "", "sync command; disabled if empty")
- syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
- syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
-
// network
httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
serverAddr = flag.String("server", "", "webserver address for command line searches")
@@ -69,6 +64,7 @@ var (
// layout control
html = flag.Bool("html", false, "print HTML in command-line mode")
srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
+ urlFlag = flag.String("url", "", "print HTML for named URL")
// command-line searches
query = flag.Bool("q", false, "arguments are considered search queries")
@@ -77,76 +73,7 @@ var (
func serveError(w http.ResponseWriter, r *http.Request, relpath string, err error) {
contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
w.WriteHeader(http.StatusNotFound)
- servePage(w, "File "+relpath, "", "", contents)
-}
-
-func exec(rw http.ResponseWriter, args []string) (status int) {
- r, w, err := os.Pipe()
- if err != nil {
- log.Printf("os.Pipe(): %v", err)
- return 2
- }
-
- bin := args[0]
- fds := []*os.File{nil, w, w}
- if *verbose {
- log.Printf("executing %v", args)
- }
- p, err := os.StartProcess(bin, args, &os.ProcAttr{Files: fds, Dir: *goroot})
- defer r.Close()
- w.Close()
- if err != nil {
- log.Printf("os.StartProcess(%q): %v", bin, err)
- return 2
- }
-
- var buf bytes.Buffer
- io.Copy(&buf, r)
- wait, err := p.Wait()
- if err != nil {
- os.Stderr.Write(buf.Bytes())
- log.Printf("os.Wait(%d, 0): %v", p.Pid, err)
- return 2
- }
- if !wait.Success() {
- os.Stderr.Write(buf.Bytes())
- log.Printf("executing %v failed", args)
- status = 1 // See comment in default case in dosync.
- return
- }
-
- if *verbose {
- os.Stderr.Write(buf.Bytes())
- }
- if rw != nil {
- rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- rw.Write(buf.Bytes())
- }
-
- return
-}
-
-func dosync(w http.ResponseWriter, r *http.Request) {
- args := []string{"/bin/sh", "-c", *syncCmd}
- switch exec(w, args) {
- case 0:
- // sync succeeded and some files have changed;
- // update package tree.
- // TODO(gri): The directory tree may be temporarily out-of-sync.
- // Consider keeping separate time stamps so the web-
- // page can indicate this discrepancy.
- initFSTree()
- fallthrough
- case 1:
- // sync failed because no files changed;
- // don't change the package tree
- syncDelay.set(time.Duration(*syncMin) * time.Minute) // revert to regular sync schedule
- default:
- // TODO(r): this cannot happen now, since Wait has a boolean exit condition,
- // not an integer.
- // sync failed because of an error - back off exponentially, but try at least once a day
- syncDelay.backoff(24 * time.Hour)
- }
+ servePage(w, relpath, "File "+relpath, "", "", contents)
}
func usage() {
@@ -225,7 +152,7 @@ func main() {
flag.Parse()
// Check usage: either server and no args, command line and args, or index creation mode
- if (*httpAddr != "") != (flag.NArg() == 0) && !*writeIndex {
+ if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
usage()
}
@@ -239,19 +166,20 @@ func main() {
// same is true for the http handlers in initHandlers.
if *zipfile == "" {
// use file system of underlying OS
- *goroot = filepath.Clean(*goroot) // normalize path separator
- fs = OS
- fsHttp = http.Dir(*goroot)
+ fs.Bind("/", OS(*goroot), "/", bindReplace)
} else {
// use file system specified via .zip file (path separator must be '/')
rc, err := zip.OpenReader(*zipfile)
if err != nil {
log.Fatalf("%s: %s\n", *zipfile, err)
}
- defer rc.Close() // be nice (e.g., -writeIndex mode)
- *goroot = path.Join("/", *goroot) // fsHttp paths are relative to '/'
- fs = NewZipFS(rc)
- fsHttp = NewHttpZipFS(rc, *goroot)
+ defer rc.Close() // be nice (e.g., -writeIndex mode)
+ fs.Bind("/", NewZipFS(rc, *zipfile), *goroot, bindReplace)
+ }
+
+ // Bind $GOPATH trees into Go root.
+ for _, p := range filepath.SplitList(build.Default.GOPATH) {
+ fs.Bind("/src/pkg", OS(p), "/src", bindAfter)
}
readTemplates()
@@ -266,7 +194,6 @@ func main() {
log.Println("initialize file systems")
*verbose = true // want to see what happens
initFSTree()
- initDirTrees()
*indexThrottle = 1
updateIndex()
@@ -286,6 +213,44 @@ func main() {
return
}
+ // Print content that would be served at the URL *urlFlag.
+ if *urlFlag != "" {
+ registerPublicHandlers(http.DefaultServeMux)
+ // Try up to 10 fetches, following redirects.
+ urlstr := *urlFlag
+ for i := 0; i < 10; i++ {
+ // Prepare request.
+ u, err := url.Parse(urlstr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ req := &http.Request{
+ URL: u,
+ }
+
+ // Invoke default HTTP handler to serve request
+ // to our buffering httpWriter.
+ w := &httpWriter{h: http.Header{}, code: 200}
+ http.DefaultServeMux.ServeHTTP(w, req)
+
+ // Return data, error, or follow redirect.
+ switch w.code {
+ case 200: // ok
+ os.Stdout.Write(w.Bytes())
+ return
+ case 301, 302, 303, 307: // redirect
+ redirect := w.h.Get("Location")
+ if redirect == "" {
+ log.Fatalf("HTTP %d without Location header", w.code)
+ }
+ urlstr = redirect
+ default:
+ log.Fatalf("HTTP error %d", w.code)
+ }
+ }
+ log.Fatalf("too many redirects")
+ }
+
if *httpAddr != "" {
// HTTP server mode.
var handler http.Handler = http.DefaultServeMux
@@ -303,41 +268,20 @@ func main() {
default:
log.Print("identifier search index enabled")
}
- if !fsMap.IsEmpty() {
- log.Print("user-defined mapping:")
- fsMap.Fprint(os.Stderr)
- }
+ fs.Fprint(os.Stderr)
handler = loggingHandler(handler)
}
registerPublicHandlers(http.DefaultServeMux)
- if *syncCmd != "" {
- http.Handle("/debug/sync", http.HandlerFunc(dosync))
- }
+
+ // Playground handlers are not available in local godoc.
+ http.HandleFunc("/compile", disabledHandler)
+ http.HandleFunc("/share", disabledHandler)
// Initialize default directory tree with corresponding timestamp.
// (Do it in a goroutine so that launch is quick.)
go initFSTree()
- // Initialize directory trees for user-defined file systems (-path flag).
- initDirTrees()
-
- // Start sync goroutine, if enabled.
- if *syncCmd != "" && *syncMin > 0 {
- syncDelay.set(*syncMin) // initial sync delay
- go func() {
- for {
- dosync(nil, nil)
- delay, _ := syncDelay.get()
- dt := delay.(time.Duration)
- if *verbose {
- log.Printf("next sync in %s", dt)
- }
- time.Sleep(dt)
- }
- }()
- }
-
// Immediately update metadata.
updateMetadata()
// Periodically refresh metadata.
@@ -374,27 +318,38 @@ func main() {
return
}
- // determine paths
+ // Determine paths.
+ //
+ // If we are passed an operating system path like . or ./foo or /foo/bar or c:\mysrc,
+ // we need to map that path somewhere in the fs name space so that routines
+ // like getPageInfo will see it. We use the arbitrarily-chosen virtual path "/target"
+ // for this. That is, if we get passed a directory like the above, we map that
+ // directory so that getPageInfo sees it as /target.
+ const target = "/target"
const cmdPrefix = "cmd/"
path := flag.Arg(0)
var forceCmd bool
- if strings.HasPrefix(path, ".") {
- // assume cwd; don't assume -goroot
+ var abspath, relpath string
+ if filepath.IsAbs(path) {
+ fs.Bind(target, OS(path), "/", bindReplace)
+ abspath = target
+ } else if build.IsLocalImport(path) {
cwd, _ := os.Getwd() // ignore errors
path = filepath.Join(cwd, path)
+ fs.Bind(target, OS(path), "/", bindReplace)
+ abspath = target
} else if strings.HasPrefix(path, cmdPrefix) {
path = path[len(cmdPrefix):]
forceCmd = true
- }
- relpath := path
- abspath := path
- if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
+ } else if bp, _ := build.Import(path, "", build.FindOnly); bp.Dir != "" && bp.ImportPath != "" {
+ fs.Bind(target, OS(bp.Dir), "/", bindReplace)
+ abspath = target
relpath = bp.ImportPath
- abspath = bp.Dir
- } else if !filepath.IsAbs(path) {
- abspath = absolutePath(path, pkgHandler.fsRoot)
} else {
- relpath = relativeURL(path)
+ abspath = pathpkg.Join(pkgHandler.fsRoot, path)
+ }
+ if relpath == "" {
+ relpath = abspath
}
var mode PageInfoMode
@@ -422,7 +377,7 @@ func main() {
// (the go command invokes godoc w/ absolute paths; don't override)
var cinfo PageInfo
if !filepath.IsAbs(path) {
- abspath = absolutePath(path, cmdHandler.fsRoot)
+ abspath = pathpkg.Join(cmdHandler.fsRoot, path)
cinfo = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
@@ -445,6 +400,10 @@ func main() {
if info.Err != nil {
log.Fatalf("%v", info.Err)
}
+ if info.PDoc != nil && info.PDoc.ImportPath == target {
+ // Replace virtual /target with actual argument from command line.
+ info.PDoc.ImportPath = flag.Arg(0)
+ }
// If we have more than one argument, use the remaining arguments for filtering
if flag.NArg() > 1 {
@@ -485,3 +444,19 @@ func main() {
log.Printf("packageText.Execute: %s", err)
}
}
+
+// An httpWriter is an http.ResponseWriter writing to a bytes.Buffer.
+type httpWriter struct {
+ bytes.Buffer
+ h http.Header
+ code int
+}
+
+func (w *httpWriter) Header() http.Header { return w.h }
+func (w *httpWriter) WriteHeader(code int) { w.code = code }
+
+// disabledHandler serves a 501 "Not Implemented" response.
+func disabledHandler(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+ fmt.Fprint(w, "This functionality is not available via local godoc.")
+}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
deleted file mode 100644
index 544dd6f66..000000000
--- a/src/cmd/godoc/mapping.go
+++ /dev/null
@@ -1,202 +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.
-
-// This file implements the Mapping data structure.
-
-package main
-
-import (
- "fmt"
- "io"
- "path"
- "path/filepath"
- "sort"
- "strings"
-)
-
-// A Mapping object maps relative paths (e.g. from URLs)
-// to absolute paths (of the file system) and vice versa.
-//
-// A Mapping object consists of a list of individual mappings
-// of the form: prefix -> path which are interpreted as follows:
-// A relative path of the form prefix/tail is to be mapped to
-// the absolute path/tail, if that absolute path exists in the file
-// system. Given a Mapping object, a relative path is mapped to an
-// absolute path by trying each of the individual mappings in order,
-// until a valid mapping is found. For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the relative paths below are mapped to absolute paths as follows:
-//
-// user/foo -> /home/user/foo
-// public/net/rpc/file1.go -> /home/user/public/net/rpc/file1.go
-//
-// If there is no /home/user/public/net/rpc/file2.go, the next public
-// mapping entry is used to map the relative path to:
-//
-// public/net/rpc/file2.go -> /home/build/public/net/rpc/file2.go
-//
-// (assuming that file exists).
-//
-// Each individual mapping also has a RWValue associated with it that
-// may be used to store mapping-specific information. See the Iterate
-// method.
-//
-type Mapping struct {
- list []mapping
- prefixes []string // lazily computed from list
-}
-
-type mapping struct {
- prefix, path string
- value *RWValue
-}
-
-// Init initializes the Mapping from a list of paths.
-// Empty paths are ignored; relative paths are assumed to be relative to
-// the current working directory and converted to absolute paths.
-// For each path of the form:
-//
-// dirname/localname
-//
-// a mapping
-//
-// localname -> path
-//
-// is added to the Mapping object, in the order of occurrence.
-// For instance, under Unix, the argument:
-//
-// /home/user:/home/build/public
-//
-// leads to the following mapping:
-//
-// user -> /home/user
-// public -> /home/build/public
-//
-func (m *Mapping) Init(paths []string) {
- pathlist := canonicalizePaths(paths, nil)
- list := make([]mapping, len(pathlist))
-
- // create mapping list
- for i, path := range pathlist {
- _, prefix := filepath.Split(path)
- list[i] = mapping{prefix, path, new(RWValue)}
- }
-
- m.list = list
-}
-
-// IsEmpty returns true if there are no mappings specified.
-func (m *Mapping) IsEmpty() bool { return len(m.list) == 0 }
-
-// PrefixList returns a list of all prefixes, with duplicates removed.
-// For instance, for the mapping:
-//
-// user -> /home/user
-// public -> /home/user/public
-// public -> /home/build/public
-//
-// the prefix list is:
-//
-// user, public
-//
-func (m *Mapping) PrefixList() []string {
- // compute the list lazily
- if m.prefixes == nil {
- list := make([]string, len(m.list))
-
- // populate list
- for i, e := range m.list {
- list[i] = e.prefix
- }
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i := 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- m.prefixes = list[0:i]
- }
-
- return m.prefixes
-}
-
-// Fprint prints the mapping.
-func (m *Mapping) Fprint(w io.Writer) {
- for _, e := range m.list {
- fmt.Fprintf(w, "\t%s -> %s\n", e.prefix, e.path)
- }
-}
-
-const sep = string(filepath.Separator)
-
-// splitFirst splits a path at the first path separator and returns
-// the path's head (the top-most directory specified by the path) and
-// its tail (the rest of the path). If there is no path separator,
-// splitFirst returns path as head, and the empty string as tail.
-// Specifically, splitFirst("foo") == splitFirst("foo/").
-//
-func splitFirst(path string) (head, tail string) {
- if i := strings.Index(path, sep); i > 0 {
- // 0 < i < len(path)
- return path[0:i], path[i+1:]
- }
- return path, ""
-}
-
-// ToAbsolute maps a slash-separated relative path to an absolute filesystem
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToAbsolute(spath string) string {
- fpath := filepath.FromSlash(spath)
- prefix, tail := splitFirst(fpath)
- for _, e := range m.list {
- if e.prefix == prefix {
- // found potential mapping
- abspath := filepath.Join(e.path, tail)
- if _, err := fs.Stat(abspath); err == nil {
- return abspath
- }
- }
- }
- return "" // no match
-}
-
-// ToRelative maps an absolute filesystem path to a relative slash-separated
-// path using the Mapping specified by the receiver. If the path cannot
-// be mapped, the empty string is returned.
-//
-func (m *Mapping) ToRelative(fpath string) string {
- for _, e := range m.list {
- // if fpath has prefix e.path, the next character must be a separator (was issue 3096)
- if strings.HasPrefix(fpath, e.path+sep) {
- spath := filepath.ToSlash(fpath)
- // /absolute/prefix/foo -> prefix/foo
- return path.Join(e.prefix, spath[len(e.path):]) // Join will remove a trailing '/'
- }
- }
- return "" // no match
-}
-
-// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
-// until f returns false.
-//
-func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
- for _, e := range m.list {
- if !f(e.path, e.value) {
- return
- }
- }
-}
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
index d6cc67cb5..c6b7c2dc8 100644
--- a/src/cmd/godoc/parser.go
+++ b/src/cmd/godoc/parser.go
@@ -14,7 +14,7 @@ import (
"go/parser"
"go/token"
"os"
- "path/filepath"
+ pathpkg "path"
)
func parseFile(fset *token.FileSet, filename string, mode parser.Mode) (*ast.File, error) {
@@ -58,7 +58,7 @@ func parseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool) (
i := 0
for _, d := range list {
if filter == nil || filter(d) {
- filenames[i] = filepath.Join(path, d.Name())
+ filenames[i] = pathpkg.Join(path, d.Name())
i++
}
}
diff --git a/src/cmd/godoc/template.go b/src/cmd/godoc/template.go
new file mode 100644
index 000000000..d709baef4
--- /dev/null
+++ b/src/cmd/godoc/template.go
@@ -0,0 +1,182 @@
+// 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.
+
+// Template support for writing HTML documents.
+// Documents that include Template: true in their
+// metadata are executed as input to text/template.
+//
+// This file defines functions for those templates to invoke.
+
+// The template uses the function "code" to inject program
+// source into the output by extracting code from files and
+// injecting them as HTML-escaped <pre> blocks.
+//
+// The syntax is simple: 1, 2, or 3 space-separated arguments:
+//
+// Whole file:
+// {{code "foo.go"}}
+// One line (here the signature of main):
+// {{code "foo.go" `/^func.main/`}}
+// Block of text, determined by start and end (here the body of main):
+// {{code "foo.go" `/^func.main/` `/^}/`
+//
+// Patterns can be `/regular expression/`, a decimal number, or "$"
+// to signify the end of the file. In multi-line matches,
+// lines that end with the four characters
+// OMIT
+// are omitted from the output, making it easy to provide marker
+// lines in the input that will not appear in the output but are easy
+// to identify by pattern.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "regexp"
+ "strings"
+ "text/template"
+)
+
+// Functions in this file panic on error, but the panic is recovered
+// to an error by 'code'.
+
+var templateFuncs = template.FuncMap{
+ "code": code,
+}
+
+// contents reads and returns the content of the named file
+// (from the virtual file system, so for example /doc refers to $GOROOT/doc).
+func contents(name string) string {
+ file, err := ReadFile(fs, name)
+ if err != nil {
+ log.Panic(err)
+ }
+ return string(file)
+}
+
+// format returns a textual representation of the arg, formatted according to its nature.
+func format(arg interface{}) string {
+ switch arg := arg.(type) {
+ case int:
+ return fmt.Sprintf("%d", arg)
+ case string:
+ if len(arg) > 2 && arg[0] == '/' && arg[len(arg)-1] == '/' {
+ return fmt.Sprintf("%#q", arg)
+ }
+ return fmt.Sprintf("%q", arg)
+ default:
+ log.Panicf("unrecognized argument: %v type %T", arg, arg)
+ }
+ return ""
+}
+
+func code(file string, arg ...interface{}) (s string, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("%v", r)
+ }
+ }()
+
+ text := contents(file)
+ var command string
+ switch len(arg) {
+ case 0:
+ // text is already whole file.
+ command = fmt.Sprintf("code %q", file)
+ case 1:
+ command = fmt.Sprintf("code %q %s", file, format(arg[0]))
+ text = oneLine(file, text, arg[0])
+ case 2:
+ command = fmt.Sprintf("code %q %s %s", file, format(arg[0]), format(arg[1]))
+ text = multipleLines(file, text, arg[0], arg[1])
+ default:
+ return "", fmt.Errorf("incorrect code invocation: code %q %q", file, arg)
+ }
+ // Trim spaces from output.
+ text = strings.Trim(text, "\n")
+ // Replace tabs by spaces, which work better in HTML.
+ text = strings.Replace(text, "\t", " ", -1)
+ var buf bytes.Buffer
+ // HTML-escape text and syntax-color comments like elsewhere.
+ FormatText(&buf, []byte(text), -1, true, "", nil)
+ // Include the command as a comment.
+ text = fmt.Sprintf("<pre><!--{{%s}}\n-->%s</pre>", command, buf.Bytes())
+ return text, nil
+}
+
+// parseArg returns the integer or string value of the argument and tells which it is.
+func parseArg(arg interface{}, file string, max int) (ival int, sval string, isInt bool) {
+ switch n := arg.(type) {
+ case int:
+ if n <= 0 || n > max {
+ log.Panicf("%q:%d is out of range", file, n)
+ }
+ return n, "", true
+ case string:
+ return 0, n, false
+ }
+ log.Panicf("unrecognized argument %v type %T", arg, arg)
+ return
+}
+
+// oneLine returns the single line generated by a two-argument code invocation.
+func oneLine(file, text string, arg interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line, pattern, isInt := parseArg(arg, file, len(lines))
+ if isInt {
+ return lines[line-1]
+ }
+ return lines[match(file, 0, lines, pattern)-1]
+}
+
+// multipleLines returns the text generated by a three-argument code invocation.
+func multipleLines(file, text string, arg1, arg2 interface{}) string {
+ lines := strings.SplitAfter(contents(file), "\n")
+ line1, pattern1, isInt1 := parseArg(arg1, file, len(lines))
+ line2, pattern2, isInt2 := parseArg(arg2, file, len(lines))
+ if !isInt1 {
+ line1 = match(file, 0, lines, pattern1)
+ }
+ if !isInt2 {
+ line2 = match(file, line1, lines, pattern2)
+ } else if line2 < line1 {
+ log.Panicf("lines out of order for %q: %d %d", text, line1, line2)
+ }
+ for k := line1 - 1; k < line2; k++ {
+ if strings.HasSuffix(lines[k], "OMIT\n") {
+ lines[k] = ""
+ }
+ }
+ return strings.Join(lines[line1-1:line2], "")
+}
+
+// match identifies the input line that matches the pattern in a code invocation.
+// If start>0, match lines starting there rather than at the beginning.
+// The return value is 1-indexed.
+func match(file string, start int, lines []string, pattern string) int {
+ // $ matches the end of the file.
+ if pattern == "$" {
+ if len(lines) == 0 {
+ log.Panicf("%q: empty file", file)
+ }
+ return len(lines)
+ }
+ // /regexp/ matches the line that matches the regexp.
+ if len(pattern) > 2 && pattern[0] == '/' && pattern[len(pattern)-1] == '/' {
+ re, err := regexp.Compile(pattern[1 : len(pattern)-1])
+ if err != nil {
+ log.Panic(err)
+ }
+ for i := start; i < len(lines); i++ {
+ if re.MatchString(lines[i]) {
+ return i + 1
+ }
+ }
+ log.Panicf("%s: no match for %#q", file, pattern)
+ }
+ log.Panicf("unrecognized pattern: %q", pattern)
+ return 0
+}
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index be0bdc306..7def015c8 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -7,12 +7,7 @@
package main
import (
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strings"
+ pathpkg "path"
"sync"
"time"
"unicode/utf8"
@@ -40,76 +35,6 @@ func (v *RWValue) get() (interface{}, time.Time) {
return v.value, v.timestamp
}
-// TODO(gri) For now, using os.Getwd() is ok here since the functionality
-// based on this code is not invoked for the appengine version,
-// but this is fragile. Determine what the right thing to do is,
-// here (possibly have some Getwd-equivalent in FileSystem).
-var cwd, _ = os.Getwd() // ignore errors
-
-// canonicalizePaths takes a list of (directory/file) paths and returns
-// the list of corresponding absolute paths in sorted (increasing) order.
-// Relative paths are assumed to be relative to the current directory,
-// empty and duplicate paths as well as paths for which filter(path) is
-// false are discarded. filter may be nil in which case it is not used.
-//
-func canonicalizePaths(list []string, filter func(path string) bool) []string {
- i := 0
- for _, path := range list {
- path = strings.TrimSpace(path)
- if len(path) == 0 {
- continue // ignore empty paths (don't assume ".")
- }
- // len(path) > 0: normalize path
- if filepath.IsAbs(path) {
- path = filepath.Clean(path)
- } else {
- path = filepath.Join(cwd, path)
- }
- // we have a non-empty absolute path
- if filter != nil && !filter(path) {
- continue
- }
- // keep the path
- list[i] = path
- i++
- }
- list = list[0:i]
-
- // sort the list and remove duplicate entries
- sort.Strings(list)
- i = 0
- prev := ""
- for _, path := range list {
- if path != prev {
- list[i] = path
- i++
- prev = path
- }
- }
-
- return list[0:i]
-}
-
-// writeFileAtomically writes data to a temporary file and then
-// atomically renames that file to the file named by filename.
-//
-func writeFileAtomically(filename string, data []byte) error {
- // TODO(gri) this won't work on appengine
- f, err := ioutil.TempFile(filepath.Split(filename))
- if err != nil {
- return err
- }
- n, err := f.Write(data)
- f.Close()
- if err != nil {
- return err
- }
- if n < len(data) {
- return io.ErrShortWrite
- }
- return os.Rename(f.Name(), filename)
-}
-
// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
@@ -146,7 +71,7 @@ var textExt = map[string]bool{
//
func isTextFile(filename string) bool {
// if the extension is known, use it for decision making
- if isText, found := textExt[filepath.Ext(filename)]; found {
+ if isText, found := textExt[pathpkg.Ext(filename)]; found {
return isText
}
diff --git a/src/cmd/godoc/zip.go b/src/cmd/godoc/zip.go
index 8c4b1101b..620eb4f3c 100644
--- a/src/cmd/godoc/zip.go
+++ b/src/cmd/godoc/zip.go
@@ -73,6 +73,11 @@ func (fi zipFI) Sys() interface{} {
type zipFS struct {
*zip.ReadCloser
list zipList
+ name string
+}
+
+func (fs *zipFS) String() string {
+ return "zip(" + fs.name + ")"
}
func (fs *zipFS) Close() error {
@@ -102,7 +107,7 @@ func (fs *zipFS) stat(abspath string) (int, zipFI, error) {
return i, zipFI{name, file}, nil
}
-func (fs *zipFS) Open(abspath string) (io.ReadCloser, error) {
+func (fs *zipFS) Open(abspath string) (readSeekCloser, error) {
_, fi, err := fs.stat(zipPath(abspath))
if err != nil {
return nil, err
@@ -110,7 +115,29 @@ func (fs *zipFS) Open(abspath string) (io.ReadCloser, error) {
if fi.IsDir() {
return nil, fmt.Errorf("Open: %s is a directory", abspath)
}
- return fi.file.Open()
+ r, err := fi.file.Open()
+ if err != nil {
+ return nil, err
+ }
+ return &zipSeek{fi.file, r}, nil
+}
+
+type zipSeek struct {
+ file *zip.File
+ io.ReadCloser
+}
+
+func (f *zipSeek) Seek(offset int64, whence int) (int64, error) {
+ if whence == 0 && offset == 0 {
+ r, err := f.file.Open()
+ if err != nil {
+ return 0, err
+ }
+ f.Close()
+ f.ReadCloser = r
+ return 0, nil
+ }
+ return 0, fmt.Errorf("unsupported Seek in %s", f.file.Name)
}
func (fs *zipFS) Lstat(abspath string) (os.FileInfo, error) {
@@ -161,11 +188,11 @@ func (fs *zipFS) ReadDir(abspath string) ([]os.FileInfo, error) {
return list, nil
}
-func NewZipFS(rc *zip.ReadCloser) FileSystem {
+func NewZipFS(rc *zip.ReadCloser, name string) FileSystem {
list := make(zipList, len(rc.File))
copy(list, rc.File) // sort a copy of rc.File
sort.Sort(list)
- return &zipFS{rc, list}
+ return &zipFS{rc, list, name}
}
type zipList []*zip.File
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 8e565563e..0bc385b5b 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -26,7 +26,7 @@ var (
// main operation modes
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
- rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
+ rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
simplifyAST = flag.Bool("s", false, "simplify code")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "print all (including spurious) errors")
@@ -41,7 +41,7 @@ var (
)
var (
- fset = token.NewFileSet()
+ fileSet = token.NewFileSet() // per process FileSet
exitCode = 0
rewrite func(*ast.File) *ast.File
parserMode parser.Mode
@@ -98,7 +98,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
return err
}
- file, adjust, err := parse(filename, src, stdin)
+ file, adjust, err := parse(fileSet, filename, src, stdin)
if err != nil {
return err
}
@@ -111,14 +111,14 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
}
}
- ast.SortImports(fset, file)
+ ast.SortImports(fileSet, file)
if *simplifyAST {
simplify(file)
}
var buf bytes.Buffer
- err = (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(&buf, fset, file)
+ err = (&printer.Config{Mode: printerMode, Tabwidth: *tabWidth}).Fprint(&buf, fileSet, file)
if err != nil {
return err
}
@@ -254,7 +254,7 @@ 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(filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
+func parse(fset *token.FileSet, filename string, src []byte, stdin bool) (*ast.File, func(orig, src []byte) []byte, error) {
// Try as whole source file.
file, err := parser.ParseFile(fset, filename, src, parserMode)
if err == nil {
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index 9a589b1ba..edbce606a 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -14,6 +14,7 @@ import (
"fmt"
"go/ast"
"go/printer"
+ "go/token"
"io"
"os"
"path/filepath"
@@ -30,8 +31,8 @@ var (
nfiles int // number of files processed
)
-func gofmt(filename string, src *bytes.Buffer) error {
- f, _, err := parse(filename, src.Bytes(), false)
+func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
+ f, _, err := parse(fset, filename, src.Bytes(), false)
if err != nil {
return err
}
@@ -58,7 +59,8 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
}
// exclude files w/ syntax errors (typically test cases)
- if _, _, err = parse(filename, b1.Bytes(), false); err != nil {
+ fset := token.NewFileSet()
+ if _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
if *verbose {
fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
}
@@ -66,7 +68,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
}
// gofmt file
- if err = gofmt(filename, b1); err != nil {
+ if err = gofmt(fset, filename, b1); err != nil {
t.Errorf("1st gofmt failed: %v", err)
return
}
@@ -76,7 +78,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
b2.Write(b1.Bytes())
// gofmt result again
- if err = gofmt(filename, b2); err != nil {
+ if err = gofmt(fset, filename, b2); err != nil {
t.Errorf("2nd gofmt failed: %v", err)
return
}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
index 4728fccb8..e99e50466 100644
--- a/src/cmd/ld/doc.go
+++ b/src/cmd/ld/doc.go
@@ -9,45 +9,52 @@ Ld is the portable code for a modified version of the Plan 9 linker. The origin
http://plan9.bell-labs.com/magic/man2html/1/2l
It reads object files (.5, .6, or .8 files) and writes a binary named for the
-architecture (5.out, 6.out, 8.out) by default.
+architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
+will be appended).
Major changes include:
- - support for ELF and Mach-O binary files
+ - support for ELF, Mach-O and PE binary files
- support for segmented stacks (this feature is implemented here, not in the compilers).
Original options are listed on the manual page linked above.
-Options new in this version:
+Usage:
+ go tool 6l [flags] mainObj
+Substitute 6l with 8l or 5l as appropriate.
--d
- Elide the dynamic linking header. With this option, the binary
- is statically linked and does not refer to dynld. Without this option
- (the default), the binary's contents are identical but it is loaded with dynld.
--Hdarwin
- Write Apple Mach-O binaries (default when $GOOS is darwin)
--Hlinux
- Write Linux ELF binaries (default when $GOOS is linux)
--Hfreebsd
- Write FreeBSD ELF binaries (default when $GOOS is freebsd)
--Hnetbsd
- Write NetBSD ELF binaries (default when $GOOS is netbsd)
--Hopenbsd
- Write OpenBSD ELF binaries (default when $GOOS is openbsd)
--Hwindows
- Write Windows PE32+ binaries (default when $GOOS is windows)
--I interpreter
- Set the ELF dynamic linker to use.
--L dir1 -L dir2
- Search for libraries (package files) in dir1, dir2, etc.
- The default is the single location $GOROOT/pkg/$GOOS_amd64.
--r dir1:dir2:...
- Set the dynamic linker search path when using ELF.
--V
- Print the linker version.
--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".
+Options new in this version:
+ -d
+ Elide the dynamic linking header. With this option, the binary
+ is statically linked and does not refer to a dynamic linker. Without this option
+ (the default), the binary's contents are identical but it is loaded with a dynamic
+ linker. This flag cannot be used when $GOOS is windows.
+ -Hdarwin (only in 6l/8l)
+ Write Apple Mach-O binaries (default when $GOOS is darwin)
+ -Hlinux
+ Write Linux ELF binaries (default when $GOOS is linux)
+ -Hfreebsd (only in 6l/8l)
+ Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+ -Hnetbsd (only in 6l/8l)
+ Write NetBSD ELF binaries (default when $GOOS is netbsd)
+ -Hopenbsd (only in 6l/8l)
+ Write OpenBSD ELF binaries (default when $GOOS is openbsd)
+ -Hwindows (only in 6l/8l)
+ Write Windows PE32+ Console binaries (default when $GOOS is windows)
+ -Hwindowsgui (only in 6l/8l)
+ Write Windows PE32+ GUI binaries
+ -I interpreter
+ Set the ELF dynamic linker to use.
+ -L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
+ The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
+ -r dir1:dir2:...
+ Set the dynamic linker search path when using ELF.
+ -V
+ Print the linker version.
+ -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".
*/
package documentation
diff --git a/src/cmd/nm/doc.go b/src/cmd/nm/doc.go
index 5e216b922..c84369a5f 100644
--- a/src/cmd/nm/doc.go
+++ b/src/cmd/nm/doc.go
@@ -14,7 +14,8 @@ Plan 9 C compiler.
This implementation adds the flag -S, which prints each symbol's size
in decimal after its address.
-It is installed as go tool nm and is architecture-independent.
+Usage:
+ go tool nm [-aghnsTu] file
*/
package documentation
diff --git a/src/cmd/pack/ar.c b/src/cmd/pack/ar.c
index 8d881f876..7e07fbc89 100644
--- a/src/cmd/pack/ar.c
+++ b/src/cmd/pack/ar.c
@@ -1382,11 +1382,14 @@ mesg(int c, char *file)
void
trim(char *s, char *buf, int n)
{
- char *p;
+ char *p, *q;
for(;;) {
p = strrchr(s, '/');
- if (!p) { /* no slash in name */
+ q = strrchr(s, '\\');
+ if (q > p)
+ p = q;
+ if (!p) { /* no (back)slash in name */
strncpy(buf, s, n);
return;
}
@@ -1394,7 +1397,7 @@ trim(char *s, char *buf, int n)
strncpy(buf, p+1, n);
return;
}
- *p = 0; /* strip trailing slash */
+ *p = 0; /* strip trailing (back)slash */
}
}
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index e51fe3768..620964aaf 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -13,7 +13,7 @@ Available checks:
1. Printf family
-Suspicious calls to functions in the Printf familiy, including any functions
+Suspicious calls to functions in the Printf family, including any functions
with these names:
Print Printf Println
Fprint Fprintf Fprintln
diff --git a/src/cmd/vet/taglit.go b/src/cmd/vet/taglit.go
index 864e7bc60..c3c4f3234 100644
--- a/src/cmd/vet/taglit.go
+++ b/src/cmd/vet/taglit.go
@@ -81,7 +81,8 @@ var untaggedLiteralWhitelist = map[string]bool{
find $GOROOT/src/pkg -type f | grep -v _test.go | xargs grep '^type.*\[\]' | \
grep -v ' map\[' | sed 's,/[^/]*go.type,,' | sed 's,.*src/pkg/,,' | \
- sed 's, ,.,' | sed 's, .*,,' | grep -v '\.[a-z]' | sort
+ sed 's, ,.,' | sed 's, .*,,' | grep -v '\.[a-z]' | \
+ sort | awk '{ print "\"" $0 "\": true," }'
*/
"crypto/x509/pkix.RDNSequence": true,
"crypto/x509/pkix.RelativeDistinguishedNameSET": true,
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
index c3b9ec5d0..bbb2da6a9 100644
--- a/src/lib9/utf/Makefile
+++ b/src/lib9/utf/Makefile
@@ -4,21 +4,17 @@
# The library is built by the Makefile in the parent directory.
# This Makefile only builds mkrunetype.
-
-include ../../Make.inc
-O:=$(HOST_O)
+# GOROOT, GOOS, and GOARCH must be set explicitly.
TARG=mkrunetype
-OFILES=\
- mkrunetype.$O\
-
-include ../../Make.ccmd
-
UnicodeData-%.txt:
curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@
mv _$@ $@
+mkrunetype: mkrunetype.c
+ cc -I../../../include -o mkrunetype -L$(GOROOT)/pkg/obj/$(GOOS)_$(GOARCH)/ mkrunetype.c -l9
+
runetypebody-%.c: mkrunetype UnicodeData-%.txt
mkrunetype -p UnicodeData-$*.txt >_$@
mv _$@ $@
@@ -30,3 +26,5 @@ UNICODE_VERSION=6.0.0
test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
+clean:
+ rm -f UnicodeData.txt mkrunetype \ No newline at end of file
diff --git a/src/make.bash b/src/make.bash
index aaee75e46..b2de37b72 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -21,10 +21,11 @@
# building the packages and commands.
#
# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
-# building the packages and commands.
+# building the commands.
#
-# CGO_ENABLED: Setting this to 0 disables the use of cgo
-# in the built and installed packages and tools.
+# CGO_ENABLED: Controls cgo usage during the build. Set it to 1
+# to include all cgo related files, .c and .go file with "cgo"
+# build directive, in the build. Set it to 0 to ignore them.
set -e
if [ ! -f run.bash ]; then
@@ -76,6 +77,9 @@ do
fi
done
+# Clean old generated file that will cause problems in the build.
+rm -f ./pkg/runtime/runtime_defs.go
+
# Finally! Run the build.
echo '# Building C bootstrap tool.'
@@ -83,7 +87,14 @@ echo cmd/dist
export GOROOT="$(cd .. && pwd)"
GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'
-gcc -O2 -Wall -Werror -ggdb -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
+
+mflag=""
+case "$GOHOSTARCH" in
+386) mflag=-m32;;
+amd64) mflag=-m64;;
+esac
+gcc $mflag -O2 -Wall -Werror -ggdb -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
+
eval $(./cmd/dist/dist env -p)
echo
diff --git a/src/make.bat b/src/make.bat
index 8bb9262c5..ec39392dd 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -1,6 +1,31 @@
:: 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.
+
+:: Environment variables that control make.bat:
+::
+:: GOROOT_FINAL: The expected final Go root, baked into binaries.
+:: The default is the location of the Go tree during the build.
+::
+:: GOHOSTARCH: The architecture for host tools (compilers and
+:: binaries). Binaries of this type must be executable on the current
+:: system, so the only common reason to set this is to set
+:: GOHOSTARCH=386 on an amd64 machine.
+::
+:: GOARCH: The target architecture for installed packages and tools.
+::
+:: GOOS: The target operating system for installed packages and tools.
+::
+:: GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+:: building the packages and commands.
+::
+:: GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+:: building the commands.
+::
+:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
+:: to include all cgo related files, .c and .go file with "cgo"
+:: build directive, in the build. Set it to 0 to ignore them.
+
@echo off
:: Keep environment variables within this script
@@ -17,6 +42,9 @@ echo Must run make.bat from Go src directory.
goto fail
:ok
+:: Clean old generated file that will cause problems in the build.
+del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
+
:: Grab default GOROOT_FINAL and set GOROOT for build.
:: The expression %VAR:\=\\% means to take %VAR%
:: and apply the substitution \ = \\, escaping the
@@ -46,8 +74,8 @@ if x%1==x--no-clean set buildall=
.\cmd\dist\dist bootstrap %buildall% -v
if errorlevel 1 goto fail
:: Delay move of dist tool to now, because bootstrap cleared tool directory.
-move .\cmd\dist\dist.exe %GOTOOLDIR%\dist.exe
-%GOTOOLDIR%\go_bootstrap clean -i std
+move .\cmd\dist\dist.exe "%GOTOOLDIR%\dist.exe"
+"%GOTOOLDIR%\go_bootstrap" clean -i std
echo.
if not %GOHOSTARCH% == %GOARCH% goto localbuild
@@ -59,20 +87,20 @@ echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%
setlocal
set GOOS=%GOHOSTOS%
set GOARCH=%GOHOSTARCH%
-%GOTOOLDIR%\go_bootstrap install -v std
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std
endlocal
if errorlevel 1 goto fail
echo.
:mainbuild
echo # Building packages and commands.
-%GOTOOLDIR%\go_bootstrap install -a -v std
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std
if errorlevel 1 goto fail
-del %GOTOOLDIR%\go_bootstrap.exe
+del "%GOTOOLDIR%\go_bootstrap.exe"
echo.
if x%1==x--no-banner goto nobanner
-%GOTOOLDIR%\dist banner
+"%GOTOOLDIR%\dist" banner
:nobanner
goto end
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index 755a730c8..1b40af812 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -18,7 +18,7 @@ import (
)
var (
- ErrHeader = errors.New("invalid tar header")
+ ErrHeader = errors.New("archive/tar: invalid tar header")
)
// A Reader provides sequential access to the contents of a tar archive.
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index d35726bf9..b2b7a58a1 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -5,18 +5,19 @@
package tar
// TODO(dsymonds):
-// - catch more errors (no first header, write after close, etc.)
+// - catch more errors (no first header, etc.)
import (
"errors"
+ "fmt"
"io"
"strconv"
)
var (
- ErrWriteTooLong = errors.New("write too long")
- ErrFieldTooLong = errors.New("header field too long")
- ErrWriteAfterClose = errors.New("write after close")
+ ErrWriteTooLong = errors.New("archive/tar: write too long")
+ ErrFieldTooLong = errors.New("archive/tar: header field too long")
+ ErrWriteAfterClose = errors.New("archive/tar: write after close")
)
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
@@ -48,6 +49,11 @@ func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
// Flush finishes writing the current file (optional).
func (tw *Writer) Flush() error {
+ if tw.nb > 0 {
+ tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
+ return tw.err
+ }
+
n := tw.nb + tw.pad
for n > 0 && tw.err == nil {
nr := n
@@ -193,6 +199,9 @@ func (tw *Writer) Close() error {
}
tw.Flush()
tw.closed = true
+ if tw.err != nil {
+ return tw.err
+ }
// trailer: two zero blocks
for i := 0; i < 2; i++ {
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 0b413722d..a214e57b9 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/archive/tar/writer_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "strings"
"testing"
"testing/iotest"
"time"
@@ -95,7 +96,8 @@ var writerTests = []*writerTest{
Uname: "dsymonds",
Gname: "eng",
},
- // no contents
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
},
},
},
@@ -150,7 +152,9 @@ testLoop:
buf := new(bytes.Buffer)
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+ big := false
for j, entry := range test.entries {
+ big = big || entry.header.Size > 1<<10
if err := tw.WriteHeader(entry.header); err != nil {
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
continue testLoop
@@ -160,7 +164,8 @@ testLoop:
continue testLoop
}
}
- if err := tw.Close(); err != nil {
+ // Only interested in Close failures for the small tests.
+ if err := tw.Close(); err != nil && !big {
t.Errorf("test %d: Failed closing archive: %v", i, err)
continue testLoop
}
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index f3826dcc4..ddd507538 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -124,10 +124,6 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
return
}
size := int64(f.CompressedSize)
- if size == 0 && f.hasDataDescriptor() {
- // permit SectionReader to see the rest of the file
- size = f.zipsize - (f.headerOffset + bodyOffset)
- }
r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
switch f.Method {
case Store: // (no compression)
@@ -136,10 +132,13 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
rc = flate.NewReader(r)
default:
err = ErrAlgorithm
+ return
}
- if rc != nil {
- rc = &checksumReader{rc, crc32.NewIEEE(), f, r}
+ var desr io.Reader
+ if f.hasDataDescriptor() {
+ desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
}
+ rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
return
}
@@ -147,23 +146,36 @@ type checksumReader struct {
rc io.ReadCloser
hash hash.Hash32
f *File
- zipr io.Reader // for reading the data descriptor
+ desr io.Reader // if non-nil, where to read the data descriptor
+ err error // sticky error
}
func (r *checksumReader) Read(b []byte) (n int, err error) {
+ if r.err != nil {
+ return 0, r.err
+ }
n, err = r.rc.Read(b)
r.hash.Write(b[:n])
- if err != io.EOF {
+ if err == nil {
return
}
- if r.f.hasDataDescriptor() {
- if err = readDataDescriptor(r.zipr, r.f); err != nil {
- return
+ if err == io.EOF {
+ if r.desr != nil {
+ if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
+ err = err1
+ } else if r.hash.Sum32() != r.f.CRC32 {
+ err = ErrChecksum
+ }
+ } else {
+ // If there's not a data descriptor, we still compare
+ // the CRC32 of what we've read against the file header
+ // or TOC's CRC32, if it seems like it was set.
+ if r.f.CRC32 != 0 && r.hash.Sum32() != r.f.CRC32 {
+ err = ErrChecksum
+ }
}
}
- if r.hash.Sum32() != r.f.CRC32 {
- err = ErrChecksum
- }
+ r.err = err
return
}
@@ -226,10 +238,31 @@ func readDirectoryHeader(f *File, r io.Reader) error {
func readDataDescriptor(r io.Reader, f *File) error {
var buf [dataDescriptorLen]byte
- if _, err := io.ReadFull(r, buf[:]); err != nil {
+
+ // The spec says: "Although not originally assigned a
+ // signature, the value 0x08074b50 has commonly been adopted
+ // as a signature value for the data descriptor record.
+ // Implementers should be aware that ZIP files may be
+ // encountered with or without this signature marking data
+ // descriptors and should account for either case when reading
+ // ZIP files to ensure compatibility."
+ //
+ // dataDescriptorLen includes the size of the signature but
+ // first read just those 4 bytes to see if it exists.
+ if _, err := io.ReadFull(r, buf[:4]); err != nil {
return err
}
- b := readBuf(buf[:])
+ off := 0
+ maybeSig := readBuf(buf[:4])
+ if maybeSig.uint32() != dataDescriptorSignature {
+ // No data descriptor signature. Keep these four
+ // bytes.
+ off += 4
+ }
+ if _, err := io.ReadFull(r, buf[off:12]); err != nil {
+ return err
+ }
+ b := readBuf(buf[:12])
f.CRC32 = b.uint32()
f.CompressedSize = b.uint32()
f.UncompressedSize = b.uint32()
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index 066a61580..5f1d1b28a 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -7,26 +7,31 @@ package zip
import (
"bytes"
"encoding/binary"
+ "encoding/hex"
"io"
"io/ioutil"
"os"
+ "path/filepath"
+ "regexp"
"testing"
"time"
)
type ZipTest struct {
Name string
+ Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
Comment string
File []ZipTestFile
Error error // the error that Opening this file should return
}
type ZipTestFile struct {
- Name string
- Content []byte // if blank, will attempt to compare against File
- File string // name of file to compare to (relative to testdata/)
- Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
- Mode os.FileMode
+ Name string
+ Content []byte // if blank, will attempt to compare against File
+ ContentErr error
+ File string // name of file to compare to (relative to testdata/)
+ Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
+ Mode os.FileMode
}
// Caution: The Mtime values found for the test files should correspond to
@@ -59,13 +64,14 @@ var tests = []ZipTest{
},
},
{
- Name: "r.zip",
+ Name: "r.zip",
+ Source: returnRecursiveZip,
File: []ZipTestFile{
{
- Name: "r/r.zip",
- File: "r.zip",
- Mtime: "03-04-10 00:24:16",
- Mode: 0666,
+ Name: "r/r.zip",
+ Content: rZipBytes(),
+ Mtime: "03-04-10 00:24:16",
+ Mode: 0666,
},
},
},
@@ -107,6 +113,99 @@ var tests = []ZipTest{
Name: "unix.zip",
File: crossPlatform,
},
+ {
+ // created by Go, before we wrote the "optional" data
+ // descriptor signatures (which are required by OS X)
+ Name: "go-no-datadesc-sig.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
+ {
+ // created by Go, after we wrote the "optional" data
+ // descriptor signatures (which are required by OS X)
+ Name: "go-with-datadesc-sig.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mode: 0666,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mode: 0666,
+ },
+ },
+ },
+ {
+ Name: "Bad-CRC32-in-data-descriptor",
+ Source: returnCorruptCRC32Zip,
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mode: 0666,
+ ContentErr: ErrChecksum,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mode: 0666,
+ },
+ },
+ },
+ // Tests that we verify (and accept valid) crc32s on files
+ // with crc32s in their file header (not in data descriptors)
+ {
+ Name: "crc32-not-streamed.zip",
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
+ // Tests that we verify (and reject invalid) crc32s on files
+ // with crc32s in their file header (not in data descriptors)
+ {
+ Name: "crc32-not-streamed.zip",
+ Source: returnCorruptNotStreamedZip,
+ File: []ZipTestFile{
+ {
+ Name: "foo.txt",
+ Content: []byte("foo\n"),
+ Mtime: "03-08-12 16:59:10",
+ Mode: 0644,
+ ContentErr: ErrChecksum,
+ },
+ {
+ Name: "bar.txt",
+ Content: []byte("bar\n"),
+ Mtime: "03-08-12 16:59:12",
+ Mode: 0644,
+ },
+ },
+ },
}
var crossPlatform = []ZipTestFile{
@@ -139,7 +238,18 @@ func TestReader(t *testing.T) {
}
func readTestZip(t *testing.T, zt ZipTest) {
- z, err := OpenReader("testdata/" + zt.Name)
+ var z *Reader
+ var err error
+ if zt.Source != nil {
+ rat, size := zt.Source()
+ z, err = NewReader(rat, size)
+ } else {
+ var rc *ReadCloser
+ rc, err = OpenReader(filepath.Join("testdata", zt.Name))
+ if err == nil {
+ z = &rc.Reader
+ }
+ }
if err != zt.Error {
t.Errorf("error=%v, want %v", err, zt.Error)
return
@@ -149,11 +259,6 @@ func readTestZip(t *testing.T, zt ZipTest) {
if err == ErrFormat {
return
}
- defer func() {
- if err := z.Close(); err != nil {
- t.Errorf("error %q when closing zip file", err)
- }
- }()
// bail here if no Files expected to be tested
// (there may actually be files in the zip, but we don't care)
@@ -170,7 +275,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
// test read of each file
for i, ft := range zt.File {
- readTestFile(t, ft, z.File[i])
+ readTestFile(t, zt, ft, z.File[i])
}
// test simultaneous reads
@@ -179,7 +284,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
for i := 0; i < 5; i++ {
for j, ft := range zt.File {
go func(j int, ft ZipTestFile) {
- readTestFile(t, ft, z.File[j])
+ readTestFile(t, zt, ft, z.File[j])
done <- true
}(j, ft)
n++
@@ -188,26 +293,11 @@ func readTestZip(t *testing.T, zt ZipTest) {
for ; n > 0; n-- {
<-done
}
-
- // test invalid checksum
- if !z.File[0].hasDataDescriptor() { // skip test when crc32 in dd
- z.File[0].CRC32++ // invalidate
- r, err := z.File[0].Open()
- if err != nil {
- t.Error(err)
- return
- }
- var b bytes.Buffer
- _, err = io.Copy(&b, r)
- if err != ErrChecksum {
- t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ErrChecksum)
- }
- }
}
-func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
+func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
if f.Name != ft.Name {
- t.Errorf("name=%q, want %q", f.Name, ft.Name)
+ t.Errorf("%s: name=%q, want %q", zt.Name, f.Name, ft.Name)
}
if ft.Mtime != "" {
@@ -217,11 +307,11 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
return
}
if ft := f.ModTime(); !ft.Equal(mtime) {
- t.Errorf("%s: mtime=%s, want %s", f.Name, ft, mtime)
+ t.Errorf("%s: %s: mtime=%s, want %s", zt.Name, f.Name, ft, mtime)
}
}
- testFileMode(t, f, ft.Mode)
+ testFileMode(t, zt.Name, f, ft.Mode)
size0 := f.UncompressedSize
@@ -237,8 +327,10 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
_, err = io.Copy(&b, r)
+ if err != ft.ContentErr {
+ t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
+ }
if err != nil {
- t.Error(err)
return
}
r.Close()
@@ -264,12 +356,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
}
}
-func testFileMode(t *testing.T, f *File, want os.FileMode) {
+func testFileMode(t *testing.T, zipName string, f *File, want os.FileMode) {
mode := f.Mode()
if want == 0 {
- t.Errorf("%s mode: got %v, want none", f.Name, mode)
+ t.Errorf("%s: %s mode: got %v, want none", zipName, f.Name, mode)
} else if mode != want {
- t.Errorf("%s mode: want %v, got %v", f.Name, want, mode)
+ t.Errorf("%s: %s mode: want %v, got %v", zipName, f.Name, want, mode)
}
}
@@ -294,3 +386,81 @@ func TestInvalidFiles(t *testing.T) {
t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
}
}
+
+func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
+ data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
+ if err != nil {
+ panic("Error reading " + fileName + ": " + err.Error())
+ }
+ corrupter(data)
+ return bytes.NewReader(data), int64(len(data))
+}
+
+func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) {
+ return messWith("go-with-datadesc-sig.zip", func(b []byte) {
+ // Corrupt one of the CRC32s in the data descriptor:
+ b[0x2d]++
+ })
+}
+
+func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) {
+ return messWith("crc32-not-streamed.zip", func(b []byte) {
+ // Corrupt foo.txt's final crc32 byte, in both
+ // the file header and TOC. (0x7e -> 0x7f)
+ b[0x11]++
+ b[0x9d]++
+
+ // TODO(bradfitz): add a new test that only corrupts
+ // one of these values, and verify that that's also an
+ // error. Currently, the reader code doesn't verify the
+ // fileheader and TOC's crc32 match if they're both
+ // non-zero and only the second line above, the TOC,
+ // is what matters.
+ })
+}
+
+// rZipBytes returns the bytes of a recursive zip file, without
+// putting it on disk and triggering certain virus scanners.
+func rZipBytes() []byte {
+ s := `
+0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4
+0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f
+0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00
+0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00
+0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00
+0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00
+0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8
+0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f
+0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e
+0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb
+00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff
+00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42
+00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14
+00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21
+00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb
+00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff
+0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a
+0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3
+0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06
+0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00
+0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf
+0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06
+0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01
+0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89
+0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00
+0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a
+00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00
+00001b0 00 00 6d 01 00 00 00 00`
+ s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
+ s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func returnRecursiveZip() (r io.ReaderAt, size int64) {
+ b := rZipBytes()
+ return bytes.NewReader(b), int64(len(b))
+}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index fdbd16da0..55f3dcfb8 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -27,10 +27,11 @@ const (
fileHeaderSignature = 0x04034b50
directoryHeaderSignature = 0x02014b50
directoryEndSignature = 0x06054b50
- fileHeaderLen = 30 // + filename + extra
- directoryHeaderLen = 46 // + filename + extra + comment
- directoryEndLen = 22 // + comment
- dataDescriptorLen = 12
+ dataDescriptorSignature = 0x08074b50 // de-facto standard; required by OS X Finder
+ fileHeaderLen = 30 // + filename + extra
+ directoryHeaderLen = 46 // + filename + extra + comment
+ directoryEndLen = 22 // + comment
+ dataDescriptorLen = 16 // four uint32: descriptor signature, crc32, compressed size, size
// Constants for the first byte in CreatorVersion
creatorFAT = 0
diff --git a/src/pkg/archive/zip/testdata/crc32-not-streamed.zip b/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
new file mode 100644
index 000000000..f268d8873
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
new file mode 100644
index 000000000..c3d593f44
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
new file mode 100644
index 000000000..bcfe121bb
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/r.zip b/src/pkg/archive/zip/testdata/r.zip
deleted file mode 100644
index ea0fa2ffc..000000000
--- a/src/pkg/archive/zip/testdata/r.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
index b2cc55bc9..45eb6bd73 100644
--- a/src/pkg/archive/zip/writer.go
+++ b/src/pkg/archive/zip/writer.go
@@ -224,6 +224,7 @@ func (w *fileWriter) close() error {
// write data descriptor
var buf [dataDescriptorLen]byte
b := writeBuf(buf[:])
+ b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X
b.uint32(fh.CRC32)
b.uint32(fh.CompressedSize)
b.uint32(fh.UncompressedSize)
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
index 88e5211ff..8b1c4dfd2 100644
--- a/src/pkg/archive/zip/writer_test.go
+++ b/src/pkg/archive/zip/writer_test.go
@@ -108,7 +108,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
if f.Name != wt.Name {
t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
}
- testFileMode(t, f, wt.Mode)
+ testFileMode(t, wt.Name, f, wt.Mode)
rc, err := f.Open()
if err != nil {
t.Fatal("opening:", err)
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index 25f7a920c..4ba0bf874 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -198,14 +198,6 @@ func (c *Config) time() time.Time {
return t()
}
-func (c *Config) rootCAs() *x509.CertPool {
- s := c.RootCAs
- if s == nil {
- s = defaultRoots()
- }
- return s
-}
-
func (c *Config) cipherSuites() []uint16 {
s := c.CipherSuites
if s == nil {
@@ -311,28 +303,16 @@ func defaultConfig() *Config {
return &emptyConfig
}
-var once sync.Once
-
-func defaultRoots() *x509.CertPool {
- once.Do(initDefaults)
- return varDefaultRoots
-}
+var (
+ once sync.Once
+ varDefaultCipherSuites []uint16
+)
func defaultCipherSuites() []uint16 {
- once.Do(initDefaults)
+ once.Do(initDefaultCipherSuites)
return varDefaultCipherSuites
}
-func initDefaults() {
- initDefaultRoots()
- initDefaultCipherSuites()
-}
-
-var (
- varDefaultRoots *x509.CertPool
- varDefaultCipherSuites []uint16
-)
-
func initDefaultCipherSuites() {
varDefaultCipherSuites = make([]uint16, len(cipherSuites))
for i, suite := range cipherSuites {
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 0d7b806ff..2877f1738 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -102,7 +102,7 @@ func (c *Conn) clientHandshake() error {
if !c.config.InsecureSkipVerify {
opts := x509.VerifyOptions{
- Roots: c.config.rootCAs(),
+ Roots: c.config.RootCAs,
CurrentTime: c.config.time(),
DNSName: c.config.ServerName,
Intermediates: x509.NewCertPool(),
@@ -166,8 +166,11 @@ func (c *Conn) clientHandshake() error {
}
var certToSend *Certificate
+ var certRequested bool
certReq, ok := msg.(*certificateRequestMsg)
if ok {
+ certRequested = true
+
// RFC 4346 on the certificateAuthorities field:
// A list of the distinguished names of acceptable certificate
// authorities. These distinguished names may specify a desired
@@ -238,9 +241,14 @@ func (c *Conn) clientHandshake() error {
}
finishedHash.Write(shd.marshal())
- if certToSend != nil {
+ // If the server requested a certificate then we have to send a
+ // Certificate message, even if it's empty because we don't have a
+ // certificate to send.
+ if certRequested {
certMsg = new(certificateMsg)
- certMsg.certificates = certToSend.Certificate
+ if certToSend != nil {
+ certMsg.certificates = certToSend.Certificate
+ }
finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index bd31d31ae..08a0ccb09 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -143,7 +143,7 @@ func testServerScript(t *testing.T, name string, serverScript [][]byte, config *
if peers != nil {
gotpeers := <-pchan
if len(peers) == len(gotpeers) {
- for i, _ := range peers {
+ for i := range peers {
if !peers[i].Equal(gotpeers[i]) {
t.Fatalf("%s: mismatch on peer cert %d", name, i)
}
diff --git a/src/pkg/crypto/tls/root_test.go b/src/pkg/crypto/tls/root_test.go
index 95a89d843..e61c21851 100644
--- a/src/pkg/crypto/tls/root_test.go
+++ b/src/pkg/crypto/tls/root_test.go
@@ -5,25 +5,25 @@
package tls
import (
+ "crypto/x509"
+ "runtime"
"testing"
)
var tlsServers = []string{
- "google.com:443",
- "github.com:443",
- "twitter.com:443",
+ "google.com",
+ "github.com",
+ "twitter.com",
}
func TestOSCertBundles(t *testing.T) {
- defaultRoots()
-
if testing.Short() {
t.Logf("skipping certificate tests in short mode")
return
}
for _, addr := range tlsServers {
- conn, err := Dial("tcp", addr, nil)
+ conn, err := Dial("tcp", addr+":443", &Config{ServerName: addr})
if err != nil {
t.Errorf("unable to verify %v: %v", addr, err)
continue
@@ -34,3 +34,28 @@ func TestOSCertBundles(t *testing.T) {
}
}
}
+
+func TestCertHostnameVerifyWindows(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ return
+ }
+
+ if testing.Short() {
+ t.Logf("skipping certificate tests in short mode")
+ return
+ }
+
+ for _, addr := range tlsServers {
+ cfg := &Config{ServerName: "example.com"}
+ conn, err := Dial("tcp", addr+":443", cfg)
+ if err == nil {
+ conn.Close()
+ t.Errorf("should fail to verify for example.com: %v", addr)
+ continue
+ }
+ _, ok := err.(x509.HostnameError)
+ if !ok {
+ t.Errorf("error type mismatch, got: %v", err)
+ }
+ }
+}
diff --git a/src/pkg/crypto/tls/root_windows.go b/src/pkg/crypto/tls/root_windows.go
deleted file mode 100644
index 319309ae6..000000000
--- a/src/pkg/crypto/tls/root_windows.go
+++ /dev/null
@@ -1,47 +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.
-
-package tls
-
-import (
- "crypto/x509"
- "syscall"
- "unsafe"
-)
-
-func loadStore(roots *x509.CertPool, name string) {
- store, err := syscall.CertOpenSystemStore(syscall.InvalidHandle, syscall.StringToUTF16Ptr(name))
- if err != nil {
- return
- }
- defer syscall.CertCloseStore(store, 0)
-
- var cert *syscall.CertContext
- for {
- cert, err = syscall.CertEnumCertificatesInStore(store, cert)
- if err != nil {
- return
- }
-
- buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
- // ParseCertificate requires its own copy of certificate data to keep.
- buf2 := make([]byte, cert.Length)
- copy(buf2, buf)
- if c, err := x509.ParseCertificate(buf2); err == nil {
- roots.AddCert(c)
- }
- }
-}
-
-func initDefaultRoots() {
- roots := x509.NewCertPool()
-
- // Roots
- loadStore(roots, "ROOT")
-
- // Intermediates
- loadStore(roots, "CA")
-
- varDefaultRoots = roots
-}
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 9184e8e81..09df5ad44 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package tls partially implements the TLS 1.1 protocol, as specified in RFC
-// 4346.
+// Package tls partially implements TLS 1.0, as specified in RFC 2246.
package tls
import (
@@ -98,7 +97,9 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
if config == nil {
config = defaultConfig()
}
- if config.ServerName != "" {
+ // If no ServerName is set, infer the ServerName
+ // from the hostname we're connecting to.
+ if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
c := *config
c.ServerName = hostname
diff --git a/src/pkg/crypto/x509/pkcs1.go b/src/pkg/crypto/x509/pkcs1.go
index 3aaa8c583..873d3966e 100644
--- a/src/pkg/crypto/x509/pkcs1.go
+++ b/src/pkg/crypto/x509/pkcs1.go
@@ -24,7 +24,7 @@ type pkcs1PrivateKey struct {
Dq *big.Int `asn1:"optional"`
Qinv *big.Int `asn1:"optional"`
- AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
}
type pkcs1AdditionalRSAPrime struct {
diff --git a/src/pkg/crypto/x509/root.go b/src/pkg/crypto/x509/root.go
new file mode 100644
index 000000000..8aae14e09
--- /dev/null
+++ b/src/pkg/crypto/x509/root.go
@@ -0,0 +1,17 @@
+// 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 x509
+
+import "sync"
+
+var (
+ once sync.Once
+ systemRoots *CertPool
+)
+
+func systemRootsPool() *CertPool {
+ once.Do(initSystemRoots)
+ return systemRoots
+}
diff --git a/src/pkg/crypto/tls/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
index 911a9a62e..0f99581e8 100644
--- a/src/pkg/crypto/tls/root_darwin.go
+++ b/src/pkg/crypto/x509/root_darwin.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.
-package tls
+package x509
/*
#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
@@ -59,13 +59,14 @@ int FetchPEMRoots(CFDataRef *pemRoots) {
}
*/
import "C"
-import (
- "crypto/x509"
- "unsafe"
-)
+import "unsafe"
-func initDefaultRoots() {
- roots := x509.NewCertPool()
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ roots := NewCertPool()
var data C.CFDataRef = nil
err := C.FetchPEMRoots(&data)
@@ -75,5 +76,5 @@ func initDefaultRoots() {
roots.AppendCertsFromPEM(buf)
}
- varDefaultRoots = roots
+ systemRoots = roots
}
diff --git a/src/pkg/crypto/tls/root_stub.go b/src/pkg/crypto/x509/root_stub.go
index ee2c3e017..568004108 100644
--- a/src/pkg/crypto/tls/root_stub.go
+++ b/src/pkg/crypto/x509/root_stub.go
@@ -4,7 +4,12 @@
// +build plan9 darwin,!cgo
-package tls
+package x509
-func initDefaultRoots() {
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ systemRoots = NewCertPool()
}
diff --git a/src/pkg/crypto/tls/root_unix.go b/src/pkg/crypto/x509/root_unix.go
index acaf3dd9d..76e79f494 100644
--- a/src/pkg/crypto/tls/root_unix.go
+++ b/src/pkg/crypto/x509/root_unix.go
@@ -4,12 +4,9 @@
// +build freebsd linux openbsd netbsd
-package tls
+package x509
-import (
- "crypto/x509"
- "io/ioutil"
-)
+import "io/ioutil"
// Possible certificate files; stop after finding one.
var certFiles = []string{
@@ -20,8 +17,12 @@ var certFiles = []string{
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
}
-func initDefaultRoots() {
- roots := x509.NewCertPool()
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func initSystemRoots() {
+ roots := NewCertPool()
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
if err == nil {
@@ -29,5 +30,6 @@ func initDefaultRoots() {
break
}
}
- varDefaultRoots = roots
+
+ systemRoots = roots
}
diff --git a/src/pkg/crypto/x509/root_windows.go b/src/pkg/crypto/x509/root_windows.go
new file mode 100644
index 000000000..7e8f2af4b
--- /dev/null
+++ b/src/pkg/crypto/x509/root_windows.go
@@ -0,0 +1,226 @@
+// 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 x509
+
+import (
+ "errors"
+ "syscall"
+ "unsafe"
+)
+
+// Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
+// certificate store containing itself and all of the intermediate certificates specified
+// in the opts.Intermediates CertPool.
+//
+// A pointer to the in-memory store is available in the returned CertContext's Store field.
+// The store is automatically freed when the CertContext is freed using
+// syscall.CertFreeCertificateContext.
+func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
+ var storeCtx *syscall.CertContext
+
+ leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(leafCtx)
+
+ handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertCloseStore(handle, 0)
+
+ err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts.Intermediates != nil {
+ for _, intermediate := range opts.Intermediates.certs {
+ ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
+ if err != nil {
+ return nil, err
+ }
+
+ err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
+ syscall.CertFreeCertificateContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return storeCtx, nil
+}
+
+// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
+func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
+ if simpleChain == nil || count == 0 {
+ return nil, errors.New("x509: invalid simple chain")
+ }
+
+ simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
+ lastChain := simpleChains[count-1]
+ elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
+ for i := 0; i < int(lastChain.NumElements); i++ {
+ // Copy the buf, since ParseCertificate does not create its own copy.
+ cert := elements[i].CertContext
+ encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
+ buf := make([]byte, cert.Length)
+ copy(buf, encodedCert[:])
+ parsedCert, err := ParseCertificate(buf)
+ if err != nil {
+ return nil, err
+ }
+ chain = append(chain, parsedCert)
+ }
+
+ return chain, nil
+}
+
+// checkChainTrustStatus checks the trust status of the certificate chain, translating
+// any errors it finds into Go errors in the process.
+func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
+ if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
+ status := chainCtx.TrustStatus.ErrorStatus
+ switch status {
+ case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
+ return CertificateInvalidError{c, Expired}
+ default:
+ return UnknownAuthorityError{c}
+ }
+ }
+ return nil
+}
+
+// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
+// use as a certificate chain for a SSL/TLS server.
+func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
+ sslPara := &syscall.SSLExtraCertChainPolicyPara{
+ AuthType: syscall.AUTHTYPE_SERVER,
+ ServerName: syscall.StringToUTF16Ptr(opts.DNSName),
+ }
+ sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
+
+ para := &syscall.CertChainPolicyPara{
+ ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
+ }
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ status := syscall.CertChainPolicyStatus{}
+ err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
+ if err != nil {
+ return err
+ }
+
+ // TODO(mkrautz): use the lChainIndex and lElementIndex fields
+ // of the CertChainPolicyStatus to provide proper context, instead
+ // using c.
+ if status.Error != 0 {
+ switch status.Error {
+ case syscall.CERT_E_EXPIRED:
+ return CertificateInvalidError{c, Expired}
+ case syscall.CERT_E_CN_NO_MATCH:
+ return HostnameError{c, opts.DNSName}
+ case syscall.CERT_E_UNTRUSTEDROOT:
+ return UnknownAuthorityError{c}
+ default:
+ return UnknownAuthorityError{c}
+ }
+ }
+
+ return nil
+}
+
+// systemVerify is like Verify, except that it uses CryptoAPI calls
+// to build certificate chains and verify them.
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ hasDNSName := opts != nil && len(opts.DNSName) > 0
+
+ storeCtx, err := createStoreContext(c, opts)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(storeCtx)
+
+ para := new(syscall.CertChainPara)
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ // If there's a DNSName set in opts, assume we're verifying
+ // a certificate from a TLS server.
+ if hasDNSName {
+ oids := []*byte{
+ &syscall.OID_PKIX_KP_SERVER_AUTH[0],
+ // Both IE and Chrome allow certificates with
+ // Server Gated Crypto as well. Some certificates
+ // in the wild require them.
+ &syscall.OID_SERVER_GATED_CRYPTO[0],
+ &syscall.OID_SGC_NETSCAPE[0],
+ }
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
+ para.RequestedUsage.Usage.Length = uint32(len(oids))
+ para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
+ } else {
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
+ para.RequestedUsage.Usage.Length = 0
+ para.RequestedUsage.Usage.UsageIdentifiers = nil
+ }
+
+ var verifyTime *syscall.Filetime
+ if opts != nil && !opts.CurrentTime.IsZero() {
+ ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
+ verifyTime = &ft
+ }
+
+ // CertGetCertificateChain will traverse Windows's root stores
+ // in an attempt to build a verified certificate chain. Once
+ // it has found a verified chain, it stops. MSDN docs on
+ // CERT_CHAIN_CONTEXT:
+ //
+ // When a CERT_CHAIN_CONTEXT is built, the first simple chain
+ // begins with an end certificate and ends with a self-signed
+ // certificate. If that self-signed certificate is not a root
+ // or otherwise trusted certificate, an attempt is made to
+ // build a new chain. CTLs are used to create the new chain
+ // beginning with the self-signed certificate from the original
+ // chain as the end certificate of the new chain. This process
+ // continues building additional simple chains until the first
+ // self-signed certificate is a trusted certificate or until
+ // an additional simple chain cannot be built.
+ //
+ // The result is that we'll only get a single trusted chain to
+ // return to our caller.
+ var chainCtx *syscall.CertChainContext
+ err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateChain(chainCtx)
+
+ err = checkChainTrustStatus(c, chainCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if hasDNSName {
+ err = checkChainSSLServerPolicy(c, chainCtx, opts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
+ if err != nil {
+ return nil, err
+ }
+
+ chains = append(chains, chain)
+
+ return chains, nil
+}
+
+func initSystemRoots() {
+ systemRoots = NewCertPool()
+}
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 3859dd8d4..307c5ef03 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -5,6 +5,7 @@
package x509
import (
+ "runtime"
"strings"
"time"
"unicode/utf8"
@@ -23,6 +24,9 @@ const (
// certificate has a name constraint which doesn't include the name
// being checked.
CANotAuthorizedForThisName
+ // TooManyIntermediates results when a path length constraint is
+ // violated.
+ TooManyIntermediates
)
// CertificateInvalidError results when an odd error occurs. Users of this
@@ -40,6 +44,8 @@ func (e CertificateInvalidError) Error() string {
return "x509: certificate has expired or is not yet valid"
case CANotAuthorizedForThisName:
return "x509: a root or intermediate certificate is not authorized to sign in this domain"
+ case TooManyIntermediates:
+ return "x509: too many intermediates for path length constraint"
}
return "x509: unknown error"
}
@@ -76,7 +82,7 @@ func (e UnknownAuthorityError) Error() string {
type VerifyOptions struct {
DNSName string
Intermediates *CertPool
- Roots *CertPool
+ Roots *CertPool // if nil, the system roots are used
CurrentTime time.Time // if zero, the current time is used
}
@@ -87,7 +93,7 @@ const (
)
// isValid performs validity checks on the c.
-func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
+func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
now := opts.CurrentTime
if now.IsZero() {
now = time.Now()
@@ -130,26 +136,44 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
return CertificateInvalidError{c, NotAuthorizedToSign}
}
+ if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
+ numIntermediates := len(currentChain) - 1
+ if numIntermediates > c.MaxPathLen {
+ return CertificateInvalidError{c, TooManyIntermediates}
+ }
+ }
+
return nil
}
// Verify attempts to verify c by building one or more chains from c to a
-// certificate in opts.roots, using certificates in opts.Intermediates if
+// certificate in opts.Roots, using certificates in opts.Intermediates if
// needed. If successful, it returns one or more chains where the first
// element of the chain is c and the last element is from opts.Roots.
//
// WARNING: this doesn't do any revocation checking.
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
- err = c.isValid(leafCertificate, &opts)
+ // Use Windows's own verification and chain building.
+ if opts.Roots == nil && runtime.GOOS == "windows" {
+ return c.systemVerify(&opts)
+ }
+
+ if opts.Roots == nil {
+ opts.Roots = systemRootsPool()
+ }
+
+ err = c.isValid(leafCertificate, nil, &opts)
if err != nil {
return
}
+
if len(opts.DNSName) > 0 {
err = c.VerifyHostname(opts.DNSName)
if err != nil {
return
}
}
+
return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
}
@@ -163,7 +187,7 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
for _, rootNum := range opts.Roots.findVerifiedParents(c) {
root := opts.Roots.certs[rootNum]
- err = root.isValid(rootCertificate, opts)
+ err = root.isValid(rootCertificate, currentChain, opts)
if err != nil {
continue
}
@@ -178,7 +202,7 @@ nextIntermediate:
continue nextIntermediate
}
}
- err = intermediate.isValid(intermediateCertificate, opts)
+ err = intermediate.isValid(intermediateCertificate, currentChain, opts)
if err != nil {
continue
}
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index 2cdd66a55..7b171b291 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -8,6 +8,7 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"errors"
+ "runtime"
"strings"
"testing"
"time"
@@ -19,7 +20,7 @@ type verifyTest struct {
roots []string
currentTime int64
dnsName string
- nilRoots bool
+ systemSkip bool
errorCallback func(*testing.T, int, error) bool
expectedChains [][]string
@@ -60,14 +61,6 @@ var verifyTests = []verifyTest{
{
leaf: googleLeaf,
intermediates: []string{thawteIntermediate},
- nilRoots: true, // verifies that we don't crash
- currentTime: 1302726541,
- dnsName: "www.google.com",
- errorCallback: expectAuthorityUnknown,
- },
- {
- leaf: googleLeaf,
- intermediates: []string{thawteIntermediate},
roots: []string{verisignRoot},
currentTime: 1,
dnsName: "www.example.com",
@@ -80,6 +73,9 @@ var verifyTests = []verifyTest{
currentTime: 1302726541,
dnsName: "www.google.com",
+ // Skip when using systemVerify, since Windows
+ // *will* find the missing intermediate cert.
+ systemSkip: true,
errorCallback: expectAuthorityUnknown,
},
{
@@ -109,6 +105,9 @@ var verifyTests = []verifyTest{
roots: []string{startComRoot},
currentTime: 1302726541,
+ // Skip when using systemVerify, since Windows
+ // can only return a single chain to us (for now).
+ systemSkip: true,
expectedChains: [][]string{
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
@@ -148,23 +147,26 @@ func certificateFromPEM(pemBytes string) (*Certificate, error) {
return ParseCertificate(block.Bytes)
}
-func TestVerify(t *testing.T) {
+func testVerify(t *testing.T, useSystemRoots bool) {
for i, test := range verifyTests {
+ if useSystemRoots && test.systemSkip {
+ continue
+ }
+
opts := VerifyOptions{
- Roots: NewCertPool(),
Intermediates: NewCertPool(),
DNSName: test.dnsName,
CurrentTime: time.Unix(test.currentTime, 0),
}
- if test.nilRoots {
- opts.Roots = nil
- }
- for j, root := range test.roots {
- ok := opts.Roots.AppendCertsFromPEM([]byte(root))
- if !ok {
- t.Errorf("#%d: failed to parse root #%d", i, j)
- return
+ if !useSystemRoots {
+ opts.Roots = NewCertPool()
+ for j, root := range test.roots {
+ ok := opts.Roots.AppendCertsFromPEM([]byte(root))
+ if !ok {
+ t.Errorf("#%d: failed to parse root #%d", i, j)
+ return
+ }
}
}
@@ -225,6 +227,19 @@ func TestVerify(t *testing.T) {
}
}
+func TestGoVerify(t *testing.T) {
+ testVerify(t, false)
+}
+
+func TestSystemVerify(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ t.Logf("skipping verify test using system APIs on %q", runtime.GOOS)
+ return
+ }
+
+ testVerify(t, true)
+}
+
func chainToDebugString(chain []*Certificate) string {
var chainStr string
for _, cert := range chain {
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index f5da86b54..8dae7e7fc 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -429,7 +429,7 @@ func (h UnhandledCriticalExtension) Error() string {
type basicConstraints struct {
IsCA bool `asn1:"optional"`
- MaxPathLen int `asn1:"optional"`
+ MaxPathLen int `asn1:"optional,default:-1"`
}
// RFC 5280 4.2.1.4
diff --git a/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
index 7f986b80f..2f5280db8 100644
--- a/src/pkg/database/sql/driver/driver.go
+++ b/src/pkg/database/sql/driver/driver.go
@@ -43,6 +43,17 @@ type Driver interface {
// documented.
var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
+// ErrBadConn should be returned by a driver to signal to the sql
+// package that a driver.Conn is in a bad state (such as the server
+// having earlier closed the connection) and the sql package should
+// retry on a new connection.
+//
+// To prevent duplicate operations, ErrBadConn should NOT be returned
+// if there's a possibility that the database server might have
+// performed the operation. Even if the server sends back an error,
+// you shouldn't return ErrBadConn.
+var ErrBadConn = errors.New("driver: bad connection")
+
// Execer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Execer, the db package's DB.Exec will
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
index fc63f0374..184e7756c 100644
--- a/src/pkg/database/sql/fakedb_test.go
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -82,6 +82,7 @@ type fakeConn struct {
mu sync.Mutex
stmtsMade int
stmtsClosed int
+ numPrepare int
}
func (c *fakeConn) incrStat(v *int) {
@@ -208,10 +209,13 @@ func (c *fakeConn) Begin() (driver.Tx, error) {
func (c *fakeConn) Close() error {
if c.currTx != nil {
- return errors.New("can't close; in a Transaction")
+ return errors.New("can't close fakeConn; in a Transaction")
}
if c.db == nil {
- return errors.New("can't close; already closed")
+ return errors.New("can't close fakeConn; already closed")
+ }
+ if c.stmtsMade > c.stmtsClosed {
+ return errors.New("can't close; dangling statement(s)")
}
c.db = nil
return nil
@@ -249,6 +253,7 @@ func errf(msg string, args ...interface{}) error {
// just a limitation for fakedb)
func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
if len(parts) != 3 {
+ stmt.Close()
return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
}
stmt.table = parts[0]
@@ -259,14 +264,17 @@ func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
nameVal := strings.Split(colspec, "=")
if len(nameVal) != 2 {
+ stmt.Close()
return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
}
column, value := nameVal[0], nameVal[1]
_, ok := c.db.columnType(stmt.table, column)
if !ok {
+ stmt.Close()
return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
}
if value != "?" {
+ stmt.Close()
return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
stmt.table, column)
}
@@ -279,12 +287,14 @@ func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, e
// parts are table|col=type,col2=type2
func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
if len(parts) != 2 {
+ stmt.Close()
return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
}
stmt.table = parts[0]
for n, colspec := range strings.Split(parts[1], ",") {
nameType := strings.Split(colspec, "=")
if len(nameType) != 2 {
+ stmt.Close()
return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
}
stmt.colName = append(stmt.colName, nameType[0])
@@ -296,17 +306,20 @@ func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, e
// parts are table|col=?,col2=val
func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
if len(parts) != 2 {
+ stmt.Close()
return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
}
stmt.table = parts[0]
for n, colspec := range strings.Split(parts[1], ",") {
nameVal := strings.Split(colspec, "=")
if len(nameVal) != 2 {
+ stmt.Close()
return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n)
}
column, value := nameVal[0], nameVal[1]
ctype, ok := c.db.columnType(stmt.table, column)
if !ok {
+ stmt.Close()
return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column)
}
stmt.colName = append(stmt.colName, column)
@@ -322,10 +335,12 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
case "int32":
i, err := strconv.Atoi(value)
if err != nil {
+ stmt.Close()
return nil, errf("invalid conversion to int32 from %q", value)
}
subsetVal = int64(i) // int64 is a subset type, but not int32
default:
+ stmt.Close()
return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype)
}
stmt.colValue = append(stmt.colValue, subsetVal)
@@ -339,6 +354,7 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
+ c.numPrepare++
if c.db == nil {
panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
}
@@ -360,6 +376,7 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
case "INSERT":
return c.prepareInsert(stmt, parts)
default:
+ stmt.Close()
return nil, errf("unsupported command type %q", cmd)
}
return stmt, nil
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
index 62b551d89..51a357b37 100644
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -175,6 +175,16 @@ var ErrNoRows = errors.New("sql: no rows in result set")
// DB is a database handle. It's safe for concurrent use by multiple
// goroutines.
+//
+// If the underlying database driver has the concept of a connection
+// and per-connection session state, the sql package manages creating
+// and freeing connections automatically, including maintaining a free
+// pool of idle connections. If observing session state is required,
+// either do not share a *DB between multiple concurrent goroutines or
+// create and observe all state only within a transaction. Once
+// DB.Open is called, the returned Tx is bound to a single isolated
+// connection. Once Tx.Commit or Tx.Rollback is called, that
+// connection is returned to DB's idle connection pool.
type DB struct {
driver driver.Driver
dsn string
@@ -241,34 +251,56 @@ func (db *DB) conn() (driver.Conn, error) {
func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
db.mu.Lock()
defer db.mu.Unlock()
- for n, conn := range db.freeConn {
- if conn == wanted {
- db.freeConn[n] = db.freeConn[len(db.freeConn)-1]
- db.freeConn = db.freeConn[:len(db.freeConn)-1]
- return wanted, true
+ for i, conn := range db.freeConn {
+ if conn != wanted {
+ continue
}
+ db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
+ db.freeConn = db.freeConn[:len(db.freeConn)-1]
+ return wanted, true
}
return nil, false
}
-func (db *DB) putConn(c driver.Conn) {
+// putConnHook is a hook for testing.
+var putConnHook func(*DB, driver.Conn)
+
+// putConn adds a connection to the db's free pool.
+// err is optionally the last error that occured on this connection.
+func (db *DB) putConn(c driver.Conn, err error) {
+ if err == driver.ErrBadConn {
+ // Don't reuse bad connections.
+ return
+ }
db.mu.Lock()
- defer db.mu.Unlock()
+ if putConnHook != nil {
+ putConnHook(db, c)
+ }
if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
db.freeConn = append(db.freeConn, c)
+ db.mu.Unlock()
return
}
- db.closeConn(c) // TODO(bradfitz): release lock before calling this?
-}
-
-func (db *DB) closeConn(c driver.Conn) {
- // TODO: check to see if we need this Conn for any prepared statements
- // that are active.
+ // TODO: check to see if we need this Conn for any prepared
+ // statements which are still active?
+ db.mu.Unlock()
c.Close()
}
// Prepare creates a prepared statement for later execution.
func (db *DB) Prepare(query string) (*Stmt, error) {
+ var stmt *Stmt
+ var err error
+ for i := 0; i < 10; i++ {
+ stmt, err = db.prepare(query)
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return stmt, err
+}
+
+func (db *DB) prepare(query string) (stmt *Stmt, err error) {
// TODO: check if db.driver supports an optional
// driver.Preparer interface and call that instead, if so,
// otherwise we make a prepared statement that's bound
@@ -279,12 +311,12 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
if err != nil {
return nil, err
}
- defer db.putConn(ci)
+ defer db.putConn(ci, err)
si, err := ci.Prepare(query)
if err != nil {
return nil, err
}
- stmt := &Stmt{
+ stmt = &Stmt{
db: db,
query: query,
css: []connStmt{{ci, si}},
@@ -295,15 +327,22 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
// Exec executes a query without returning any rows.
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
sargs, err := subsetTypeArgs(args)
- if err != nil {
- return nil, err
+ var res Result
+ for i := 0; i < 10; i++ {
+ res, err = db.exec(query, sargs)
+ if err != driver.ErrBadConn {
+ break
+ }
}
+ return res, err
+}
+func (db *DB) exec(query string, sargs []driver.Value) (res Result, err error) {
ci, err := db.conn()
if err != nil {
return nil, err
}
- defer db.putConn(ci)
+ defer db.putConn(ci, err)
if execer, ok := ci.(driver.Execer); ok {
resi, err := execer.Exec(query, sargs)
@@ -354,13 +393,25 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
// Begin starts a transaction. The isolation level is dependent on
// the driver.
func (db *DB) Begin() (*Tx, error) {
+ var tx *Tx
+ var err error
+ for i := 0; i < 10; i++ {
+ tx, err = db.begin()
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return tx, err
+}
+
+func (db *DB) begin() (tx *Tx, err error) {
ci, err := db.conn()
if err != nil {
return nil, err
}
txi, err := ci.Begin()
if err != nil {
- db.putConn(ci)
+ db.putConn(ci, err)
return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err)
}
return &Tx{
@@ -406,7 +457,7 @@ func (tx *Tx) close() {
panic("double close") // internal error
}
tx.done = true
- tx.db.putConn(tx.ci)
+ tx.db.putConn(tx.ci, nil)
tx.ci = nil
tx.txi = nil
}
@@ -561,9 +612,11 @@ func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
return nil, err
}
rows, err := stmt.Query(args...)
- if err == nil {
- rows.closeStmt = stmt
+ if err != nil {
+ stmt.Close()
+ return nil, err
}
+ rows.closeStmt = stmt
return rows, err
}
@@ -609,7 +662,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
if err != nil {
return nil, err
}
- defer releaseConn()
+ defer releaseConn(nil)
// -1 means the driver doesn't know how to count the number of
// placeholders, so we won't sanity check input here and instead let the
@@ -672,7 +725,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
// connStmt returns a free driver connection on which to execute the
// statement, a function to call to release the connection, and a
// statement bound to that connection.
-func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) {
+func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.Stmt, err error) {
if err = s.stickyErr; err != nil {
return
}
@@ -691,7 +744,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
if err != nil {
return
}
- releaseConn = func() { s.tx.releaseConn() }
+ releaseConn = func(error) { s.tx.releaseConn() }
return ci, releaseConn, s.txsi, nil
}
@@ -700,7 +753,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
for _, v := range s.css {
// TODO(bradfitz): lazily clean up entries in this
// list with dead conns while enumerating
- if _, match = s.db.connIfFree(cs.ci); match {
+ if _, match = s.db.connIfFree(v.ci); match {
cs = v
break
}
@@ -710,22 +763,28 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
// Make a new conn if all are busy.
// TODO(bradfitz): or wait for one? make configurable later?
if !match {
- ci, err := s.db.conn()
- if err != nil {
- return nil, nil, nil, err
- }
- si, err := ci.Prepare(s.query)
- if err != nil {
- return nil, nil, nil, err
+ for i := 0; ; i++ {
+ ci, err := s.db.conn()
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ si, err := ci.Prepare(s.query)
+ if err == driver.ErrBadConn && i < 10 {
+ continue
+ }
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ s.mu.Lock()
+ cs = connStmt{ci, si}
+ s.css = append(s.css, cs)
+ s.mu.Unlock()
+ break
}
- s.mu.Lock()
- cs = connStmt{ci, si}
- s.css = append(s.css, cs)
- s.mu.Unlock()
}
conn := cs.ci
- releaseConn = func() { s.db.putConn(conn) }
+ releaseConn = func(err error) { s.db.putConn(conn, err) }
return conn, releaseConn, cs.si, nil
}
@@ -749,7 +808,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
}
rowsi, err := si.Query(sargs)
if err != nil {
- s.db.putConn(ci)
+ releaseConn(err)
return nil, err
}
// Note: ownership of ci passes to the *Rows, to be freed
@@ -800,7 +859,7 @@ func (s *Stmt) Close() error {
for _, v := range s.css {
if ci, match := s.db.connIfFree(v.ci); match {
v.si.Close()
- s.db.putConn(ci)
+ s.db.putConn(ci, nil)
} else {
// TODO(bradfitz): care that we can't close
// this statement because the statement's
@@ -827,7 +886,7 @@ func (s *Stmt) Close() error {
type Rows struct {
db *DB
ci driver.Conn // owned; must call putconn when closed to release
- releaseConn func()
+ releaseConn func(error)
rowsi driver.Rows
closed bool
@@ -939,7 +998,7 @@ func (rs *Rows) Close() error {
}
rs.closed = true
err := rs.rowsi.Close()
- rs.releaseConn()
+ rs.releaseConn(err)
if rs.closeStmt != nil {
rs.closeStmt.Close()
}
@@ -963,7 +1022,7 @@ func (r *Row) Scan(dest ...interface{}) error {
}
// TODO(bradfitz): for now we need to defensively clone all
- // []byte that the driver returned (not permitting
+ // []byte that the driver returned (not permitting
// *RawBytes in Rows.Scan), since we're about to close
// the Rows in our defer, when we return from this function.
// the contract with the driver.Next(...) interface is that it
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index c985a10be..b29670586 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -5,13 +5,35 @@
package sql
import (
+ "database/sql/driver"
"fmt"
"reflect"
+ "runtime"
"strings"
"testing"
"time"
)
+func init() {
+ type dbConn struct {
+ db *DB
+ c driver.Conn
+ }
+ freedFrom := make(map[dbConn]string)
+ putConnHook = func(db *DB, c driver.Conn) {
+ for _, oc := range db.freeConn {
+ if oc == c {
+ // print before panic, as panic may get lost due to conflicting panic
+ // (all goroutines asleep) elsewhere, since we might not unlock
+ // the mutex in freeConn here.
+ println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
+ panic("double free of conn.")
+ }
+ }
+ freedFrom[dbConn{db, c}] = stack()
+ }
+}
+
const fakeDBName = "foo"
var chrisBirthday = time.Unix(123456789, 0)
@@ -47,9 +69,19 @@ func closeDB(t *testing.T, db *DB) {
}
}
+// numPrepares assumes that db has exactly 1 idle conn and returns
+// its count of calls to Prepare
+func numPrepares(t *testing.T, db *DB) int {
+ if n := len(db.freeConn); n != 1 {
+ t.Fatalf("free conns = %d; want 1", n)
+ }
+ return db.freeConn[0].(*fakeConn).numPrepare
+}
+
func TestQuery(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
rows, err := db.Query("SELECT|people|age,name|")
if err != nil {
t.Fatalf("Query: %v", err)
@@ -83,7 +115,10 @@ func TestQuery(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
if n := len(db.freeConn); n != 1 {
- t.Errorf("free conns after query hitting EOF = %d; want 1", n)
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
}
}
@@ -216,6 +251,7 @@ func TestStatementQueryRow(t *testing.T) {
if err != nil {
t.Fatalf("Prepare: %v", err)
}
+ defer stmt.Close()
var age int
for n, tt := range []struct {
name string
@@ -256,6 +292,7 @@ func TestExec(t *testing.T) {
if err != nil {
t.Errorf("Stmt, err = %v, %v", stmt, err)
}
+ defer stmt.Close()
type execTest struct {
args []interface{}
@@ -297,11 +334,14 @@ func TestTxStmt(t *testing.T) {
if err != nil {
t.Fatalf("Stmt, err = %v, %v", stmt, err)
}
+ defer stmt.Close()
tx, err := db.Begin()
if err != nil {
t.Fatalf("Begin = %v", err)
}
- _, err = tx.Stmt(stmt).Exec("Bobby", 7)
+ txs := tx.Stmt(stmt)
+ defer txs.Close()
+ _, err = txs.Exec("Bobby", 7)
if err != nil {
t.Fatalf("Exec = %v", err)
}
@@ -330,6 +370,7 @@ func TestTxQuery(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+ defer r.Close()
if !r.Next() {
if r.Err() != nil {
@@ -345,6 +386,22 @@ func TestTxQuery(t *testing.T) {
}
}
+func TestTxQueryInvalid(t *testing.T) {
+ db := newTestDB(t, "")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ _, err = tx.Query("SELECT|t1|name|")
+ if err == nil {
+ t.Fatal("Error expected")
+ }
+}
+
// Tests fix for issue 2542, that we release a lock when querying on
// a closed connection.
func TestIssue2542Deadlock(t *testing.T) {
@@ -450,48 +507,48 @@ type nullTestSpec struct {
func TestNullStringParam(t *testing.T) {
spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
- nullTestRow{NullString{"aqua", true}, "", NullString{"aqua", true}},
- nullTestRow{NullString{"brown", false}, "", NullString{"", false}},
- nullTestRow{"chartreuse", "", NullString{"chartreuse", true}},
- nullTestRow{NullString{"darkred", true}, "", NullString{"darkred", true}},
- nullTestRow{NullString{"eel", false}, "", NullString{"", false}},
- nullTestRow{"foo", NullString{"black", false}, nil},
+ {NullString{"aqua", true}, "", NullString{"aqua", true}},
+ {NullString{"brown", false}, "", NullString{"", false}},
+ {"chartreuse", "", NullString{"chartreuse", true}},
+ {NullString{"darkred", true}, "", NullString{"darkred", true}},
+ {NullString{"eel", false}, "", NullString{"", false}},
+ {"foo", NullString{"black", false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullInt64Param(t *testing.T) {
spec := nullTestSpec{"nullint64", "int64", [6]nullTestRow{
- nullTestRow{NullInt64{31, true}, 1, NullInt64{31, true}},
- nullTestRow{NullInt64{-22, false}, 1, NullInt64{0, false}},
- nullTestRow{22, 1, NullInt64{22, true}},
- nullTestRow{NullInt64{33, true}, 1, NullInt64{33, true}},
- nullTestRow{NullInt64{222, false}, 1, NullInt64{0, false}},
- nullTestRow{0, NullInt64{31, false}, nil},
+ {NullInt64{31, true}, 1, NullInt64{31, true}},
+ {NullInt64{-22, false}, 1, NullInt64{0, false}},
+ {22, 1, NullInt64{22, true}},
+ {NullInt64{33, true}, 1, NullInt64{33, true}},
+ {NullInt64{222, false}, 1, NullInt64{0, false}},
+ {0, NullInt64{31, false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullFloat64Param(t *testing.T) {
spec := nullTestSpec{"nullfloat64", "float64", [6]nullTestRow{
- nullTestRow{NullFloat64{31.2, true}, 1, NullFloat64{31.2, true}},
- nullTestRow{NullFloat64{13.1, false}, 1, NullFloat64{0, false}},
- nullTestRow{-22.9, 1, NullFloat64{-22.9, true}},
- nullTestRow{NullFloat64{33.81, true}, 1, NullFloat64{33.81, true}},
- nullTestRow{NullFloat64{222, false}, 1, NullFloat64{0, false}},
- nullTestRow{10, NullFloat64{31.2, false}, nil},
+ {NullFloat64{31.2, true}, 1, NullFloat64{31.2, true}},
+ {NullFloat64{13.1, false}, 1, NullFloat64{0, false}},
+ {-22.9, 1, NullFloat64{-22.9, true}},
+ {NullFloat64{33.81, true}, 1, NullFloat64{33.81, true}},
+ {NullFloat64{222, false}, 1, NullFloat64{0, false}},
+ {10, NullFloat64{31.2, false}, nil},
}}
nullTestRun(t, spec)
}
func TestNullBoolParam(t *testing.T) {
spec := nullTestSpec{"nullbool", "bool", [6]nullTestRow{
- nullTestRow{NullBool{false, true}, true, NullBool{false, true}},
- nullTestRow{NullBool{true, false}, false, NullBool{false, false}},
- nullTestRow{true, true, NullBool{true, true}},
- nullTestRow{NullBool{true, true}, false, NullBool{true, true}},
- nullTestRow{NullBool{true, false}, true, NullBool{false, false}},
- nullTestRow{true, NullBool{true, false}, nil},
+ {NullBool{false, true}, true, NullBool{false, true}},
+ {NullBool{true, false}, false, NullBool{false, false}},
+ {true, true, NullBool{true, true}},
+ {NullBool{true, true}, false, NullBool{true, true}},
+ {NullBool{true, false}, true, NullBool{false, false}},
+ {true, NullBool{true, false}, nil},
}}
nullTestRun(t, spec)
}
@@ -510,6 +567,7 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
if err != nil {
t.Fatalf("prepare: %v", err)
}
+ defer stmt.Close()
if _, err := stmt.Exec(3, "chris", spec.rows[2].nullParam, spec.rows[2].notNullParam); err != nil {
t.Errorf("exec insert chris: %v", err)
}
@@ -549,3 +607,8 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
}
}
}
+
+func stack() string {
+ buf := make([]byte, 1024)
+ return string(buf[:runtime.Stack(buf, false)])
+}
diff --git a/src/pkg/encoding/asn1/asn1.go b/src/pkg/encoding/asn1/asn1.go
index 4d1ae38c4..3bf81a68c 100644
--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -250,10 +250,14 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
func parseUTCTime(bytes []byte) (ret time.Time, err error) {
s := string(bytes)
ret, err = time.Parse("0601021504Z0700", s)
- if err == nil {
- return
+ if err != nil {
+ ret, err = time.Parse("060102150405Z0700", s)
}
- ret, err = time.Parse("060102150405Z0700", s)
+ if err == nil && ret.Year() >= 2050 {
+ // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
+ ret = ret.AddDate(-100, 0, 0)
+ }
+
return
}
diff --git a/src/pkg/encoding/asn1/asn1_test.go b/src/pkg/encoding/asn1/asn1_test.go
index 92c9eb62d..93803f435 100644
--- a/src/pkg/encoding/asn1/asn1_test.go
+++ b/src/pkg/encoding/asn1/asn1_test.go
@@ -321,7 +321,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
{"default:42", fieldParameters{defaultValue: newInt64(42)}},
{"tag:17", fieldParameters{tag: newInt(17)}},
{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
- {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false}},
+ {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}},
{"set", fieldParameters{set: true}},
}
diff --git a/src/pkg/encoding/asn1/common.go b/src/pkg/encoding/asn1/common.go
index f7cb3acbb..03856bc55 100644
--- a/src/pkg/encoding/asn1/common.go
+++ b/src/pkg/encoding/asn1/common.go
@@ -75,6 +75,7 @@ type fieldParameters struct {
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
stringType int // the string tag to use when marshaling.
set bool // true iff this should be encoded as a SET
+ omitEmpty bool // true iff this should be omitted if empty when marshaling.
// Invariants:
// if explicit is set, tag is non-nil.
@@ -116,6 +117,8 @@ func parseFieldParameters(str string) (ret fieldParameters) {
if ret.tag == nil {
ret.tag = new(int)
}
+ case part == "omitempty":
+ ret.omitEmpty = true
}
}
return
diff --git a/src/pkg/encoding/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index 774bee74b..163bca575 100644
--- a/src/pkg/encoding/asn1/marshal.go
+++ b/src/pkg/encoding/asn1/marshal.go
@@ -463,6 +463,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return marshalField(out, v.Elem(), params)
}
+ if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
+ return
+ }
+
if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
return
}
diff --git a/src/pkg/encoding/asn1/marshal_test.go b/src/pkg/encoding/asn1/marshal_test.go
index a7447f978..f43bcae68 100644
--- a/src/pkg/encoding/asn1/marshal_test.go
+++ b/src/pkg/encoding/asn1/marshal_test.go
@@ -54,6 +54,10 @@ type optionalRawValueTest struct {
A RawValue `asn1:"optional"`
}
+type omitEmptyTest struct {
+ A []string `asn1:"omitempty"`
+}
+
type testSET []int
var PST = time.FixedZone("PST", -8*60*60)
@@ -116,6 +120,8 @@ var marshalTests = []marshalTest{
{rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
{RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
{testSET([]int{10}), "310302010a"},
+ {omitEmptyTest{[]string{}}, "3000"},
+ {omitEmptyTest{[]string{"1"}}, "30053003130131"},
}
func TestMarshal(t *testing.T) {
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index 02f090d53..712e490e6 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package binary implements translation between
-// unsigned integer values and byte sequences
-// and the reading and writing of fixed-size values.
+// Package binary implements translation between numbers and byte sequences
+// and encoding and decoding of varints.
+//
+// Numbers are translated by reading and writing fixed-size values.
// A fixed-size value is either a fixed-size arithmetic
// 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.
package binary
import (
diff --git a/src/pkg/encoding/csv/reader.go b/src/pkg/encoding/csv/reader.go
index 9aa398e58..db4d98852 100644
--- a/src/pkg/encoding/csv/reader.go
+++ b/src/pkg/encoding/csv/reader.go
@@ -92,7 +92,8 @@ var (
// If FieldsPerRecord is positive, Read requires each record to
// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
// the number of fields in the first record, so that future records must
-// have the same field count.
+// have the same field count. If FieldsPerRecord is negative, no check is
+// made and records may have a variable number of fields.
//
// If LazyQuotes is true, a quote may appear in an unquoted field and a
// non-doubled quote may appear in a quoted field.
diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index 0708a83c9..e32a178ab 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -707,6 +707,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
if name == "" {
// Copy the representation of the nil interface value to the target.
// This is horribly unsafe and special.
+ if indir > 0 {
+ p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
*(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.InterfaceData()
return
}
diff --git a/src/pkg/encoding/gob/doc.go b/src/pkg/encoding/gob/doc.go
index c9ad18e76..96885f8de 100644
--- a/src/pkg/encoding/gob/doc.go
+++ b/src/pkg/encoding/gob/doc.go
@@ -226,7 +226,7 @@ where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
See "Gobs of data" for a design discussion of the gob wire format:
-http://blog.golang.org/2011/03/gobs-of-data.html
+http://golang.org/doc/articles/gobs_of_data.html
*/
package gob
diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go
index 050786dfd..c4947cbb8 100644
--- a/src/pkg/encoding/gob/encoder_test.go
+++ b/src/pkg/encoding/gob/encoder_test.go
@@ -694,8 +694,8 @@ type Bug3 struct {
func TestGobPtrSlices(t *testing.T) {
in := []*Bug3{
- &Bug3{1, nil},
- &Bug3{2, nil},
+ {1, nil},
+ {2, nil},
}
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(&in)
diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go
index 83644c033..45240d764 100644
--- a/src/pkg/encoding/gob/gobencdec_test.go
+++ b/src/pkg/encoding/gob/gobencdec_test.go
@@ -573,3 +573,22 @@ func TestGobEncodeIsZero(t *testing.T) {
t.Fatalf("%v != %v", x, y)
}
}
+
+func TestGobEncodePtrError(t *testing.T) {
+ var err error
+ b := new(bytes.Buffer)
+ enc := NewEncoder(b)
+ err = enc.Encode(&err)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ dec := NewDecoder(b)
+ err2 := fmt.Errorf("foo")
+ err = dec.Decode(&err2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if err2 != nil {
+ t.Fatalf("expected nil, got %v", err2)
+ }
+}
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index 5425a3a90..14957b848 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -6,7 +6,7 @@
// RFC 4627.
//
// See "JSON and Go" for an introduction to this package:
-// http://blog.golang.org/2011/01/json-and-go.html
+// http://golang.org/doc/articles/json_and_go.html
package json
import (
@@ -43,7 +43,8 @@ import (
// to keep some browsers from misinterpreting JSON output as HTML.
//
// Array and slice values encode as JSON arrays, except that
-// []byte encodes as a base64-encoded string.
+// []byte encodes as a base64-encoded string, and a nil slice
+// encodes as the null JSON object.
//
// Struct values encode as JSON objects. Each exported struct field
// becomes a member of the object unless
diff --git a/src/pkg/exp/norm/maketables.go b/src/pkg/exp/norm/maketables.go
index bb21bb581..1deedc949 100644
--- a/src/pkg/exp/norm/maketables.go
+++ b/src/pkg/exp/norm/maketables.go
@@ -577,7 +577,7 @@ type decompSet [4]map[string]bool
func makeDecompSet() decompSet {
m := decompSet{}
- for i, _ := range m {
+ for i := range m {
m[i] = make(map[string]bool)
}
return m
@@ -646,7 +646,7 @@ func printCharInfoTables() int {
fmt.Println("const (")
for i, m := range decompSet {
sa := []string{}
- for s, _ := range m {
+ for s := range m {
sa = append(sa, s)
}
sort.Strings(sa)
diff --git a/src/pkg/exp/norm/normalize.go b/src/pkg/exp/norm/normalize.go
index b5cd44abf..c1d74f89d 100644
--- a/src/pkg/exp/norm/normalize.go
+++ b/src/pkg/exp/norm/normalize.go
@@ -356,7 +356,7 @@ func lastBoundary(fd *formInfo, b []byte) int {
return -1
}
if info.size == 0 { // ends with incomplete rune
- if p == 0 { // starts wtih incomplete rune
+ if p == 0 { // starts with incomplete rune
return -1
}
i = p
diff --git a/src/pkg/exp/types/universe.go b/src/pkg/exp/types/universe.go
index 46cff31bc..cb89397b2 100644
--- a/src/pkg/exp/types/universe.go
+++ b/src/pkg/exp/types/universe.go
@@ -102,11 +102,6 @@ func init() {
defType("Pointer")
defFun("Alignof")
- defFun("New")
- defFun("NewArray")
defFun("Offsetof")
- defFun("Reflect")
defFun("Sizeof")
- defFun("Typeof")
- defFun("Unreflect")
}
diff --git a/src/pkg/exp/wingui/Makefile b/src/pkg/exp/wingui/Makefile
deleted file mode 100644
index bf69c98a5..000000000
--- a/src/pkg/exp/wingui/Makefile
+++ /dev/null
@@ -1,24 +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.
-
-GOOS=windows
-
-include ../../../Make.inc
-
-LD:=$(LD) -Hwindowsgui
-
-TARG=wingui
-
-GOFILES=\
- gui.go\
- winapi.go\
- zwinapi.go\
-
-include ../../../Make.cmd
-
-zwinapi.go: winapi.go
- (echo '// +build windows'; \
- $(GOROOT)/src/pkg/syscall/mksyscall_windows.pl $<) \
- | gofmt \
- > $@
diff --git a/src/pkg/exp/wingui/gui.go b/src/pkg/exp/wingui/gui.go
deleted file mode 100644
index 3b79873fa..000000000
--- a/src/pkg/exp/wingui/gui.go
+++ /dev/null
@@ -1,155 +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.
-
-// +build windows
-
-package main
-
-import (
- "fmt"
- "os"
- "syscall"
- "unsafe"
-)
-
-// some help functions
-
-func abortf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stdout, format, a...)
- os.Exit(1)
-}
-
-func abortErrNo(funcname string, err error) {
- errno, _ := err.(syscall.Errno)
- abortf("%s failed: %d %s\n", funcname, uint32(errno), err)
-}
-
-// global vars
-
-var (
- mh syscall.Handle
- bh syscall.Handle
-)
-
-// WinProc called by windows to notify us of all windows events we might be interested in.
-func WndProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) (rc uintptr) {
- switch msg {
- case WM_CREATE:
- var e error
- // CreateWindowEx
- bh, e = CreateWindowEx(
- 0,
- syscall.StringToUTF16Ptr("button"),
- syscall.StringToUTF16Ptr("Quit"),
- WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
- 75, 70, 140, 25,
- hwnd, 1, mh, 0)
- if e != nil {
- abortErrNo("CreateWindowEx", e)
- }
- fmt.Printf("button handle is %x\n", bh)
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- case WM_COMMAND:
- switch syscall.Handle(lparam) {
- case bh:
- e := PostMessage(hwnd, WM_CLOSE, 0, 0)
- if e != nil {
- abortErrNo("PostMessage", e)
- }
- default:
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- }
- case WM_CLOSE:
- DestroyWindow(hwnd)
- case WM_DESTROY:
- PostQuitMessage(0)
- default:
- rc = DefWindowProc(hwnd, msg, wparam, lparam)
- }
- //fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc)
- return
-}
-
-func rungui() int {
- var e error
-
- // GetModuleHandle
- mh, e = GetModuleHandle(nil)
- if e != nil {
- abortErrNo("GetModuleHandle", e)
- }
-
- // Get icon we're going to use.
- myicon, e := LoadIcon(0, IDI_APPLICATION)
- if e != nil {
- abortErrNo("LoadIcon", e)
- }
-
- // Get cursor we're going to use.
- mycursor, e := LoadCursor(0, IDC_ARROW)
- if e != nil {
- abortErrNo("LoadCursor", e)
- }
-
- // Create callback
- wproc := syscall.NewCallback(WndProc)
-
- // RegisterClassEx
- wcname := syscall.StringToUTF16Ptr("myWindowClass")
- var wc Wndclassex
- wc.Size = uint32(unsafe.Sizeof(wc))
- wc.WndProc = wproc
- wc.Instance = mh
- wc.Icon = myicon
- wc.Cursor = mycursor
- wc.Background = COLOR_BTNFACE + 1
- wc.MenuName = nil
- wc.ClassName = wcname
- wc.IconSm = myicon
- if _, e := RegisterClassEx(&wc); e != nil {
- abortErrNo("RegisterClassEx", e)
- }
-
- // CreateWindowEx
- wh, e := CreateWindowEx(
- WS_EX_CLIENTEDGE,
- wcname,
- syscall.StringToUTF16Ptr("My window"),
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
- 0, 0, mh, 0)
- if e != nil {
- abortErrNo("CreateWindowEx", e)
- }
- fmt.Printf("main window handle is %x\n", wh)
-
- // ShowWindow
- ShowWindow(wh, SW_SHOWDEFAULT)
-
- // UpdateWindow
- if e := UpdateWindow(wh); e != nil {
- abortErrNo("UpdateWindow", e)
- }
-
- // Process all windows messages until WM_QUIT.
- var m Msg
- for {
- r, e := GetMessage(&m, 0, 0, 0)
- if e != nil {
- abortErrNo("GetMessage", e)
- }
- if r == 0 {
- // WM_QUIT received -> get out
- break
- }
- TranslateMessage(&m)
- DispatchMessage(&m)
- }
- return int(m.Wparam)
-}
-
-func main() {
- rc := rungui()
- os.Exit(rc)
-}
diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go
deleted file mode 100644
index f876088e9..000000000
--- a/src/pkg/exp/wingui/winapi.go
+++ /dev/null
@@ -1,134 +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.
-
-// +build windows
-
-package main
-
-import (
- "syscall"
- "unsafe"
-)
-
-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
-}
-
-type Point struct {
- X uintptr
- Y uintptr
-}
-
-type Msg struct {
- Hwnd syscall.Handle
- Message uint32
- Wparam uintptr
- Lparam uintptr
- Time uint32
- Pt Point
-}
-
-const (
- // Window styles
- WS_OVERLAPPED = 0
- WS_POPUP = 0x80000000
- WS_CHILD = 0x40000000
- WS_MINIMIZE = 0x20000000
- WS_VISIBLE = 0x10000000
- WS_DISABLED = 0x8000000
- WS_CLIPSIBLINGS = 0x4000000
- WS_CLIPCHILDREN = 0x2000000
- WS_MAXIMIZE = 0x1000000
- WS_CAPTION = WS_BORDER | WS_DLGFRAME
- WS_BORDER = 0x800000
- WS_DLGFRAME = 0x400000
- WS_VSCROLL = 0x200000
- WS_HSCROLL = 0x100000
- WS_SYSMENU = 0x80000
- WS_THICKFRAME = 0x40000
- WS_GROUP = 0x20000
- WS_TABSTOP = 0x10000
- WS_MINIMIZEBOX = 0x20000
- WS_MAXIMIZEBOX = 0x10000
- WS_TILED = WS_OVERLAPPED
- WS_ICONIC = WS_MINIMIZE
- WS_SIZEBOX = WS_THICKFRAME
- // Common Window Styles
- WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
- WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
- WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU
- WS_CHILDWINDOW = WS_CHILD
-
- WS_EX_CLIENTEDGE = 0x200
-
- // Some windows messages
- WM_CREATE = 1
- WM_DESTROY = 2
- WM_CLOSE = 16
- WM_COMMAND = 273
-
- // Some button control styles
- BS_DEFPUSHBUTTON = 1
-
- // Some color constants
- COLOR_WINDOW = 5
- COLOR_BTNFACE = 15
-
- // Default window position
- CW_USEDEFAULT = 0x80000000 - 0x100000000
-
- // Show window default style
- SW_SHOWDEFAULT = 10
-)
-
-var (
- // Some globally known cursors
- IDC_ARROW = MakeIntResource(32512)
- IDC_IBEAM = MakeIntResource(32513)
- IDC_WAIT = MakeIntResource(32514)
- IDC_CROSS = MakeIntResource(32515)
-
- // Some globally known icons
- IDI_APPLICATION = MakeIntResource(32512)
- IDI_HAND = MakeIntResource(32513)
- IDI_QUESTION = MakeIntResource(32514)
- IDI_EXCLAMATION = MakeIntResource(32515)
- IDI_ASTERISK = MakeIntResource(32516)
- IDI_WINLOGO = MakeIntResource(32517)
- IDI_WARNING = IDI_EXCLAMATION
- IDI_ERROR = IDI_HAND
- IDI_INFORMATION = IDI_ASTERISK
-)
-
-//sys GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) = GetModuleHandleW
-//sys RegisterClassEx(wndclass *Wndclassex) (atom uint16, err error) = user32.RegisterClassExW
-//sys CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent syscall.Handle, menu syscall.Handle, instance syscall.Handle, param uintptr) (hwnd syscall.Handle, err error) = user32.CreateWindowExW
-//sys DefWindowProc(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) = user32.DefWindowProcW
-//sys DestroyWindow(hwnd syscall.Handle) (err error) = user32.DestroyWindow
-//sys PostQuitMessage(exitcode int32) = user32.PostQuitMessage
-//sys ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) = user32.ShowWindow
-//sys UpdateWindow(hwnd syscall.Handle) (err error) = user32.UpdateWindow
-//sys GetMessage(msg *Msg, hwnd syscall.Handle, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) [failretval==-1] = user32.GetMessageW
-//sys TranslateMessage(msg *Msg) (done bool) = user32.TranslateMessage
-//sys DispatchMessage(msg *Msg) (ret int32) = user32.DispatchMessageW
-//sys LoadIcon(instance syscall.Handle, iconname *uint16) (icon syscall.Handle, err error) = user32.LoadIconW
-//sys LoadCursor(instance syscall.Handle, cursorname *uint16) (cursor syscall.Handle, err error) = user32.LoadCursorW
-//sys SetCursor(cursor syscall.Handle) (precursor syscall.Handle, err error) = user32.SetCursor
-//sys SendMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) = user32.SendMessageW
-//sys PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) = user32.PostMessageW
-
-func MakeIntResource(id uint16) *uint16 {
- return (*uint16)(unsafe.Pointer(uintptr(id)))
-}
diff --git a/src/pkg/exp/wingui/zwinapi.go b/src/pkg/exp/wingui/zwinapi.go
deleted file mode 100644
index 5666c6de5..000000000
--- a/src/pkg/exp/wingui/zwinapi.go
+++ /dev/null
@@ -1,192 +0,0 @@
-// +build windows
-// mksyscall_windows.pl winapi.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-package main
-
-import "unsafe"
-import "syscall"
-
-var (
- modkernel32 = syscall.NewLazyDLL("kernel32.dll")
- moduser32 = syscall.NewLazyDLL("user32.dll")
-
- procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
- procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
- procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
- procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
- procDestroyWindow = moduser32.NewProc("DestroyWindow")
- procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
- procShowWindow = moduser32.NewProc("ShowWindow")
- procUpdateWindow = moduser32.NewProc("UpdateWindow")
- procGetMessageW = moduser32.NewProc("GetMessageW")
- procTranslateMessage = moduser32.NewProc("TranslateMessage")
- procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
- procLoadIconW = moduser32.NewProc("LoadIconW")
- procLoadCursorW = moduser32.NewProc("LoadCursorW")
- procSetCursor = moduser32.NewProc("SetCursor")
- procSendMessageW = moduser32.NewProc("SendMessageW")
- procPostMessageW = moduser32.NewProc("PostMessageW")
-)
-
-func GetModuleHandle(modname *uint16) (handle syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
- handle = syscall.Handle(r0)
- if handle == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func RegisterClassEx(wndclass *Wndclassex) (atom uint16, err error) {
- r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
- atom = uint16(r0)
- if atom == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent syscall.Handle, menu syscall.Handle, instance syscall.Handle, param uintptr) (hwnd syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
- hwnd = syscall.Handle(r0)
- if hwnd == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) {
- r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
- lresult = uintptr(r0)
- return
-}
-
-func DestroyWindow(hwnd syscall.Handle) (err error) {
- r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func PostQuitMessage(exitcode int32) {
- syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
- return
-}
-
-func ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) {
- r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
- wasvisible = bool(r0 != 0)
- return
-}
-
-func UpdateWindow(hwnd syscall.Handle) (err error) {
- r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func GetMessage(msg *Msg, hwnd syscall.Handle, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) {
- r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
- ret = int32(r0)
- if ret == -1 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func TranslateMessage(msg *Msg) (done bool) {
- r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
- done = bool(r0 != 0)
- return
-}
-
-func DispatchMessage(msg *Msg) (ret int32) {
- r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
- ret = int32(r0)
- return
-}
-
-func LoadIcon(instance syscall.Handle, iconname *uint16) (icon syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
- icon = syscall.Handle(r0)
- if icon == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func LoadCursor(instance syscall.Handle, cursorname *uint16) (cursor syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
- cursor = syscall.Handle(r0)
- if cursor == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func SetCursor(cursor syscall.Handle) (precursor syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
- precursor = syscall.Handle(r0)
- if precursor == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func SendMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (lresult uintptr) {
- r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
- lresult = uintptr(r0)
- return
-}
-
-func PostMessage(hwnd syscall.Handle, msg uint32, wparam uintptr, lparam uintptr) (err error) {
- r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
- if int(r1) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index 1919296ea..b06599505 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -41,10 +41,14 @@ type Var interface {
// Int is a 64-bit integer variable that satisfies the Var interface.
type Int struct {
i int64
- mu sync.Mutex
+ mu sync.RWMutex
}
-func (v *Int) String() string { return strconv.FormatInt(v.i, 10) }
+func (v *Int) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.FormatInt(v.i, 10)
+}
func (v *Int) Add(delta int64) {
v.mu.Lock()
@@ -61,10 +65,14 @@ func (v *Int) Set(value int64) {
// Float is a 64-bit float variable that satisfies the Var interface.
type Float struct {
f float64
- mu sync.Mutex
+ mu sync.RWMutex
}
-func (v *Float) String() string { return strconv.FormatFloat(v.f, 'g', -1, 64) }
+func (v *Float) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.FormatFloat(v.f, 'g', -1, 64)
+}
// Add adds delta to v.
func (v *Float) Add(delta float64) {
@@ -95,17 +103,17 @@ type KeyValue struct {
func (v *Map) String() string {
v.mu.RLock()
defer v.mu.RUnlock()
- b := new(bytes.Buffer)
- fmt.Fprintf(b, "{")
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "{")
first := true
for key, val := range v.m {
if !first {
- fmt.Fprintf(b, ", ")
+ fmt.Fprintf(&b, ", ")
}
- fmt.Fprintf(b, "\"%s\": %v", key, val)
+ fmt.Fprintf(&b, "\"%s\": %v", key, val)
first = false
}
- fmt.Fprintf(b, "}")
+ fmt.Fprintf(&b, "}")
return b.String()
}
@@ -180,12 +188,21 @@ func (v *Map) Do(f func(KeyValue)) {
// String is a string variable, and satisfies the Var interface.
type String struct {
- s string
+ s string
+ mu sync.RWMutex
}
-func (v *String) String() string { return strconv.Quote(v.s) }
+func (v *String) String() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return strconv.Quote(v.s)
+}
-func (v *String) Set(value string) { v.s = value }
+func (v *String) Set(value string) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.s = value
+}
// Func implements Var by calling the function
// and formatting the returned value using JSON.
diff --git a/src/pkg/flag/example_test.go b/src/pkg/flag/example_test.go
new file mode 100644
index 000000000..04a0d20ee
--- /dev/null
+++ b/src/pkg/flag/example_test.go
@@ -0,0 +1,83 @@
+// 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.
+
+// These examples demonstrate more intricate uses of the flag package.
+package flag_test
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "strings"
+ "time"
+)
+
+// Example 1: A single string flag called "species" with default value "gopher".
+var species = flag.String("species", "gopher", "the species we are studying")
+
+// Example 2: Two flags sharing a variable, so we can have a shorthand.
+// The order of initialization is undefined, so make sure both use the
+// same default value. They must be set up with an init function.
+var gopherType string
+
+func init() {
+ const (
+ defaultGopher = "pocket"
+ usage = "the variety of gopher"
+ )
+ flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
+ flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
+}
+
+// Example 3: A user-defined flag type, a slice of durations.
+type interval []time.Duration
+
+// String is the method to format the flag's value, part of the flag.Value interface.
+// The String method's output will be used in diagnostics.
+func (i *interval) String() string {
+ return fmt.Sprint(*i)
+}
+
+// Set is the method to set the flag value, part of the flag.Value interface.
+// Set's argument is a string to be parsed to set the flag.
+// It's a comma-separated list, so we split it.
+func (i *interval) Set(value string) error {
+ // If we wanted to allow the flag to be set multiple times,
+ // accumulating values, we would delete this if statement.
+ // That would permit usages such as
+ // -deltaT 10s -deltaT 15s
+ // and other combinations.
+ if len(*i) > 0 {
+ return errors.New("interval flag already set")
+ }
+ for _, dt := range strings.Split(value, ",") {
+ duration, err := time.ParseDuration(dt)
+ if err != nil {
+ return err
+ }
+ *i = append(*i, duration)
+ }
+ return nil
+}
+
+// Define a flag to accumulate durations. Because it has a special type,
+// we need to use the Var function and therefore create the flag during
+// init.
+
+var intervalFlag interval
+
+func init() {
+ // Tie the command-line flag to the intervalFlag variable and
+ // set a usage message.
+ flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
+}
+
+func Example() {
+ // All the interesting pieces are with the variables declared above, but
+ // to enable the flag package to see the flags defined there, one must
+ // execute, typically at the start of main (not init!):
+ // flag.Parse()
+ // We don't run it here because this is not a main function and
+ // the testing suite has already parsed the flags.
+}
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 7d4178da7..9660370c2 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -7,7 +7,8 @@
to C's printf and scanf. The format 'verbs' are derived from C's but
are simpler.
- Printing:
+
+ Printing
The verbs:
@@ -127,7 +128,8 @@
by a single character (the verb) and end with a parenthesized
description.
- Scanning:
+
+ Scanning
An analogous set of functions scans formatted text to yield
values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
diff --git a/src/pkg/fmt/export_test.go b/src/pkg/fmt/export_test.go
new file mode 100644
index 000000000..89d57ee6c
--- /dev/null
+++ b/src/pkg/fmt/export_test.go
@@ -0,0 +1,7 @@
+// 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 fmt
+
+var IsSpace = isSpace
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 86db9bc67..758fc50d0 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -13,6 +13,7 @@ import (
"strings"
"testing"
"time"
+ "unicode"
)
type (
@@ -828,3 +829,13 @@ func TestBadVerbRecursion(t *testing.T) {
t.Error("fail with value")
}
}
+
+func TestIsSpace(t *testing.T) {
+ // This tests the internal isSpace function.
+ // IsSpace = isSpace is defined in export_test.go.
+ for i := rune(0); i <= unicode.MaxRune; i++ {
+ if IsSpace(i) != unicode.IsSpace(i) {
+ t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))
+ }
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 78d9e998b..2186f334b 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -5,9 +5,7 @@
package fmt
import (
- "bytes"
"strconv"
- "unicode"
"unicode/utf8"
)
@@ -36,10 +34,10 @@ func init() {
}
// A fmt is the raw formatter used by Printf etc.
-// It prints into a bytes.Buffer that must be set up externally.
+// It prints into a buffer that must be set up separately.
type fmt struct {
intbuf [nByte]byte
- buf *bytes.Buffer
+ buf *buffer
// width, precision
wid int
prec int
@@ -69,7 +67,7 @@ func (f *fmt) clearflags() {
f.zero = false
}
-func (f *fmt) init(buf *bytes.Buffer) {
+func (f *fmt) init(buf *buffer) {
f.buf = buf
f.clearflags()
}
@@ -247,7 +245,7 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
}
// If we want a quoted char for %#U, move the data up to make room.
- if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(rune(a)) {
+ if f.unicode && f.uniQuote && a >= 0 && a <= utf8.MaxRune && strconv.IsPrint(rune(a)) {
runeWidth := utf8.RuneLen(rune(a))
width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
@@ -290,16 +288,15 @@ func (f *fmt) fmt_s(s string) {
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmt_sx(s, digits string) {
// TODO: Avoid buffer by pre-padding.
- var b bytes.Buffer
+ var b []byte
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
- b.WriteByte(' ')
+ b = append(b, ' ')
}
v := s[i]
- b.WriteByte(digits[v>>4])
- b.WriteByte(digits[v&0xF])
+ b = append(b, digits[v>>4], digits[v&0xF])
}
- f.pad(b.Bytes())
+ f.pad(b)
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index c3ba2f339..13438243c 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -5,13 +5,11 @@
package fmt
import (
- "bytes"
"errors"
"io"
"os"
"reflect"
"sync"
- "unicode"
"unicode/utf8"
)
@@ -71,11 +69,45 @@ type GoStringer interface {
GoString() string
}
+// Use simple []byte instead of bytes.Buffer to avoid large dependency.
+type buffer []byte
+
+func (b *buffer) Write(p []byte) (n int, err error) {
+ *b = append(*b, p...)
+ return len(p), nil
+}
+
+func (b *buffer) WriteString(s string) (n int, err error) {
+ *b = append(*b, s...)
+ return len(s), nil
+}
+
+func (b *buffer) WriteByte(c byte) error {
+ *b = append(*b, c)
+ return nil
+}
+
+func (bp *buffer) WriteRune(r rune) error {
+ if r < utf8.RuneSelf {
+ *bp = append(*bp, byte(r))
+ return nil
+ }
+
+ b := *bp
+ n := len(b)
+ for n+utf8.UTFMax > cap(b) {
+ b = append(b, 0)
+ }
+ w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
+ *bp = b[:n+w]
+ return nil
+}
+
type pp struct {
n int
panicking bool
erroring bool // printing an error condition
- buf bytes.Buffer
+ buf buffer
// field holds the current item, as an interface{}.
field interface{}
// value holds the current item, as a reflect.Value, and will be
@@ -133,10 +165,10 @@ func newPrinter() *pp {
// Save used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
// Don't hold on to pp structs with large buffers.
- if cap(p.buf.Bytes()) > 1024 {
+ if cap(p.buf) > 1024 {
return
}
- p.buf.Reset()
+ p.buf = p.buf[:0]
p.field = nil
p.value = reflect.Value{}
ppFree.put(p)
@@ -179,7 +211,7 @@ func (p *pp) Write(b []byte) (ret int, err error) {
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
return int(n64), err
}
@@ -194,7 +226,7 @@ func Printf(format string, a ...interface{}) (n int, err error) {
func Sprintf(format string, a ...interface{}) string {
p := newPrinter()
p.doPrintf(format, a)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
@@ -213,7 +245,7 @@ func Errorf(format string, a ...interface{}) error {
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, false, false)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
return int(n64), err
}
@@ -230,7 +262,7 @@ func Print(a ...interface{}) (n int, err error) {
func Sprint(a ...interface{}) string {
p := newPrinter()
p.doPrint(a, false, false)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
@@ -245,7 +277,7 @@ func Sprint(a ...interface{}) string {
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, true, true)
- n64, err := p.buf.WriteTo(w)
+ n64, err := w.Write(p.buf)
p.free()
return int(n64), err
}
@@ -262,7 +294,7 @@ func Println(a ...interface{}) (n int, err error) {
func Sprintln(a ...interface{}) string {
p := newPrinter()
p.doPrint(a, true, true)
- s := p.buf.String()
+ s := string(p.buf)
p.free()
return s
}
@@ -352,7 +384,7 @@ func (p *pp) fmtInt64(v int64, verb rune) {
case 'o':
p.fmt.integer(v, 8, signed, ldigits)
case 'q':
- if 0 <= v && v <= unicode.MaxRune {
+ if 0 <= v && v <= utf8.MaxRune {
p.fmt.fmt_qc(v)
} else {
p.badVerb(verb)
@@ -416,7 +448,7 @@ func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
case 'o':
p.fmt.integer(int64(v), 8, unsigned, ldigits)
case 'q':
- if 0 <= v && v <= unicode.MaxRune {
+ if 0 <= v && v <= utf8.MaxRune {
p.fmt.fmt_qc(int64(v))
} else {
p.badVerb(verb)
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index fa9a5584a..0b3e04069 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -5,15 +5,12 @@
package fmt
import (
- "bytes"
"errors"
"io"
"math"
"os"
"reflect"
"strconv"
- "strings"
- "unicode"
"unicode/utf8"
)
@@ -87,25 +84,36 @@ func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
+type stringReader string
+
+func (r *stringReader) Read(b []byte) (n int, err error) {
+ n = copy(b, *r)
+ *r = (*r)[n:]
+ if n == 0 {
+ err = io.EOF
+ }
+ return
+}
+
// Sscan scans the argument string, storing successive space-separated
// values into successive arguments. Newlines count as space. It
// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
func Sscan(str string, a ...interface{}) (n int, err error) {
- return Fscan(strings.NewReader(str), a...)
+ return Fscan((*stringReader)(&str), a...)
}
// Sscanln is similar to Sscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
func Sscanln(str string, a ...interface{}) (n int, err error) {
- return Fscanln(strings.NewReader(str), a...)
+ return Fscanln((*stringReader)(&str), a...)
}
// Sscanf scans the argument string, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
- return Fscanf(strings.NewReader(str), format, a...)
+ return Fscanf((*stringReader)(&str), format, a...)
}
// Fscan scans text read from r, storing successive space-separated
@@ -149,7 +157,7 @@ const eof = -1
// ss is the internal implementation of ScanState.
type ss struct {
rr io.RuneReader // where to read input
- buf bytes.Buffer // token accumulator
+ buf buffer // token accumulator
peekRune rune // one-rune lookahead
prevRune rune // last rune returned by ReadRune
count int // runes consumed so far.
@@ -262,14 +270,46 @@ func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) {
if f == nil {
f = notSpace
}
- s.buf.Reset()
+ s.buf = s.buf[:0]
tok = s.token(skipSpace, f)
return
}
+// space is a copy of the unicode.White_Space ranges,
+// to avoid depending on package unicode.
+var space = [][2]uint16{
+ {0x0009, 0x000d},
+ {0x0020, 0x0020},
+ {0x0085, 0x0085},
+ {0x00a0, 0x00a0},
+ {0x1680, 0x1680},
+ {0x180e, 0x180e},
+ {0x2000, 0x200a},
+ {0x2028, 0x2029},
+ {0x202f, 0x202f},
+ {0x205f, 0x205f},
+ {0x3000, 0x3000},
+}
+
+func isSpace(r rune) bool {
+ if r >= 1<<16 {
+ return false
+ }
+ rx := uint16(r)
+ for _, rng := range space {
+ if rx < rng[0] {
+ return false
+ }
+ if rx <= rng[1] {
+ return true
+ }
+ }
+ return false
+}
+
// notSpace is the default scanning function used in Token.
func notSpace(r rune) bool {
- return !unicode.IsSpace(r)
+ return !isSpace(r)
}
// skipSpace provides Scan() methods the ability to skip space and newline characters
@@ -378,10 +418,10 @@ func (s *ss) free(old ssave) {
return
}
// Don't hold on to ss structs with large buffers.
- if cap(s.buf.Bytes()) > 1024 {
+ if cap(s.buf) > 1024 {
return
}
- s.buf.Reset()
+ s.buf = s.buf[:0]
s.rr = nil
ssFree.put(s)
}
@@ -403,7 +443,7 @@ func (s *ss) skipSpace(stopAtNewline bool) {
s.errorString("unexpected newline")
return
}
- if !unicode.IsSpace(r) {
+ if !isSpace(r) {
s.UnreadRune()
break
}
@@ -429,7 +469,7 @@ func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
}
s.buf.WriteRune(r)
}
- return s.buf.Bytes()
+ return s.buf
}
// typeError indicates that the type of the operand did not match the format
@@ -440,6 +480,15 @@ func (s *ss) typeError(field interface{}, expected string) {
var complexError = errors.New("syntax error scanning complex number")
var boolError = errors.New("syntax error scanning boolean")
+func indexRune(s string, r rune) int {
+ for i, c := range s {
+ if c == r {
+ return i
+ }
+ }
+ return -1
+}
+
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
func (s *ss) consume(ok string, accept bool) bool {
@@ -447,7 +496,7 @@ func (s *ss) consume(ok string, accept bool) bool {
if r == eof {
return false
}
- if strings.IndexRune(ok, r) >= 0 {
+ if indexRune(ok, r) >= 0 {
if accept {
s.buf.WriteRune(r)
}
@@ -465,7 +514,7 @@ func (s *ss) peek(ok string) bool {
if r != eof {
s.UnreadRune()
}
- return strings.IndexRune(ok, r) >= 0
+ return indexRune(ok, r) >= 0
}
func (s *ss) notEOF() {
@@ -560,7 +609,7 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string {
}
for s.accept(digits) {
}
- return s.buf.String()
+ return string(s.buf)
}
// scanRune returns the next rune value in the input.
@@ -660,16 +709,16 @@ func (s *ss) scanUint(verb rune, bitSize int) uint64 {
// if the width is specified. It's not rigorous about syntax because it doesn't check that
// we have at least some digits, but Atof will do that.
func (s *ss) floatToken() string {
- s.buf.Reset()
+ s.buf = s.buf[:0]
// NaN?
if s.accept("nN") && s.accept("aA") && s.accept("nN") {
- return s.buf.String()
+ return string(s.buf)
}
// leading sign?
s.accept(sign)
// Inf?
if s.accept("iI") && s.accept("nN") && s.accept("fF") {
- return s.buf.String()
+ return string(s.buf)
}
// digits?
for s.accept(decimalDigits) {
@@ -688,7 +737,7 @@ func (s *ss) floatToken() string {
for s.accept(decimalDigits) {
}
}
- return s.buf.String()
+ return string(s.buf)
}
// complexTokens returns the real and imaginary parts of the complex number starting here.
@@ -698,13 +747,13 @@ func (s *ss) complexTokens() (real, imag string) {
// TODO: accept N and Ni independently?
parens := s.accept("(")
real = s.floatToken()
- s.buf.Reset()
+ s.buf = s.buf[:0]
// Must now have a sign.
if !s.accept("+-") {
s.error(complexError)
}
// Sign is now in buffer
- imagSign := s.buf.String()
+ imagSign := string(s.buf)
imag = s.floatToken()
if !s.accept("i") {
s.error(complexError)
@@ -717,7 +766,7 @@ func (s *ss) complexTokens() (real, imag string) {
// convertFloat converts the string to a float64value.
func (s *ss) convertFloat(str string, n int) float64 {
- if p := strings.Index(str, "p"); p >= 0 {
+ if p := indexRune(str, 'p'); p >= 0 {
// Atof doesn't handle power-of-2 exponents,
// but they're easy to evaluate.
f, err := strconv.ParseFloat(str[:p], n)
@@ -794,7 +843,7 @@ func (s *ss) quotedString() string {
}
s.buf.WriteRune(r)
}
- return s.buf.String()
+ return string(s.buf)
case '"':
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
s.buf.WriteRune(quote)
@@ -811,7 +860,7 @@ func (s *ss) quotedString() string {
break
}
}
- result, err := strconv.Unquote(s.buf.String())
+ result, err := strconv.Unquote(string(s.buf))
if err != nil {
s.error(err)
}
@@ -844,7 +893,7 @@ func (s *ss) hexByte() (b byte, ok bool) {
if rune1 == eof {
return
}
- if unicode.IsSpace(rune1) {
+ if isSpace(rune1) {
s.UnreadRune()
return
}
@@ -862,11 +911,11 @@ func (s *ss) hexString() string {
}
s.buf.WriteByte(b)
}
- if s.buf.Len() == 0 {
+ if len(s.buf) == 0 {
s.errorString("Scan: no hex data for %x string")
return ""
}
- return s.buf.String()
+ return string(s.buf)
}
const floatVerbs = "beEfFgGv"
@@ -875,7 +924,7 @@ const hugeWid = 1 << 30
// scanOne scans a single value, deriving the scanner from the type of the argument.
func (s *ss) scanOne(verb rune, field interface{}) {
- s.buf.Reset()
+ s.buf = s.buf[:0]
var err error
// If the parameter has its own Scan method, use that.
if v, ok := field.(Scanner); ok {
@@ -1004,7 +1053,7 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
if r == '\n' || r == eof {
break
}
- if !unicode.IsSpace(r) {
+ if !isSpace(r) {
s.errorString("Scan: expected newline")
break
}
@@ -1032,7 +1081,7 @@ func (s *ss) advance(format string) (i int) {
i += w // skip the first %
}
sawSpace := false
- for unicode.IsSpace(fmtc) && i < len(format) {
+ for isSpace(fmtc) && i < len(format) {
sawSpace = true
i += w
fmtc, w = utf8.DecodeRuneInString(format[i:])
@@ -1044,7 +1093,7 @@ func (s *ss) advance(format string) (i int) {
if inputc == eof {
return
}
- if !unicode.IsSpace(inputc) {
+ if !isSpace(inputc) {
// Space in format but not in input: error
s.errorString("expected space in input to match format")
}
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 61b48f9cc..320857b73 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -810,7 +810,7 @@ func TestMultiLine(t *testing.T) {
}
}
-// RecursiveInt accepts an string matching %d.%d.%d....
+// RecursiveInt accepts a string matching %d.%d.%d....
// and parses it into a linked list.
// It allows us to benchmark recursive descent style scanners.
type RecursiveInt struct {
@@ -826,7 +826,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
next := new(RecursiveInt)
_, err = Fscanf(state, ".%v", next)
if err != nil {
- if err == errors.New("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == io.ErrUnexpectedEOF {
err = nil
}
return
diff --git a/src/pkg/go/build/Makefile b/src/pkg/go/build/Makefile
deleted file mode 100644
index 3bb3912cb..000000000
--- a/src/pkg/go/build/Makefile
+++ /dev/null
@@ -1,11 +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.
-
-syslist.go: ../../../Make.inc Makefile
- echo '// Generated automatically by make.' >$@
- echo >>$@
- echo 'package build' >>$@
- echo >>$@
- echo 'const goosList = "$(GOOS_LIST)"' >>$@
- echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index eece76105..d113dc135 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -34,7 +34,7 @@ type Context struct {
CgoEnabled bool // whether cgo can be used
BuildTags []string // additional tags to recognize in +build lines
UseAllFiles bool // use files regardless of +build lines, file names
- Gccgo bool // assume use of gccgo when computing object paths
+ Compiler string // compiler to assume when computing target paths
// By default, Import uses the operating system's file system calls
// to read directories and files. To read from other sources,
@@ -210,6 +210,7 @@ func (ctxt *Context) SrcDirs() []string {
// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
var Default Context = defaultContext()
+// This list is also known to ../../../cmd/dist/build.c.
var cgoEnabled = map[string]bool{
"darwin/386": true,
"darwin/amd64": true,
@@ -228,6 +229,7 @@ func defaultContext() Context {
c.GOOS = envOr("GOOS", runtime.GOOS)
c.GOROOT = runtime.GOROOT()
c.GOPATH = envOr("GOPATH", "")
+ c.Compiler = runtime.Compiler
switch os.Getenv("CGO_ENABLED") {
case "1":
@@ -277,11 +279,12 @@ type Package struct {
PkgObj string // installed .a file
// Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go source files that import "C"
- CFiles []string // .c source files
- HFiles []string // .h source files
- SFiles []string // .s source files
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go source files that import "C"
+ CFiles []string // .c source files
+ HFiles []string // .h source files
+ SFiles []string // .s source files
+ SysoFiles []string // .syso system object files to add to archive
// Cgo directives
CgoPkgConfig []string // Cgo pkg-config directives
@@ -314,42 +317,58 @@ func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
return ctxt.Import(".", dir, mode)
}
+// NoGoError is the error used by Import to describe a directory
+// containing no Go source files.
+type NoGoError struct {
+ Dir string
+}
+
+func (e *NoGoError) Error() string {
+ return "no Go source files in " + e.Dir
+}
+
// Import returns details about the Go package named by the import path,
-// interpreting local import paths relative to the src directory. If the path
-// is a local import path naming a package that can be imported using a
-// standard import path, the returned package will set p.ImportPath to
-// that path.
+// interpreting local import paths relative to the srcDir directory.
+// If the path is a local import path naming a package that can be imported
+// using a standard import path, the returned package will set p.ImportPath
+// to that path.
//
// In the directory containing the package, .go, .c, .h, and .s files are
// considered part of the package except for:
//
// - .go files in package documentation
-// - files starting with _ or .
+// - files starting with _ or . (likely editor temporary files)
// - files with build constraints not satisfied by the context
//
// If an error occurs, Import returns a non-nil error also returns a non-nil
// *Package containing partial information.
//
-func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) {
+func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
p := &Package{
ImportPath: path,
}
var pkga string
- if ctxt.Gccgo {
+ var pkgerr error
+ switch ctxt.Compiler {
+ case "gccgo":
dir, elem := pathpkg.Split(p.ImportPath)
pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
- } else {
+ case "gc":
pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
+ default:
+ // Save error for end of function.
+ pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
}
binaryOnly := false
if IsLocalImport(path) {
- if src == "" {
+ pkga = "" // local imports have no installed path
+ if srcDir == "" {
return p, fmt.Errorf("import %q: import relative to unknown directory", path)
}
if !ctxt.isAbsPath(path) {
- p.Dir = ctxt.joinPath(src, path)
+ p.Dir = ctxt.joinPath(srcDir, path)
}
// Determine canonical import path, if any.
if ctxt.GOROOT != "" {
@@ -396,7 +415,7 @@ func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package,
if ctxt.GOROOT != "" {
dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
isDir := ctxt.isDir(dir)
- binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
+ binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Goroot = true
@@ -407,7 +426,7 @@ func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package,
for _, root := range ctxt.gopath() {
dir := ctxt.joinPath(root, "src", path)
isDir := ctxt.isDir(dir)
- binaryOnly = !isDir && mode&AllowBinary != 0 && ctxt.isFile(ctxt.joinPath(root, pkga))
+ binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
if isDir || binaryOnly {
p.Dir = dir
p.Root = root
@@ -426,14 +445,16 @@ Found:
}
p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
p.BinDir = ctxt.joinPath(p.Root, "bin")
- p.PkgObj = ctxt.joinPath(p.Root, pkga)
+ if pkga != "" {
+ p.PkgObj = ctxt.joinPath(p.Root, pkga)
+ }
}
if mode&FindOnly != 0 {
- return p, nil
+ return p, pkgerr
}
if binaryOnly && (mode&AllowBinary) != 0 {
- return p, nil
+ return p, pkgerr
}
dirs, err := ctxt.readDir(p.Dir)
@@ -467,7 +488,13 @@ Found:
ext := name[i:]
switch ext {
case ".go", ".c", ".s", ".h", ".S":
- // tentatively okay
+ // tentatively okay - read to make sure
+ case ".syso":
+ // binary objects to add to package archive
+ // Likely of the form foo_windows.syso, but
+ // the name was vetted above with goodOSArchFile.
+ p.SysoFiles = append(p.SysoFiles, name)
+ continue
default:
// skip
continue
@@ -586,7 +613,7 @@ Found:
}
}
if p.Name == "" {
- return p, fmt.Errorf("no Go source files in %s", p.Dir)
+ return p, &NoGoError{p.Dir}
}
p.Imports, p.ImportPos = cleanImports(imported)
@@ -601,7 +628,7 @@ Found:
sort.Strings(p.SFiles)
}
- return p, nil
+ return p, pkgerr
}
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
@@ -614,8 +641,8 @@ func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.P
}
// Import is shorthand for Default.Import.
-func Import(path, src string, mode ImportMode) (*Package, error) {
- return Default.Import(path, src, mode)
+func Import(path, srcDir string, mode ImportMode) (*Package, error) {
+ return Default.Import(path, srcDir, mode)
}
// ImportDir is shorthand for Default.ImportDir.
@@ -848,7 +875,7 @@ func splitQuoted(s string) (r []string, err error) {
// !cgo (if cgo is disabled)
// tag (if tag is listed in ctxt.BuildTags)
// !tag (if tag is not listed in ctxt.BuildTags)
-// a slash-separated list of any of these
+// a comma-separated list of any of these
//
func (ctxt *Context) match(name string) bool {
if name == "" {
@@ -862,11 +889,11 @@ func (ctxt *Context) match(name string) bool {
return false
}
if strings.HasPrefix(name, "!") { // negation
- return !ctxt.match(name[1:])
+ return len(name) > 1 && !ctxt.match(name[1:])
}
// Tags must be letters, digits, underscores.
- // Unlike in Go identifiers, all digits is fine (e.g., "386").
+ // Unlike in Go identifiers, all digits are fine (e.g., "386").
for _, c := range name {
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
return false
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index 06b8b0e94..560ebad5c 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -36,6 +36,7 @@ func TestMatch(t *testing.T) {
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",!foo")
match(runtime.GOOS + "," + runtime.GOARCH + ",!bar")
nomatch(runtime.GOOS + "," + runtime.GOARCH + ",bar")
+ nomatch("!")
}
func TestDotSlashImport(t *testing.T) {
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
new file mode 100644
index 000000000..4e9f32a03
--- /dev/null
+++ b/src/pkg/go/build/deps_test.go
@@ -0,0 +1,424 @@
+// 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.
+
+// This file exercises the import parser but also checks that
+// some low-level packages do not have new dependencies added.
+
+package build_test
+
+import (
+ "go/build"
+ "sort"
+ "testing"
+)
+
+// pkgDeps defines the expected dependencies between packages in
+// the Go source tree. It is a statement of policy.
+// Changes should not be made to this map without prior discussion.
+//
+// The map contains two kinds of entries:
+// 1) Lower-case keys are standard import paths and list the
+// allowed imports in that package.
+// 2) Upper-case keys define aliases for package sets, which can then
+// be used as dependencies by other rules.
+//
+// DO NOT CHANGE THIS DATA TO FIX BUILDS.
+//
+var pkgDeps = map[string][]string{
+ // L0 is the lowest level, core, nearly unavoidable packages.
+ "errors": {},
+ "io": {"errors", "sync"},
+ "runtime": {"unsafe"},
+ "sync": {"sync/atomic"},
+ "sync/atomic": {"unsafe"},
+ "unsafe": {},
+
+ "L0": {
+ "errors",
+ "io",
+ "runtime",
+ "sync",
+ "sync/atomic",
+ "unsafe",
+ },
+
+ // L1 adds simple functions and strings processing,
+ // but not Unicode tables.
+ "math": {"unsafe"},
+ "math/cmplx": {"math"},
+ "math/rand": {"L0", "math"},
+ "sort": {"math"},
+ "strconv": {"L0", "unicode/utf8", "math"},
+ "unicode/utf16": {},
+ "unicode/utf8": {},
+
+ "L1": {
+ "L0",
+ "math",
+ "math/cmplx",
+ "math/rand",
+ "sort",
+ "strconv",
+ "unicode/utf16",
+ "unicode/utf8",
+ },
+
+ // L2 adds Unicode and strings processing.
+ "bufio": {"L0", "unicode/utf8", "bytes"},
+ "bytes": {"L0", "unicode", "unicode/utf8"},
+ "path": {"L0", "unicode/utf8", "strings"},
+ "strings": {"L0", "unicode", "unicode/utf8"},
+ "unicode": {},
+
+ "L2": {
+ "L1",
+ "bufio",
+ "bytes",
+ "path",
+ "strings",
+ "unicode",
+ },
+
+ // L3 adds reflection and some basic utility packages
+ // and interface definitions, but nothing that makes
+ // system calls.
+ "crypto": {"L2", "hash"}, // interfaces
+ "crypto/cipher": {"L2"}, // interfaces
+ "encoding/base32": {"L2"},
+ "encoding/base64": {"L2"},
+ "encoding/binary": {"L2", "reflect"},
+ "hash": {"L2"}, // interfaces
+ "hash/adler32": {"L2", "hash"},
+ "hash/crc32": {"L2", "hash"},
+ "hash/crc64": {"L2", "hash"},
+ "hash/fnv": {"L2", "hash"},
+ "image": {"L2", "image/color"}, // interfaces
+ "image/color": {"L2"}, // interfaces
+ "reflect": {"L2"},
+
+ "L3": {
+ "L2",
+ "crypto",
+ "crypto/cipher",
+ "encoding/base32",
+ "encoding/base64",
+ "encoding/binary",
+ "hash",
+ "hash/adler32",
+ "hash/crc32",
+ "hash/crc64",
+ "hash/fnv",
+ "image",
+ "image/color",
+ "reflect",
+ },
+
+ // End of linear dependency definitions.
+
+ // Operating system access.
+ "syscall": {"L0", "unicode/utf16"},
+ "time": {"L0", "syscall"},
+ "os": {"L1", "os", "syscall", "time"},
+ "path/filepath": {"L2", "os", "syscall"},
+ "io/ioutil": {"L2", "os", "path/filepath", "time"},
+ "os/exec": {"L2", "os", "syscall"},
+ "os/signal": {"L2", "os", "syscall"},
+
+ // OS enables basic operating system functionality,
+ // but not direct use of package syscall, nor os/signal.
+ "OS": {
+ "io/ioutil",
+ "os",
+ "os/exec",
+ "path/filepath",
+ "time",
+ },
+
+ // Formatted I/O: few dependencies (L1) but we must add reflect.
+ "fmt": {"L1", "os", "reflect"},
+ "log": {"L1", "os", "fmt", "time"},
+
+ // Packages used by testing must be low-level (L2+fmt).
+ "regexp": {"L2", "regexp/syntax"},
+ "regexp/syntax": {"L2"},
+ "runtime/debug": {"L2", "fmt", "io/ioutil", "os"},
+ "runtime/pprof": {"L2", "fmt", "text/tabwriter"},
+ "text/tabwriter": {"L2"},
+
+ "testing": {"L2", "flag", "fmt", "os", "runtime/pprof", "time"},
+ "testing/iotest": {"L2", "log"},
+ "testing/quick": {"L2", "flag", "fmt", "reflect"},
+
+ // L4 is defined as L3+fmt+log+time, because in general once
+ // you're using L3 packages, use of fmt, log, or time is not a big deal.
+ "L4": {
+ "L3",
+ "fmt",
+ "log",
+ "time",
+ },
+
+ // Go parser.
+ "go/ast": {"L4", "OS", "go/scanner", "go/token"},
+ "go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"},
+ "go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
+ "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
+ "go/scanner": {"L4", "OS", "go/token"},
+ "go/token": {"L4"},
+
+ "GOPARSER": {
+ "go/ast",
+ "go/doc",
+ "go/parser",
+ "go/printer",
+ "go/scanner",
+ "go/token",
+ },
+
+ // One of a kind.
+ "archive/tar": {"L4", "OS"},
+ "archive/zip": {"L4", "OS", "compress/flate"},
+ "compress/bzip2": {"L4"},
+ "compress/flate": {"L4"},
+ "compress/gzip": {"L4", "compress/flate"},
+ "compress/lzw": {"L4"},
+ "compress/zlib": {"L4", "compress/flate"},
+ "database/sql": {"L4", "database/sql/driver"},
+ "database/sql/driver": {"L4", "time"},
+ "debug/dwarf": {"L4"},
+ "debug/elf": {"L4", "OS", "debug/dwarf"},
+ "debug/gosym": {"L4"},
+ "debug/macho": {"L4", "OS", "debug/dwarf"},
+ "debug/pe": {"L4", "OS", "debug/dwarf"},
+ "encoding/ascii85": {"L4"},
+ "encoding/asn1": {"L4", "math/big"},
+ "encoding/csv": {"L4"},
+ "encoding/gob": {"L4", "OS"},
+ "encoding/hex": {"L4"},
+ "encoding/json": {"L4"},
+ "encoding/pem": {"L4"},
+ "encoding/xml": {"L4"},
+ "flag": {"L4", "OS"},
+ "go/build": {"L4", "OS", "GOPARSER"},
+ "html": {"L4"},
+ "image/draw": {"L4"},
+ "image/gif": {"L4", "compress/lzw"},
+ "image/jpeg": {"L4"},
+ "image/png": {"L4", "compress/zlib"},
+ "index/suffixarray": {"L4", "regexp"},
+ "math/big": {"L4"},
+ "mime": {"L4", "OS", "syscall"},
+ "net/url": {"L4"},
+ "text/scanner": {"L4", "OS"},
+ "text/template/parse": {"L4"},
+
+ "html/template": {
+ "L4", "OS", "encoding/json", "html", "text/template",
+ "text/template/parse",
+ },
+ "text/template": {
+ "L4", "OS", "net/url", "text/template/parse",
+ },
+
+ // Cgo.
+ "runtime/cgo": {"L0", "C"},
+ "CGO": {"C", "runtime/cgo"},
+
+ // Fake entry to satisfy the pseudo-import "C"
+ // that shows up in programs that use cgo.
+ "C": {},
+
+ "os/user": {"L4", "CGO", "syscall"},
+
+ // Basic networking.
+ // Because net must be used by any package that wants to
+ // do networking portably, it must have a small dependency set: just L1+basic os.
+ "net": {"L1", "CGO", "os", "syscall", "time"},
+
+ // NET enables use of basic network-related packages.
+ "NET": {
+ "net",
+ "mime",
+ "net/textproto",
+ "net/url",
+ },
+
+ // Uses of networking.
+ "log/syslog": {"L4", "OS", "net"},
+ "net/mail": {"L4", "NET", "OS"},
+ "net/textproto": {"L4", "OS", "net"},
+
+ // Core crypto.
+ "crypto/aes": {"L3"},
+ "crypto/des": {"L3"},
+ "crypto/hmac": {"L3"},
+ "crypto/md5": {"L3"},
+ "crypto/rc4": {"L3"},
+ "crypto/sha1": {"L3"},
+ "crypto/sha256": {"L3"},
+ "crypto/sha512": {"L3"},
+ "crypto/subtle": {"L3"},
+
+ "CRYPTO": {
+ "crypto/aes",
+ "crypto/des",
+ "crypto/hmac",
+ "crypto/md5",
+ "crypto/rc4",
+ "crypto/sha1",
+ "crypto/sha256",
+ "crypto/sha512",
+ "crypto/subtle",
+ },
+
+ // Random byte, number generation.
+ // This would be part of core crypto except that it imports
+ // math/big, which imports fmt.
+ "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall"},
+
+ // Mathematical crypto: dependencies on fmt (L4) and math/big.
+ // We could avoid some of the fmt, but math/big imports fmt anyway.
+ "crypto/dsa": {"L4", "CRYPTO", "math/big"},
+ "crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big"},
+ "crypto/elliptic": {"L4", "CRYPTO", "math/big"},
+ "crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
+
+ "CRYPTO-MATH": {
+ "CRYPTO",
+ "crypto/dsa",
+ "crypto/ecdsa",
+ "crypto/elliptic",
+ "crypto/rand",
+ "crypto/rsa",
+ "encoding/asn1",
+ "math/big",
+ },
+
+ // SSL/TLS.
+ "crypto/tls": {
+ "L4", "CRYPTO-MATH", "CGO", "OS",
+ "crypto/x509", "encoding/pem", "net", "syscall",
+ },
+ "crypto/x509": {"L4", "CRYPTO-MATH", "OS", "CGO", "crypto/x509/pkix", "encoding/pem", "syscall"},
+ "crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
+
+ // Simple net+crypto-aware packages.
+ "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto"},
+ "net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"},
+
+ // HTTP, kingpin of dependencies.
+ "net/http": {
+ "L4", "NET", "OS",
+ "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+ },
+
+ // HTTP-using packages.
+ "expvar": {"L4", "OS", "encoding/json", "net/http"},
+ "net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
+ "net/http/fcgi": {"L4", "NET", "OS", "net/http", "net/http/cgi"},
+ "net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
+ "net/http/httputil": {"L4", "NET", "OS", "net/http"},
+ "net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof"},
+ "net/rpc": {"L4", "NET", "encoding/gob", "net/http", "text/template"},
+ "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
+}
+
+// isMacro reports whether p is a package dependency macro
+// (uppercase name).
+func isMacro(p string) bool {
+ return 'A' <= p[0] && p[0] <= 'Z'
+}
+
+func allowed(pkg string) map[string]bool {
+ m := map[string]bool{}
+ var allow func(string)
+ allow = func(p string) {
+ if m[p] {
+ return
+ }
+ m[p] = true // set even for macros, to avoid loop on cycle
+
+ // Upper-case names are macro-expanded.
+ if isMacro(p) {
+ for _, pp := range pkgDeps[p] {
+ allow(pp)
+ }
+ }
+ }
+ for _, pp := range pkgDeps[pkg] {
+ allow(pp)
+ }
+ return m
+}
+
+var bools = []bool{false, true}
+var geese = []string{"darwin", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}
+var goarches = []string{"386", "amd64", "arm"}
+
+type osPkg struct {
+ goos, pkg string
+}
+
+// allowedErrors are the operating systems and packages known to contain errors
+// (currently just "no Go source files")
+var allowedErrors = map[osPkg]bool{
+ osPkg{"windows", "log/syslog"}: true,
+ osPkg{"plan9", "log/syslog"}: true,
+}
+
+func TestDependencies(t *testing.T) {
+ var all []string
+
+ for k := range pkgDeps {
+ all = append(all, k)
+ }
+ sort.Strings(all)
+
+ ctxt := build.Default
+ test := func(mustImport bool) {
+ for _, pkg := range all {
+ if isMacro(pkg) {
+ continue
+ }
+ p, err := ctxt.Import(pkg, "", 0)
+ if err != nil {
+ if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
+ continue
+ }
+ // Some of the combinations we try might not
+ // be reasonable (like arm,plan9,cgo), so ignore
+ // errors for the auto-generated combinations.
+ if !mustImport {
+ continue
+ }
+ t.Errorf("%s/%s/cgo=%v %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, err)
+ continue
+ }
+ ok := allowed(pkg)
+ var bad []string
+ for _, imp := range p.Imports {
+ if !ok[imp] {
+ bad = append(bad, imp)
+ }
+ }
+ if bad != nil {
+ t.Errorf("%s/%s/cgo=%v unexpected dependency: %s imports %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, pkg, bad)
+ }
+ }
+ }
+ test(true)
+
+ if testing.Short() {
+ t.Logf("skipping other systems")
+ return
+ }
+
+ for _, ctxt.GOOS = range geese {
+ for _, ctxt.GOARCH = range goarches {
+ for _, ctxt.CgoEnabled = range bools {
+ test(false)
+ }
+ }
+ }
+}
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
index 8a2db8fa3..ea21f3c74 100644
--- a/src/pkg/go/build/syslist.go
+++ b/src/pkg/go/build/syslist.go
@@ -1,4 +1,6 @@
-// Generated automatically by make.
+// 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 build
diff --git a/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
new file mode 100644
index 000000000..377c8b80c
--- /dev/null
+++ b/src/pkg/go/parser/error_test.go
@@ -0,0 +1,166 @@
+// 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.
+
+// This file implements a parser test harness. The files in the testdata
+// directory are parsed and the errors reported are compared against the
+// error messages expected in the test files. The test files must end in
+// .src rather than .go so that they are not disturbed by gofmt runs.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package p
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+
+package parser
+
+import (
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+const testdata = "testdata"
+
+// getFile assumes that each filename occurs at most once
+func getFile(filename string) (file *token.File) {
+ fset.Iterate(func(f *token.File) bool {
+ if f.Name() == filename {
+ if file != nil {
+ panic(filename + " used multiple times")
+ }
+ file = f
+ }
+ return true
+ })
+ return file
+}
+
+func getPos(filename string, offset int) token.Pos {
+ if f := getFile(filename); f != nil {
+ return f.Pos(offset)
+ }
+ return token.NoPos
+}
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+//
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]string {
+ errors := make(map[token.Pos]string)
+
+ var s scanner.Scanner
+ // file was parsed already - do not add it again to the file
+ // set otherwise the position information returned here will
+ // not match the position information collected by the parser
+ s.Init(getFile(filename), src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment, non-semicolon token
+
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ return errors
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ errors[prev] = string(s[1])
+ }
+ default:
+ prev = pos
+ }
+ }
+
+ panic("unreachable")
+}
+
+// compareErrors compares the map of expected error messages with the list
+// of found errors and reports discrepancies.
+//
+func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) {
+ for _, error := range found {
+ // error.Pos is a token.Position, but we want
+ // a token.Pos so we can do a map lookup
+ pos := getPos(error.Pos.Filename, error.Pos.Offset)
+ if msg, found := expected[pos]; found {
+ // we expect a message at pos; check if it matches
+ rx, err := regexp.Compile(msg)
+ if err != nil {
+ t.Errorf("%s: %v", error.Pos, err)
+ continue
+ }
+ if match := rx.MatchString(error.Msg); !match {
+ t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
+ continue
+ }
+ // we have a match - eliminate this error
+ delete(expected, pos)
+ } else {
+ // To keep in mind when analyzing failed test output:
+ // If the same error position occurs multiple times in errors,
+ // this message will be triggered (because the first error at
+ // the position removes this position from the expected errors).
+ t.Errorf("%s: unexpected error: %s", error.Pos, error.Msg)
+ }
+ }
+
+ // there should be no expected errors left
+ if len(expected) > 0 {
+ t.Errorf("%d errors not reported:", len(expected))
+ for pos, msg := range expected {
+ t.Errorf("%s: %s\n", fset.Position(pos), msg)
+ }
+ }
+}
+
+func checkErrors(t *testing.T, filename string, input interface{}) {
+ src, err := readSource(filename, input)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ _, err = ParseFile(fset, filename, src, DeclarationErrors)
+ found, ok := err.(scanner.ErrorList)
+ if err != nil && !ok {
+ t.Error(err)
+ return
+ }
+
+ // we are expecting the following errors
+ // (collect these after parsing a file so that it is found in the file set)
+ expected := expectedErrors(t, filename, src)
+
+ // verify errors returned by the parser
+ compareErrors(t, expected, found)
+}
+
+func TestErrors(t *testing.T) {
+ list, err := ioutil.ReadDir(testdata)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, fi := range list {
+ name := fi.Name()
+ if !fi.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".src") {
+ checkErrors(t, filepath.Join(testdata, name), nil)
+ }
+ }
+}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index a122baf08..e362e13a7 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -40,6 +40,13 @@ type parser struct {
tok token.Token // one token look-ahead
lit string // token literal
+ // Error recovery
+ // (used to limit the number of calls to syncXXX functions
+ // w/o making scanning progress - avoids potential endless
+ // loops across multiple parser functions during error recovery)
+ syncPos token.Pos // last synchronization position
+ syncCnt int // number of calls to syncXXX without progress
+
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
@@ -362,18 +369,36 @@ func (p *parser) expect(tok token.Token) token.Pos {
// expectClosing is like expect but provides a better error message
// for the common case of a missing comma before a newline.
//
-func (p *parser) expectClosing(tok token.Token, construct string) token.Pos {
+func (p *parser) expectClosing(tok token.Token, context string) token.Pos {
if p.tok != tok && p.tok == token.SEMICOLON && p.lit == "\n" {
- p.error(p.pos, "missing ',' before newline in "+construct)
+ p.error(p.pos, "missing ',' before newline in "+context)
p.next()
}
return p.expect(tok)
}
func (p *parser) expectSemi() {
+ // semicolon is optional before a closing ')' or '}'
if p.tok != token.RPAREN && p.tok != token.RBRACE {
- p.expect(token.SEMICOLON)
+ if p.tok == token.SEMICOLON {
+ p.next()
+ } else {
+ p.errorExpected(p.pos, "';'")
+ syncStmt(p)
+ }
+ }
+}
+
+func (p *parser) atComma(context string) bool {
+ if p.tok == token.COMMA {
+ return true
+ }
+ if p.tok == token.SEMICOLON && p.lit == "\n" {
+ p.error(p.pos, "missing ',' before newline in "+context)
+ return true // "insert" the comma and continue
+
}
+ return false
}
func assert(cond bool, msg string) {
@@ -382,6 +407,68 @@ func assert(cond bool, msg string) {
}
}
+// syncStmt advances to the next statement.
+// Used for synchronization after an error.
+//
+func syncStmt(p *parser) {
+ for {
+ switch p.tok {
+ case token.BREAK, token.CONST, token.CONTINUE, token.DEFER,
+ token.FALLTHROUGH, token.FOR, token.GO, token.GOTO,
+ token.IF, token.RETURN, token.SELECT, token.SWITCH,
+ token.TYPE, token.VAR:
+ // Return only if parser made some progress since last
+ // sync or if it has not reached 10 sync calls without
+ // progress. Otherwise consume at least one token to
+ // avoid an endless parser loop (it is possible that
+ // both parseOperand and parseStmt call syncStmt and
+ // correctly do not advance, thus the need for the
+ // invocation limit p.syncCnt).
+ if p.pos == p.syncPos && p.syncCnt < 10 {
+ p.syncCnt++
+ return
+ }
+ if p.pos > p.syncPos {
+ p.syncPos = p.pos
+ p.syncCnt = 0
+ return
+ }
+ // Reaching here indicates a parser bug, likely an
+ // incorrect token list in this function, but it only
+ // leads to skipping of possibly correct code if a
+ // previous error is present, and thus is preferred
+ // over a non-terminating parse.
+ case token.EOF:
+ return
+ }
+ p.next()
+ }
+}
+
+// syncDecl advances to the next declaration.
+// Used for synchronization after an error.
+//
+func syncDecl(p *parser) {
+ for {
+ switch p.tok {
+ case token.CONST, token.TYPE, token.VAR:
+ // see comments in syncStmt
+ if p.pos == p.syncPos && p.syncCnt < 10 {
+ p.syncCnt++
+ return
+ }
+ if p.pos > p.syncPos {
+ p.syncPos = p.pos
+ p.syncCnt = 0
+ return
+ }
+ case token.EOF:
+ return
+ }
+ p.next()
+ }
+}
+
// ----------------------------------------------------------------------------
// Identifiers
@@ -522,9 +609,11 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
for i, x := range list {
ident, isIdent := x.(*ast.Ident)
if !isIdent {
- pos := x.Pos()
- p.errorExpected(pos, "identifier")
- ident = &ast.Ident{NamePos: pos, Name: "_"}
+ if _, isBad := x.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(x.Pos(), "identifier")
+ }
+ ident = &ast.Ident{NamePos: x.Pos(), Name: "_"}
}
idents[i] = ident
}
@@ -688,7 +777,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
p.declare(field, nil, scope, ast.Var, idents...)
- if p.tok != token.COMMA {
+ if !p.atComma("parameter list") {
break
}
p.next()
@@ -991,19 +1080,19 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
case token.FUNC:
return p.parseFuncTypeOrLit()
+ }
- default:
- if typ := p.tryIdentOrType(true); typ != nil {
- // could be type for composite literal or conversion
- _, isIdent := typ.(*ast.Ident)
- assert(!isIdent, "type cannot be identifier")
- return typ
- }
+ if typ := p.tryIdentOrType(true); typ != nil {
+ // could be type for composite literal or conversion
+ _, isIdent := typ.(*ast.Ident)
+ assert(!isIdent, "type cannot be identifier")
+ return typ
}
+ // we have an error
pos := p.pos
p.errorExpected(pos, "operand")
- p.next() // make progress
+ syncStmt(p)
return &ast.BadExpr{From: pos, To: p.pos}
}
@@ -1078,7 +1167,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
ellipsis = p.pos
p.next()
}
- if p.tok != token.COMMA {
+ if !p.atComma("argument list") {
break
}
p.next()
@@ -1118,7 +1207,7 @@ func (p *parser) parseElementList() (list []ast.Expr) {
for p.tok != token.RBRACE && p.tok != token.EOF {
list = append(list, p.parseElement(true))
- if p.tok != token.COMMA {
+ if !p.atComma("composite literal") {
break
}
p.next()
@@ -1262,8 +1351,8 @@ L:
x = p.parseTypeAssertion(p.checkExpr(x))
default:
pos := p.pos
- p.next() // make progress
p.errorExpected(pos, "selector or type assertion")
+ p.next() // make progress
x = &ast.BadExpr{From: pos, To: p.pos}
}
case token.LBRACK:
@@ -1471,7 +1560,10 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
- p.errorExpected(x.Pos(), "function/method call")
+ if _, isBad := x.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(x.Pos(), "function/method call")
+ }
return nil
}
@@ -1862,7 +1954,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
switch p.tok {
case token.CONST, token.TYPE, token.VAR:
- s = &ast.DeclStmt{Decl: p.parseDecl()}
+ s = &ast.DeclStmt{Decl: p.parseDecl(syncStmt)}
case
// tokens that may start an expression
token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
@@ -1904,7 +1996,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
// no statement found
pos := p.pos
p.errorExpected(pos, "statement")
- p.next() // make progress
+ syncStmt(p)
s = &ast.BadStmt{From: pos, To: p.pos}
}
@@ -2095,8 +2187,13 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
recv := par.List[0]
base := deref(recv.Type)
if _, isIdent := base.(*ast.Ident); !isIdent {
- p.errorExpected(base.Pos(), "(unqualified) identifier")
- par.List = []*ast.Field{{Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}}}
+ if _, isBad := base.(*ast.BadExpr); !isBad {
+ // only report error if it's a new one
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ }
+ par.List = []*ast.Field{
+ {Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
+ }
}
return par
@@ -2152,7 +2249,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
return decl
}
-func (p *parser) parseDecl() ast.Decl {
+func (p *parser) parseDecl(sync func(*parser)) ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
}
@@ -2174,9 +2271,8 @@ func (p *parser) parseDecl() ast.Decl {
default:
pos := p.pos
p.errorExpected(pos, "declaration")
- p.next() // make progress
- decl := &ast.BadDecl{From: pos, To: p.pos}
- return decl
+ sync(p)
+ return &ast.BadDecl{From: pos, To: p.pos}
}
return p.parseGenDecl(p.tok, f)
@@ -2215,7 +2311,7 @@ func (p *parser) parseFile() *ast.File {
if p.mode&ImportsOnly == 0 {
// rest of package body
for p.tok != token.EOF {
- decls = append(decls, p.parseDecl())
+ decls = append(decls, p.parseDecl(syncDecl))
}
}
}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 93ca3d6aa..5e45acd00 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -14,87 +14,14 @@ import (
var fset = token.NewFileSet()
-var illegalInputs = []interface{}{
- nil,
- 3.14,
- []byte(nil),
- "foo!",
- `package p; func f() { if /* should have condition */ {} };`,
- `package p; func f() { if ; /* should have condition */ {} };`,
- `package p; func f() { if f(); /* should have condition */ {} };`,
- `package p; const c; /* should have constant value */`,
- `package p; func f() { if _ = range x; true {} };`,
- `package p; func f() { switch _ = range x; true {} };`,
- `package p; func f() { for _ = range x ; ; {} };`,
- `package p; func f() { for ; ; _ = range x {} };`,
- `package p; func f() { for ; _ = range x ; {} };`,
- `package p; func f() { switch t = t.(type) {} };`,
- `package p; func f() { switch t, t = t.(type) {} };`,
- `package p; func f() { switch t = t.(type), t {} };`,
- `package p; var a = [1]int; /* illegal expression */`,
- `package p; var a = [...]int; /* illegal expression */`,
- `package p; var a = struct{} /* illegal expression */`,
- `package p; var a = func(); /* illegal expression */`,
- `package p; var a = interface{} /* illegal expression */`,
- `package p; var a = []int /* illegal expression */`,
- `package p; var a = map[int]int /* illegal expression */`,
- `package p; var a = chan int; /* illegal expression */`,
- `package p; var a = []int{[]int}; /* illegal expression */`,
- `package p; var a = ([]int); /* illegal expression */`,
- `package p; var a = a[[]int:[]int]; /* illegal expression */`,
- `package p; var a = <- chan int; /* illegal expression */`,
- `package p; func f() { select { case _ <- chan int: } };`,
-}
-
-func TestParseIllegalInputs(t *testing.T) {
- for _, src := range illegalInputs {
- _, err := ParseFile(fset, "", src, 0)
- if err == nil {
- t.Errorf("ParseFile(%v) should have failed", src)
- }
- }
-}
-
-var validPrograms = []string{
- "package p\n",
- `package p;`,
- `package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
- `package p; func f() { if f(T{}) {} };`,
- `package p; func f() { _ = (<-chan int)(x) };`,
- `package p; func f() { _ = (<-chan <-chan int)(x) };`,
- `package p; func f(func() func() func());`,
- `package p; func f(...T);`,
- `package p; func f(float, ...int);`,
- `package p; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
- `package p; func f(int,) {};`,
- `package p; func f(...int,) {};`,
- `package p; func f(x ...int,) {};`,
- `package p; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
- `package p; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
- `package p; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
- `package p; var a = T{{1, 2}, {3, 4}}`,
- `package p; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
- `package p; func f() { select { case x := (<-c): } };`,
- `package p; func f() { if ; true {} };`,
- `package p; func f() { switch ; {} };`,
- `package p; func f() { for _ = range "foo" + "bar" {} };`,
-}
-
-func TestParseValidPrograms(t *testing.T) {
- for _, src := range validPrograms {
- _, err := ParseFile(fset, "", src, SpuriousErrors)
- if err != nil {
- t.Errorf("ParseFile(%q): %v", src, err)
- }
- }
-}
-
var validFiles = []string{
"parser.go",
"parser_test.go",
+ "error_test.go",
+ "short_test.go",
}
-func TestParse3(t *testing.T) {
+func TestParse(t *testing.T) {
for _, filename := range validFiles {
_, err := ParseFile(fset, filename, nil, DeclarationErrors)
if err != nil {
@@ -116,7 +43,7 @@ func nameFilter(filename string) bool {
func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
-func TestParse4(t *testing.T) {
+func TestParseDir(t *testing.T) {
path := "."
pkgs, err := ParseDir(fset, path, dirFilter, 0)
if err != nil {
@@ -158,7 +85,7 @@ func TestParseExpr(t *testing.T) {
}
// it must not crash
- for _, src := range validPrograms {
+ for _, src := range valids {
ParseExpr(src)
}
}
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
new file mode 100644
index 000000000..238492bf3
--- /dev/null
+++ b/src/pkg/go/parser/short_test.go
@@ -0,0 +1,75 @@
+// 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.
+
+// This file contains test cases for short valid and invalid programs.
+
+package parser
+
+import "testing"
+
+var valids = []string{
+ "package p\n",
+ `package p;`,
+ `package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
+ `package p; func f() { if f(T{}) {} };`,
+ `package p; func f() { _ = (<-chan int)(x) };`,
+ `package p; func f() { _ = (<-chan <-chan int)(x) };`,
+ `package p; func f(func() func() func());`,
+ `package p; func f(...T);`,
+ `package p; func f(float, ...int);`,
+ `package p; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+ `package p; func f(int,) {};`,
+ `package p; func f(...int,) {};`,
+ `package p; func f(x ...int,) {};`,
+ `package p; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+ `package p; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+ `package p; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+ `package p; var a = T{{1, 2}, {3, 4}}`,
+ `package p; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
+ `package p; func f() { select { case x := (<-c): } };`,
+ `package p; func f() { if ; true {} };`,
+ `package p; func f() { switch ; {} };`,
+ `package p; func f() { for _ = range "foo" + "bar" {} };`,
+}
+
+func TestValid(t *testing.T) {
+ for _, src := range valids {
+ checkErrors(t, src, src)
+ }
+}
+
+var invalids = []string{
+ `foo /* ERROR "expected 'package'" */ !`,
+ `package p; func f() { if { /* ERROR "expected operand" */ } };`,
+ `package p; func f() { if ; { /* ERROR "expected operand" */ } };`,
+ `package p; func f() { if f(); { /* ERROR "expected operand" */ } };`,
+ `package p; const c; /* ERROR "expected '='" */`,
+ `package p; func f() { if _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { switch _ /* ERROR "expected condition" */ = range x; true {} };`,
+ `package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
+ `package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
+ `package p; func f() { for ; _ /* ERROR "expected condition" */ = range x ; {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ , t = t.(type) {} };`,
+ `package p; func f() { switch t /* ERROR "expected condition" */ = t.(type), t {} };`,
+ `package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
+ `package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
+ `package p; var a = struct /* ERROR "expected expression" */ {}`,
+ `package p; var a = func /* ERROR "expected expression" */ ();`,
+ `package p; var a = interface /* ERROR "expected expression" */ {}`,
+ `package p; var a = [ /* ERROR "expected expression" */ ]int`,
+ `package p; var a = map /* ERROR "expected expression" */ [int]int`,
+ `package p; var a = chan /* ERROR "expected expression" */ int;`,
+ `package p; var a = []int{[ /* ERROR "expected expression" */ ]int};`,
+ `package p; var a = ( /* ERROR "expected expression" */ []int);`,
+ `package p; var a = a[[ /* ERROR "expected expression" */ ]int:[]int];`,
+ `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
+ `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
+}
+
+func TestInvalid(t *testing.T) {
+ for _, src := range invalids {
+ checkErrors(t, src, src)
+ }
+}
diff --git a/src/pkg/go/parser/testdata/commas.src b/src/pkg/go/parser/testdata/commas.src
new file mode 100644
index 000000000..af6e70645
--- /dev/null
+++ b/src/pkg/go/parser/testdata/commas.src
@@ -0,0 +1,19 @@
+// 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.
+
+// Test case for error messages/parser synchronization
+// after missing commas.
+
+package p
+
+var _ = []int{
+ 0 /* ERROR "missing ','" */
+}
+
+var _ = []int{
+ 0,
+ 1,
+ 2,
+ 3 /* ERROR "missing ','" */
+}
diff --git a/src/pkg/go/parser/testdata/issue3106.src b/src/pkg/go/parser/testdata/issue3106.src
new file mode 100644
index 000000000..82796c8ce
--- /dev/null
+++ b/src/pkg/go/parser/testdata/issue3106.src
@@ -0,0 +1,46 @@
+// 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.
+
+// Test case for issue 3106: Better synchronization of
+// parser after certain syntax errors.
+
+package main
+
+func f() {
+ var m Mutex
+ c := MakeCond(&m)
+ percent := 0
+ const step = 10
+ for i := 0; i < 5; i++ {
+ go func() {
+ for {
+ // Emulates some useful work.
+ time.Sleep(1e8)
+ m.Lock()
+ defer
+ if /* ERROR "expected operand, found 'if'" */ percent == 100 {
+ m.Unlock()
+ break
+ }
+ percent++
+ if percent % step == 0 {
+ //c.Signal()
+ }
+ m.Unlock()
+ }
+ }()
+ }
+ for {
+ m.Lock()
+ if percent == 0 || percent % step != 0 {
+ c.Wait()
+ }
+ fmt.Print(",")
+ if percent == 100 {
+ m.Unlock()
+ break
+ }
+ m.Unlock()
+ }
+}
diff --git a/src/pkg/go/printer/example_test.go b/src/pkg/go/printer/example_test.go
new file mode 100644
index 000000000..e570040ba
--- /dev/null
+++ b/src/pkg/go/printer/example_test.go
@@ -0,0 +1,67 @@
+// 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 printer_test
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "strings"
+ "testing"
+)
+
+// Dummy test function so that godoc does not use the entire file as example.
+func Test(*testing.T) {}
+
+func parseFunc(filename, functionname string) (fun *ast.FuncDecl, fset *token.FileSet) {
+ fset = token.NewFileSet()
+ if file, err := parser.ParseFile(fset, filename, nil, 0); err == nil {
+ for _, d := range file.Decls {
+ if f, ok := d.(*ast.FuncDecl); ok && f.Name.Name == functionname {
+ fun = f
+ return
+ }
+ }
+ }
+ panic("function not found")
+}
+
+func ExampleFprint() {
+ // Parse source file and extract the AST without comments for
+ // this function, with position information referring to the
+ // file set fset.
+ funcAST, fset := parseFunc("example_test.go", "ExampleFprint")
+
+ // Print the function body into buffer buf.
+ // The file set is provided to the printer so that it knows
+ // about the original source formatting and can add additional
+ // line breaks where they were present in the source.
+ var buf bytes.Buffer
+ printer.Fprint(&buf, fset, funcAST.Body)
+
+ // Remove braces {} enclosing the function body, unindent,
+ // and trim leading and trailing white space.
+ s := buf.String()
+ s = s[1 : len(s)-1]
+ s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))
+
+ // Print the cleaned-up body text to stdout.
+ fmt.Println(s)
+
+ // output:
+ // funcAST, fset := parseFunc("example_test.go", "ExampleFprint")
+ //
+ // var buf bytes.Buffer
+ // printer.Fprint(&buf, fset, funcAST.Body)
+ //
+ // s := buf.String()
+ // s = s[1 : len(s)-1]
+ // s = strings.TrimSpace(strings.Replace(s, "\n\t", "\n", -1))
+ //
+ // fmt.Println(s)
+}
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 05b4ef59a..727d2a371 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -15,7 +15,7 @@ import (
"unicode/utf8"
)
-// Other formatting issues:
+// Formatting issues:
// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
// when the comment spans multiple lines; if such a comment is just two lines, formatting is
// not idempotent
@@ -365,7 +365,7 @@ func (p *printer) setLineComment(text string) {
}
func (p *printer) isMultiLine(n ast.Node) bool {
- return p.lineFor(n.End())-p.lineFor(n.Pos()) > 1
+ return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
}
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
@@ -964,6 +964,41 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
}
+// indentList reports whether an expression list would look better if it
+// were indented wholesale (starting with the very first element, rather
+// than starting at the first line break).
+//
+func (p *printer) indentList(list []ast.Expr) bool {
+ // Heuristic: indentList returns true if there are more than one multi-
+ // line element in the list, or if there is any element that is not
+ // starting on the same line as the previous one ends.
+ if len(list) >= 2 {
+ var b = p.lineFor(list[0].Pos())
+ var e = p.lineFor(list[len(list)-1].End())
+ if 0 < b && b < e {
+ // list spans multiple lines
+ n := 0 // multi-line element count
+ line := b
+ for _, x := range list {
+ xb := p.lineFor(x.Pos())
+ xe := p.lineFor(x.End())
+ if line < xb {
+ // x is not starting on the same
+ // line as the previous one ended
+ return true
+ }
+ if xb < xe {
+ // x is a multi-line element
+ n++
+ }
+ line = xe
+ }
+ return n > 1
+ }
+ }
+ return false
+}
+
func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(stmt.Pos())
@@ -1030,7 +1065,18 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
p.print(token.RETURN)
if s.Results != nil {
p.print(blank)
- p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos)
+ // Use indentList heuristic to make corner cases look
+ // better (issue 1207). A more systematic approach would
+ // always indent, but this would cause significant
+ // reformatting of the code base and not necessarily
+ // lead to more nicely formatted code in general.
+ if p.indentList(s.Results) {
+ p.print(indent)
+ p.exprList(s.Pos(), s.Results, 1, noIndent, token.NoPos)
+ p.print(unindent)
+ } else {
+ p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos)
+ }
}
case *ast.BranchStmt:
@@ -1200,9 +1246,9 @@ func keepTypeColumn(specs []ast.Spec) []bool {
return m
}
-func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool) {
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
p.setComment(s.Doc)
- p.identList(s.Names, doIndent) // always present
+ p.identList(s.Names, false) // always present
extraTabs := 3
if s.Type != nil || keepType {
p.print(vtab)
@@ -1290,7 +1336,7 @@ func (p *printer) genDecl(d *ast.GenDecl) {
if i > 0 {
p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
}
- p.valueSpec(s.(*ast.ValueSpec), keepType[i], false)
+ p.valueSpec(s.(*ast.ValueSpec), keepType[i])
newSection = p.isMultiLine(s)
}
} else {
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 7ed7cb61a..71ed32ed1 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -500,7 +500,7 @@ type _ struct {
type _ struct {
a, b,
- c, d int // this line should be indented
+ c, d int // this line should be indented
u, v, w, x float // this line should be indented
p, q,
r, s float // this line should be indented
@@ -562,10 +562,21 @@ var a2, b2,
var (
a3, b3,
- c3, d3 int // this line should be indented
+ c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented
)
+// Test case from issue 3304: multi-line declarations must end
+// a formatting section and not influence indentation of the
+// next line.
+var (
+ minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
+ "minimum time window between two refreshes for a given user.")
+ x = flag.Int64("refresh_user_rollout_percent", 100,
+ "temporary flag to ramp up the refresh user rpc")
+ aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
+)
+
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{},
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index df8c2b167..d74cff25d 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -577,6 +577,16 @@ c3, d3 int // this line should be indented
a4, b4, c4 int // this line should be indented
)
+// Test case from issue 3304: multi-line declarations must end
+// a formatting section and not influence indentation of the
+// next line.
+var (
+ minRefreshTimeSec = flag.Int64("min_refresh_time_sec", 604800,
+ "minimum time window between two refreshes for a given user.")
+ x = flag.Int64("refresh_user_rollout_percent", 100,
+ "temporary flag to ramp up the refresh user rpc")
+ aVeryLongVariableName = stats.GetVarInt("refresh-user-count")
+)
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
index ffca21edb..4d70617bf 100644
--- a/src/pkg/go/printer/testdata/statements.golden
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -55,12 +55,24 @@ func _f() {
return T{
1,
2,
- },
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
nil
return T{
- 1,
- 2,
- },
+ 1,
+ 2,
+ },
T{
x: 3,
y: 4,
@@ -70,10 +82,10 @@ func _f() {
z
return func() {}
return func() {
- _ = 0
- }, T{
- 1, 2,
- }
+ _ = 0
+ }, T{
+ 1, 2,
+ }
return func() {
_ = 0
}
@@ -84,6 +96,37 @@ func _f() {
}
}
+// Formatting of multi-line returns: test cases from issue 1207.
+func F() (*T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ nil
+}
+
+func G() (*T, *T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ &T{
+ X: 3,
+ Y: 4,
+ },
+ nil
+}
+
+func _() interface{} {
+ return &fileStat{
+ name: basename(file.name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSysFromFI(&d),
+ }, nil
+}
+
// Formatting of if-statement headers.
func _() {
if true {
diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input
index 99945e955..bd03bc98b 100644
--- a/src/pkg/go/printer/testdata/statements.input
+++ b/src/pkg/go/printer/testdata/statements.input
@@ -55,6 +55,18 @@ func _f() {
return T{
1,
2,
+ }, nil
+ return T{
+ 1,
+ 2,
+ },
+ T{
+ x: 3,
+ y: 4,
+ }, nil
+ return T{
+ 1,
+ 2,
},
nil
return T{
@@ -84,6 +96,37 @@ func _f() {
}
}
+// Formatting of multi-line returns: test cases from issue 1207.
+func F() (*T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ nil
+}
+
+func G() (*T, *T, os.Error) {
+ return &T{
+ X: 1,
+ Y: 2,
+ },
+ &T{
+ X: 3,
+ Y: 4,
+ },
+ nil
+}
+
+func _() interface{} {
+ return &fileStat{
+ name: basename(file.name),
+ size: mkSize(d.FileSizeHigh, d.FileSizeLow),
+ modTime: mkModTime(d.LastWriteTime),
+ mode: mkMode(d.FileAttributes),
+ sys: mkSysFromFI(&d),
+ }, nil
+}
+
// Formatting of if-statement headers.
func _() {
if true {}
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 2395363b0..da508747a 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -109,7 +109,7 @@ const (
func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
// Explicitly initialize all fields since a scanner may be reused.
if file.Size() != len(src) {
- panic("file size does not match src len")
+ panic(fmt.Sprintf("file size (%d) does not match src len (%d)", file.Size(), len(src)))
}
s.file = file
s.dir, _ = filepath.Split(file.Name())
diff --git a/src/pkg/html/template/clone_test.go b/src/pkg/html/template/clone_test.go
index c612775d4..2663cddc2 100644
--- a/src/pkg/html/template/clone_test.go
+++ b/src/pkg/html/template/clone_test.go
@@ -113,3 +113,36 @@ func TestClone(t *testing.T) {
t.Errorf("t3: got %q want %q", got, want)
}
}
+
+func TestTemplates(t *testing.T) {
+ names := []string{"t0", "a", "lhs", "rhs"}
+ // Some template definitions borrowed from TestClone.
+ const tmpl = `
+ {{define "a"}}{{template "lhs"}}{{.}}{{template "rhs"}}{{end}}
+ {{define "lhs"}} <a href=" {{end}}
+ {{define "rhs"}} "></a> {{end}}`
+ t0 := Must(New("t0").Parse(tmpl))
+ templates := t0.Templates()
+ if len(templates) != len(names) {
+ t.Errorf("expected %d templates; got %d", len(names), len(templates))
+ }
+ for _, name := range names {
+ found := false
+ for _, tmpl := range templates {
+ if name == tmpl.text.Name() {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Error("could not find template", name)
+ }
+ }
+}
+
+// This used to crash; http://golang.org/issue/3281
+func TestCloneCrash(t *testing.T) {
+ t1 := New("all")
+ Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
+ t1.Clone()
+}
diff --git a/src/pkg/html/template/content.go b/src/pkg/html/template/content.go
index 539664f97..c1bd2e494 100644
--- a/src/pkg/html/template/content.go
+++ b/src/pkg/html/template/content.go
@@ -26,10 +26,10 @@ type (
HTML string
// HTMLAttr encapsulates an HTML attribute from a trusted source,
- // for example: ` dir="ltr"`.
+ // for example, ` dir="ltr"`.
HTMLAttr string
- // JS encapsulates a known safe EcmaScript5 Expression, or example,
+ // JS encapsulates a known safe EcmaScript5 Expression, for example,
// `(x + y * z())`.
// Template authors are responsible for ensuring that typed expressions
// do not break the intended precedence and that there is no
diff --git a/src/pkg/html/template/doc.go b/src/pkg/html/template/doc.go
index 3699ea1a9..f470facfd 100644
--- a/src/pkg/html/template/doc.go
+++ b/src/pkg/html/template/doc.go
@@ -29,7 +29,7 @@ can be safely embedded in an HTML document. The escaping is contextual, so
actions can appear within JavaScript, CSS, and URI contexts.
The security model used by this package assumes that template authors are
-trusted, while text/template Execute's data parameter is not. More details are
+trusted, while Execute's data parameter is not. More details are
provided below.
Example
diff --git a/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go
index a058e20d7..5f0e28e8c 100644
--- a/src/pkg/html/template/escape.go
+++ b/src/pkg/html/template/escape.go
@@ -8,6 +8,7 @@ import (
"bytes"
"fmt"
"html"
+ "io"
"text/template"
"text/template/parse"
)
@@ -751,3 +752,44 @@ func (e *escaper) template(name string) *template.Template {
}
return t
}
+
+// Forwarding functions so that clients need only import this package
+// to reach the general escaping functions of text/template.
+
+// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
+func HTMLEscape(w io.Writer, b []byte) {
+ template.HTMLEscape(w, b)
+}
+
+// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
+func HTMLEscapeString(s string) string {
+ return template.HTMLEscapeString(s)
+}
+
+// HTMLEscaper returns the escaped HTML equivalent of the textual
+// representation of its arguments.
+func HTMLEscaper(args ...interface{}) string {
+ return template.HTMLEscaper(args...)
+}
+
+// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+func JSEscape(w io.Writer, b []byte) {
+ template.JSEscape(w, b)
+}
+
+// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
+func JSEscapeString(s string) string {
+ return template.JSEscapeString(s)
+}
+
+// JSEscaper returns the escaped JavaScript equivalent of the textual
+// representation of its arguments.
+func JSEscaper(args ...interface{}) string {
+ return template.JSEscaper(args...)
+}
+
+// URLQueryEscaper returns the escaped value of the textual representation of
+// its arguments in a form suitable for embedding in a URL query.
+func URLQueryEscaper(args ...interface{}) string {
+ return template.URLQueryEscaper(args...)
+}
diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go
index 2bbb1b1bc..ce12c1795 100644
--- a/src/pkg/html/template/escape_test.go
+++ b/src/pkg/html/template/escape_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "os"
"strings"
"testing"
"text/template"
@@ -1637,6 +1638,14 @@ func TestIndirectPrint(t *testing.T) {
}
}
+// This is a test for issue 3272.
+func TestEmptyTemplate(t *testing.T) {
+ page := Must(New("page").ParseFiles(os.DevNull))
+ if err := page.ExecuteTemplate(os.Stdout, "page", "nothing"); err == nil {
+ t.Fatal("expected error")
+ }
+}
+
func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer
diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
index b0bae7a54..edac7335c 100644
--- a/src/pkg/html/template/template.go
+++ b/src/pkg/html/template/template.go
@@ -31,6 +31,20 @@ type nameSpace struct {
set map[string]*Template
}
+// Templates returns a slice of the templates associated with t, including t
+// itself.
+func (t *Template) Templates() []*Template {
+ ns := t.nameSpace
+ ns.mu.Lock()
+ defer ns.mu.Unlock()
+ // Return a slice so we don't expose the map.
+ m := make([]*Template, 0, len(ns.set))
+ for _, v := range ns.set {
+ m = append(m, v)
+ }
+ return m
+}
+
// Execute applies a parsed template to the specified data object,
// writing the output to wr.
func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
@@ -64,7 +78,13 @@ func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err err
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
tmpl = t.set[name]
- if (tmpl == nil) != (t.text.Lookup(name) == nil) {
+ if tmpl == nil {
+ return nil, fmt.Errorf("html/template: %q is undefined", name)
+ }
+ if tmpl.text.Tree == nil || tmpl.text.Root == nil {
+ return nil, fmt.Errorf("html/template: %q is an incomplete template", name)
+ }
+ if t.text.Lookup(name) == nil {
panic("html/template internal error: template escaping out of sync")
}
if tmpl != nil && !tmpl.escaped {
@@ -160,9 +180,11 @@ func (t *Template) Clone() (*Template, error) {
if src == nil || src.escaped {
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
}
- x.Tree = &parse.Tree{
- Name: x.Tree.Name,
- Root: x.Tree.Root.CopyList(),
+ if x.Tree != nil {
+ x.Tree = &parse.Tree{
+ Name: x.Tree.Name,
+ Root: x.Tree.Root.CopyList(),
+ }
}
ret.set[name] = &Template{
false,
@@ -274,7 +296,7 @@ func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
func parseFiles(t *Template, filenames ...string) (*Template, error) {
if len(filenames) == 0 {
// Not really a problem, but be consistent.
- return nil, fmt.Errorf("template: no files named in call to ParseFiles")
+ return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
}
for _, filename := range filenames {
b, err := ioutil.ReadFile(filename)
@@ -331,7 +353,7 @@ func parseGlob(t *Template, pattern string) (*Template, error) {
return nil, err
}
if len(filenames) == 0 {
- return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
+ return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern)
}
return parseFiles(t, filenames...)
}
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
index 3b6679f7c..bef325c0c 100644
--- a/src/pkg/image/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -5,7 +5,7 @@
// Package draw provides image composition functions.
//
// See "The Go image/draw package" for an introduction to this package:
-// http://blog.golang.org/2011/09/go-imagedraw-package.html
+// http://golang.org/doc/articles/image_draw.html
package draw
import (
diff --git a/src/pkg/index/suffixarray/qsufsort.go b/src/pkg/index/suffixarray/qsufsort.go
index c69be43c2..9c36a98f8 100644
--- a/src/pkg/index/suffixarray/qsufsort.go
+++ b/src/pkg/index/suffixarray/qsufsort.go
@@ -11,7 +11,7 @@
// Consecutive groups of suffixes in sa are labeled as sorted groups or
// unsorted groups. For a given pass of the sorter, all suffixes are ordered
// up to their first h characters, and sa is h-ordered. Suffixes in their
-// final positions and unambiguouly sorted in h-order are in a sorted group.
+// final positions and unambiguously sorted in h-order are in a sorted group.
// Consecutive groups of suffixes with identical first h characters are an
// unsorted group. In each pass of the algorithm, unsorted groups are sorted
// according to the group number of their following suffix.
@@ -78,7 +78,7 @@ func sortedByFirstByte(data []byte) []int {
for _, b := range data {
count[b]++
}
- // make count[b] equal index of first occurence of b in sorted array
+ // make count[b] equal index of first occurrence of b in sorted array
sum := 0
for b := range count {
count[b], sum = sum, count[b]+sum
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index 7074834d6..54bf159eb 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -173,6 +173,13 @@ type ReaderAt interface {
// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// WriteAt must return a non-nil error if it returns n < len(p).
+//
+// If WriteAt is writing to a destination with a seek offset,
+// WriteAt should not affect nor be affected by the underlying
+// seek offset.
+//
+// Clients of WriteAt can execute parallel WriteAt calls on the same
+// destination if the ranges do not overlap.
type WriterAt interface {
WriteAt(p []byte, off int64) (n int, err error)
}
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index 180afc2c2..f072b8c75 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -53,10 +53,13 @@ func ReadFile(filename string) ([]byte, error) {
defer f.Close()
// It's a good but not certain bet that FileInfo will tell us exactly how much to
// read, so let's try it but be prepared for the answer to be wrong.
- fi, err := f.Stat()
var n int64
- if size := fi.Size(); err == nil && size < 2e9 { // Don't preallocate a huge buffer, just in case.
- n = size
+
+ if fi, err := f.Stat(); err == nil {
+ // Don't preallocate a huge buffer, just in case.
+ if size := fi.Size(); size < 1e9 {
+ n = size
+ }
}
// As initial capacity for readAll, use n + a little extra in case Size is zero,
// and to avoid another allocation after Read has filled the buffer. The readAll
diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go
index a5d88fd9b..1d7f209d1 100644
--- a/src/pkg/log/log.go
+++ b/src/pkg/log/log.go
@@ -13,7 +13,6 @@
package log
import (
- "bytes"
"fmt"
"io"
"os"
@@ -28,7 +27,7 @@ const (
// order they appear (the order listed here) or the format they present (as
// described in the comments). A colon appears after these items:
// 2009/0123 01:23:23.123123 /a/b/c/d.go:23: message
- Ldate = 1 << iota // the date: 2009/0123
+ Ldate = 1 << iota // the date: 2009/01/23
Ltime // the time: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
@@ -41,11 +40,11 @@ const (
// the Writer's Write method. A Logger can be used simultaneously from
// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
- mu sync.Mutex // ensures atomic writes; protects the following fields
- prefix string // prefix to write at beginning of each line
- flag int // properties
- out io.Writer // destination for output
- buf bytes.Buffer // for accumulating text to write
+ mu sync.Mutex // ensures atomic writes; protects the following fields
+ prefix string // prefix to write at beginning of each line
+ flag int // properties
+ out io.Writer // destination for output
+ buf []byte // for accumulating text to write
}
// New creates a new Logger. The out variable sets the
@@ -60,10 +59,10 @@ var std = New(os.Stderr, "", LstdFlags)
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
// Knows the buffer has capacity.
-func itoa(buf *bytes.Buffer, i int, wid int) {
+func itoa(buf *[]byte, i int, wid int) {
var u uint = uint(i)
if u == 0 && wid <= 1 {
- buf.WriteByte('0')
+ *buf = append(*buf, '0')
return
}
@@ -75,38 +74,33 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
wid--
b[bp] = byte(u%10) + '0'
}
-
- // avoid slicing b to avoid an allocation.
- for bp < len(b) {
- buf.WriteByte(b[bp])
- bp++
- }
+ *buf = append(*buf, b[bp:]...)
}
-func (l *Logger) formatHeader(buf *bytes.Buffer, t time.Time, file string, line int) {
- buf.WriteString(l.prefix)
+func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
+ *buf = append(*buf, l.prefix...)
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
if l.flag&Ldate != 0 {
year, month, day := t.Date()
itoa(buf, year, 4)
- buf.WriteByte('/')
+ *buf = append(*buf, '/')
itoa(buf, int(month), 2)
- buf.WriteByte('/')
+ *buf = append(*buf, '/')
itoa(buf, day, 2)
- buf.WriteByte(' ')
+ *buf = append(*buf, ' ')
}
if l.flag&(Ltime|Lmicroseconds) != 0 {
hour, min, sec := t.Clock()
itoa(buf, hour, 2)
- buf.WriteByte(':')
+ *buf = append(*buf, ':')
itoa(buf, min, 2)
- buf.WriteByte(':')
+ *buf = append(*buf, ':')
itoa(buf, sec, 2)
if l.flag&Lmicroseconds != 0 {
- buf.WriteByte('.')
+ *buf = append(*buf, '.')
itoa(buf, t.Nanosecond()/1e3, 6)
}
- buf.WriteByte(' ')
+ *buf = append(*buf, ' ')
}
}
if l.flag&(Lshortfile|Llongfile) != 0 {
@@ -120,10 +114,10 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, t time.Time, file string, line
}
file = short
}
- buf.WriteString(file)
- buf.WriteByte(':')
+ *buf = append(*buf, file...)
+ *buf = append(*buf, ':')
itoa(buf, line, -1)
- buf.WriteString(": ")
+ *buf = append(*buf, ": "...)
}
}
@@ -150,13 +144,13 @@ func (l *Logger) Output(calldepth int, s string) error {
}
l.mu.Lock()
}
- l.buf.Reset()
+ l.buf = l.buf[:0]
l.formatHeader(&l.buf, now, file, line)
- l.buf.WriteString(s)
+ l.buf = append(l.buf, s...)
if len(s) > 0 && s[len(s)-1] != '\n' {
- l.buf.WriteByte('\n')
+ l.buf = append(l.buf, '\n')
}
- _, err := l.out.Write(l.buf.Bytes())
+ _, err := l.out.Write(l.buf)
return err
}
diff --git a/src/pkg/log/syslog/syslog_windows.go b/src/pkg/log/syslog/syslog_windows.go
new file mode 100644
index 000000000..8d99e2e59
--- /dev/null
+++ b/src/pkg/log/syslog/syslog_windows.go
@@ -0,0 +1,8 @@
+// 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 syslog provides a simple interface to the system log service.
+package syslog
+
+// BUG(brainman): This package is not implemented on Windows yet.
diff --git a/src/pkg/math/big/nat.go b/src/pkg/math/big/nat.go
index da1ac944c..0bc6572b9 100644
--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -826,7 +826,7 @@ func (x nat) string(charset string) string {
// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
-// specfic hardware.
+// specific hardware.
//
func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
// split larger blocks recursively
diff --git a/src/pkg/math/erf.go b/src/pkg/math/erf.go
index 87c70c251..c6f32bdbe 100644
--- a/src/pkg/math/erf.go
+++ b/src/pkg/math/erf.go
@@ -248,7 +248,7 @@ func Erf(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
}
- z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign {
return r/x - 1
@@ -321,7 +321,7 @@ func Erfc(x float64) float64 {
R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6)))))
S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7))))))
}
- z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precison x
+ z := Float64frombits(Float64bits(x) & 0xffffffff00000000) // pseudo-single (20-bit) precision x
r := Exp(-z*z-0.5625) * Exp((z-x)*(z+x)+R/S)
if sign {
return 2 - r/x
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index 5f5aea146..7212087fe 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -6,6 +6,7 @@ package net
import (
"flag"
+ "fmt"
"regexp"
"runtime"
"testing"
@@ -32,7 +33,7 @@ func TestDialTimeout(t *testing.T) {
numConns := listenerBacklog + 10
// TODO(bradfitz): It's hard to test this in a portable
- // way. This is unforunate, but works for now.
+ // way. This is unfortunate, but works for now.
switch runtime.GOOS {
case "linux":
// The kernel will start accepting TCP connections before userspace
@@ -44,13 +45,25 @@ func TestDialTimeout(t *testing.T) {
errc <- err
}()
}
- case "darwin":
+ case "darwin", "windows":
// At least OS X 10.7 seems to accept any number of
// connections, ignoring listen's backlog, so resort
// to connecting to a hopefully-dead 127/8 address.
// Same for windows.
+ //
+ // Use an IANA reserved port (49151) instead of 80, because
+ // on our 386 builder, this Dial succeeds, connecting
+ // to an IIS web server somewhere. The data center
+ // or VM or firewall must be stealing the TCP connection.
+ //
+ // IANA Service Name and Transport Protocol Port Number Registry
+ // <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
go func() {
- _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
+ c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
+ if err == nil {
+ err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
+ c.Close()
+ }
errc <- err
}()
default:
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index f4ed8b87c..e69cb3188 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -5,8 +5,6 @@
package net
import (
- "bytes"
- "fmt"
"math/rand"
"sort"
)
@@ -45,20 +43,22 @@ func reverseaddr(addr string) (arpa string, err error) {
return "", &DNSError{Err: "unrecognized address", Name: addr}
}
if ip.To4() != nil {
- return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
+ return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
+ itoa(int(ip[12])) + ".in-addr.arpa.", nil
}
// Must be IPv6
- var buf bytes.Buffer
+ buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
// Add it, in reverse, to the buffer
for i := len(ip) - 1; i >= 0; i-- {
- s := fmt.Sprintf("%02x", ip[i])
- buf.WriteByte(s[1])
- buf.WriteByte('.')
- buf.WriteByte(s[0])
- buf.WriteByte('.')
+ v := ip[i]
+ buf = append(buf, hexDigit[v&0xF])
+ buf = append(buf, '.')
+ buf = append(buf, hexDigit[v>>4])
+ buf = append(buf, '.')
}
// Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
+ buf = append(buf, "ip6.arpa."...)
+ return string(buf), nil
}
// Find answer for name in dns message.
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 97c506210..b6ebe1173 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -7,11 +7,10 @@
// This is intended to support name resolution during Dial.
// It doesn't have to be blazing fast.
//
-// Rather than write the usual handful of routines to pack and
-// unpack every message that can appear on the wire, we use
-// reflection to write a generic pack/unpack for structs and then
-// use it. Thus, if in the future we need to define new message
-// structs, no new pack/unpack/printing code needs to be written.
+// Each message structure has a Walk method that is used by
+// a generic pack/unpack routine. Thus, if in the future we need
+// to define new message structs, no new pack/unpack/printing code
+// needs to be written.
//
// The first half of this file defines the DNS message formats.
// The second half implements the conversion to and from wire format.
@@ -23,12 +22,6 @@
package net
-import (
- "fmt"
- "os"
- "reflect"
-)
-
// Packet formats
// Wire constants.
@@ -75,6 +68,20 @@ const (
dnsRcodeRefused = 5
)
+// A dnsStruct describes how to iterate over its fields to emulate
+// reflective marshalling.
+type dnsStruct interface {
+ // Walk iterates over fields of a structure and calls f
+ // with a reference to that field, the name of the field
+ // and a tag ("", "domain", "ipv4", "ipv6") specifying
+ // particular encodings. Possible concrete types
+ // for v are *uint16, *uint32, *string, or []byte, and
+ // *int, *bool in the case of dnsMsgHdr.
+ // Whenever f returns false, Walk must stop and return
+ // false, and otherwise return true.
+ Walk(f func(v interface{}, name, tag string) (ok bool)) (ok bool)
+}
+
// The wire format for the DNS packet header.
type dnsHeader struct {
Id uint16
@@ -82,6 +89,15 @@ type dnsHeader struct {
Qdcount, Ancount, Nscount, Arcount uint16
}
+func (h *dnsHeader) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Id, "Id", "") &&
+ f(&h.Bits, "Bits", "") &&
+ f(&h.Qdcount, "Qdcount", "") &&
+ f(&h.Ancount, "Ancount", "") &&
+ f(&h.Nscount, "Nscount", "") &&
+ f(&h.Arcount, "Arcount", "")
+}
+
const (
// dnsHeader.Bits
_QR = 1 << 15 // query/response (response=1)
@@ -98,6 +114,12 @@ type dnsQuestion struct {
Qclass uint16
}
+func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&q.Name, "Name", "domain") &&
+ f(&q.Qtype, "Qtype", "") &&
+ f(&q.Qclass, "Qclass", "")
+}
+
// DNS responses (resource records).
// There are many types of messages,
// but they all share the same header.
@@ -113,7 +135,16 @@ func (h *dnsRR_Header) Header() *dnsRR_Header {
return h
}
+func (h *dnsRR_Header) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.Name, "Name", "domain") &&
+ f(&h.Rrtype, "Rrtype", "") &&
+ f(&h.Class, "Class", "") &&
+ f(&h.Ttl, "Ttl", "") &&
+ f(&h.Rdlength, "Rdlength", "")
+}
+
type dnsRR interface {
+ dnsStruct
Header() *dnsRR_Header
}
@@ -128,6 +159,10 @@ func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
+}
+
type dnsRR_HINFO struct {
Hdr dnsRR_Header
Cpu string
@@ -138,6 +173,10 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
+}
+
type dnsRR_MB struct {
Hdr dnsRR_Header
Mb string `net:"domain-name"`
@@ -147,6 +186,10 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
+}
+
type dnsRR_MG struct {
Hdr dnsRR_Header
Mg string `net:"domain-name"`
@@ -156,6 +199,10 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
+}
+
type dnsRR_MINFO struct {
Hdr dnsRR_Header
Rmail string `net:"domain-name"`
@@ -166,6 +213,10 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
+}
+
type dnsRR_MR struct {
Hdr dnsRR_Header
Mr string `net:"domain-name"`
@@ -175,6 +226,10 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
+}
+
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
@@ -185,6 +240,10 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Pref, "Pref", "") && f(&rr.Mx, "Mx", "domain")
+}
+
type dnsRR_NS struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -194,6 +253,10 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ns, "Ns", "domain")
+}
+
type dnsRR_PTR struct {
Hdr dnsRR_Header
Ptr string `net:"domain-name"`
@@ -203,6 +266,10 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Ptr, "Ptr", "domain")
+}
+
type dnsRR_SOA struct {
Hdr dnsRR_Header
Ns string `net:"domain-name"`
@@ -218,6 +285,17 @@ func (rr *dnsRR_SOA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SOA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Ns, "Ns", "domain") &&
+ f(&rr.Mbox, "Mbox", "domain") &&
+ f(&rr.Serial, "Serial", "") &&
+ f(&rr.Refresh, "Refresh", "") &&
+ f(&rr.Retry, "Retry", "") &&
+ f(&rr.Expire, "Expire", "") &&
+ f(&rr.Minttl, "Minttl", "")
+}
+
type dnsRR_TXT struct {
Hdr dnsRR_Header
Txt string // not domain name
@@ -227,6 +305,10 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
+}
+
type dnsRR_SRV struct {
Hdr dnsRR_Header
Priority uint16
@@ -239,6 +321,14 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) &&
+ f(&rr.Priority, "Priority", "") &&
+ f(&rr.Weight, "Weight", "") &&
+ f(&rr.Port, "Port", "") &&
+ f(&rr.Target, "Target", "domain")
+}
+
type dnsRR_A struct {
Hdr dnsRR_Header
A uint32 `net:"ipv4"`
@@ -248,6 +338,10 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(&rr.A, "A", "ipv4")
+}
+
type dnsRR_AAAA struct {
Hdr dnsRR_Header
AAAA [16]byte `net:"ipv6"`
@@ -257,6 +351,10 @@ func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
return &rr.Hdr
}
+func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return rr.Hdr.Walk(f) && f(rr.AAAA[:], "AAAA", "ipv6")
+}
+
// Packing and unpacking.
//
// All the packers and unpackers take a (msg []byte, off int)
@@ -386,134 +484,107 @@ Loop:
return s, off1, true
}
-// TODO(rsc): Move into generic library?
-// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string,
-// [n]byte, and other (often anonymous) structs.
-func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// packStruct packs a structure into msg at specified offset off, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func packStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = packStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
+ i := *fv
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- i := fv.Uint()
msg[off] = byte(i >> 8)
msg[off+1] = byte(i)
off += 2
- case reflect.Uint32:
- if off+4 > len(msg) {
- return len(msg), false
- }
- i := fv.Uint()
+ case *uint32:
+ i := *fv
msg[off] = byte(i >> 24)
msg[off+1] = byte(i >> 16)
msg[off+2] = byte(i >> 8)
msg[off+3] = byte(i)
off += 4
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(reflect.ValueOf(msg[off:off+n]), fv)
+ copy(msg[off:off+n], fv)
off += n
- case reflect.String:
- // There are multiple string encodings.
- // The tag distinguishes ordinary strings from domain names.
- s := fv.String()
- switch f.Tag {
+ case *string:
+ s := *fv
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
off, ok = packDomainName(s, msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
// Counted string: 1 byte length.
if len(s) > 255 || off+1+len(s) > len(msg) {
- return len(msg), false
+ return false
}
msg[off] = byte(len(s))
off++
off += copy(msg[off:], s)
}
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func structValue(any interface{}) reflect.Value {
- return reflect.ValueOf(any).Elem()
-}
-
-func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = packStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// TODO(rsc): Move into generic library?
-// Unpack a reflect.StructValue from msg.
-// Same restrictions as packStructValue.
-func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool) {
- for i := 0; i < val.NumField(); i++ {
- f := val.Type().Field(i)
- switch fv := val.Field(i); fv.Kind() {
+// unpackStruct decodes msg[off:] into the given structure, and
+// returns off1 such that msg[off:off1] is the encoded data.
+func unpackStruct(any dnsStruct, msg []byte, off int) (off1 int, ok bool) {
+ ok = any.Walk(func(field interface{}, name, tag string) bool {
+ switch fv := field.(type) {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- case reflect.Struct:
- off, ok = unpackStructValue(fv, msg, off)
- case reflect.Uint16:
+ println("net: dns: unknown packing type")
+ return false
+ case *uint16:
if off+2 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint16(msg[off])<<8 | uint16(msg[off+1])
- fv.SetUint(uint64(i))
+ *fv = uint16(msg[off])<<8 | uint16(msg[off+1])
off += 2
- case reflect.Uint32:
+ case *uint32:
if off+4 > len(msg) {
- return len(msg), false
+ return false
}
- i := uint32(msg[off])<<24 | uint32(msg[off+1])<<16 | uint32(msg[off+2])<<8 | uint32(msg[off+3])
- fv.SetUint(uint64(i))
+ *fv = uint32(msg[off])<<24 | uint32(msg[off+1])<<16 |
+ uint32(msg[off+2])<<8 | uint32(msg[off+3])
off += 4
- case reflect.Array:
- if fv.Type().Elem().Kind() != reflect.Uint8 {
- fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
- return len(msg), false
- }
- n := fv.Len()
+ case []byte:
+ n := len(fv)
if off+n > len(msg) {
- return len(msg), false
+ return false
}
- reflect.Copy(fv, reflect.ValueOf(msg[off:off+n]))
+ copy(fv, msg[off:off+n])
off += n
- case reflect.String:
+ case *string:
var s string
- switch f.Tag {
+ switch tag {
default:
- fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
- return len(msg), false
- case `net:"domain-name"`:
+ println("net: dns: unknown string tag", tag)
+ return false
+ case "domain":
s, off, ok = unpackDomainName(msg, off)
if !ok {
- return len(msg), false
+ return false
}
case "":
if off >= len(msg) || off+1+int(msg[off]) > len(msg) {
- return len(msg), false
+ return false
}
n := int(msg[off])
off++
@@ -524,51 +595,77 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += n
s = string(b)
}
- fv.SetString(s)
+ *fv = s
}
+ return true
+ })
+ if !ok {
+ return len(msg), false
}
return off, true
}
-func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
- off, ok = unpackStructValue(structValue(any), msg, off)
- return off, ok
-}
-
-// Generic struct printer.
-// Doesn't care about the string tag `net:"domain-name"`,
-// but does look for an `net:"ipv4"` tag on uint32 variables
-// and the `net:"ipv6"` tag on array variables,
-// printing them as IP addresses.
-func printStructValue(val reflect.Value) string {
+// Generic struct printer. Prints fields with tag "ipv4" or "ipv6"
+// as IP addresses.
+func printStruct(any dnsStruct) string {
s := "{"
- for i := 0; i < val.NumField(); i++ {
- if i > 0 {
+ i := 0
+ any.Walk(func(val interface{}, name, tag string) bool {
+ i++
+ if i > 1 {
s += ", "
}
- f := val.Type().Field(i)
- if !f.Anonymous {
- s += f.Name + "="
- }
- fval := val.Field(i)
- if fv := fval; fv.Kind() == reflect.Struct {
- s += printStructValue(fv)
- } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == `net:"ipv4"` {
- i := fv.Uint()
+ s += name + "="
+ switch tag {
+ case "ipv4":
+ i := val.(uint32)
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
- i := fv.Interface().([]byte)
+ case "ipv6":
+ i := val.([]byte)
s += IP(i).String()
- } else {
- s += fmt.Sprint(fval.Interface())
+ default:
+ var i int64
+ switch v := val.(type) {
+ default:
+ // can't really happen.
+ s += "<unknown type>"
+ return true
+ case *string:
+ s += *v
+ return true
+ case []byte:
+ s += string(v)
+ return true
+ case *bool:
+ if *v {
+ s += "true"
+ } else {
+ s += "false"
+ }
+ return true
+ case *int:
+ i = int64(*v)
+ case *uint:
+ i = int64(*v)
+ case *uint8:
+ i = int64(*v)
+ case *uint16:
+ i = int64(*v)
+ case *uint32:
+ i = int64(*v)
+ case *uint64:
+ i = int64(*v)
+ case *uintptr:
+ i = int64(*v)
+ }
+ s += itoa(int(i))
}
- }
+ return true
+ })
s += "}"
return s
}
-func printStruct(any interface{}) string { return printStructValue(structValue(any)) }
-
// Resource record packer.
func packRR(rr dnsRR, msg []byte, off int) (off2 int, ok bool) {
var off1 int
@@ -627,6 +724,17 @@ type dnsMsgHdr struct {
rcode int
}
+func (h *dnsMsgHdr) Walk(f func(v interface{}, name, tag string) bool) bool {
+ return f(&h.id, "id", "") &&
+ f(&h.response, "response", "") &&
+ f(&h.opcode, "opcode", "") &&
+ f(&h.authoritative, "authoritative", "") &&
+ f(&h.truncated, "truncated", "") &&
+ f(&h.recursion_desired, "recursion_desired", "") &&
+ f(&h.recursion_available, "recursion_available", "") &&
+ f(&h.rcode, "rcode", "")
+}
+
type dnsMsg struct {
dnsMsgHdr
question []dnsQuestion
diff --git a/src/pkg/net/dnsmsg_test.go b/src/pkg/net/dnsmsg_test.go
index 06152a01a..c39dbdb04 100644
--- a/src/pkg/net/dnsmsg_test.go
+++ b/src/pkg/net/dnsmsg_test.go
@@ -6,6 +6,7 @@ package net
import (
"encoding/hex"
+ "reflect"
"testing"
)
@@ -19,6 +20,7 @@ func TestDNSParseSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -38,6 +40,16 @@ func TestDNSParseSRVReply(t *testing.T) {
t.Errorf("len(addrs) = %d; want %d", g, e)
t.Logf("addrs = %#v", addrs)
}
+ // repack and unpack.
+ data2, ok := msg.Pack()
+ msg2 := new(dnsMsg)
+ msg2.Unpack(data2)
+ switch {
+ case !ok:
+ t.Errorf("failed to repack message")
+ case !reflect.DeepEqual(msg, msg2):
+ t.Errorf("repacked message differs from original")
+ }
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
@@ -50,6 +62,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
if !ok {
t.Fatalf("unpacking packet failed")
}
+ msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go
index a1d62acc7..085e42307 100644
--- a/src/pkg/net/fd_linux.go
+++ b/src/pkg/net/fd_linux.go
@@ -84,7 +84,8 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
events, already := p.events[fd]
if !already {
- print("Epoll unexpected fd=", fd, "\n")
+ // The fd returned by the kernel may have been
+ // cancelled already; return silently.
return
}
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index 868388efa..95c0b6699 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -27,7 +27,8 @@ type connFile interface {
}
func testFileListener(t *testing.T, net, laddr string) {
- if net == "tcp" {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
laddr += ":0" // any available port
}
l, err := Listen(net, laddr)
@@ -55,20 +56,52 @@ func testFileListener(t *testing.T, net, laddr string) {
}
}
+var fileListenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "tcp", laddr: ""},
+ {net: "tcp", laddr: "0.0.0.0"},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]"},
+ {net: "tcp", laddr: "[::]", ipv6: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: ""},
+ {net: "tcp4", laddr: "0.0.0.0"},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]"},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
+
+ {net: "unix", laddr: "@gotest/net", linux: true},
+ {net: "unixpacket", laddr: "@gotest/net", linux: true},
+}
+
func TestFileListener(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFileListener(t, "tcp", "127.0.0.1")
- testFileListener(t, "tcp", "127.0.0.1")
- if supportsIPv6 && supportsIPv4map {
- testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
- testFileListener(t, "tcp", "127.0.0.1")
- testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
- }
- if runtime.GOOS == "linux" {
- testFileListener(t, "unix", "@gotest/net")
- testFileListener(t, "unixpacket", "@gotest/net")
+
+ for _, tt := range fileListenerTests {
+ if skipServerTest(tt.net, "unix", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ if skipServerTest(tt.net, "unixpacket", tt.laddr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFileListener(t, tt.net, tt.laddr)
}
}
@@ -98,9 +131,13 @@ func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
}
func testFilePacketConnListen(t *testing.T, net, laddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ laddr += ":0" // any available port
+ }
l, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ t.Fatalf("ListenPacket failed: %v", err)
}
testFilePacketConn(t, l.(packetConnFile), true)
if err := l.Close(); err != nil {
@@ -109,6 +146,10 @@ func testFilePacketConnListen(t *testing.T, net, laddr string) {
}
func testFilePacketConnDial(t *testing.T, net, raddr string) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ raddr += ":12345"
+ }
c, err := Dial(net, raddr)
if err != nil {
t.Fatalf("Dial failed: %v", err)
@@ -119,19 +160,42 @@ func testFilePacketConnDial(t *testing.T, net, raddr string) {
}
}
+var filePacketConnTests = []struct {
+ net string
+ addr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {net: "udp", addr: "127.0.0.1"},
+ {net: "udp", addr: "[::ffff:127.0.0.1]"},
+ {net: "udp", addr: "[::1]", ipv6: true},
+
+ {net: "udp4", addr: "127.0.0.1"},
+ {net: "udp4", addr: "[::ffff:127.0.0.1]"},
+
+ {net: "udp6", addr: "[::1]", ipv6: true},
+
+ {net: "unixgram", addr: "@gotest3/net", linux: true},
+}
+
func TestFilePacketConn(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testFilePacketConnListen(t, "udp", "127.0.0.1:0")
- testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
- if supportsIPv6 {
- testFilePacketConnListen(t, "udp", "[::1]:0")
- }
- if supportsIPv6 && supportsIPv4map {
- testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
- }
- if runtime.GOOS == "linux" {
- testFilePacketConnListen(t, "unixgram", "@gotest1/net")
+
+ for _, tt := range filePacketConnTests {
+ if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
+ continue
+ }
+ testFilePacketConnListen(t, tt.net, tt.addr)
+ switch tt.addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ default:
+ if tt.net != "unixgram" {
+ testFilePacketConnDial(t, tt.net, tt.addr)
+ }
+ }
}
}
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index aa0bf4be6..e00b62e59 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -238,9 +238,9 @@ func TestRedirects(t *testing.T) {
}
var expectedCookies = []*Cookie{
- &Cookie{Name: "ChocolateChip", Value: "tasty"},
- &Cookie{Name: "First", Value: "Hit"},
- &Cookie{Name: "Second", Value: "Hit"},
+ {Name: "ChocolateChip", Value: "tasty"},
+ {Name: "First", Value: "Hit"},
+ {Name: "Second", Value: "Hit"},
}
var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 527765780..f5bc6eb91 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -455,11 +455,13 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
// First line: GET /index.html HTTP/1.0
var s string
if s, err = tp.ReadLine(); err != nil {
+ return nil, err
+ }
+ defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
- return nil, err
- }
+ }()
var f []string
if f = strings.SplitN(s, " ", 3); len(f) < 3 {
diff --git a/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 7a3556d03..6e00b9bfd 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -5,6 +5,7 @@
package http_test
import (
+ "bufio"
"bytes"
"fmt"
"io"
@@ -177,6 +178,24 @@ func TestRequestMultipartCallOrder(t *testing.T) {
}
}
+var readRequestErrorTests = []struct {
+ in string
+ err error
+}{
+ {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
+ {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
+ {"", io.EOF},
+}
+
+func TestReadRequestErrors(t *testing.T) {
+ for i, tt := range readRequestErrorTests {
+ _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err != tt.err {
+ t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index fa0df54a2..228ac4019 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -601,7 +601,7 @@ func (c *conn) serve() {
// while they're still writing their
// request. Undefined behavior.
msg = "413 Request Entity Too Large"
- } else if err == io.ErrUnexpectedEOF {
+ } else if err == io.EOF {
break // Don't reply
} else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
break // Don't reply
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index 09579f8a0..024975946 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -196,7 +196,7 @@ func (t *Transport) CloseIdleConnections() {
pconn.close()
}
}
- t.idleConn = nil
+ t.idleConn = make(map[string][]*persistConn)
}
//
diff --git a/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index cbb3884f9..a9e401de5 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -698,6 +698,32 @@ func TestTransportPersistConnLeak(t *testing.T) {
}
}
+// This used to crash; http://golang.org/issue/3266
+func TestTransportIdleConnCrash(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+
+ unblockCh := make(chan bool, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ <-unblockCh
+ tr.CloseIdleConnections()
+ }))
+ defer ts.Close()
+
+ didreq := make(chan bool)
+ go func() {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Error(err)
+ } else {
+ res.Body.Close() // returns idle conn
+ }
+ didreq <- true
+ }()
+ unblockCh <- true
+ <-didreq
+}
+
type fooProto struct{}
func (fooProto) RoundTrip(req *Request) (*Response, error) {
diff --git a/src/pkg/net/http/triv.go b/src/pkg/net/http/triv.go
index 269af0ca3..232d65089 100644
--- a/src/pkg/net/http/triv.go
+++ b/src/pkg/net/http/triv.go
@@ -15,7 +15,9 @@ import (
"log"
"net/http"
"os"
+ "os/exec"
"strconv"
+ "sync"
)
// hello world, the web server
@@ -28,14 +30,21 @@ func HelloServer(w http.ResponseWriter, req *http.Request) {
// Simple counter server. POSTing to it will set the value.
type Counter struct {
- n int
+ mu sync.Mutex // protects n
+ n int
}
// This makes Counter satisfy the expvar.Var interface, so we can export
// it directly.
-func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
+func (ctr *Counter) String() string {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
+ return fmt.Sprintf("%d", ctr.n)
+}
func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ ctr.mu.Lock()
+ defer ctr.mu.Unlock()
switch req.Method {
case "GET":
ctr.n++
@@ -95,54 +104,36 @@ func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// exec a program, redirecting output
func DateServer(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- r, w, err := os.Pipe()
- if err != nil {
- fmt.Fprintf(rw, "pipe: %s\n", err)
- return
- }
- p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
- defer r.Close()
- w.Close()
- if err != nil {
- fmt.Fprintf(rw, "fork/exec: %s\n", err)
- return
- }
- io.Copy(rw, r)
- wait, err := p.Wait(0)
+ date, err := exec.Command("/bin/date").Output()
if err != nil {
- fmt.Fprintf(rw, "wait: %s\n", err)
- return
- }
- if !wait.Exited() || wait.ExitStatus() != 0 {
- fmt.Fprintf(rw, "date: %v\n", wait)
+ http.Error(rw, err.Error(), 500)
return
}
+ rw.Write(date)
}
func Logger(w http.ResponseWriter, req *http.Request) {
- log.Print(req.URL.Raw)
- w.WriteHeader(404)
- w.Write([]byte("oops"))
+ log.Print(req.URL)
+ http.Error(w, "oops", 404)
}
-var webroot = flag.String("root", "/home/rsc", "web root directory")
+var webroot = flag.String("root", os.Getenv("HOME"), "web root directory")
func main() {
flag.Parse()
// The counter is published as a variable directly.
ctr := new(Counter)
- http.Handle("/counter", ctr)
expvar.Publish("counter", ctr)
-
+ http.Handle("/counter", ctr)
http.Handle("/", http.HandlerFunc(Logger))
http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
- http.Handle("/flags", http.HandlerFunc(FlagServer))
- http.Handle("/args", http.HandlerFunc(ArgServer))
- http.Handle("/go/hello", http.HandlerFunc(HelloServer))
http.Handle("/chan", ChanCreate())
- http.Handle("/date", http.HandlerFunc(DateServer))
+ http.HandleFunc("/flags", FlagServer)
+ http.HandleFunc("/args", ArgServer)
+ http.HandleFunc("/go/hello", HelloServer)
+ http.HandleFunc("/date", DateServer)
err := http.ListenAndServe(":12345", nil)
if err != nil {
log.Panicln("ListenAndServe:", err)
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index f25d046c1..ee23570a9 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -78,7 +78,7 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
return interfaceMulticastAddrTable(ifi.Index)
}
-// Interfaces returns a list of the systems's network interfaces.
+// Interfaces returns a list of the system's network interfaces.
func Interfaces() ([]Interface, error) {
return interfaceTable(0)
}
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 15c2f3781..825b20227 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -7,14 +7,13 @@
package net
import (
- "fmt"
"os"
"syscall"
"unsafe"
)
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otheriwse it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
@@ -194,7 +193,9 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr {
name = f[1]
case len(f[0]) == 8:
if ifi == nil || name == ifi.Name {
- fmt.Sscanf(f[0], "%08x", &b)
+ for i := 0; i+1 < len(f[0]); i += 2 {
+ b[i/2], _ = xtoi2(f[0][i:i+2], 0)
+ }
ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
ifmat = append(ifmat, ifma.toAddr())
}
@@ -218,10 +219,11 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
continue
}
if ifi == nil || f[1] == ifi.Name {
- fmt.Sscanf(f[2], "%32x", &b)
+ for i := 0; i+1 < len(f[2]); i += 2 {
+ b[i/2], _ = xtoi2(f[2][i:i+2], 0)
+ }
ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
ifmat = append(ifmat, ifma.toAddr())
-
}
}
return ifmat
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index 4876b3af3..d4d7ce9c7 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -9,7 +9,7 @@
package net
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otheriwse it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
return nil, nil
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
index d0c975326..4368b3306 100644
--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -56,7 +56,7 @@ func getInterfaceList() ([]syscall.InterfaceInfo, error) {
}
// If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces. Otheriwse it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
// interface.
func interfaceTable(ifindex int) ([]Interface, error) {
ai, err := getAdapterList()
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 9caa86985..6bbe67c3d 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -34,6 +34,13 @@ func (a *IPAddr) family() int {
return syscall.AF_INET6
}
+func (a *IPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0)
}
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index 4841057d6..ed313195c 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/net/ipsock_posix.go
@@ -38,6 +38,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
continue
}
defer closesocket(s)
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
if err != nil {
continue
@@ -55,58 +56,75 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
// favoriteAddrFamily returns the appropriate address family to
// the given net, laddr, raddr and mode. At first it figures
// address family out from the net. If mode indicates "listen"
-// and laddr.(type).IP is nil, it assumes that the user wants to
-// make a passive connection with wildcard address family, both
-// INET and INET6, and wildcard address. Otherwise guess: if the
-// addresses are IPv4 then returns INET, or else returns INET6.
-func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) int {
+// and laddr is a wildcard, it assumes that the user wants to
+// make a passive connection with a wildcard address family, both
+// AF_INET and AF_INET6, and a wildcard address like following:
+//
+// 1. A wild-wild listen, "tcp" + ""
+// If the platform supports both IPv6 and IPv6 IPv4-mapping
+// capabilities, we assume that the user want to listen on
+// both IPv4 and IPv6 wildcard address over an AF_INET6
+// socket with IPV6_V6ONLY=0. Otherwise we prefer an IPv4
+// wildcard address listen over an AF_INET socket.
+//
+// 2. A wild-ipv4wild listen, "tcp" + "0.0.0.0"
+// Same as 1.
+//
+// 3. A wild-ipv6wild listen, "tcp" + "[::]"
+// Almost same as 1 but we prefer an IPv6 wildcard address
+// listen over an AF_INET6 socket with IPV6_V6ONLY=0 when
+// the platform supports IPv6 capability but not IPv6 IPv4-
+// mapping capability.
+//
+// 4. A ipv4-ipv4wild listen, "tcp4" + "" or "0.0.0.0"
+// We use an IPv4 (AF_INET) wildcard address listen.
+//
+// 5. A ipv6-ipv6wild listen, "tcp6" + "" or "[::]"
+// We use an IPv6 (AF_INET6, IPV6_V6ONLY=1) wildcard address
+// listen.
+//
+// Otherwise guess: if the addresses are IPv4 then returns AF_INET,
+// or else returns AF_INET6. It also returns a boolean value what
+// designates IPV6_V6ONLY option.
+//
+// Note that OpenBSD allows neither "net.inet6.ip6.v6only=1" change
+// nor IPPROTO_IPV6 level IPV6_V6ONLY socket option setting.
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
switch net[len(net)-1] {
case '4':
- return syscall.AF_INET
+ return syscall.AF_INET, false
case '6':
- return syscall.AF_INET6
+ return syscall.AF_INET6, true
}
- if mode == "listen" {
- // Note that OpenBSD allows neither "net.inet6.ip6.v6only"
- // change nor IPPROTO_IPV6 level IPV6_V6ONLY socket option
- // setting.
- switch a := laddr.(type) {
- case *TCPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
- case *UDPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
- case *IPAddr:
- if a.IP == nil && supportsIPv6 && supportsIPv4map {
- return syscall.AF_INET6
- }
+ if mode == "listen" && laddr.isWildcard() {
+ if supportsIPv4map {
+ return syscall.AF_INET6, false
}
+ return laddr.family(), false
}
if (laddr == nil || laddr.family() == syscall.AF_INET) &&
(raddr == nil || raddr.family() == syscall.AF_INET) {
- return syscall.AF_INET
+ return syscall.AF_INET, false
}
- return syscall.AF_INET6
+ return syscall.AF_INET6, false
}
-// Internet sockets (TCP, UDP)
+// Internet sockets (TCP, UDP, IP)
-// A sockaddr represents a TCP or UDP network address that can
+// A sockaddr represents a TCP, UDP or IP network address that can
// be converted into a syscall.Sockaddr.
type sockaddr interface {
Addr
- sockaddr(family int) (syscall.Sockaddr, error)
family() int
+ isWildcard() bool
+ sockaddr(family int) (syscall.Sockaddr, error)
}
func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
var la, ra syscall.Sockaddr
- family := favoriteAddrFamily(net, laddr, raddr, mode)
+ family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
if laddr != nil {
if la, err = laddr.sockaddr(family); err != nil {
goto Error
@@ -117,7 +135,7 @@ func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode s
goto Error
}
}
- fd, err = socket(net, family, sotype, proto, la, ra, toAddr)
+ fd, err = socket(net, family, sotype, proto, ipv6only, la, ra, toAddr)
if err != nil {
goto Error
}
@@ -152,7 +170,7 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, error) {
}
// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
- // which it refuses to do. Rewrite to the IPv6 all zeros.
+ // which it refuses to do. Rewrite to the IPv6 unspecified address.
if ip.Equal(IPv4zero) {
ip = IPv6zero
}
diff --git a/src/pkg/net/mac.go b/src/pkg/net/mac.go
index e0637d00b..d616b1f68 100644
--- a/src/pkg/net/mac.go
+++ b/src/pkg/net/mac.go
@@ -6,24 +6,26 @@
package net
-import (
- "bytes"
- "errors"
- "fmt"
-)
+import "errors"
+
+const hexDigit = "0123456789abcdef"
// A HardwareAddr represents a physical hardware address.
type HardwareAddr []byte
func (a HardwareAddr) String() string {
- var buf bytes.Buffer
+ if len(a) == 0 {
+ return ""
+ }
+ buf := make([]byte, 0, len(a)*3-1)
for i, b := range a {
if i > 0 {
- buf.WriteByte(':')
+ buf = append(buf, ':')
}
- fmt.Fprintf(&buf, "%02x", b)
+ buf = append(buf, hexDigit[b>>4])
+ buf = append(buf, hexDigit[b&0xF])
}
- return buf.String()
+ return string(buf)
}
// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the
diff --git a/src/pkg/net/mac_test.go b/src/pkg/net/mac_test.go
index 3837e740c..8f9dc6685 100644
--- a/src/pkg/net/mac_test.go
+++ b/src/pkg/net/mac_test.go
@@ -43,12 +43,24 @@ func match(err error, s string) bool {
return err != nil && strings.Contains(err.Error(), s)
}
-func TestParseMAC(t *testing.T) {
- for _, tt := range mactests {
+func TestMACParseString(t *testing.T) {
+ for i, tt := range mactests {
out, err := ParseMAC(tt.in)
if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
tt.err)
}
+ if tt.err == "" {
+ // Verify that serialization works too, and that it round-trips.
+ s := out.String()
+ out2, err := ParseMAC(s)
+ if err != nil {
+ t.Errorf("%d. ParseMAC(%q) = %v", i, s, err)
+ continue
+ }
+ if !reflect.DeepEqual(out2, out) {
+ t.Errorf("%d. ParseMAC(%q) = %v, want %v", i, s, out2, out)
+ }
+ }
}
}
diff --git a/src/pkg/net/mail/message.go b/src/pkg/net/mail/message.go
index bf22c711e..0917bbedf 100644
--- a/src/pkg/net/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -394,8 +394,7 @@ func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
i := 1
for ; i < p.len() && isAtext((*p)[i], dot); i++ {
}
- // TODO(dsymonds): Remove the []byte() conversion here when 6g doesn't need it.
- atom, *p = string([]byte((*p)[:i])), (*p)[i:]
+ atom, *p = string((*p)[:i]), (*p)[i:]
return atom, nil
}
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 1d760c210..67261b1ee 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -47,9 +47,11 @@ var multicastListenerTests = []struct {
func TestMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "netbsd", "openbsd", "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
case "linux":
if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+ t.Logf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
return
}
}
@@ -86,7 +88,13 @@ func TestMulticastListener(t *testing.T) {
func TestSimpleMulticastListener(t *testing.T) {
switch runtime.GOOS {
case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
+ case "windows":
+ if testing.Short() || !*testExternal {
+ t.Logf("skipping test on windows to avoid firewall")
+ return
+ }
}
for _, tt := range multicastListenerTests {
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index bf242ff8d..9ebcdbe99 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -54,6 +54,8 @@ type Addr interface {
}
// Conn is a generic stream-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
// Read can be made to time out and return a Error with Timeout() == true
@@ -66,6 +68,7 @@ type Conn interface {
Write(b []byte) (n int, err error)
// Close closes the connection.
+ // Any blocked Read or Write operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address.
@@ -89,11 +92,11 @@ type Conn interface {
// A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for Read calls.
+ // SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for Write calls.
+ // SetWriteDeadline sets the deadline for future Write calls.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
@@ -108,6 +111,8 @@ type Error interface {
}
// PacketConn is a generic packet-oriented network connection.
+//
+// Multiple goroutines may invoke methods on a PacketConn simultaneously.
type PacketConn interface {
// ReadFrom reads a packet from the connection,
// copying the payload into b. It returns the number of
@@ -126,6 +131,7 @@ type PacketConn interface {
WriteTo(b []byte, addr Addr) (n int, err error)
// Close closes the connection.
+ // Any blocked ReadFrom or WriteTo operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address.
@@ -135,13 +141,13 @@ type PacketConn interface {
// with the connection.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for all Read calls to return.
+ // SetReadDeadline sets the deadline for future Read calls.
// If the deadline is reached, Read will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for all Write calls to return.
+ // SetWriteDeadline sets the deadline for future Write calls.
// If the deadline is reached, Write will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Write will not time out.
@@ -151,11 +157,14 @@ type PacketConn interface {
}
// A Listener is a generic network listener for stream-oriented protocols.
+//
+// Multiple goroutines may invoke methods on a Listener simultaneously.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (c Conn, err error)
// Close closes the listener.
+ // Any blocked Accept operations will be unblocked and return errors.
Close() error
// Addr returns the listener's network address.
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index c1a90de01..fd145e1d7 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -13,6 +13,7 @@ import (
func TestShutdown(t *testing.T) {
if runtime.GOOS == "plan9" {
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
l, err := Listen("tcp", "127.0.0.1:0")
diff --git a/src/pkg/net/parse_test.go b/src/pkg/net/parse_test.go
index dfbaba4d9..30fda45df 100644
--- a/src/pkg/net/parse_test.go
+++ b/src/pkg/net/parse_test.go
@@ -13,7 +13,9 @@ import (
func TestReadLine(t *testing.T) {
// /etc/services file does not exist on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
filename := "/etc/services" // a nice big file
diff --git a/src/pkg/net/rpc/client.go b/src/pkg/net/rpc/client.go
index f7abf21f1..db2da8e44 100644
--- a/src/pkg/net/rpc/client.go
+++ b/src/pkg/net/rpc/client.go
@@ -36,7 +36,8 @@ type Call struct {
// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
-// with a single Client.
+// with a single Client, and a Client may be used by
+// multiple goroutines simultaneously.
type Client struct {
mutex sync.Mutex // protects pending, seq, request
sending sync.Mutex
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index b98621681..158b9477d 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,234 +9,461 @@ import (
"io"
"os"
"runtime"
- "strings"
"testing"
"time"
)
-// Do not test empty datagrams by default.
-// It causes unexplained timeouts on some systems,
-// including Snow Leopard. I think that the kernel
-// doesn't quite expect them.
-var testUDP = flag.Bool("udp", false, "whether to test UDP datagrams")
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+ switch runtime.GOOS {
+ case "linux":
+ case "plan9", "windows":
+ // "unix" sockets are not supported on Windows and Plan 9.
+ if net == unixsotype {
+ return true
+ }
+ default:
+ if net == unixsotype && linuxonly {
+ return true
+ }
+ }
+ switch addr {
+ case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+ if testing.Short() || !*testExternal {
+ return true
+ }
+ }
+ if ipv6 && !supportsIPv6 {
+ return true
+ }
+ if ipv4map && !supportsIPv4map {
+ return true
+ }
+ return false
+}
-func runEcho(fd io.ReadWriter, done chan<- int) {
- var buf [1024]byte
+var streamConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "[::1]", ipv6: true},
- for {
- n, err := fd.Read(buf[0:])
- if err != nil || n == 0 || string(buf[:n]) == "END" {
- break
+ {snet: "tcp", saddr: "", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "0.0.0.0", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+ {snet: "tcp", saddr: "[::]", cnet: "tcp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "tcp", saddr: "127.0.0.1", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::ffff:127.0.0.1]", cnet: "tcp", caddr: "127.0.0.1"},
+ {snet: "tcp", saddr: "[::1]", cnet: "tcp", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp4", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+ {snet: "tcp4", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"},
+
+ {snet: "tcp6", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+ {snet: "tcp6", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+ {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+}
+
+func TestStreamConnServer(t *testing.T) {
+ for _, tt := range streamConnServerTests {
+ if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "tcp", "tcp4", "tcp6":
+ tt.saddr += ":0"
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "tcp", "tcp4", "tcp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ }
+
+ runStreamConnClient(t, tt.cnet, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unix":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+ }
+}
+
+var seqpacketConnServerTests = []struct {
+ net string
+ saddr string // server address
+ caddr string // client address
+ empty bool // test with empty data
+}{
+ {net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+ {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+}
+
+func TestSeqpacketConnServer(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range seqpacketConnServerTests {
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ runStreamConnClient(t, tt.net, taddr, tt.empty)
+ <-done // make sure server stopped
+
+ switch tt.net {
+ case "unixpacket":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
}
- fd.Write(buf[0:n])
}
- done <- 1
}
-func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- l, err := Listen(network, addr)
+func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ l, err := Listen(net, laddr)
if err != nil {
- t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer l.Close()
listening <- l.Addr().String()
+ echo := func(rw io.ReadWriter, done chan<- int) {
+ buf := make([]byte, 1024)
+ for {
+ n, err := rw.Read(buf[0:])
+ if err != nil || n == 0 || string(buf[:n]) == "END" {
+ break
+ }
+ rw.Write(buf[0:n])
+ }
+ done <- 1
+ }
+
+run:
for {
- fd, err := l.Accept()
+ c, err := l.Accept()
if err != nil {
- break
+ continue run
}
echodone := make(chan int)
- go runEcho(fd, echodone)
- <-echodone // make sure Echo stops
- l.Close()
+ go echo(c, echodone)
+ <-echodone // make sure echo stopped
+ c.Close()
+ break run
}
done <- 1
}
-func connect(t *testing.T, network, addr string, isEmpty bool) {
- var fd Conn
- var err error
- if network == "unixgram" {
- fd, err = DialUnix(network, &UnixAddr{addr + ".local", network}, &UnixAddr{addr, network})
- } else {
- fd, err = Dial(network, addr)
- }
+func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
+ c, err := Dial(net, taddr)
if err != nil {
- t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
}
- fd.SetReadDeadline(time.Now().Add(1 * time.Second))
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
- var b []byte
+ var wb []byte
if !isEmpty {
- b = []byte("hello, world\n")
+ wb = []byte("StreamConnClient by Dial\n")
}
- var b1 [100]byte
-
- n, err1 := fd.Write(b)
- if n != len(b) {
- t.Fatalf("fd.Write(%q) = %d, %v", b, n, err1)
+ if n, err := c.Write(wb); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
- n, err1 = fd.Read(b1[0:])
- if n != len(b) || err1 != nil {
- t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b))
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
// Send explicit ending for unixpacket.
// Older Linux kernels do not stop reads on close.
- if network == "unixpacket" {
- fd.Write([]byte("END"))
+ switch net {
+ case "unixpacket":
+ c.Write([]byte("END"))
}
-
- fd.Close()
}
-func doTest(t *testing.T, network, listenaddr, dialaddr string) {
- t.Logf("Test %q %q %q", network, listenaddr, dialaddr)
- switch listenaddr {
- case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
- if testing.Short() || !*testExternal {
- t.Logf("skip wildcard listen during short test")
- return
- }
- }
- listening := make(chan string)
- done := make(chan int)
- if network == "tcp" || network == "tcp4" || network == "tcp6" {
- listenaddr += ":0" // any available port
- }
- go runServe(t, network, listenaddr, listening, done)
- addr := <-listening // wait for server to start
- if network == "tcp" || network == "tcp4" || network == "tcp6" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, false)
- <-done // make sure server stopped
-}
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard. I think that the kernel
+// doesn't quite expect them.
+var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
-func TestTCPServer(t *testing.T) {
- doTest(t, "tcp", "", "127.0.0.1")
- doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
- doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
- doTest(t, "tcp4", "", "127.0.0.1")
- doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
- doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
- if supportsIPv6 {
- doTest(t, "tcp", "[::]", "[::1]")
- doTest(t, "tcp", "[::1]", "[::1]")
- doTest(t, "tcp6", "", "[::1]")
- doTest(t, "tcp6", "[::]", "[::1]")
- doTest(t, "tcp6", "[::1]", "[::1]")
- }
- if supportsIPv6 && supportsIPv4map {
- doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp", "[::]", "127.0.0.1")
- doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp6", "", "127.0.0.1")
- doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
- doTest(t, "tcp6", "[::]", "127.0.0.1")
- doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
- doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
- doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
- doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
- }
+var datagramPacketConnServerTests = []struct {
+ snet string // server side
+ saddr string
+ cnet string // client side
+ caddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ ipv4map bool // test with IPv6 IPv4-mapping functionality
+ dial bool // test with Dial or DialUnix
+ empty bool // test with empty data
+ linux bool // test with abstract unix domain socket, a Linux-ism
+}{
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "0.0.0.0", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+ {snet: "udp", saddr: "[::]", cnet: "udp4", caddr: "127.0.0.1", ipv4map: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::ffff:127.0.0.1]", cnet: "udp", caddr: "127.0.0.1"},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp4", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+ {snet: "udp4", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
+
+ {snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
+ {snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", empty: true},
+ {snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
+
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
+ {snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
+ {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+
+ {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
}
-func TestUnixServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func TestDatagramPacketConnServer(t *testing.T) {
+ if !*testDatagram {
return
}
- os.Remove("/tmp/gotest.net")
- doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- if runtime.GOOS == "linux" {
- doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net")
- os.Remove("/tmp/gotest.net")
- // Test abstract unix domain socket, a Linux-ism
- doTest(t, "unix", "@gotest/net", "@gotest/net")
- doTest(t, "unixpacket", "@gotest/net", "@gotest/net")
+
+ for _, tt := range datagramPacketConnServerTests {
+ if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+ continue
+ }
+
+ listening := make(chan string)
+ done := make(chan int)
+ switch tt.snet {
+ case "udp", "udp4", "udp6":
+ tt.saddr += ":0"
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
+
+ go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
+ taddr := <-listening // wait for server to start
+
+ switch tt.cnet {
+ case "udp", "udp4", "udp6":
+ _, port, err := SplitHostPort(taddr)
+ if err != nil {
+ t.Errorf("SplitHostPort(%q) failed: %v", taddr, err)
+ return
+ }
+ taddr = tt.caddr + ":" + port
+ tt.caddr += ":0"
+ }
+ if tt.dial {
+ runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ } else {
+ runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+ }
+ <-done // tell server to stop
+ <-done // make sure server stopped
+
+ switch tt.snet {
+ case "unixgram":
+ os.Remove(tt.saddr)
+ os.Remove(tt.caddr)
+ }
}
}
-func runPacket(t *testing.T, network, addr string, listening chan<- string, done chan<- int) {
- c, err := ListenPacket(network, addr)
+func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+ c, err := ListenPacket(net, laddr)
if err != nil {
- t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err)
+ t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ listening <- "<nil>"
+ done <- 1
+ return
}
+ defer c.Close()
listening <- c.LocalAddr().String()
- var buf [1000]byte
-Run:
+
+ buf := make([]byte, 1024)
+run:
for {
c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
- n, addr, err := c.ReadFrom(buf[0:])
- if e, ok := err.(Error); ok && e.Timeout() {
+ n, ra, err := c.ReadFrom(buf[0:])
+ if nerr, ok := err.(Error); ok && nerr.Timeout() {
select {
case done <- 1:
- break Run
+ break run
default:
- continue Run
+ continue run
}
}
if err != nil {
- break
+ break run
}
- if _, err = c.WriteTo(buf[0:n], addr); err != nil {
- t.Fatalf("WriteTo %v: %v", addr, err)
+ if _, err = c.WriteTo(buf[0:n], ra); err != nil {
+ t.Errorf("WriteTo(%v) failed: %v", ra, err)
+ break run
}
}
- c.Close()
done <- 1
}
-func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) {
- t.Logf("TestPacket %q %q %q", network, listenaddr, dialaddr)
- listening := make(chan string)
- done := make(chan int)
- if network == "udp" {
- listenaddr += ":0" // any available port
- }
- go runPacket(t, network, listenaddr, listening, done)
- addr := <-listening // wait for server to start
- if network == "udp" {
- dialaddr += addr[strings.LastIndex(addr, ":"):]
- }
- connect(t, network, dialaddr, isEmpty)
- <-done // tell server to stop
- <-done // wait for stop
-}
+func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var c Conn
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ c, err = Dial(net, taddr)
+ if err != nil {
+ t.Errorf("Dial(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ c, err = DialUnix(net, &UnixAddr{laddr, net}, &UnixAddr{taddr, net})
+ if err != nil {
+ t.Errorf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
+ return
+ }
+ }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
-func TestUDPServer(t *testing.T) {
- if !*testUDP {
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramConnClient by Dial\n")
+ }
+ if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
return
}
- for _, isEmpty := range []bool{false, true} {
- doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
- doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
- if supportsIPv6 && supportsIPv4map {
- doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
- doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
- doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
- }
+
+ rb := make([]byte, 1024)
+ if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
-func TestUnixDatagramServer(t *testing.T) {
- // "unix" sockets are not supported on windows and Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+ var ra Addr
+ var err error
+ switch net {
+ case "udp", "udp4", "udp6":
+ ra, err = ResolveUDPAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ case "unixgram":
+ ra, err = ResolveUnixAddr(net, taddr)
+ if err != nil {
+ t.Errorf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
+ return
+ }
+ }
+ c, err := ListenPacket(net, laddr)
+ if err != nil {
+ t.Errorf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
return
}
- for _, isEmpty := range []bool{false} {
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty)
- os.Remove("/tmp/gotest1.net")
- os.Remove("/tmp/gotest1.net.local")
- if runtime.GOOS == "linux" {
- // Test abstract unix domain socket, a Linux-ism
- doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty)
- }
+ defer c.Close()
+ c.SetReadDeadline(time.Now().Add(1 * time.Second))
+
+ var wb []byte
+ if !isEmpty {
+ wb = []byte("DatagramPacketConnClient by ListenPacket\n")
+ }
+ if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
+ t.Errorf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
+ return
+ }
+
+ rb := make([]byte, 1024)
+ if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
+ t.Errorf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+ return
}
}
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index dc139f04a..3ae16054e 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -16,7 +16,7 @@ import (
var listenerBacklog = maxListenerBacklog()
// Generic socket creation.
-func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
+func socket(net string, f, t, p int, ipv6only bool, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) {
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
s, err := syscall.Socket(f, t, p)
@@ -27,7 +27,7 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
- err = setDefaultSockopts(s, f, t)
+ err = setDefaultSockopts(s, f, t, ipv6only)
if err != nil {
closesocket(s)
return nil, err
diff --git a/src/pkg/net/sockopt.go b/src/pkg/net/sockopt.go
index 0a051d7ae..0cd19266f 100644
--- a/src/pkg/net/sockopt.go
+++ b/src/pkg/net/sockopt.go
@@ -9,7 +9,6 @@
package net
import (
- "bytes"
"os"
"syscall"
"time"
@@ -98,7 +97,7 @@ func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error {
}
}
done:
- if bytes.Equal(mreq.Multiaddr[:], IPv4zero.To4()) {
+ if bytesEqual(mreq.Multiaddr[:], IPv4zero.To4()) {
return errNoSuchMulticastInterface
}
return nil
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index 79e0e57e2..fff65f362 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -13,12 +13,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s, f, t int) error {
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/src/pkg/net/sockopt_linux.go b/src/pkg/net/sockopt_linux.go
index 7509c29ee..0f47538c5 100644
--- a/src/pkg/net/sockopt_linux.go
+++ b/src/pkg/net/sockopt_linux.go
@@ -11,12 +11,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s, f, t int) error {
+func setDefaultSockopts(s, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/src/pkg/net/sockopt_windows.go b/src/pkg/net/sockopt_windows.go
index b18af67d7..509b5963b 100644
--- a/src/pkg/net/sockopt_windows.go
+++ b/src/pkg/net/sockopt_windows.go
@@ -11,12 +11,17 @@ import (
"syscall"
)
-func setDefaultSockopts(s syscall.Handle, f, t int) error {
+func setDefaultSockopts(s syscall.Handle, f, t int, ipv6only bool) error {
switch f {
case syscall.AF_INET6:
- // Allow both IP versions even if the OS default is otherwise.
- // Note that some operating systems never admit this option.
- syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ if ipv6only {
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
+ } else {
+ // Allow both IP versions even if the OS default
+ // is otherwise. Note that some operating systems
+ // never admit this option.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
}
// Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index e05bc1017..15f8efdd7 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -9,7 +9,6 @@
package net
import (
- "fmt"
"io"
"os"
"syscall"
@@ -30,7 +29,7 @@ func sockaddrToTCP(sa syscall.Sockaddr) Addr {
default:
if sa != nil {
// Diagnose when we will turn a non-nil sockaddr into a nil.
- panic(fmt.Sprintf("unexpected type in sockaddrToTCP: %T", sa))
+ panic("unexpected type in sockaddrToTCP")
}
}
return nil
@@ -46,6 +45,13 @@ func (a *TCPAddr) family() int {
return syscall.AF_INET6
}
+func (a *TCPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index ef350f0f9..672fb7241 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -11,13 +11,13 @@ import (
"time"
)
-func testTimeout(t *testing.T, network, addr string, readFrom bool) {
- fd, err := Dial(network, addr)
+func testTimeout(t *testing.T, net, addr string, readFrom bool) {
+ c, err := Dial(net, addr)
if err != nil {
- t.Errorf("dial %s %s failed: %v", network, addr, err)
+ t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
return
}
- defer fd.Close()
+ defer c.Close()
what := "Read"
if readFrom {
what = "ReadFrom"
@@ -26,22 +26,22 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
errc := make(chan error, 1)
go func() {
t0 := time.Now()
- fd.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+ c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
var b [100]byte
var n int
- var err1 error
+ var err error
if readFrom {
- n, _, err1 = fd.(PacketConn).ReadFrom(b[0:])
+ n, _, err = c.(PacketConn).ReadFrom(b[0:])
} else {
- n, err1 = fd.Read(b[0:])
+ n, err = c.Read(b[0:])
}
t1 := time.Now()
- if n != 0 || err1 == nil || !err1.(Error).Timeout() {
- errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1)
+ if n != 0 || err == nil || !err.(Error).Timeout() {
+ errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
return
}
if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
- errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt)
+ errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
return
}
errc <- nil
@@ -52,26 +52,39 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
t.Error(err)
}
case <-time.After(1 * time.Second):
- t.Errorf("%s on %s %s took over 1 second, expected 0.1s", what, network, addr)
+ t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
}
}
func TestTimeoutUDP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- testTimeout(t, "udp", "127.0.0.1:53", false)
- testTimeout(t, "udp", "127.0.0.1:53", true)
+
+ // set up a listener that won't talk back
+ listening := make(chan string)
+ done := make(chan int)
+ go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
+ addr := <-listening
+
+ testTimeout(t, "udp", addr, false)
+ testTimeout(t, "udp", addr, true)
+ <-done
}
func TestTimeoutTCP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
+
// set up a listener that won't talk back
listening := make(chan string)
done := make(chan int)
- go runServe(t, "tcp", "127.0.0.1:0", listening, done)
+ go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
addr := <-listening
testTimeout(t, "tcp", addr, false)
@@ -79,7 +92,9 @@ func TestTimeoutTCP(t *testing.T) {
}
func TestDeadlineReset(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
ln, err := Listen("tcp", "127.0.0.1:0")
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index ea5fad41a..f80d3b5a9 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -10,7 +10,9 @@ import (
)
func TestWriteToUDP(t *testing.T) {
- if runtime.GOOS == "plan9" {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 1f99dc538..9e820e1c5 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -37,6 +37,13 @@ func (a *UDPAddr) family() int {
return syscall.AF_INET6
}
+func (a *UDPAddr) isWildcard() bool {
+ if a == nil || a.IP == nil {
+ return true
+ }
+ return a.IP.IsUnspecified()
+}
+
func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port)
}
diff --git a/src/pkg/net/unicast_test.go b/src/pkg/net/unicast_test.go
index 297276d3a..e5dd013db 100644
--- a/src/pkg/net/unicast_test.go
+++ b/src/pkg/net/unicast_test.go
@@ -5,83 +5,482 @@
package net
import (
- "io"
"runtime"
+ "syscall"
"testing"
)
-var unicastTests = []struct {
- net string
- laddr string
- ipv6 bool
- packet bool
+var listenerTests = []struct {
+ net string
+ laddr string
+ ipv6 bool // test with underlying AF_INET6 socket
+ wildcard bool // test with wildcard address
}{
- {net: "tcp4", laddr: "127.0.0.1:0"},
- {net: "tcp4", laddr: "previous"},
- {net: "tcp6", laddr: "[::1]:0", ipv6: true},
- {net: "tcp6", laddr: "previous", ipv6: true},
- {net: "udp4", laddr: "127.0.0.1:0", packet: true},
- {net: "udp6", laddr: "[::1]:0", ipv6: true, packet: true},
+ {net: "tcp", laddr: "", wildcard: true},
+ {net: "tcp", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+ {net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp", laddr: "127.0.0.1"},
+ {net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+ {net: "tcp", laddr: "[::1]", ipv6: true},
+
+ {net: "tcp4", laddr: "", wildcard: true},
+ {net: "tcp4", laddr: "0.0.0.0", wildcard: true},
+ {net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+
+ {net: "tcp4", laddr: "127.0.0.1"},
+ {net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+ {net: "tcp6", laddr: "", ipv6: true, wildcard: true},
+ {net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
+
+ {net: "tcp6", laddr: "[::1]", ipv6: true},
}
-func TestUnicastTCPAndUDP(t *testing.T) {
- if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
return
}
- prevladdr := ""
- for _, tt := range unicastTests {
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
if tt.ipv6 && !supportsIPv6 {
continue
}
- var (
- fd *netFD
- closer io.Closer
- )
- if !tt.packet {
- if tt.laddr == "previous" {
- tt.laddr = prevladdr
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*TCPListener).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.Close()
+ }
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 && !supportsIPv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ fd := l1.(*UDPConn).fd
+ switch fd.family {
+ case syscall.AF_INET:
+ testIPv4UnicastSocketOptions(t, fd)
+ case syscall.AF_INET6:
+ testIPv6UnicastSocketOptions(t, fd)
+ }
+ l1.Close()
+ }
+}
+
+func TestSimpleTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ l1, port := usableListenPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := Listen(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.Close()
+ }
+}
+
+func TestSimpleUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range listenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ if tt.ipv6 {
+ continue
+ }
+ tt.net = toudpnet(tt.net)
+ l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+ checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+ l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+ checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+ l1.Close()
+ }
+}
+
+var dualStackListenerTests = []struct {
+ net1 string // first listener
+ laddr1 string
+ net2 string // second listener
+ laddr2 string
+ wildcard bool // test with wildcard address
+ xerr error // expected error value, nil or other
+}{
+ // Test cases and expected results for the attemping 2nd listen on the same port
+ // 1st listen 2nd listen darwin freebsd linux openbsd
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "" - - - -
+ // "tcp" "" "tcp" "0.0.0.0" - - - -
+ // "tcp" "0.0.0.0" "tcp" "" - - - -
+ // ------------------------------------------------------------------------------------
+ // "tcp" "" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "" - - - ok
+ // "tcp" "0.0.0.0" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "0.0.0.0" - - - ok
+ // "tcp" "[::ffff:0.0.0.0]" "tcp" "[::]" - - - ok
+ // "tcp" "[::]" "tcp" "[::ffff:0.0.0.0]" - - - ok
+ // ------------------------------------------------------------------------------------
+ // "tcp4" "" "tcp6" "" ok ok ok ok
+ // "tcp6" "" "tcp4" "" ok ok ok ok
+ // "tcp4" "0.0.0.0" "tcp6" "[::]" ok ok ok ok
+ // "tcp6" "[::]" "tcp4" "0.0.0.0" ok ok ok ok
+ // ------------------------------------------------------------------------------------
+ // "tcp" "127.0.0.1" "tcp" "[::1]" ok ok ok ok
+ // "tcp" "[::1]" "tcp" "127.0.0.1" ok ok ok ok
+ // "tcp4" "127.0.0.1" "tcp6" "[::1]" ok ok ok ok
+ // "tcp6" "[::1]" "tcp4" "127.0.0.1" ok ok ok ok
+ //
+ // Platform default configurations:
+ // darwin, kernel version 11.3.0
+ // net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // freebsd, kernel version 8.2
+ // net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+ // linux, kernel version 3.0.0
+ // net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+ // openbsd, kernel version 5.0
+ // net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+ {net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
+
+ {net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
+ {net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
+ {net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
+ {net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
+
+ {net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
+ {net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
+ {net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
+ {net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackTCPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
+ }
+ }
+ l1, port := usableListenPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := Listen(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ if !supportsIPv6 {
+ return
+ }
+
+ toudpnet := func(net string) string {
+ switch net {
+ case "tcp":
+ return "udp"
+ case "tcp4":
+ return "udp4"
+ case "tcp6":
+ return "udp6"
+ }
+ return "<nil>"
+ }
+
+ for _, tt := range dualStackListenerTests {
+ if tt.wildcard && (testing.Short() || !*testExternal) {
+ continue
+ }
+ tt.net1 = toudpnet(tt.net1)
+ tt.net2 = toudpnet(tt.net2)
+ switch runtime.GOOS {
+ case "openbsd":
+ if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+ tt.xerr = nil
}
- l, err := Listen(tt.net, tt.laddr)
- if err != nil {
- t.Fatalf("Listen failed: %v", err)
+ }
+ l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
+ laddr := tt.laddr1 + ":" + port
+ checkFirstListener(t, tt.net1, laddr, l1)
+ laddr = tt.laddr2 + ":" + port
+ l2, err := ListenPacket(tt.net2, laddr)
+ checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+ l1.Close()
+ }
+}
+
+func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPort net=" + net)
+ case "tcp", "tcp4", "tcp6":
+ l, err = Listen(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*TCPListener).Addr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
+ var nladdr string
+ var err error
+ switch net {
+ default:
+ panic("usableListenPacketPort net=" + net)
+ case "udp", "udp4", "udp6":
+ l, err = ListenPacket(net, laddr+":0")
+ if err != nil {
+ t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
+ }
+ nladdr = l.(*UDPConn).LocalAddr().String()
+ }
+ _, port, err = SplitHostPort(nladdr)
+ if err != nil {
+ t.Fatalf("SplitHostPort failed: %v", err)
+ }
+ return l, port
+}
+
+func differentWildcardAddr(i, j string) bool {
+ if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+ return false
+ }
+ if i == "[::]" && j == "[::]" {
+ return false
+ }
+ return true
+}
+
+func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
+ switch net {
+ case "tcp":
+ fd := l.(*TCPListener).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "tcp4":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "tcp6":
+ fd := l.(*TCPListener).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ case "udp":
+ fd := l.(*UDPConn).fd
+ checkDualStackAddrFamily(t, net, laddr, fd)
+ case "udp4":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+ }
+ case "udp6":
+ fd := l.(*UDPConn).fd
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if err == nil {
+ l.(*TCPListener).Close()
+ t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
+ }
+ case "udp", "udp4", "udp6":
+ if err == nil {
+ l.(*UDPConn).Close()
+ t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
+ }
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*TCPListener).Close()
+ case "udp", "udp4", "udp6":
+ if xerr == nil && err != nil || xerr != nil && err == nil {
+ t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+ }
+ l.(*UDPConn).Close()
+ default:
+ t.Fatalf("Unexpected network: %q", net)
+ }
+}
+
+func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
+ switch a := fd.laddr.(type) {
+ case *TCPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
}
- prevladdr = l.Addr().String()
- closer = l
- fd = l.(*TCPListener).fd
} else {
- c, err := ListenPacket(tt.net, tt.laddr)
- if err != nil {
- t.Fatalf("ListenPacket failed: %v", err)
+ if fd.family != a.family() {
+ t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
}
- closer = c
- fd = c.(*UDPConn).fd
}
- if !tt.ipv6 {
- testIPv4UnicastSocketOptions(t, fd)
+ case *UDPAddr:
+ // If a node under test supports both IPv6 capability
+ // and IPv6 IPv4-mapping capability, we can assume
+ // that the node listens on a wildcard address with an
+ // AF_INET6 socket.
+ if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+ if fd.family != syscall.AF_INET6 {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+ }
} else {
- testIPv6UnicastSocketOptions(t, fd)
+ if fd.family != a.family() {
+ t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+ }
}
- closer.Close()
+ default:
+ t.Fatalf("Unexpected protocol address type: %T", a)
}
}
func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
- tos, err := ipv4TOS(fd)
+ _, err := ipv4TOS(fd)
if err != nil {
t.Fatalf("ipv4TOS failed: %v", err)
}
- t.Logf("IPv4 TOS: %v", tos)
err = setIPv4TOS(fd, 1)
if err != nil {
t.Fatalf("setIPv4TOS failed: %v", err)
}
-
- ttl, err := ipv4TTL(fd)
+ _, err = ipv4TTL(fd)
if err != nil {
t.Fatalf("ipv4TTL failed: %v", err)
}
- t.Logf("IPv4 TTL: %v", ttl)
err = setIPv4TTL(fd, 1)
if err != nil {
t.Fatalf("setIPv4TTL failed: %v", err)
@@ -89,23 +488,51 @@ func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) {
}
func testIPv6UnicastSocketOptions(t *testing.T, fd *netFD) {
- tos, err := ipv6TrafficClass(fd)
+ _, err := ipv6TrafficClass(fd)
if err != nil {
t.Fatalf("ipv6TrafficClass failed: %v", err)
}
- t.Logf("IPv6 TrafficClass: %v", tos)
err = setIPv6TrafficClass(fd, 1)
if err != nil {
t.Fatalf("setIPv6TrafficClass failed: %v", err)
}
-
- hoplim, err := ipv6HopLimit(fd)
+ _, err = ipv6HopLimit(fd)
if err != nil {
t.Fatalf("ipv6HopLimit failed: %v", err)
}
- t.Logf("IPv6 HopLimit: %v", hoplim)
err = setIPv6HopLimit(fd, 1)
if err != nil {
t.Fatalf("setIPv6HopLimit failed: %v", err)
}
}
+
+var prohibitionaryDialArgTests = []struct {
+ net string
+ addr string
+}{
+ {"tcp6", "127.0.0.1"},
+ {"tcp6", "[::ffff:127.0.0.1]"},
+}
+
+func TestProhibitionaryDialArgs(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Logf("skipping test on %q", runtime.GOOS)
+ return
+ }
+ // This test requires both IPv6 and IPv6 IPv4-mapping functionality.
+ if !supportsIPv4map || testing.Short() || !*testExternal {
+ return
+ }
+
+ l, port := usableListenPort(t, "tcp", "[::]")
+ defer l.Close()
+
+ for _, tt := range prohibitionaryDialArgTests {
+ c, err := Dial(tt.net, tt.addr+":"+port)
+ if err == nil {
+ c.Close()
+ t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
+ }
+ }
+}
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 3a94cf5c5..37a2b1e09 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -59,7 +59,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err
f = sockaddrToUnixpacket
}
- fd, err = socket(net, syscall.AF_UNIX, sotype, 0, la, ra, f)
+ fd, err = socket(net, syscall.AF_UNIX, sotype, 0, false, la, ra, f)
if err != nil {
goto Error
}
@@ -208,8 +208,8 @@ func (c *UnixConn) SetWriteBuffer(bytes int) error {
}
// ReadFromUnix reads a packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
+// It returns the number of bytes copied into b and the source address
+// of the packet.
//
// ReadFromUnix can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
@@ -264,6 +264,11 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
return c.WriteToUnix(b, a)
}
+// ReadMsgUnix reads a packet from c, copying the payload into b
+// and the associated out-of-band data into oob.
+// It returns the number of bytes copied into b, the number of
+// bytes copied into oob, the flags that were set on the packet,
+// and the source address of the packet.
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
@@ -276,6 +281,9 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
return
}
+// WriteMsgUnix writes a packet to addr via c, copying the payload from b
+// and the associated out-of-band data from oob. It returns the number
+// of payload and out-of-band bytes written.
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if !c.ok() {
return 0, 0, syscall.EINVAL
diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go
index e0b83b5c2..b88e49400 100644
--- a/src/pkg/os/error.go
+++ b/src/pkg/os/error.go
@@ -42,3 +42,21 @@ func NewSyscallError(syscall string, err error) error {
}
return &SyscallError{syscall, err}
}
+
+// IsExist returns whether the error is known to report that a file or directory
+// already exists. It is satisfied by ErrExist as well as some syscall errors.
+func IsExist(err error) bool {
+ return isExist(err)
+}
+
+// IsNotExist returns whether the error is known to report that a file or directory
+// does not exist. It is satisfied by ErrNotExist as well as some syscall errors.
+func IsNotExist(err error) bool {
+ return isNotExist(err)
+}
+
+// IsPermission returns whether the error is known to report that permission is denied.
+// It is satisfied by ErrPermission as well as some syscall errors.
+func IsPermission(err error) bool {
+ return isPermission(err)
+}
diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go
index 159d685e7..3c9dfb0b1 100644
--- a/src/pkg/os/error_plan9.go
+++ b/src/pkg/os/error_plan9.go
@@ -4,24 +4,21 @@
package os
-// IsExist returns whether the error is known to report that a file already exists.
-func IsExist(err error) bool {
+func isExist(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
return contains(err.Error(), " exists")
}
-// IsNotExist returns whether the error is known to report that a file does not exist.
-func IsNotExist(err error) bool {
+func isNotExist(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
return contains(err.Error(), "does not exist")
}
-// IsPermission returns whether the error is known to report that permission is denied.
-func IsPermission(err error) bool {
+func isPermission(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go
index 74b75d112..1685c1f21 100644
--- a/src/pkg/os/error_posix.go
+++ b/src/pkg/os/error_posix.go
@@ -2,33 +2,27 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin freebsd linux netbsd openbsd windows
+// +build darwin freebsd linux netbsd openbsd
package os
import "syscall"
-// IsExist returns whether the error is known to report that a file already exists.
-// It is satisfied by ErrExist as well as some syscall errors.
-func IsExist(err error) bool {
+func isExist(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
return err == syscall.EEXIST || err == ErrExist
}
-// IsNotExist returns whether the error is known to report that a file does not exist.
-// It is satisfied by ErrNotExist as well as some syscall errors.
-func IsNotExist(err error) bool {
+func isNotExist(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
return err == syscall.ENOENT || err == ErrNotExist
}
-// IsPermission returns whether the error is known to report that permission is denied.
-// It is satisfied by ErrPermission as well as some syscall errors.
-func IsPermission(err error) bool {
+func isPermission(err error) bool {
if pe, ok := err.(*PathError); ok {
err = pe.Err
}
diff --git a/src/pkg/os/error_test.go b/src/pkg/os/error_test.go
new file mode 100644
index 000000000..42f846fa3
--- /dev/null
+++ b/src/pkg/os/error_test.go
@@ -0,0 +1,81 @@
+// 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 os_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestErrIsExist(t *testing.T) {
+ f, err := ioutil.TempFile("", "_Go_ErrIsExist")
+ if err != nil {
+ t.Fatalf("open ErrIsExist tempfile: %s", err)
+ return
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ f2, err := os.OpenFile(f.Name(), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ if err == nil {
+ f2.Close()
+ t.Fatal("Open should have failed")
+ return
+ }
+ if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
+ t.Fatal(s)
+ return
+ }
+}
+
+func testErrNotExist(name string) string {
+ f, err := os.Open(name)
+ if err == nil {
+ f.Close()
+ return "Open should have failed"
+ }
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ return s
+ }
+
+ err = os.Chdir(name)
+ if err == nil {
+ return "Chdir should have failed"
+ }
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ return s
+ }
+ return ""
+}
+
+func TestErrIsNotExist(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "_Go_ErrIsNotExist")
+ if err != nil {
+ t.Fatalf("create ErrIsNotExist tempdir: %s", err)
+ return
+ }
+ defer os.RemoveAll(tmpDir)
+
+ name := filepath.Join(tmpDir, "NotExists")
+ if s := testErrNotExist(name); s != "" {
+ t.Fatal(s)
+ return
+ }
+
+ name = filepath.Join(name, "NotExists2")
+ if s := testErrNotExist(name); s != "" {
+ t.Fatal(s)
+ return
+ }
+}
+
+func checkErrorPredicate(predName string, pred func(error) bool, err error) string {
+ if !pred(err) {
+ return fmt.Sprintf("%s does not work as expected for %#v", predName, err)
+ }
+ return ""
+}
diff --git a/src/pkg/os/error_windows.go b/src/pkg/os/error_windows.go
new file mode 100644
index 000000000..5d692b073
--- /dev/null
+++ b/src/pkg/os/error_windows.go
@@ -0,0 +1,30 @@
+// 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 os
+
+import "syscall"
+
+func isExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.ERROR_ALREADY_EXISTS ||
+ err == syscall.ERROR_FILE_EXISTS || err == ErrExist
+}
+
+func isNotExist(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == syscall.ERROR_FILE_NOT_FOUND ||
+ err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
+}
+
+func isPermission(err error) bool {
+ if pe, ok := err.(*PathError); ok {
+ err = pe.Err
+ }
+ return err == ErrPermission
+}
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index ebe92a9fb..bbd04902b 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -59,7 +59,7 @@ type Cmd struct {
// If either is nil, Run connects the corresponding file descriptor
// to the null device (os.DevNull).
//
- // If Stdout and Stderr are are the same writer, at most one
+ // If Stdout and Stderr are the same writer, at most one
// goroutine at a time will call Write.
Stdout io.Writer
Stderr io.Writer
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index 6aa0280f4..6271c3189 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -173,7 +173,21 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
func (f *File) write(b []byte) (n int, err error) {
- return syscall.Write(f.fd, b)
+ for {
+ m, err := syscall.Write(f.fd, b)
+ n += m
+
+ // If the syscall wrote some data but not all (short write)
+ // or it returned EINTR, then assume it stopped early for
+ // reasons that are uninteresting to the caller, and try again.
+ if 0 < m && m < len(b) || err == syscall.EINTR {
+ b = b[m:]
+ continue
+ }
+
+ return n, err
+ }
+ panic("not reached")
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index d1e241f00..dec80cc09 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -1047,3 +1047,22 @@ func TestSameFile(t *testing.T) {
t.Errorf("files should be different")
}
}
+
+func TestDevNullFile(t *testing.T) {
+ f, err := Open(DevNull)
+ if err != nil {
+ t.Fatalf("Open(%s): %v", DevNull, err)
+ }
+ defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("Stat(%s): %v", DevNull, err)
+ }
+ name := filepath.Base(DevNull)
+ if fi.Name() != name {
+ t.Fatalf("wrong file name have %v want %v", fi.Name(), name)
+ }
+ if fi.Size() != 0 {
+ t.Fatalf("wrong file size have %d want 0", fi.Size())
+ }
+}
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
index 19e215e93..75351c805 100644
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -21,6 +21,9 @@ func (file *File) Stat() (fi FileInfo, err error) {
// I don't know any better way to do that for directory
return Stat(file.name)
}
+ if file.name == DevNull {
+ return statDevNull()
+ }
var d syscall.ByHandleFileInformation
e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d)
if e != nil {
@@ -41,6 +44,9 @@ func Stat(name string) (fi FileInfo, err error) {
if len(name) == 0 {
return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
}
+ if name == DevNull {
+ return statDevNull()
+ }
var d syscall.Win32FileAttributeData
e := syscall.GetFileAttributesEx(syscall.StringToUTF16Ptr(name), syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d)))
if e != nil {
@@ -69,6 +75,22 @@ func Lstat(name string) (fi FileInfo, err error) {
return Stat(name)
}
+// statDevNull return FileInfo structure describing DevNull file ("NUL").
+// It creates invented data, since none of windows api will return
+// that information.
+func statDevNull() (fi FileInfo, err error) {
+ return &fileStat{
+ name: DevNull,
+ mode: ModeDevice | ModeCharDevice | 0666,
+ sys: &winSys{
+ // hopefully this will work for SameFile
+ vol: 0,
+ idxhi: 0,
+ idxlo: 0,
+ },
+ }, nil
+}
+
// basename removes trailing slashes and the leading
// directory name and drive letter from path name.
func basename(name string) string {
@@ -199,7 +221,7 @@ func (s *winSys) loadFileId() error {
}
s.Lock()
defer s.Unlock()
- h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, 0, 0)
+ h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if e != nil {
return e
}
diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go
index c7c5199be..01dddf50d 100644
--- a/src/pkg/os/types.go
+++ b/src/pkg/os/types.go
@@ -15,7 +15,7 @@ func Getpagesize() int { return syscall.Getpagesize() }
// A FileInfo describes a file and is returned by Stat and Lstat
type FileInfo interface {
Name() string // base name of the file
- Size() int64 // length in bytes
+ Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 38d264fb9..db8b0260c 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -7,6 +7,7 @@ package filepath
import (
"errors"
"os"
+ "runtime"
"sort"
"strings"
"unicode/utf8"
@@ -37,6 +38,9 @@ var ErrBadPattern = errors.New("syntax error in pattern")
// The only possible returned error is ErrBadPattern, when pattern
// is malformed.
//
+// On Windows, escaping is disabled. Instead, '\\' is treated as
+// path separator.
+//
func Match(pattern, name string) (matched bool, err error) {
Pattern:
for len(pattern) > 0 {
@@ -95,9 +99,11 @@ Scan:
for i = 0; i < len(pattern); i++ {
switch pattern[i] {
case '\\':
- // error check handled in matchChunk: bad pattern.
- if i+1 < len(pattern) {
- i++
+ if runtime.GOOS != "windows" {
+ // error check handled in matchChunk: bad pattern.
+ if i+1 < len(pattern) {
+ i++
+ }
}
case '[':
inrange = true
@@ -167,10 +173,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) {
chunk = chunk[1:]
case '\\':
- chunk = chunk[1:]
- if len(chunk) == 0 {
- err = ErrBadPattern
- return
+ if runtime.GOOS != "windows" {
+ chunk = chunk[1:]
+ if len(chunk) == 0 {
+ err = ErrBadPattern
+ return
+ }
}
fallthrough
@@ -191,7 +199,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
err = ErrBadPattern
return
}
- if chunk[0] == '\\' {
+ if chunk[0] == '\\' && runtime.GOOS != "windows" {
chunk = chunk[1:]
if len(chunk) == 0 {
err = ErrBadPattern
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
index 7bdc449bc..7b0ea8017 100644
--- a/src/pkg/path/filepath/match_test.go
+++ b/src/pkg/path/filepath/match_test.go
@@ -7,6 +7,7 @@ package filepath_test
import (
. "path/filepath"
"runtime"
+ "strings"
"testing"
)
@@ -76,21 +77,26 @@ func errp(e error) string {
}
func TestMatch(t *testing.T) {
- if runtime.GOOS == "windows" {
- // XXX: Don't pass for windows.
- return
- }
for _, tt := range matchTests {
- ok, err := Match(tt.pattern, tt.s)
+ pattern := tt.pattern
+ s := tt.s
+ if runtime.GOOS == "windows" {
+ if strings.Index(pattern, "\\") >= 0 {
+ // no escape allowed on windows.
+ continue
+ }
+ pattern = Clean(pattern)
+ s = Clean(s)
+ }
+ ok, err := Match(pattern, s)
if ok != tt.match || err != tt.err {
- t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err))
+ t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
}
}
}
// contains returns true if vector contains the string s.
func contains(vector []string, s string) bool {
- s = ToSlash(s)
for _, elem := range vector {
if elem == s {
return true
@@ -109,18 +115,20 @@ var globTests = []struct {
}
func TestGlob(t *testing.T) {
- if runtime.GOOS == "windows" {
- // XXX: Don't pass for windows.
- return
- }
for _, tt := range globTests {
- matches, err := Glob(tt.pattern)
+ pattern := tt.pattern
+ result := tt.result
+ if runtime.GOOS == "windows" {
+ pattern = Clean(pattern)
+ result = Clean(result)
+ }
+ matches, err := Glob(pattern)
if err != nil {
- t.Errorf("Glob error for %q: %s", tt.pattern, err)
+ t.Errorf("Glob error for %q: %s", pattern, err)
continue
}
- if !contains(matches, tt.result) {
- t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
+ if !contains(matches, result) {
+ t.Errorf("Glob(%#q) = %#v want %v", pattern, matches, result)
}
}
for _, pattern := range []string{"no_match", "../*/no_match"} {
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index cfe46981f..1e7487263 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -7,10 +7,8 @@
package filepath
import (
- "bytes"
"errors"
"os"
- "runtime"
"sort"
"strings"
)
@@ -191,64 +189,7 @@ func Ext(path string) string {
// If path is relative the result will be relative to the current directory,
// unless one of the components is an absolute symbolic link.
func EvalSymlinks(path string) (string, error) {
- if runtime.GOOS == "windows" {
- // Symlinks are not supported under windows.
- _, err := os.Lstat(path)
- if err != nil {
- return "", err
- }
- return Clean(path), nil
- }
- const maxIter = 255
- originalPath := path
- // consume path by taking each frontmost path element,
- // expanding it if it's a symlink, and appending it to b
- var b bytes.Buffer
- for n := 0; path != ""; n++ {
- if n > maxIter {
- return "", errors.New("EvalSymlinks: too many links in " + originalPath)
- }
-
- // find next path component, p
- i := strings.IndexRune(path, Separator)
- var p string
- if i == -1 {
- p, path = path, ""
- } else {
- p, path = path[:i], path[i+1:]
- }
-
- if p == "" {
- if b.Len() == 0 {
- // must be absolute path
- b.WriteRune(Separator)
- }
- continue
- }
-
- fi, err := os.Lstat(b.String() + p)
- if err != nil {
- return "", err
- }
- if fi.Mode()&os.ModeSymlink == 0 {
- b.WriteString(p)
- if path != "" {
- b.WriteRune(Separator)
- }
- continue
- }
-
- // it's a symlink, put it at the front of path
- dest, err := os.Readlink(b.String() + p)
- if err != nil {
- return "", err
- }
- if IsAbs(dest) {
- b.Reset()
- }
- path = dest + string(Separator) + path
- }
- return Clean(b.String()), nil
+ return evalSymlinks(path)
}
// Abs returns an absolute representation of path.
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index 98ff46642..87cb5e553 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -440,7 +440,7 @@ func TestBase(t *testing.T) {
tests := basetests
if runtime.GOOS == "windows" {
// make unix tests work on windows
- for i, _ := range tests {
+ for i := range tests {
tests[i].result = filepath.Clean(tests[i].result)
}
// add windows specific tests
@@ -483,7 +483,7 @@ func TestDir(t *testing.T) {
tests := dirtests
if runtime.GOOS == "windows" {
// make unix tests work on windows
- for i, _ := range tests {
+ for i := range tests {
tests[i].result = filepath.Clean(tests[i].result)
}
// add windows specific tests
@@ -621,6 +621,12 @@ func TestEvalSymlinks(t *testing.T) {
if d.path == d.dest {
// will test only real files and directories
tests = append(tests, d)
+ // test "canonical" names
+ d2 := EvalSymlinksTest{
+ path: strings.ToUpper(d.path),
+ dest: d.dest,
+ }
+ tests = append(tests, d2)
}
}
} else {
@@ -642,33 +648,61 @@ func TestEvalSymlinks(t *testing.T) {
}
}
-// Test paths relative to $GOROOT/src
-var abstests = []string{
- "../AUTHORS",
- "pkg/../../AUTHORS",
- "Make.inc",
- "pkg/math",
+// Test directories relative to temporary directory.
+// The tests are run in absTestDirs[0].
+var absTestDirs = []string{
+ "a",
+ "a/b",
+ "a/b/c",
+}
+
+// Test paths relative to temporary directory. $ expands to the directory.
+// The tests are run in absTestDirs[0].
+// We create absTestDirs first.
+var absTests = []string{
".",
- "$GOROOT/src/Make.inc",
- "$GOROOT/src/../src/Make.inc",
- "$GOROOT/misc/cgo",
- "$GOROOT",
+ "b",
+ "../a",
+ "../a/b",
+ "../a/b/./c/../../.././a",
+ "$",
+ "$/.",
+ "$/a/../a/b",
+ "$/a/b/c/../../.././a",
}
func TestAbs(t *testing.T) {
- t.Logf("test needs to be rewritten; disabled")
- return
-
oldwd, err := os.Getwd()
if err != nil {
- t.Fatal("Getwd failed: " + err.Error())
+ t.Fatal("Getwd failed: ", err)
}
defer os.Chdir(oldwd)
- goroot := os.Getenv("GOROOT")
- cwd := filepath.Join(goroot, "src")
- os.Chdir(cwd)
- for _, path := range abstests {
- path = strings.Replace(path, "$GOROOT", goroot, -1)
+
+ root, err := ioutil.TempDir("", "TestAbs")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(root)
+
+ err = os.Chdir(root)
+ if err != nil {
+ t.Fatal("chdir failed: ", err)
+ }
+
+ for _, dir := range absTestDirs {
+ err = os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal("Mkdir failed: ", err)
+ }
+ }
+
+ err = os.Chdir(absTestDirs[0])
+ if err != nil {
+ t.Fatal("chdir failed: ", err)
+ }
+
+ for _, path := range absTests {
+ path = strings.Replace(path, "$", root, -1)
info, err := os.Stat(path)
if err != nil {
t.Errorf("%s: %s", path, err)
diff --git a/src/pkg/path/filepath/symlink.go b/src/pkg/path/filepath/symlink.go
new file mode 100644
index 000000000..307dd0f8f
--- /dev/null
+++ b/src/pkg/path/filepath/symlink.go
@@ -0,0 +1,67 @@
+// 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.
+
+// +build !windows
+
+package filepath
+
+import (
+ "bytes"
+ "errors"
+ "os"
+ "strings"
+)
+
+func evalSymlinks(path string) (string, error) {
+ const maxIter = 255
+ originalPath := path
+ // consume path by taking each frontmost path element,
+ // expanding it if it's a symlink, and appending it to b
+ var b bytes.Buffer
+ for n := 0; path != ""; n++ {
+ if n > maxIter {
+ return "", errors.New("EvalSymlinks: too many links in " + originalPath)
+ }
+
+ // find next path component, p
+ i := strings.IndexRune(path, Separator)
+ var p string
+ if i == -1 {
+ p, path = path, ""
+ } else {
+ p, path = path[:i], path[i+1:]
+ }
+
+ if p == "" {
+ if b.Len() == 0 {
+ // must be absolute path
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ fi, err := os.Lstat(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if fi.Mode()&os.ModeSymlink == 0 {
+ b.WriteString(p)
+ if path != "" {
+ b.WriteRune(Separator)
+ }
+ continue
+ }
+
+ // it's a symlink, put it at the front of path
+ dest, err := os.Readlink(b.String() + p)
+ if err != nil {
+ return "", err
+ }
+ if IsAbs(dest) {
+ b.Reset()
+ }
+ path = dest + string(Separator) + path
+ }
+ return Clean(b.String()), nil
+}
diff --git a/src/pkg/path/filepath/symlink_windows.go b/src/pkg/path/filepath/symlink_windows.go
new file mode 100644
index 000000000..afa88bfe8
--- /dev/null
+++ b/src/pkg/path/filepath/symlink_windows.go
@@ -0,0 +1,27 @@
+// 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 filepath
+
+import (
+ "syscall"
+)
+
+func evalSymlinks(path string) (string, error) {
+ p := syscall.StringToUTF16(path)
+ b := p // GetLongPathName says we can reuse buffer
+ n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+ if err != nil {
+ return "", err
+ }
+ }
+ b = b[:n]
+ return Clean(syscall.UTF16ToString(b)), nil
+}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 6356b296d..64550b8f6 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -66,9 +66,10 @@ type Type interface {
// It returns an empty string for unnamed types.
Name() string
- // PkgPath returns the type's package path.
- // The package path is a full package import path like "encoding/base64".
- // PkgPath returns an empty string for unnamed or predeclared types.
+ // PkgPath returns a named type's package path, that is, the import path
+ // that uniquely identifies the package, such as "encoding/base64".
+ // If the type was predeclared (string, error) or unnamed (*T, struct{}, []int),
+ // the package path will be the empty string.
PkgPath() string
// Size returns the number of bytes needed to store
@@ -243,7 +244,7 @@ type commonType struct {
fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
- string *string // string form; unnecessary but undeniably useful
+ string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *runtimeType // pointer to this type, if used in binary or has methods
}
@@ -354,11 +355,18 @@ type structType struct {
// Method represents a single method.
type Method struct {
- PkgPath string // empty for uppercase Name
+ // Name is the method name.
+ // PkgPath is the package path that qualifies a lower case (unexported)
+ // method name. It is empty for upper case (exported) method names.
+ // The combination of PkgPath and Name uniquely identifies a method
+ // in a method set.
+ // See http://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
- Type Type
- Func Value
- Index int
+ PkgPath string
+
+ Type Type // method type
+ Func Value // func with receiver as first argument
+ Index int // index for Type.Method
}
// High bit says whether type has
@@ -697,14 +705,20 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
return
}
+// A StructField describes a single field in a struct.
type StructField struct {
- PkgPath string // empty for uppercase Name
- Name string
- Type Type
- Tag StructTag
- Offset uintptr
- Index []int
- Anonymous bool
+ // Name is the field name.
+ // PkgPath is the package path that qualifies a lower case (unexported)
+ // field name. It is empty for upper case (exported) field names.
+ // See http://golang.org/ref/spec#Uniqueness_of_identifiers
+ Name string
+ PkgPath string
+
+ Type Type // field type
+ Tag StructTag // field tag string
+ Offset uintptr // offset within struct, in bytes
+ Index []int // index sequence for Type.FieldByIndex
+ Anonymous bool // is an anonymous field
}
// A StructTag is the tag string in a struct field.
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index f3f7d639a..79476ad22 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -54,6 +54,10 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) {
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
+//
+// A Value can be used concurrently by multiple goroutines provided that
+// the underlying Go value can be used concurrently for the equivalent
+// direct operations.
type Value struct {
// typ holds the type of the value represented by a Value.
typ *commonType
@@ -1628,6 +1632,15 @@ func MakeSlice(typ Type, len, cap int) Value {
if typ.Kind() != Slice {
panic("reflect.MakeSlice of non-slice type")
}
+ if len < 0 {
+ panic("reflect.MakeSlice: negative len")
+ }
+ if cap < 0 {
+ panic("reflect.MakeSlice: negative cap")
+ }
+ if len > cap {
+ panic("reflect.MakeSlice: len > cap")
+ }
// Declare slice so that gc can see the base pointer in it.
var x []byte
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 6bbec3063..21bd293ab 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -425,6 +425,14 @@ TEXT runtime·cgocallback(SB),7,$12
// Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX)
MOVL m(CX), BP
+
+ // If m is nil, it is almost certainly because we have been called
+ // on a thread that Go did not create. We're going to crash as
+ // soon as we try to use m; instead, try to print a nice error and exit.
+ CMPL BP, $0
+ JNE 2(PC)
+ CALL runtime·badcallback(SB)
+
MOVL m_g0(BP), SI
PUSHL (g_sched+gobuf_sp)(SI)
MOVL SP, (g_sched+gobuf_sp)(SI)
@@ -552,4 +560,13 @@ TEXT runtime·emptyfunc(SB),0,$0
TEXT runtime·abort(SB),7,$0
INT $0x3
+TEXT runtime·stackguard(SB),7,$0
+ MOVL SP, DX
+ MOVL DX, sp+0(FP)
+ get_tls(CX)
+ MOVL g(CX), BX
+ MOVL g_stackguard(BX), DX
+ MOVL DX, guard+4(FP)
+ RET
+
GLOBL runtime·tls0(SB), $32
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 2ea87a779..d41ab96d0 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -73,7 +73,7 @@ ok:
// start this M
CALL runtime·mstart(SB)
- CALL runtime·notok(SB) // never returns
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·breakpoint(SB),7,$0
@@ -471,6 +471,14 @@ TEXT runtime·cgocallback(SB),7,$24
// Save current m->g0->sched.sp on stack and then set it to SP.
get_tls(CX)
MOVQ m(CX), BP
+
+ // If m is nil, it is almost certainly because we have been called
+ // on a thread that Go did not create. We're going to crash as
+ // soon as we try to use m; instead, try to print a nice error and exit.
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badcallback(SB)
+
MOVQ m_g0(BP), SI
PUSHQ (g_sched+gobuf_sp)(SI)
MOVQ SP, (g_sched+gobuf_sp)(SI)
@@ -579,4 +587,13 @@ TEXT runtime·cputicks(SB),7,$0
ADDQ DX, AX
RET
+TEXT runtime·stackguard(SB),7,$0
+ MOVQ SP, DX
+ MOVQ DX, sp+0(FP)
+ get_tls(CX)
+ MOVQ g(CX), BX
+ MOVQ g_stackguard(BX), DX
+ MOVQ DX, guard+8(FP)
+ RET
+
GLOBL runtime·tls0(SB), $64
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 3d9a7a73e..423fda7a0 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -313,3 +313,10 @@ casl:
casfail:
MOVW $0, R0
RET
+
+TEXT runtime·stackguard(SB),7,$0
+ MOVW R13, R1
+ MOVW g_stackguard(g), R2
+ MOVW R1, sp+0(FP)
+ MOVW R2, limit+4(FP)
+ RET
diff --git a/src/pkg/runtime/cgo/gcc_darwin_386.c b/src/pkg/runtime/cgo/gcc_darwin_386.c
index d9f25347a..2c30c666f 100644
--- a/src/pkg/runtime/cgo/gcc_darwin_386.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_386.c
@@ -4,6 +4,7 @@
#include <string.h> /* for strerror */
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
@@ -120,14 +121,21 @@ void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_darwin_amd64.c b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
index a0b026ee2..89dc7a4e8 100644
--- a/src/pkg/runtime/cgo/gcc_darwin_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_darwin_amd64.c
@@ -4,6 +4,7 @@
#include <string.h> /* for strerror */
#include <pthread.h>
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
@@ -90,14 +91,21 @@ void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index 8401a75ca..7d84acc11 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <string.h>
+#include <signal.h>
#include "libcgo.h"
static void *threadentry(void*);
@@ -26,10 +27,14 @@ void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
// Not sure why the memset is necessary here,
// but without it, we get a bogus stack size
// out of pthread_attr_getstacksize. C'est la Linux.
@@ -39,6 +44,9 @@ libcgo_sys_thread_start(ThreadStart *ts)
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index 6ce3333a8..28cbf78c5 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <string.h> // strerror
+#include <signal.h>
#include "libcgo.h"
static void* threadentry(void*);
@@ -26,14 +27,21 @@ void
libcgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
+ sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
+ sigfillset(&ign);
+ sigprocmask(SIG_SETMASK, &ign, &oset);
+
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
ts->g->stackguard = size;
err = pthread_create(&p, &attr, threadentry, ts);
+
+ sigprocmask(SIG_SETMASK, &oset, nil);
+
if (err != 0) {
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
abort();
diff --git a/src/pkg/runtime/compiler.go b/src/pkg/runtime/compiler.go
new file mode 100644
index 000000000..562a46022
--- /dev/null
+++ b/src/pkg/runtime/compiler.go
@@ -0,0 +1,13 @@
+// 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
+
+// Compiler is the name of the compiler toolchain that built the
+// running binary. Known toolchains are:
+//
+// gc The 5g/6g/8g compiler suite at code.google.com/p/go.
+// gccgo The gccgo front end, part of the GCC compiler suite.
+//
+const Compiler = "gc"
diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go
index 94293bb93..f33f5072b 100644
--- a/src/pkg/runtime/debug/stack_test.go
+++ b/src/pkg/runtime/debug/stack_test.go
@@ -39,13 +39,20 @@ func TestStack(t *testing.T) {
if len(lines) <= 6 {
t.Fatal("too few lines")
}
- check(t, lines[0], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[1], "\t(*T).ptrmethod: return Stack()")
- check(t, lines[2], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[3], "\tT.method: return t.ptrmethod()")
- check(t, lines[4], "src/pkg/runtime/debug/stack_test.go")
- check(t, lines[5], "\tTestStack: b := T(0).method()")
- check(t, lines[6], "src/pkg/testing/testing.go")
+ n := 0
+ frame := func(line, code string) {
+ check(t, lines[n], line)
+ n++
+ // The source might not be available while running the test.
+ if strings.HasPrefix(lines[n], "\t") {
+ check(t, lines[n], code)
+ n++
+ }
+ }
+ frame("src/pkg/runtime/debug/stack_test.go", "\t(*T).ptrmethod: return Stack()")
+ frame("src/pkg/runtime/debug/stack_test.go", "\tT.method: return t.ptrmethod()")
+ frame("src/pkg/runtime/debug/stack_test.go", "\tTestStack: b := T(0).method()")
+ frame("src/pkg/testing/testing.go", "")
}
func check(t *testing.T, line, has string) {
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index c603e1b0d..51921135b 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -19,7 +19,9 @@ var F64toint = f64toint
func entersyscall()
func exitsyscall()
func golockedOSThread() bool
+func stackguard() (sp, limit uintptr)
var Entersyscall = entersyscall
var Exitsyscall = exitsyscall
var LockedOSThread = golockedOSThread
+var Stackguard = stackguard
diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c
deleted file mode 100644
index b59a69c5e..000000000
--- a/src/pkg/runtime/goc2c.c
+++ /dev/null
@@ -1,750 +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.
-
-// +build ignore
-
-/*
- * Translate a .goc file into a .c file. A .goc file is a combination
- * of a limited form of Go with C.
- */
-
-/*
- package PACKAGENAME
- {# line}
- func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
- C code with proper brace nesting
- \}
-*/
-
-/*
- * We generate C code which implements the function such that it can
- * be called from Go and executes the C code.
- */
-
-#include <u.h>
-#include <stdio.h>
-#include <libc.h>
-
-/* Whether we're emitting for gcc */
-static int gcc;
-
-/* File and line number */
-static const char *file;
-static unsigned int lineno = 1;
-
-/* List of names and types. */
-struct params {
- struct params *next;
- char *name;
- char *type;
-};
-
-/* index into type_table */
-enum {
- Bool,
- Float,
- Int,
- Uint,
- Uintptr,
- String,
- Slice,
- Eface,
-};
-
-static struct {
- char *name;
- int size;
-} type_table[] = {
- /* variable sized first, for easy replacement */
- /* order matches enum above */
- /* default is 32-bit architecture sizes */
- "bool", 1,
- "float", 4,
- "int", 4,
- "uint", 4,
- "uintptr", 4,
- "String", 8,
- "Slice", 12,
- "Eface", 8,
-
- /* fixed size */
- "float32", 4,
- "float64", 8,
- "byte", 1,
- "int8", 1,
- "uint8", 1,
- "int16", 2,
- "uint16", 2,
- "int32", 4,
- "uint32", 4,
- "int64", 8,
- "uint64", 8,
-
- NULL,
-};
-
-/* Fixed structure alignment (non-gcc only) */
-int structround = 4;
-
-/* Unexpected EOF. */
-static void
-bad_eof(void)
-{
- sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
-}
-
-/* Out of memory. */
-static void
-bad_mem(void)
-{
- sysfatal("%s:%ud: out of memory\n", file, lineno);
-}
-
-/* Allocate memory without fail. */
-static void *
-xmalloc(unsigned int size)
-{
- void *ret = malloc(size);
- if (ret == NULL)
- bad_mem();
- return ret;
-}
-
-/* Reallocate memory without fail. */
-static void*
-xrealloc(void *buf, unsigned int size)
-{
- void *ret = realloc(buf, size);
- if (ret == NULL)
- bad_mem();
- return ret;
-}
-
-/* Free a list of parameters. */
-static void
-free_params(struct params *p)
-{
- while (p != NULL) {
- struct params *next;
-
- next = p->next;
- free(p->name);
- free(p->type);
- free(p);
- p = next;
- }
-}
-
-/* Read a character, tracking lineno. */
-static int
-getchar_update_lineno(void)
-{
- int c;
-
- c = getchar();
- if (c == '\n')
- ++lineno;
- return c;
-}
-
-/* Read a character, giving an error on EOF, tracking lineno. */
-static int
-getchar_no_eof(void)
-{
- int c;
-
- c = getchar_update_lineno();
- if (c == EOF)
- bad_eof();
- return c;
-}
-
-/* Read a character, skipping comments. */
-static int
-getchar_skipping_comments(void)
-{
- int c;
-
- while (1) {
- c = getchar_update_lineno();
- if (c != '/')
- return c;
-
- c = getchar();
- if (c == '/') {
- do {
- c = getchar_update_lineno();
- } while (c != EOF && c != '\n');
- return c;
- } else if (c == '*') {
- while (1) {
- c = getchar_update_lineno();
- if (c == EOF)
- return EOF;
- if (c == '*') {
- do {
- c = getchar_update_lineno();
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- } else {
- ungetc(c, stdin);
- return '/';
- }
- }
-}
-
-/*
- * Read and return a token. Tokens are string or character literals
- * or else delimited by whitespace or by [(),{}].
- * The latter are all returned as single characters.
- */
-static char *
-read_token(void)
-{
- int c, q;
- char *buf;
- unsigned int alc, off;
- const char* delims = "(),{}";
-
- while (1) {
- c = getchar_skipping_comments();
- if (c == EOF)
- return NULL;
- if (!isspace(c))
- break;
- }
- alc = 16;
- buf = xmalloc(alc + 1);
- off = 0;
- if(c == '"' || c == '\'') {
- q = c;
- buf[off] = c;
- ++off;
- while (1) {
- if (off+2 >= alc) { // room for c and maybe next char
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- c = getchar_no_eof();
- buf[off] = c;
- ++off;
- if(c == q)
- break;
- if(c == '\\') {
- buf[off] = getchar_no_eof();
- ++off;
- }
- }
- } else if (strchr(delims, c) != NULL) {
- buf[off] = c;
- ++off;
- } else {
- while (1) {
- if (off >= alc) {
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- buf[off] = c;
- ++off;
- c = getchar_skipping_comments();
- if (c == EOF)
- break;
- if (isspace(c) || strchr(delims, c) != NULL) {
- if (c == '\n')
- lineno--;
- ungetc(c, stdin);
- break;
- }
- }
- }
- buf[off] = '\0';
- return buf;
-}
-
-/* Read a token, giving an error on EOF. */
-static char *
-read_token_no_eof(void)
-{
- char *token = read_token();
- if (token == NULL)
- bad_eof();
- return token;
-}
-
-/* Read the package clause, and return the package name. */
-static char *
-read_package(void)
-{
- char *token;
-
- token = read_token_no_eof();
- if (token == nil)
- sysfatal("%s:%ud: no token\n", file, lineno);
- if (strcmp(token, "package") != 0) {
- sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
- file, lineno, token);
- }
- return read_token_no_eof();
-}
-
-/* Read and copy preprocessor lines. */
-static void
-read_preprocessor_lines(void)
-{
- while (1) {
- int c;
-
- do {
- c = getchar_skipping_comments();
- } while (isspace(c));
- if (c != '#') {
- ungetc(c, stdin);
- break;
- }
- putchar(c);
- do {
- c = getchar_update_lineno();
- putchar(c);
- } while (c != '\n');
- }
-}
-
-/*
- * Read a type in Go syntax and return a type in C syntax. We only
- * permit basic types and pointers.
- */
-static char *
-read_type(void)
-{
- char *p, *op, *q;
- int pointer_count;
- unsigned int len;
-
- p = read_token_no_eof();
- if (*p != '*')
- return p;
- op = p;
- pointer_count = 0;
- while (*p == '*') {
- ++pointer_count;
- ++p;
- }
- len = strlen(p);
- q = xmalloc(len + pointer_count + 1);
- memcpy(q, p, len);
- while (pointer_count > 0) {
- q[len] = '*';
- ++len;
- --pointer_count;
- }
- q[len] = '\0';
- free(op);
- return q;
-}
-
-/* Return the size of the given type. */
-static int
-type_size(char *p)
-{
- int i;
-
- if(p[strlen(p)-1] == '*')
- return type_table[Uintptr].size;
-
- for(i=0; type_table[i].name; i++)
- if(strcmp(type_table[i].name, p) == 0)
- return type_table[i].size;
- sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
- return 0;
-}
-
-/*
- * Read a list of parameters. Each parameter is a name and a type.
- * The list ends with a ')'. We have already read the '('.
- */
-static struct params *
-read_params(int *poffset)
-{
- char *token;
- struct params *ret, **pp, *p;
- int offset, size, rnd;
-
- ret = NULL;
- pp = &ret;
- token = read_token_no_eof();
- offset = 0;
- if (strcmp(token, ")") != 0) {
- while (1) {
- p = xmalloc(sizeof(struct params));
- p->name = token;
- p->type = read_type();
- p->next = NULL;
- *pp = p;
- pp = &p->next;
-
- size = type_size(p->type);
- rnd = size;
- if(rnd > structround)
- rnd = structround;
- if(offset%rnd)
- offset += rnd - offset%rnd;
- offset += size;
-
- token = read_token_no_eof();
- if (strcmp(token, ",") != 0)
- break;
- token = read_token_no_eof();
- }
- }
- if (strcmp(token, ")") != 0) {
- sysfatal("%s:%ud: expected '('\n",
- file, lineno);
- }
- if (poffset != NULL)
- *poffset = offset;
- return ret;
-}
-
-/*
- * Read a function header. This reads up to and including the initial
- * '{' character. Returns 1 if it read a header, 0 at EOF.
- */
-static int
-read_func_header(char **name, struct params **params, int *paramwid, struct params **rets)
-{
- int lastline;
- char *token;
-
- lastline = -1;
- while (1) {
- token = read_token();
- if (token == NULL)
- return 0;
- if (strcmp(token, "func") == 0) {
- if(lastline != -1)
- printf("\n");
- break;
- }
- if (lastline != lineno) {
- if (lastline == lineno-1)
- printf("\n");
- else
- printf("\n#line %d \"%s\"\n", lineno, file);
- lastline = lineno;
- }
- printf("%s ", token);
- }
-
- *name = read_token_no_eof();
-
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0) {
- sysfatal("%s:%ud: expected \"(\"\n",
- file, lineno);
- }
- *params = read_params(paramwid);
-
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0)
- *rets = NULL;
- else {
- *rets = read_params(NULL);
- token = read_token();
- }
- if (token == NULL || strcmp(token, "{") != 0) {
- sysfatal("%s:%ud: expected \"{\"\n",
- file, lineno);
- }
- return 1;
-}
-
-/* Write out parameters. */
-static void
-write_params(struct params *params, int *first)
-{
- struct params *p;
-
- for (p = params; p != NULL; p = p->next) {
- if (*first)
- *first = 0;
- else
- printf(", ");
- printf("%s %s", p->type, p->name);
- }
-}
-
-/* Write a 6g function header. */
-static void
-write_6g_func_header(char *package, char *name, struct params *params,
- int paramwid, struct params *rets)
-{
- int first, n;
-
- printf("void\n%s·%s(", package, name);
- first = 1;
- write_params(params, &first);
-
- /* insert padding to align output struct */
- if(rets != NULL && paramwid%structround != 0) {
- n = structround - paramwid%structround;
- if(n & 1)
- printf(", uint8");
- if(n & 2)
- printf(", uint16");
- if(n & 4)
- printf(", uint32");
- }
-
- write_params(rets, &first);
- printf(")\n{\n");
-}
-
-/* Write a 6g function trailer. */
-static void
-write_6g_func_trailer(struct params *rets)
-{
- struct params *p;
-
- for (p = rets; p != NULL; p = p->next)
- printf("\tFLUSH(&%s);\n", p->name);
- printf("}\n");
-}
-
-/* Define the gcc function return type if necessary. */
-static void
-define_gcc_return_type(char *package, char *name, struct params *rets)
-{
- struct params *p;
-
- if (rets == NULL || rets->next == NULL)
- return;
- printf("struct %s_%s_ret {\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
- printf("};\n");
-}
-
-/* Write out the gcc function return type. */
-static void
-write_gcc_return_type(char *package, char *name, struct params *rets)
-{
- if (rets == NULL)
- printf("void");
- else if (rets->next == NULL)
- printf("%s", rets->type);
- else
- printf("struct %s_%s_ret", package, name);
-}
-
-/* Write out a gcc function header. */
-static void
-write_gcc_func_header(char *package, char *name, struct params *params,
- struct params *rets)
-{
- int first;
- struct params *p;
-
- define_gcc_return_type(package, name, rets);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(") asm (\"%s.%s\");\n", package, name);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(")\n{\n");
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
-}
-
-/* Write out a gcc function trailer. */
-static void
-write_gcc_func_trailer(char *package, char *name, struct params *rets)
-{
- if (rets == NULL)
- ;
- else if (rets->next == NULL)
- printf("return %s;\n", rets->name);
- else {
- struct params *p;
-
- printf(" {\n struct %s_%s_ret __ret;\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" __ret.%s = %s;\n", p->name, p->name);
- printf(" return __ret;\n }\n");
- }
- printf("}\n");
-}
-
-/* Write out a function header. */
-static void
-write_func_header(char *package, char *name,
- struct params *params, int paramwid,
- struct params *rets)
-{
- if (gcc)
- write_gcc_func_header(package, name, params, rets);
- else
- write_6g_func_header(package, name, params, paramwid, rets);
- printf("#line %d \"%s\"\n", lineno, file);
-}
-
-/* Write out a function trailer. */
-static void
-write_func_trailer(char *package, char *name,
- struct params *rets)
-{
- if (gcc)
- write_gcc_func_trailer(package, name, rets);
- else
- write_6g_func_trailer(rets);
-}
-
-/*
- * Read and write the body of the function, ending in an unnested }
- * (which is read but not written).
- */
-static void
-copy_body(void)
-{
- int nesting = 0;
- while (1) {
- int c;
-
- c = getchar_no_eof();
- if (c == '}' && nesting == 0)
- return;
- putchar(c);
- switch (c) {
- default:
- break;
- case '{':
- ++nesting;
- break;
- case '}':
- --nesting;
- break;
- case '/':
- c = getchar_update_lineno();
- putchar(c);
- if (c == '/') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c != '\n');
- } else if (c == '*') {
- while (1) {
- c = getchar_no_eof();
- putchar(c);
- if (c == '*') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- }
- break;
- case '"':
- case '\'':
- {
- int delim = c;
- do {
- c = getchar_no_eof();
- putchar(c);
- if (c == '\\') {
- c = getchar_no_eof();
- putchar(c);
- c = '\0';
- }
- } while (c != delim);
- }
- break;
- }
- }
-}
-
-/* Process the entire file. */
-static void
-process_file(void)
-{
- char *package, *name;
- struct params *params, *rets;
- int paramwid;
-
- package = read_package();
- read_preprocessor_lines();
- while (read_func_header(&name, &params, &paramwid, &rets)) {
- write_func_header(package, name, params, paramwid, rets);
- copy_body();
- write_func_trailer(package, name, rets);
- free(name);
- free_params(params);
- free_params(rets);
- }
- free(package);
-}
-
-static void
-usage(void)
-{
- sysfatal("Usage: goc2c [--6g | --gc] [file]\n");
-}
-
-void
-main(int argc, char **argv)
-{
- char *goarch;
-
- argv0 = argv[0];
- while(argc > 1 && argv[1][0] == '-') {
- if(strcmp(argv[1], "-") == 0)
- break;
- if(strcmp(argv[1], "--6g") == 0)
- gcc = 0;
- else if(strcmp(argv[1], "--gcc") == 0)
- gcc = 1;
- else
- usage();
- argc--;
- argv++;
- }
-
- if(argc <= 1 || strcmp(argv[1], "-") == 0) {
- file = "<stdin>";
- process_file();
- exits(0);
- }
-
- if(argc > 2)
- usage();
-
- file = argv[1];
- if(freopen(file, "r", stdin) == 0) {
- sysfatal("open %s: %r\n", file);
- }
-
- if(!gcc) {
- // 6g etc; update size table
- goarch = getenv("GOARCH");
- if(goarch != NULL && strcmp(goarch, "amd64") == 0) {
- type_table[Uintptr].size = 8;
- type_table[String].size = 16;
- type_table[Slice].size = 8+4+4;
- type_table[Eface].size = 8+8;
- structround = 8;
- }
- }
-
- printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
- process_file();
- exits(0);
-}
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index af03f8018..fbdd6bb02 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -371,6 +371,22 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
{
byte *p;
+ if(n > h->arena_end - h->arena_used) {
+ // We are in 32-bit mode, maybe we didn't use all possible address space yet.
+ // Reserve some more space.
+ byte *new_end;
+ uintptr needed;
+
+ needed = (uintptr)h->arena_used + n - (uintptr)h->arena_end;
+ // Round wanted arena size to a multiple of 256MB.
+ needed = (needed + (256<<20) - 1) & ~((256<<20)-1);
+ new_end = h->arena_end + needed;
+ if(new_end <= h->arena_start + MaxArena32) {
+ p = runtime·SysReserve(h->arena_end, new_end - h->arena_end);
+ if(p == h->arena_end)
+ h->arena_end = new_end;
+ }
+ }
if(n <= h->arena_end - h->arena_used) {
// Keep taking from our reservation.
p = h->arena_used;
@@ -392,7 +408,8 @@ runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
return nil;
if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
- runtime·printf("runtime: memory allocated by OS not in usable range\n");
+ runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
+ p, h->arena_start, h->arena_start+MaxArena32);
runtime·SysFree(p, n);
return nil;
}
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index 2dc7aef7e..82bb2a292 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -24,8 +24,9 @@ func TestCPUProfile(t *testing.T) {
}
vers := string(out)
t.Logf("uname -a: %v", vers)
- if strings.Contains(vers, "Darwin Kernel Version 10.8.0") && strings.Contains(vers, "root:xnu-1504.15.3~1/RELEASE_X86_64") {
- t.Logf("skipping test on known-broken kernel (64-bit Snow Leopard)")
+ // Lion uses "Darwin Kernel Version 11".
+ if strings.Contains(vers, "Darwin Kernel Version 10") && strings.Contains(vers, "RELEASE_X86_64") {
+ t.Logf("skipping test on known-broken kernel (64-bit Leopard / Snow Leopard)")
return
}
case "plan9":
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index de7090c52..962f748ce 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -200,7 +200,9 @@ runtime·schedinit(void)
n = maxgomaxprocs;
runtime·gomaxprocs = n;
}
- setmcpumax(runtime·gomaxprocs);
+ // wait for the main goroutine to start before taking
+ // GOMAXPROCS into account.
+ setmcpumax(1);
runtime·singleproc = runtime·gomaxprocs == 1;
canaddmcpu(); // mcpu++ to account for bootstrap m
@@ -225,6 +227,8 @@ runtime·main(void)
// by calling runtime.LockOSThread during initialization
// to preserve the lock.
runtime·LockOSThread();
+ // From now on, newgoroutines may use non-main threads.
+ setmcpumax(runtime·gomaxprocs);
runtime·sched.init = true;
scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main);
main·init();
@@ -730,6 +734,12 @@ runtime·mstart(void)
m->g0->sched.pc = (void*)-1; // make sure it is never used
runtime·asminit();
runtime·minit();
+
+ // Install signal handlers; after minit so that minit can
+ // prepare the thread to be able to handle the signals.
+ if(m == &runtime·m0)
+ runtime·initsig();
+
schedule(nil);
}
@@ -1158,6 +1168,11 @@ runtime·malg(int32 stacksize)
G *newg;
byte *stk;
+ 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 = runtime·malloc(sizeof(G));
if(stacksize >= 0) {
if(g == m->g0) {
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index afe8c5abe..ebb5544fb 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -119,7 +119,7 @@ void
runtime·panicstring(int8 *s)
{
Eface err;
-
+
if(m->gcing) {
runtime·printf("panic: %s\n", s);
runtime·throw("panic during gc");
@@ -189,7 +189,7 @@ runtime·goargs(void)
{
String *s;
int32 i;
-
+
// for windows implementation see "os" package
if(Windows)
return;
@@ -207,7 +207,7 @@ runtime·goenvs_unix(void)
{
String *s;
int32 i, n;
-
+
for(n=0; argv[argc+1+n] != 0; n++)
;
@@ -342,8 +342,6 @@ runtime·check(void)
runtime·throw("float32nan2");
if(!(i != i1))
runtime·throw("float32nan3");
-
- runtime·initsig();
}
void
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index f2669fdb7..6f5aea11d 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -675,7 +675,6 @@ void runtime·panicslice(void);
/*
* runtime c-called (but written in Go)
*/
-void runtime·newError(String, Eface*);
void runtime·printany(Eface);
void runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
void runtime·newErrorString(String, Eface*);
@@ -706,7 +705,6 @@ float64 runtime·ldexp(float64 d, int32 e);
float64 runtime·modf(float64 d, float64 *ip);
void runtime·semacquire(uint32*);
void runtime·semrelease(uint32*);
-String runtime·signame(int32 sig);
int32 runtime·gomaxprocsfunc(int32 n);
void runtime·procyield(uint32);
void runtime·osyield(void);
diff --git a/src/pkg/runtime/signal_plan9_386.c b/src/pkg/runtime/signal_plan9_386.c
index 5eb04023f..d26688516 100644
--- a/src/pkg/runtime/signal_plan9_386.c
+++ b/src/pkg/runtime/signal_plan9_386.c
@@ -4,12 +4,6 @@
#include "runtime.h"
-String
-runtime·signame(int32)
-{
- return runtime·emptystring;
-}
-
void
runtime·sigenable(uint32 sig)
{
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
index 0b9d2a55a..9b7e8b03a 100644
--- a/src/pkg/runtime/signal_unix.c
+++ b/src/pkg/runtime/signal_unix.c
@@ -10,14 +10,6 @@
extern SigTab runtime·sigtab[];
-String
-runtime·signame(int32 sig)
-{
- if(sig < 0 || sig >= NSIG)
- return runtime·emptystring;
- return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
-}
-
void
runtime·initsig(void)
{
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index f56dac120..d42385d6c 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -94,4 +94,9 @@ 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 = 72,
};
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
new file mode 100644
index 000000000..01c6b6e2f
--- /dev/null
+++ b/src/pkg/runtime/stack_test.go
@@ -0,0 +1,1528 @@
+// 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.
+
+// 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
+
+package runtime_test
+
+import (
+ . "runtime"
+ "testing"
+ "unsafe"
+)
+
+// See stack.h.
+const (
+ StackGuard = 256
+ StackLimit = 128
+)
+
+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 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,
+}
+
+var Used byte
+
+func use(buf []byte) {
+ for _, c := range buf {
+ Used += c
+ }
+}
+
+// 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/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index c2dab8931..3cf3506ad 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -8,15 +8,11 @@
#include "zasm_GOOS_GOARCH.h"
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
-
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),7,$0
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Exit this OS thread (like pthread_exit, which eventually
@@ -25,7 +21,7 @@ TEXT runtime·exit1(SB),7,$0
MOVL $361, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$0
@@ -52,14 +48,14 @@ TEXT runtime·madvise(SB),7,$0
MOVL $75, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·munmap(SB),7,$0
MOVL $73, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB),7,$0
@@ -110,14 +106,14 @@ TEXT runtime·sigprocmask(SB),7,$0
MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaction(SB),7,$0
MOVL $46, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Sigtramp's job is to call the actual signal handler.
@@ -130,13 +126,18 @@ TEXT runtime·sigaction(SB),7,$0
// 20(FP) context
TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), BP
+ CMPL BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
- MOVL m(CX), BP
MOVL m_gsignal(BP), BP
MOVL BP, g(CX)
@@ -165,14 +166,14 @@ TEXT runtime·sigtramp(SB),7,$40
MOVL BX, 8(SP)
MOVL $184, AX // sigreturn(ucontext, infostyle)
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·usleep(SB),7,$32
@@ -268,7 +269,7 @@ TEXT runtime·bsdthread_register(SB),7,$40
MOVL $0, 24(SP) // dispatchqueue_offset
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Invoke Mach system call.
diff --git a/src/pkg/runtime/sys_darwin_amd64.s b/src/pkg/runtime/sys_darwin_amd64.s
index 4b215d04d..90571baae 100644
--- a/src/pkg/runtime/sys_darwin_amd64.s
+++ b/src/pkg/runtime/sys_darwin_amd64.s
@@ -18,7 +18,7 @@ TEXT runtime·exit(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Exit this OS thread (like pthread_exit, which eventually
@@ -27,7 +27,7 @@ TEXT runtime·exit1(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$0
@@ -62,7 +62,7 @@ TEXT runtime·madvise(SB), 7, $0
MOVL $(0x2000000+75), AX // syscall entry madvise
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// func now() (sec int64, nsec int32)
@@ -99,7 +99,7 @@ TEXT runtime·sigprocmask(SB),7,$0
MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process)
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaction(SB),7,$0
@@ -111,18 +111,23 @@ TEXT runtime·sigaction(SB),7,$0
MOVL $(0x2000000+46), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 48(SP)
// g = m->gsignal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -164,12 +169,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $(0x2000000+73), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
@@ -178,7 +178,7 @@ TEXT runtime·sigaltstack(SB),7,$0
MOVQ $(0x2000000+53), AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·usleep(SB),7,$16
@@ -266,7 +266,7 @@ TEXT runtime·bsdthread_register(SB),7,$0
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index aab444494..a72d8972b 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -45,14 +45,14 @@ TEXT runtime·thr_start(SB),7,$0
TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-4
MOVL $431, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-4
@@ -79,10 +79,6 @@ TEXT runtime·raisesigpipe(SB),7,$12
INT $0x80
RET
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
-
TEXT runtime·mmap(SB),7,$32
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
@@ -103,7 +99,7 @@ TEXT runtime·munmap(SB),7,$-4
MOVL $73, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB), 7, $-4
@@ -157,18 +153,23 @@ TEXT runtime·sigaction(SB),7,$-4
MOVL $416, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
- MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
@@ -194,14 +195,14 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL AX, 4(SP)
MOVL $417, AX // sigreturn(ucontext)
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·usleep(SB),7,$20
@@ -220,8 +221,6 @@ TEXT runtime·usleep(SB),7,$20
MOVL $0, 8(SP) // arg 2 - rmtp
MOVL $240, AX // sys_nanosleep
INT $0x80
- JAE 2(PC)
- CALL runtime·notok(SB)
RET
/*
@@ -319,7 +318,7 @@ TEXT runtime·sigprocmask(SB),7,$16
MOVL $340, AX // sys_sigprocmask
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 3984ef40e..36e034a80 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -47,14 +47,14 @@ TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $1, AX
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-8
MOVQ 8(SP), DI // arg 1 exit status
MOVL $431, AX
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-8
@@ -129,18 +129,23 @@ TEXT runtime·sigaction(SB),7,$-8
MOVL $416, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -174,12 +179,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $73, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$-8
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$-8
@@ -188,7 +188,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVQ $53, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·usleep(SB),7,$16
@@ -205,8 +205,6 @@ TEXT runtime·usleep(SB),7,$16
MOVQ $0, SI // arg 2 - rmtp
MOVL $240, AX // sys_nanosleep
SYSCALL
- JCC 2(PC)
- CALL runtime·notok(SB)
RET
// set tls base to DI
@@ -218,7 +216,7 @@ TEXT runtime·settls(SB),7,$8
MOVQ $165, AX // sysarch
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sysctl(SB),7,$0
@@ -248,5 +246,5 @@ TEXT runtime·sigprocmask(SB),7,$0
MOVL $340, AX // sys_sigprocmask
SYSCALL
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index b4cefc53f..602d9ddac 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -167,6 +167,12 @@ TEXT runtime·rt_sigaction(SB),7,$0
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index 0de5b2aa4..657ab7e0b 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -139,7 +139,7 @@ TEXT runtime·rtsigprocmask(SB),7,$0-32
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·rt_sigaction(SB),7,$0-32
@@ -154,12 +154,17 @@ TEXT runtime·rt_sigaction(SB),7,$0-32
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->gsignal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -205,7 +210,7 @@ TEXT runtime·munmap(SB),7,$0
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·madvise(SB),7,$0
@@ -216,12 +221,7 @@ TEXT runtime·madvise(SB),7,$0
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$0
- MOVQ $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
// int64 futex(int32 *uaddr, int32 op, int32 val,
@@ -290,7 +290,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// set tls base to DI
@@ -303,7 +303,7 @@ TEXT runtime·settls(SB),7,$32
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·osyield(SB),7,$0
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 439df3afa..03e173d26 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -38,11 +38,6 @@
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
-TEXT notok<>(SB),7,$0
- MOVW $0, R9
- MOVW R9, (R9)
- B 0(PC)
-
TEXT runtime·open(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
@@ -126,7 +121,8 @@ TEXT runtime·munmap(SB),7,$0
SWI $0
MOVW $0xfffff001, R6
CMP R6, R0
- BL.HI notok<>(SB)
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
RET
TEXT runtime·madvise(SB),7,$0
@@ -137,7 +133,8 @@ TEXT runtime·madvise(SB),7,$0
SWI $0
MOVW $0xfffff001, R6
CMP R6, R0
- BL.HI notok<>(SB)
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
RET
TEXT runtime·setitimer(SB),7,$0
@@ -291,7 +288,8 @@ TEXT runtime·sigaltstack(SB),7,$0
SWI $0
MOVW $0xfffff001, R6
CMP R6, R0
- BL.HI notok<>(SB)
+ MOVW.HI $0, R9 // crash on syscall failure
+ MOVW.HI R9, (R9)
RET
TEXT runtime·sigtramp(SB),7,$24
diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s
index 632286102..11f8c7aaa 100644
--- a/src/pkg/runtime/sys_netbsd_386.s
+++ b/src/pkg/runtime/sys_netbsd_386.s
@@ -12,14 +12,14 @@
TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-4
MOVL $302, AX // sys_threxit
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-4
@@ -55,10 +55,6 @@ TEXT runtime·raisesigpipe(SB),7,$12
INT $0x80
RET
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
-
TEXT runtime·mmap(SB),7,$36
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
@@ -83,7 +79,7 @@ TEXT runtime·munmap(SB),7,$-4
MOVL $73, AX // sys_munmap
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB),7,$-4
@@ -136,18 +132,23 @@ TEXT runtime·sigaction(SB),7,$-4
MOVL $46, AX // sys_sigaction
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
- MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
@@ -173,7 +174,7 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL AX, 4(SP) // arg 1 - sigcontext
MOVL $103, AX // sys_sigreturn
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
@@ -285,7 +286,7 @@ TEXT runtime·settls(SB),7,$16
MOVL $165, AX // sys_sysarch
INT $0x80
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·osyield(SB),7,$-4
diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s
index 7abeb159b..0b83cd4d8 100644
--- a/src/pkg/runtime/sys_netbsd_amd64.s
+++ b/src/pkg/runtime/sys_netbsd_amd64.s
@@ -83,13 +83,13 @@ TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 - exit status
MOVL $1, AX // sys_exit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-8
MOVL $302, AX // sys_threxit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-8
@@ -170,18 +170,23 @@ TEXT runtime·sigaction(SB),7,$-8
MOVL $46, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -221,12 +226,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $73, AX // sys_munmap
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$-8
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$-8
@@ -235,7 +235,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVQ $288, AX // sys_sigaltstack
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// set tls base to DI
@@ -248,7 +248,7 @@ TEXT runtime·settls(SB),7,$8
MOVQ $165, AX // sys_sysarch
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sysctl(SB),7,$0
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index d49d32b95..593b4a9df 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -12,14 +12,14 @@
TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-4
MOVL $302, AX // sys_threxit
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-4
@@ -55,10 +55,6 @@ TEXT runtime·raisesigpipe(SB),7,$12
INT $0x80
RET
-TEXT runtime·notok(SB),7,$0
- MOVL $0xf1, 0xf1
- RET
-
TEXT runtime·mmap(SB),7,$36
LEAL arg0+0(FP), SI
LEAL 4(SP), DI
@@ -83,7 +79,7 @@ TEXT runtime·munmap(SB),7,$-4
MOVL $73, AX // sys_munmap
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·setitimer(SB),7,$-4
@@ -136,18 +132,23 @@ TEXT runtime·sigaction(SB),7,$-4
MOVL $46, AX // sys_sigaction
INT $0x80
JAE 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$44
get_tls(CX)
+ // check that m exists
+ MOVL m(CX), BX
+ CMPL BX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVL g(CX), DI
MOVL DI, 20(SP)
// g = m->gsignal
- MOVL m(CX), BX
MOVL m_gsignal(BX), BX
MOVL BX, g(CX)
@@ -173,7 +174,7 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL AX, 4(SP) // arg 1 - sigcontext
MOVL $103, AX // sys_sigreturn
INT $0x80
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
@@ -285,7 +286,7 @@ TEXT runtime·settls(SB),7,$16
MOVL $165, AX // sys_sysarch
INT $0x80
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·osyield(SB),7,$-4
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 5bf2e813e..d2d48e6b5 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -83,13 +83,13 @@ TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 - exit status
MOVL $1, AX // sys_exit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·exit1(SB),7,$-8
MOVL $302, AX // sys_threxit
SYSCALL
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·write(SB),7,$-8
@@ -170,18 +170,23 @@ TEXT runtime·sigaction(SB),7,$-8
MOVL $46, AX
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigtramp(SB),7,$64
get_tls(BX)
+ // check that m exists
+ MOVQ m(BX), BP
+ CMPQ BP, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
// save g
MOVQ g(BX), R10
MOVQ R10, 40(SP)
// g = m->signal
- MOVQ m(BX), BP
MOVQ m_gsignal(BP), BP
MOVQ BP, g(BX)
@@ -221,12 +226,7 @@ TEXT runtime·munmap(SB),7,$0
MOVL $73, AX // sys_munmap
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
- RET
-
-TEXT runtime·notok(SB),7,$-8
- MOVL $0xf1, BP
- MOVQ BP, (BP)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sigaltstack(SB),7,$-8
@@ -235,7 +235,7 @@ TEXT runtime·sigaltstack(SB),7,$-8
MOVQ $288, AX // sys_sigaltstack
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
// set tls base to DI
@@ -248,7 +248,7 @@ TEXT runtime·settls(SB),7,$8
MOVQ $165, AX // sys_sysarch
SYSCALL
JCC 2(PC)
- CALL runtime·notok(SB)
+ MOVL $0xf1, 0xf1 // crash
RET
TEXT runtime·sysctl(SB),7,$0
diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s
index 5290f6093..d5646bfea 100644
--- a/src/pkg/runtime/sys_windows_386.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -38,6 +38,46 @@ TEXT runtime·asmstdcall(SB),7,$0
RET
+TEXT runtime·badcallback(SB),7,$24
+ // stderr
+ MOVL $-12, 0(SP)
+ MOVL SP, BP
+ CALL *runtime·GetStdHandle(SB)
+ MOVL BP, SP
+
+ MOVL AX, 0(SP) // handle
+ MOVL $runtime·badcallbackmsg(SB), DX // pointer
+ MOVL DX, 4(SP)
+ MOVL runtime·badcallbacklen(SB), DX // count
+ MOVL DX, 8(SP)
+ LEAL 20(SP), DX // written count
+ MOVL $0, 0(DX)
+ MOVL DX, 12(SP)
+ MOVL $0, 16(SP) // overlapped
+ CALL *runtime·WriteFile(SB)
+ MOVL BP, SI
+ RET
+
+TEXT runtime·badsignal(SB),7,$24
+ // stderr
+ MOVL $-12, 0(SP)
+ MOVL SP, BP
+ CALL *runtime·GetStdHandle(SB)
+ MOVL BP, SP
+
+ MOVL AX, 0(SP) // handle
+ MOVL $runtime·badsignalmsg(SB), DX // pointer
+ MOVL DX, 4(SP)
+ MOVL runtime·badsignallen(SB), DX // count
+ MOVL DX, 8(SP)
+ LEAL 20(SP), DX // written count
+ MOVL $0, 0(DX)
+ MOVL DX, 12(SP)
+ MOVL $0, 16(SP) // overlapped
+ CALL *runtime·WriteFile(SB)
+ MOVL BP, SI
+ RET
+
// faster get/set last error
TEXT runtime·getlasterror(SB),7,$0
MOVL 0x34(FS), AX
@@ -59,7 +99,15 @@ TEXT runtime·sigtramp(SB),7,$28
MOVL CX, 0(SP)
MOVL context+8(FP), CX
MOVL CX, 4(SP)
+
get_tls(CX)
+
+ // check that m exists
+ MOVL m(CX), AX
+ CMPL AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
MOVL g(CX), CX
MOVL CX, 8(SP)
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
index 76b5ee5fb..11909cda2 100644
--- a/src/pkg/runtime/sys_windows_amd64.s
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -60,6 +60,55 @@ loadregs:
RET
+// This should be called on a system stack,
+// so we don't need to concern about split stack.
+TEXT runtime·badcallback(SB),7,$0
+ SUBQ $48, SP
+
+ // stderr
+ MOVQ $-12, CX // stderr
+ MOVQ CX, 0(SP)
+ MOVQ runtime·GetStdHandle(SB), AX
+ CALL AX
+
+ MOVQ AX, CX // handle
+ MOVQ CX, 0(SP)
+ MOVQ $runtime·badcallbackmsg(SB), DX // pointer
+ MOVQ DX, 8(SP)
+ MOVL $runtime·badcallbacklen(SB), R8 // count
+ MOVQ R8, 16(SP)
+ LEAQ 40(SP), R9 // written count
+ MOVQ $0, 0(R9)
+ MOVQ R9, 24(SP)
+ MOVQ $0, 32(SP) // overlapped
+ MOVQ runtime·WriteFile(SB), AX
+ CALL AX
+
+ ADDQ $48, SP
+ RET
+
+TEXT runtime·badsignal(SB),7,$48
+ // stderr
+ MOVQ $-12, CX // stderr
+ MOVQ CX, 0(SP)
+ MOVQ runtime·GetStdHandle(SB), AX
+ CALL AX
+
+ MOVQ AX, CX // handle
+ MOVQ CX, 0(SP)
+ MOVQ $runtime·badsignalmsg(SB), DX // pointer
+ MOVQ DX, 8(SP)
+ MOVL $runtime·badsignallen(SB), R8 // count
+ MOVQ R8, 16(SP)
+ LEAQ 40(SP), R9 // written count
+ MOVQ $0, 0(R9)
+ MOVQ R9, 24(SP)
+ MOVQ $0, 32(SP) // overlapped
+ MOVQ runtime·WriteFile(SB), AX
+ CALL AX
+
+ RET
+
// faster get/set last error
TEXT runtime·getlasterror(SB),7,$0
MOVQ 0x30(GS), AX
@@ -72,7 +121,7 @@ TEXT runtime·setlasterror(SB),7,$0
MOVL AX, 0x68(CX)
RET
-TEXT runtime·sigtramp(SB),7,$56
+TEXT runtime·sigtramp(SB),7,$0
// CX: exception record
// R8: context
@@ -81,10 +130,23 @@ TEXT runtime·sigtramp(SB),7,$56
MOVL $1, AX
JNZ sigdone
- // copy arguments for call to sighandler
+ // copy arguments for call to sighandler.
+
+ // Stack adjustment is here to hide from 6l,
+ // which doesn't understand that sigtramp
+ // runs on essentially unlimited stack.
+ SUBQ $56, SP
MOVQ CX, 0(SP)
MOVQ R8, 8(SP)
+
get_tls(CX)
+
+ // check that m exists
+ MOVQ m(CX), AX
+ CMPQ AX, $0
+ JNE 2(PC)
+ CALL runtime·badsignal(SB)
+
MOVQ g(CX), CX
MOVQ CX, 16(SP)
@@ -99,6 +161,8 @@ TEXT runtime·sigtramp(SB),7,$56
MOVQ 32(SP), BP
MOVQ 40(SP), SI
MOVQ 48(SP), DI
+ ADDQ $56, SP
+
sigdone:
RET
@@ -207,15 +271,18 @@ TEXT runtime·callbackasm(SB),7,$0
MOVQ R14, 8(SP)
MOVQ R15, 0(SP)
+ // prepare call stack. use SUBQ to hide from stack frame checks
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
- PUSHQ DX // uintptr framesize
- PUSHQ CX // void *frame
- PUSHQ AX // void (*fn)(void*)
+ SUBQ $24, SP
+ MOVQ DX, 16(SP) // uintptr framesize
+ MOVQ CX, 8(SP) // void *frame
+ MOVQ AX, 0(SP) // void (*fn)(void*)
CLD
CALL runtime·cgocallback(SB)
- POPQ AX
- POPQ CX
- POPQ DX
+ MOVQ 0(SP), AX
+ MOVQ 8(SP), CX
+ MOVQ 16(SP), DX
+ ADDQ $24, SP
// restore registers as required for windows callback
// 6l does not allow writing many POPs here issuing a warning "nosplit stack overflow"
@@ -268,11 +335,6 @@ TEXT runtime·tstart_stdcall(SB),7,$0
XORL AX, AX // return 0 == success
RET
-TEXT runtime·notok(SB),7,$0
- MOVQ $0xf1, BP
- MOVQ BP, (BP)
- RET
-
// set tls base to DI
TEXT runtime·settls(SB),7,$0
CALL runtime·setstacklimits(SB)
diff --git a/src/pkg/runtime/thread_darwin.c b/src/pkg/runtime/thread_darwin.c
index 556fb67e8..6a83e48a3 100644
--- a/src/pkg/runtime/thread_darwin.c
+++ b/src/pkg/runtime/thread_darwin.c
@@ -477,3 +477,23 @@ runtime·setprof(bool on)
else
runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_freebsd.c b/src/pkg/runtime/thread_freebsd.c
index 77e8bb3da..4c546178f 100644
--- a/src/pkg/runtime/thread_freebsd.c
+++ b/src/pkg/runtime/thread_freebsd.c
@@ -195,3 +195,23 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_linux.c b/src/pkg/runtime/thread_linux.c
index 6b428440e..858be7036 100644
--- a/src/pkg/runtime/thread_linux.c
+++ b/src/pkg/runtime/thread_linux.c
@@ -255,3 +255,23 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/thread_netbsd.c
index 62e133c44..1b2df85cd 100644
--- a/src/pkg/runtime/thread_netbsd.c
+++ b/src/pkg/runtime/thread_netbsd.c
@@ -213,3 +213,23 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_openbsd.c b/src/pkg/runtime/thread_openbsd.c
index bee0c5755..d0f947210 100644
--- a/src/pkg/runtime/thread_openbsd.c
+++ b/src/pkg/runtime/thread_openbsd.c
@@ -213,3 +213,23 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·write(2, badcallback, sizeof badcallback - 1);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·write(2, badsignal, sizeof badsignal - 1);
+}
diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/thread_plan9.c
index aaed5050b..3b0dca69f 100644
--- a/src/pkg/runtime/thread_plan9.c
+++ b/src/pkg/runtime/thread_plan9.c
@@ -247,3 +247,23 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+static int8 badcallback[] = "runtime: cgo callback on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badcallback(void)
+{
+ runtime·pwrite(2, badcallback, sizeof badcallback - 1, -1LL);
+}
+
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(void)
+{
+ runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
+}
diff --git a/src/pkg/runtime/thread_windows.c b/src/pkg/runtime/thread_windows.c
index 8a448bc37..f684d3733 100644
--- a/src/pkg/runtime/thread_windows.c
+++ b/src/pkg/runtime/thread_windows.c
@@ -302,21 +302,6 @@ runtime·initsig(void)
USED(p);
}
-String
-runtime·signame(int32 sig)
-{
- int8 *s;
-
- switch(sig) {
- case SIGINT:
- s = "SIGINT: interrupt";
- break;
- default:
- return runtime·emptystring;
- }
- return runtime·gostringnocopy((byte*)s);
-}
-
uint32
runtime·ctrlhandler1(uint32 type)
{
@@ -437,3 +422,9 @@ runtime·setprof(bool on)
{
USED(on);
}
+
+int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n";
+int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1;
+
+int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
+int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index 31da3c83d..62a4d55e7 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -183,17 +183,21 @@ func quickSort(data Interface, a, b, maxDepth int) {
}
}
+// Sort sorts data.
+// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
+// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
- // Switch to heapsort if depth of 2*ceil(lg(n)) is reached.
+ // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
n := data.Len()
maxDepth := 0
- for 1<<uint(maxDepth) < n {
+ for i := n; i > 0; i >>= 1 {
maxDepth++
}
maxDepth *= 2
quickSort(data, 0, n, maxDepth)
}
+// IsSorted reports whether data is sorted.
func IsSorted(data Interface) bool {
n := data.Len()
for i := n - 1; i > 0; i-- {
diff --git a/src/pkg/strconv/isprint.go b/src/pkg/strconv/isprint.go
new file mode 100644
index 000000000..a03a07bfb
--- /dev/null
+++ b/src/pkg/strconv/isprint.go
@@ -0,0 +1,521 @@
+// DO NOT EDIT. GENERATED BY
+// go run makeisprint.go >x && mv x isprint.go
+
+package strconv
+
+// (474+134+42)*2 + (180)*4 = 2020 bytes
+
+var isPrint16 = []uint16{
+ 0x0020, 0x007e,
+ 0x00a1, 0x0377,
+ 0x037a, 0x037e,
+ 0x0384, 0x0527,
+ 0x0531, 0x0556,
+ 0x0559, 0x058a,
+ 0x0591, 0x05c7,
+ 0x05d0, 0x05ea,
+ 0x05f0, 0x05f4,
+ 0x0606, 0x061b,
+ 0x061e, 0x070d,
+ 0x0710, 0x074a,
+ 0x074d, 0x07b1,
+ 0x07c0, 0x07fa,
+ 0x0800, 0x082d,
+ 0x0830, 0x085b,
+ 0x085e, 0x085e,
+ 0x0900, 0x098c,
+ 0x098f, 0x0990,
+ 0x0993, 0x09b2,
+ 0x09b6, 0x09b9,
+ 0x09bc, 0x09c4,
+ 0x09c7, 0x09c8,
+ 0x09cb, 0x09ce,
+ 0x09d7, 0x09d7,
+ 0x09dc, 0x09e3,
+ 0x09e6, 0x09fb,
+ 0x0a01, 0x0a0a,
+ 0x0a0f, 0x0a10,
+ 0x0a13, 0x0a39,
+ 0x0a3c, 0x0a42,
+ 0x0a47, 0x0a48,
+ 0x0a4b, 0x0a4d,
+ 0x0a51, 0x0a51,
+ 0x0a59, 0x0a5e,
+ 0x0a66, 0x0a75,
+ 0x0a81, 0x0ab9,
+ 0x0abc, 0x0acd,
+ 0x0ad0, 0x0ad0,
+ 0x0ae0, 0x0ae3,
+ 0x0ae6, 0x0af1,
+ 0x0b01, 0x0b0c,
+ 0x0b0f, 0x0b10,
+ 0x0b13, 0x0b39,
+ 0x0b3c, 0x0b44,
+ 0x0b47, 0x0b48,
+ 0x0b4b, 0x0b4d,
+ 0x0b56, 0x0b57,
+ 0x0b5c, 0x0b63,
+ 0x0b66, 0x0b77,
+ 0x0b82, 0x0b8a,
+ 0x0b8e, 0x0b95,
+ 0x0b99, 0x0b9f,
+ 0x0ba3, 0x0ba4,
+ 0x0ba8, 0x0baa,
+ 0x0bae, 0x0bb9,
+ 0x0bbe, 0x0bc2,
+ 0x0bc6, 0x0bcd,
+ 0x0bd0, 0x0bd0,
+ 0x0bd7, 0x0bd7,
+ 0x0be6, 0x0bfa,
+ 0x0c01, 0x0c39,
+ 0x0c3d, 0x0c4d,
+ 0x0c55, 0x0c59,
+ 0x0c60, 0x0c63,
+ 0x0c66, 0x0c6f,
+ 0x0c78, 0x0c7f,
+ 0x0c82, 0x0cb9,
+ 0x0cbc, 0x0ccd,
+ 0x0cd5, 0x0cd6,
+ 0x0cde, 0x0ce3,
+ 0x0ce6, 0x0cf2,
+ 0x0d02, 0x0d3a,
+ 0x0d3d, 0x0d4e,
+ 0x0d57, 0x0d57,
+ 0x0d60, 0x0d63,
+ 0x0d66, 0x0d75,
+ 0x0d79, 0x0d7f,
+ 0x0d82, 0x0d96,
+ 0x0d9a, 0x0dbd,
+ 0x0dc0, 0x0dc6,
+ 0x0dca, 0x0dca,
+ 0x0dcf, 0x0ddf,
+ 0x0df2, 0x0df4,
+ 0x0e01, 0x0e3a,
+ 0x0e3f, 0x0e5b,
+ 0x0e81, 0x0e84,
+ 0x0e87, 0x0e8a,
+ 0x0e8d, 0x0e8d,
+ 0x0e94, 0x0ea7,
+ 0x0eaa, 0x0ebd,
+ 0x0ec0, 0x0ecd,
+ 0x0ed0, 0x0ed9,
+ 0x0edc, 0x0edd,
+ 0x0f00, 0x0f6c,
+ 0x0f71, 0x0fda,
+ 0x1000, 0x10c5,
+ 0x10d0, 0x10fc,
+ 0x1100, 0x124d,
+ 0x1250, 0x125d,
+ 0x1260, 0x128d,
+ 0x1290, 0x12b5,
+ 0x12b8, 0x12c5,
+ 0x12c8, 0x1315,
+ 0x1318, 0x135a,
+ 0x135d, 0x137c,
+ 0x1380, 0x1399,
+ 0x13a0, 0x13f4,
+ 0x1400, 0x169c,
+ 0x16a0, 0x16f0,
+ 0x1700, 0x1714,
+ 0x1720, 0x1736,
+ 0x1740, 0x1753,
+ 0x1760, 0x1773,
+ 0x1780, 0x17b3,
+ 0x17b6, 0x17dd,
+ 0x17e0, 0x17e9,
+ 0x17f0, 0x17f9,
+ 0x1800, 0x180d,
+ 0x1810, 0x1819,
+ 0x1820, 0x1877,
+ 0x1880, 0x18aa,
+ 0x18b0, 0x18f5,
+ 0x1900, 0x191c,
+ 0x1920, 0x192b,
+ 0x1930, 0x193b,
+ 0x1940, 0x1940,
+ 0x1944, 0x196d,
+ 0x1970, 0x1974,
+ 0x1980, 0x19ab,
+ 0x19b0, 0x19c9,
+ 0x19d0, 0x19da,
+ 0x19de, 0x1a1b,
+ 0x1a1e, 0x1a7c,
+ 0x1a7f, 0x1a89,
+ 0x1a90, 0x1a99,
+ 0x1aa0, 0x1aad,
+ 0x1b00, 0x1b4b,
+ 0x1b50, 0x1b7c,
+ 0x1b80, 0x1baa,
+ 0x1bae, 0x1bb9,
+ 0x1bc0, 0x1bf3,
+ 0x1bfc, 0x1c37,
+ 0x1c3b, 0x1c49,
+ 0x1c4d, 0x1c7f,
+ 0x1cd0, 0x1cf2,
+ 0x1d00, 0x1de6,
+ 0x1dfc, 0x1f15,
+ 0x1f18, 0x1f1d,
+ 0x1f20, 0x1f45,
+ 0x1f48, 0x1f4d,
+ 0x1f50, 0x1f7d,
+ 0x1f80, 0x1fd3,
+ 0x1fd6, 0x1fef,
+ 0x1ff2, 0x1ffe,
+ 0x2010, 0x2027,
+ 0x2030, 0x205e,
+ 0x2070, 0x2071,
+ 0x2074, 0x209c,
+ 0x20a0, 0x20b9,
+ 0x20d0, 0x20f0,
+ 0x2100, 0x2189,
+ 0x2190, 0x23f3,
+ 0x2400, 0x2426,
+ 0x2440, 0x244a,
+ 0x2460, 0x2b4c,
+ 0x2b50, 0x2b59,
+ 0x2c00, 0x2cf1,
+ 0x2cf9, 0x2d25,
+ 0x2d30, 0x2d65,
+ 0x2d6f, 0x2d70,
+ 0x2d7f, 0x2d96,
+ 0x2da0, 0x2e31,
+ 0x2e80, 0x2ef3,
+ 0x2f00, 0x2fd5,
+ 0x2ff0, 0x2ffb,
+ 0x3001, 0x3096,
+ 0x3099, 0x30ff,
+ 0x3105, 0x312d,
+ 0x3131, 0x31ba,
+ 0x31c0, 0x31e3,
+ 0x31f0, 0x4db5,
+ 0x4dc0, 0x9fcb,
+ 0xa000, 0xa48c,
+ 0xa490, 0xa4c6,
+ 0xa4d0, 0xa62b,
+ 0xa640, 0xa673,
+ 0xa67c, 0xa697,
+ 0xa6a0, 0xa6f7,
+ 0xa700, 0xa791,
+ 0xa7a0, 0xa7a9,
+ 0xa7fa, 0xa82b,
+ 0xa830, 0xa839,
+ 0xa840, 0xa877,
+ 0xa880, 0xa8c4,
+ 0xa8ce, 0xa8d9,
+ 0xa8e0, 0xa8fb,
+ 0xa900, 0xa953,
+ 0xa95f, 0xa97c,
+ 0xa980, 0xa9d9,
+ 0xa9de, 0xa9df,
+ 0xaa00, 0xaa36,
+ 0xaa40, 0xaa4d,
+ 0xaa50, 0xaa59,
+ 0xaa5c, 0xaa7b,
+ 0xaa80, 0xaac2,
+ 0xaadb, 0xaadf,
+ 0xab01, 0xab06,
+ 0xab09, 0xab0e,
+ 0xab11, 0xab16,
+ 0xab20, 0xab2e,
+ 0xabc0, 0xabed,
+ 0xabf0, 0xabf9,
+ 0xac00, 0xd7a3,
+ 0xd7b0, 0xd7c6,
+ 0xd7cb, 0xd7fb,
+ 0xf900, 0xfa2d,
+ 0xfa30, 0xfa6d,
+ 0xfa70, 0xfad9,
+ 0xfb00, 0xfb06,
+ 0xfb13, 0xfb17,
+ 0xfb1d, 0xfbc1,
+ 0xfbd3, 0xfd3f,
+ 0xfd50, 0xfd8f,
+ 0xfd92, 0xfdc7,
+ 0xfdf0, 0xfdfd,
+ 0xfe00, 0xfe19,
+ 0xfe20, 0xfe26,
+ 0xfe30, 0xfe6b,
+ 0xfe70, 0xfefc,
+ 0xff01, 0xffbe,
+ 0xffc2, 0xffc7,
+ 0xffca, 0xffcf,
+ 0xffd2, 0xffd7,
+ 0xffda, 0xffdc,
+ 0xffe0, 0xffee,
+ 0xfffc, 0xfffd,
+}
+
+var isNotPrint16 = []uint16{
+ 0x00ad,
+ 0x038b,
+ 0x038d,
+ 0x03a2,
+ 0x0560,
+ 0x0588,
+ 0x06dd,
+ 0x083f,
+ 0x0978,
+ 0x0980,
+ 0x0984,
+ 0x09a9,
+ 0x09b1,
+ 0x09de,
+ 0x0a04,
+ 0x0a29,
+ 0x0a31,
+ 0x0a34,
+ 0x0a37,
+ 0x0a3d,
+ 0x0a5d,
+ 0x0a84,
+ 0x0a8e,
+ 0x0a92,
+ 0x0aa9,
+ 0x0ab1,
+ 0x0ab4,
+ 0x0ac6,
+ 0x0aca,
+ 0x0af0,
+ 0x0b04,
+ 0x0b29,
+ 0x0b31,
+ 0x0b34,
+ 0x0b5e,
+ 0x0b84,
+ 0x0b91,
+ 0x0b9b,
+ 0x0b9d,
+ 0x0bc9,
+ 0x0c04,
+ 0x0c0d,
+ 0x0c11,
+ 0x0c29,
+ 0x0c34,
+ 0x0c45,
+ 0x0c49,
+ 0x0c57,
+ 0x0c84,
+ 0x0c8d,
+ 0x0c91,
+ 0x0ca9,
+ 0x0cb4,
+ 0x0cc5,
+ 0x0cc9,
+ 0x0cdf,
+ 0x0cf0,
+ 0x0d04,
+ 0x0d0d,
+ 0x0d11,
+ 0x0d45,
+ 0x0d49,
+ 0x0d84,
+ 0x0db2,
+ 0x0dbc,
+ 0x0dd5,
+ 0x0dd7,
+ 0x0e83,
+ 0x0e89,
+ 0x0e98,
+ 0x0ea0,
+ 0x0ea4,
+ 0x0ea6,
+ 0x0eac,
+ 0x0eba,
+ 0x0ec5,
+ 0x0ec7,
+ 0x0f48,
+ 0x0f98,
+ 0x0fbd,
+ 0x0fcd,
+ 0x1249,
+ 0x1257,
+ 0x1259,
+ 0x1289,
+ 0x12b1,
+ 0x12bf,
+ 0x12c1,
+ 0x12d7,
+ 0x1311,
+ 0x1680,
+ 0x170d,
+ 0x176d,
+ 0x1771,
+ 0x1a5f,
+ 0x1f58,
+ 0x1f5a,
+ 0x1f5c,
+ 0x1f5e,
+ 0x1fb5,
+ 0x1fc5,
+ 0x1fdc,
+ 0x1ff5,
+ 0x208f,
+ 0x2700,
+ 0x27cb,
+ 0x27cd,
+ 0x2c2f,
+ 0x2c5f,
+ 0x2da7,
+ 0x2daf,
+ 0x2db7,
+ 0x2dbf,
+ 0x2dc7,
+ 0x2dcf,
+ 0x2dd7,
+ 0x2ddf,
+ 0x2e9a,
+ 0x3040,
+ 0x318f,
+ 0x321f,
+ 0x32ff,
+ 0xa78f,
+ 0xa9ce,
+ 0xab27,
+ 0xfb37,
+ 0xfb3d,
+ 0xfb3f,
+ 0xfb42,
+ 0xfb45,
+ 0xfe53,
+ 0xfe67,
+ 0xfe75,
+ 0xffe7,
+}
+
+var isPrint32 = []uint32{
+ 0x010000, 0x01004d,
+ 0x010050, 0x01005d,
+ 0x010080, 0x0100fa,
+ 0x010100, 0x010102,
+ 0x010107, 0x010133,
+ 0x010137, 0x01018a,
+ 0x010190, 0x01019b,
+ 0x0101d0, 0x0101fd,
+ 0x010280, 0x01029c,
+ 0x0102a0, 0x0102d0,
+ 0x010300, 0x010323,
+ 0x010330, 0x01034a,
+ 0x010380, 0x0103c3,
+ 0x0103c8, 0x0103d5,
+ 0x010400, 0x01049d,
+ 0x0104a0, 0x0104a9,
+ 0x010800, 0x010805,
+ 0x010808, 0x010838,
+ 0x01083c, 0x01083c,
+ 0x01083f, 0x01085f,
+ 0x010900, 0x01091b,
+ 0x01091f, 0x010939,
+ 0x01093f, 0x01093f,
+ 0x010a00, 0x010a06,
+ 0x010a0c, 0x010a33,
+ 0x010a38, 0x010a3a,
+ 0x010a3f, 0x010a47,
+ 0x010a50, 0x010a58,
+ 0x010a60, 0x010a7f,
+ 0x010b00, 0x010b35,
+ 0x010b39, 0x010b55,
+ 0x010b58, 0x010b72,
+ 0x010b78, 0x010b7f,
+ 0x010c00, 0x010c48,
+ 0x010e60, 0x010e7e,
+ 0x011000, 0x01104d,
+ 0x011052, 0x01106f,
+ 0x011080, 0x0110c1,
+ 0x012000, 0x01236e,
+ 0x012400, 0x012462,
+ 0x012470, 0x012473,
+ 0x013000, 0x01342e,
+ 0x016800, 0x016a38,
+ 0x01b000, 0x01b001,
+ 0x01d000, 0x01d0f5,
+ 0x01d100, 0x01d126,
+ 0x01d129, 0x01d172,
+ 0x01d17b, 0x01d1dd,
+ 0x01d200, 0x01d245,
+ 0x01d300, 0x01d356,
+ 0x01d360, 0x01d371,
+ 0x01d400, 0x01d49f,
+ 0x01d4a2, 0x01d4a2,
+ 0x01d4a5, 0x01d4a6,
+ 0x01d4a9, 0x01d50a,
+ 0x01d50d, 0x01d546,
+ 0x01d54a, 0x01d6a5,
+ 0x01d6a8, 0x01d7cb,
+ 0x01d7ce, 0x01d7ff,
+ 0x01f000, 0x01f02b,
+ 0x01f030, 0x01f093,
+ 0x01f0a0, 0x01f0ae,
+ 0x01f0b1, 0x01f0be,
+ 0x01f0c1, 0x01f0df,
+ 0x01f100, 0x01f10a,
+ 0x01f110, 0x01f169,
+ 0x01f170, 0x01f19a,
+ 0x01f1e6, 0x01f202,
+ 0x01f210, 0x01f23a,
+ 0x01f240, 0x01f248,
+ 0x01f250, 0x01f251,
+ 0x01f300, 0x01f320,
+ 0x01f330, 0x01f37c,
+ 0x01f380, 0x01f393,
+ 0x01f3a0, 0x01f3ca,
+ 0x01f3e0, 0x01f3f0,
+ 0x01f400, 0x01f4fc,
+ 0x01f500, 0x01f53d,
+ 0x01f550, 0x01f567,
+ 0x01f5fb, 0x01f625,
+ 0x01f628, 0x01f62d,
+ 0x01f630, 0x01f640,
+ 0x01f645, 0x01f64f,
+ 0x01f680, 0x01f6c5,
+ 0x01f700, 0x01f773,
+ 0x020000, 0x02a6d6,
+ 0x02a700, 0x02b734,
+ 0x02b740, 0x02b81d,
+ 0x02f800, 0x02fa1d,
+ 0x0e0100, 0x0e01ef,
+}
+
+var isNotPrint32 = []uint16{ // add 0x10000 to each entry
+ 0x000c,
+ 0x0027,
+ 0x003b,
+ 0x003e,
+ 0x031f,
+ 0x039e,
+ 0x0809,
+ 0x0836,
+ 0x0856,
+ 0x0a04,
+ 0x0a14,
+ 0x0a18,
+ 0x10bd,
+ 0xd455,
+ 0xd49d,
+ 0xd4ad,
+ 0xd4ba,
+ 0xd4bc,
+ 0xd4c4,
+ 0xd506,
+ 0xd515,
+ 0xd51d,
+ 0xd53a,
+ 0xd53f,
+ 0xd545,
+ 0xd551,
+ 0xf0d0,
+ 0xf12f,
+ 0xf336,
+ 0xf3c5,
+ 0xf43f,
+ 0xf441,
+ 0xf4f8,
+ 0xf600,
+ 0xf611,
+ 0xf615,
+ 0xf617,
+ 0xf619,
+ 0xf61b,
+ 0xf61f,
+ 0xf62c,
+ 0xf634,
+}
diff --git a/src/pkg/strconv/makeisprint.go b/src/pkg/strconv/makeisprint.go
new file mode 100644
index 000000000..8a6699bdb
--- /dev/null
+++ b/src/pkg/strconv/makeisprint.go
@@ -0,0 +1,162 @@
+// 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.
+
+// +build ignore
+
+// makeisprint generates the tables for strconv's compact isPrint.
+package main
+
+import (
+ "fmt"
+ "os"
+ "unicode"
+)
+
+var (
+ range16 []uint16
+ except16 []uint16
+ range32 []uint32
+ except32 []uint32
+)
+
+// bsearch16 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch16 returns len(a).
+func bsearch16(a []uint16, x uint16) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+// bsearch32 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch32 returns len(a).
+func bsearch32(a []uint32, x uint32) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+func isPrint(r rune) bool {
+ // Same algorithm, either on uint16 or uint32 value.
+ // First, find first i such that rang[i] >= x.
+ // This is the index of either the start or end of a pair that might span x.
+ // The start is even (rang[i&^1]) and the end is odd (rang[i|1]).
+ // If we find x in a range, make sure x is not in exception list.
+
+ if 0 <= r && r < 1<<16 {
+ rr, rang, except := uint16(r), range16, except16
+ i := bsearch16(rang, rr)
+ if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
+ return false
+ }
+ j := bsearch16(except, rr)
+ return j >= len(except) || except[j] != rr
+ }
+
+ rr, rang, except := uint32(r), range32, except32
+ i := bsearch32(rang, rr)
+ if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr {
+ return false
+ }
+ j := bsearch32(except, rr)
+ return j >= len(except) || except[j] != rr
+}
+
+func scan(min, max rune) (rang, except []uint32) {
+ lo := rune(-1)
+ for i := min; ; i++ {
+ if (i > max || !unicode.IsPrint(i)) && lo >= 0 {
+ // End range, but avoid flip flop.
+ if i+1 <= max && unicode.IsPrint(i+1) {
+ except = append(except, uint32(i))
+ continue
+ }
+ rang = append(rang, uint32(lo), uint32(i-1))
+ lo = -1
+ }
+ if i > max {
+ break
+ }
+ if lo < 0 && unicode.IsPrint(i) {
+ lo = i
+ }
+ }
+ return
+}
+
+func to16(x []uint32) []uint16 {
+ var y []uint16
+ for _, v := range x {
+ if uint32(uint16(v)) != v {
+ panic("bad 32->16 conversion")
+ }
+ y = append(y, uint16(v))
+ }
+ return y
+}
+
+func main() {
+ rang, except := scan(0, 0xFFFF)
+ range16 = to16(rang)
+ except16 = to16(except)
+ range32, except32 = scan(0x10000, unicode.MaxRune)
+
+ for i := rune(0); i <= unicode.MaxRune; i++ {
+ if isPrint(i) != unicode.IsPrint(i) {
+ fmt.Fprintf(os.Stderr, "%U: isPrint=%v, want %v\n", i, isPrint(i), unicode.IsPrint(i))
+ return
+ }
+ }
+
+ fmt.Printf("// DO NOT EDIT. GENERATED BY\n")
+ fmt.Printf("// go run makeisprint.go >x && mv x isprint.go\n\n")
+ fmt.Printf("package strconv\n\n")
+
+ fmt.Printf("// (%d+%d+%d)*2 + (%d)*4 = %d bytes\n\n",
+ len(range16), len(except16), len(except32),
+ len(range32),
+ (len(range16)+len(except16)+len(except32))*2+
+ (len(range32))*4)
+
+ fmt.Printf("var isPrint16 = []uint16{\n")
+ for i := 0; i < len(range16); i += 2 {
+ fmt.Printf("\t%#04x, %#04x,\n", range16[i], range16[i+1])
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isNotPrint16 = []uint16{\n")
+ for _, r := range except16 {
+ fmt.Printf("\t%#04x,\n", r)
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isPrint32 = []uint32{\n")
+ for i := 0; i < len(range32); i += 2 {
+ fmt.Printf("\t%#06x, %#06x,\n", range32[i], range32[i+1])
+ }
+ fmt.Printf("}\n\n")
+
+ fmt.Printf("var isNotPrint32 = []uint16{ // add 0x10000 to each entry\n")
+ for _, r := range except32 {
+ if r >= 0x20000 {
+ fmt.Fprintf(os.Stderr, "%U too big for isNotPrint32\n", r)
+ return
+ }
+ fmt.Printf("\t%#04x,\n", r-0x10000)
+ }
+ fmt.Printf("}\n")
+}
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 61dbcae70..8a73f9d3b 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -5,17 +5,15 @@
package strconv
import (
- "bytes"
- "strings"
- "unicode"
"unicode/utf8"
)
const lowerhex = "0123456789abcdef"
func quoteWith(s string, quote byte, ASCIIonly bool) string {
- var buf bytes.Buffer
- buf.WriteByte(quote)
+ var runeTmp [utf8.UTFMax]byte
+ buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+ buf = append(buf, quote)
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
@@ -23,71 +21,72 @@ func quoteWith(s string, quote byte, ASCIIonly bool) string {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
- buf.WriteString(`\x`)
- buf.WriteByte(lowerhex[s[0]>>4])
- buf.WriteByte(lowerhex[s[0]&0xF])
+ buf = append(buf, `\x`...)
+ buf = append(buf, lowerhex[s[0]>>4])
+ buf = append(buf, lowerhex[s[0]&0xF])
continue
}
if r == rune(quote) || r == '\\' { // always backslashed
- buf.WriteByte('\\')
- buf.WriteByte(byte(r))
+ buf = append(buf, '\\')
+ buf = append(buf, byte(r))
continue
}
if ASCIIonly {
- if r <= unicode.MaxASCII && unicode.IsPrint(r) {
- buf.WriteRune(r)
+ if r < utf8.RuneSelf && IsPrint(r) {
+ buf = append(buf, byte(r))
continue
}
- } else if unicode.IsPrint(r) {
- buf.WriteRune(r)
+ } else if IsPrint(r) {
+ n := utf8.EncodeRune(runeTmp[:], r)
+ buf = append(buf, runeTmp[:n]...)
continue
}
switch r {
case '\a':
- buf.WriteString(`\a`)
+ buf = append(buf, `\a`...)
case '\b':
- buf.WriteString(`\b`)
+ buf = append(buf, `\b`...)
case '\f':
- buf.WriteString(`\f`)
+ buf = append(buf, `\f`...)
case '\n':
- buf.WriteString(`\n`)
+ buf = append(buf, `\n`...)
case '\r':
- buf.WriteString(`\r`)
+ buf = append(buf, `\r`...)
case '\t':
- buf.WriteString(`\t`)
+ buf = append(buf, `\t`...)
case '\v':
- buf.WriteString(`\v`)
+ buf = append(buf, `\v`...)
default:
switch {
case r < ' ':
- buf.WriteString(`\x`)
- buf.WriteByte(lowerhex[s[0]>>4])
- buf.WriteByte(lowerhex[s[0]&0xF])
- case r > unicode.MaxRune:
+ buf = append(buf, `\x`...)
+ buf = append(buf, lowerhex[s[0]>>4])
+ buf = append(buf, lowerhex[s[0]&0xF])
+ case r > utf8.MaxRune:
r = 0xFFFD
fallthrough
case r < 0x10000:
- buf.WriteString(`\u`)
+ buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
- buf.WriteByte(lowerhex[r>>uint(s)&0xF])
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
- buf.WriteString(`\U`)
+ buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
- buf.WriteByte(lowerhex[r>>uint(s)&0xF])
+ buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
}
- buf.WriteByte(quote)
- return buf.String()
+ buf = append(buf, quote)
+ return string(buf)
}
// Quote returns a double-quoted Go string literal representing s. The
// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
// control characters and non-printable characters as defined by
-// unicode.IsPrint.
+// IsPrint.
func Quote(s string) string {
return quoteWith(s, '"', false)
}
@@ -100,8 +99,7 @@ func AppendQuote(dst []byte, s string) []byte {
// QuoteToASCII returns a double-quoted Go string literal representing s.
// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
-// non-ASCII characters and non-printable characters as defined by
-// unicode.IsPrint.
+// non-ASCII characters and non-printable characters as defined by IsPrint.
func QuoteToASCII(s string) string {
return quoteWith(s, '"', true)
}
@@ -114,8 +112,7 @@ func AppendQuoteToASCII(dst []byte, s string) []byte {
// QuoteRune returns a single-quoted Go character literal representing the
// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
-// for control characters and non-printable characters as defined by
-// unicode.IsPrint.
+// for control characters and non-printable characters as defined by IsPrint.
func QuoteRune(r rune) string {
// TODO: avoid the allocation here.
return quoteWith(string(r), '\'', false)
@@ -130,7 +127,7 @@ func AppendQuoteRune(dst []byte, r rune) []byte {
// QuoteRuneToASCII returns a single-quoted Go character literal representing
// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
// \u0100) for non-ASCII characters and non-printable characters as defined
-// by unicode.IsPrint.
+// by IsPrint.
func QuoteRuneToASCII(r rune) string {
// TODO: avoid the allocation here.
return quoteWith(string(r), '\'', true)
@@ -245,7 +242,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
value = v
break
}
- if v > unicode.MaxRune {
+ if v > utf8.MaxRune {
err = ErrSyntax
return
}
@@ -304,7 +301,7 @@ func Unquote(s string) (t string, err error) {
s = s[1 : n-1]
if quote == '`' {
- if strings.Contains(s, "`") {
+ if contains(s, '`') {
return "", ErrSyntax
}
return s, nil
@@ -312,12 +309,12 @@ func Unquote(s string) (t string, err error) {
if quote != '"' && quote != '\'' {
return "", ErrSyntax
}
- if strings.Index(s, "\n") >= 0 {
+ if contains(s, '\n') {
return "", ErrSyntax
}
// Is it trivial? Avoid allocation.
- if strings.Index(s, `\`) < 0 && strings.IndexRune(s, rune(quote)) < 0 {
+ if !contains(s, '\\') && !contains(s, quote) {
switch quote {
case '"':
return s, nil
@@ -329,7 +326,8 @@ func Unquote(s string) (t string, err error) {
}
}
- var buf bytes.Buffer
+ var runeTmp [utf8.UTFMax]byte
+ buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
for len(s) > 0 {
c, multibyte, ss, err := UnquoteChar(s, quote)
if err != nil {
@@ -337,14 +335,107 @@ func Unquote(s string) (t string, err error) {
}
s = ss
if c < utf8.RuneSelf || !multibyte {
- buf.WriteByte(byte(c))
+ buf = append(buf, byte(c))
} else {
- buf.WriteString(string(c))
+ n := utf8.EncodeRune(runeTmp[:], c)
+ buf = append(buf, runeTmp[:n]...)
}
if quote == '\'' && len(s) != 0 {
// single-quoted must be single character
return "", ErrSyntax
}
}
- return buf.String(), nil
+ return string(buf), nil
+}
+
+// contains reports whether the string contains the byte c.
+func contains(s string, c byte) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] == c {
+ return true
+ }
+ }
+ return false
+}
+
+// bsearch16 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch16 returns len(a).
+func bsearch16(a []uint16, x uint16) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+// bsearch32 returns the smallest i such that a[i] >= x.
+// If there is no such i, bsearch32 returns len(a).
+func bsearch32(a []uint32, x uint32) int {
+ i, j := 0, len(a)
+ for i < j {
+ h := i + (j-i)/2
+ if a[h] < x {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ return i
+}
+
+// TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests
+// to give the same answer. It allows this package not to depend on unicode,
+// and therefore not pull in all the Unicode tables. If the linker were better
+// at tossing unused tables, we could get rid of this implementation.
+// That would be nice.
+
+// IsPrint reports whether the rune is defined as printable by Go, with
+// the same definition as unicode.IsPrint: letters, numbers, punctuation,
+// symbols and ASCII space.
+func IsPrint(r rune) bool {
+ // Fast check for Latin-1
+ if r <= 0xFF {
+ if 0x20 <= r && r <= 0x7E {
+ // All the ASCII is printable from space through DEL-1.
+ return true
+ }
+ if 0xA1 <= r && r <= 0xFF {
+ // Similarly for ¡ through ÿ...
+ return r != 0xAD // ...except for the bizarre soft hyphen.
+ }
+ return false
+ }
+
+ // Same algorithm, either on uint16 or uint32 value.
+ // First, find first i such that isPrint[i] >= x.
+ // This is the index of either the start or end of a pair that might span x.
+ // The start is even (isPrint[i&^1]) and the end is odd (isPrint[i|1]).
+ // If we find x in a range, make sure x is not in isNotPrint list.
+
+ if 0 <= r && r < 1<<16 {
+ rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16
+ i := bsearch16(isPrint, rr)
+ if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr {
+ return false
+ }
+ j := bsearch16(isNotPrint, rr)
+ return j >= len(isNotPrint) || isNotPrint[j] != rr
+ }
+
+ rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32
+ i := bsearch32(isPrint, rr)
+ if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr {
+ return false
+ }
+ if r >= 0x20000 {
+ return true
+ }
+ r -= 0x10000
+ j := bsearch16(isNotPrint, uint16(r))
+ return j >= len(isNotPrint) || isNotPrint[j] != uint16(r)
}
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 3f544c43c..61d9bf9a5 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -7,8 +7,23 @@ package strconv_test
import (
. "strconv"
"testing"
+ "unicode"
)
+// Verify that our isPrint agrees with unicode.IsPrint
+func TestIsPrint(t *testing.T) {
+ n := 0
+ for r := rune(0); r <= unicode.MaxRune; r++ {
+ if IsPrint(r) != unicode.IsPrint(r) {
+ t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r))
+ n++
+ if n > 10 {
+ return
+ }
+ }
+ }
+}
+
type quoteTest struct {
in string
out string
diff --git a/src/pkg/strings/example_test.go b/src/pkg/strings/example_test.go
index daeb85ef6..114171072 100644
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/strings/example_test.go
@@ -60,7 +60,7 @@ func ExampleIndex() {
// -1
}
-func ExampleRune() {
+func ExampleIndexRune() {
fmt.Println(strings.IndexRune("chicken", 'k'))
fmt.Println(strings.IndexRune("chicken", 'd'))
// Output:
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index a06c85c3a..f60d997ce 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -1012,6 +1012,10 @@ func TestHammerStoreLoad(t *testing.T) {
}
func TestStoreLoadSeqCst32(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
N := int32(1e3)
if testing.Short() {
@@ -1049,6 +1053,10 @@ func TestStoreLoadSeqCst32(t *testing.T) {
}
func TestStoreLoadSeqCst64(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
if test64err != nil {
t.Logf("Skipping 64-bit tests: %v", test64err)
return
@@ -1090,6 +1098,10 @@ func TestStoreLoadSeqCst64(t *testing.T) {
}
func TestStoreLoadRelAcq32(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
N := int32(1e3)
if testing.Short() {
@@ -1132,6 +1144,10 @@ func TestStoreLoadRelAcq32(t *testing.T) {
}
func TestStoreLoadRelAcq64(t *testing.T) {
+ if runtime.NumCPU() == 1 {
+ t.Logf("Skipping test on %v processor machine", runtime.NumCPU())
+ return
+ }
if test64err != nil {
t.Logf("Skipping 64-bit tests: %v", test64err)
return
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index 853c3f7a0..9e2d98f0d 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -144,8 +144,8 @@ linux_amd64)
;;
linux_arm)
mkerrors="$mkerrors"
- mksyscall="./mksyscall.pl -b32"
- mksysnum="./mksysnum_linux.pl /usr/include/asm/unistd.h"
+ mksyscall="./mksyscall.pl -l32 -arm"
+ mksysnum="curl -s 'http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=arch/arm/include/asm/unistd.h;hb=HEAD' | ./mksysnum_linux.pl"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_386)
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index 963599c3a..09949688e 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -27,6 +27,7 @@ my $_32bit = "";
my $plan9 = 0;
my $openbsd = 0;
my $netbsd = 0;
+my $arm = 0; # 64-bit value should use (even, odd)-pair
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
@@ -47,6 +48,10 @@ if($ARGV[0] eq "-netbsd") {
$netbsd = 1;
shift;
}
+if($ARGV[0] eq "-arm") {
+ $arm = 1;
+ shift;
+}
if($ARGV[0] =~ /^-/) {
print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
@@ -135,6 +140,11 @@ while(<>) {
push @args, "uintptr($name)";
}
} elsif($type eq "int64" && $_32bit ne "") {
+ if(@args % 2 && $arm) {
+ # arm abi specifies 64-bit argument uses
+ # (even, odd) pair
+ push @args, "0"
+ }
if($_32bit eq "big-endian") {
push @args, "uintptr($name>>32)", "uintptr($name)";
} else {
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 59e167ce5..89fb68192 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -627,7 +627,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
// Remainder.
for len(out) > 0 {
- // We use an internal buffer to gaurantee alignment.
+ // We use an internal buffer to guarantee alignment.
// It's not documented if this is necessary, but we're paranoid.
err = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
if err != nil {
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 744e035f7..48b5d31d7 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -4,8 +4,6 @@
package syscall
-import "unsafe"
-
func Getpagesize() int { return 4096 }
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -23,52 +21,6 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-// Pread and Pwrite are special: they insert padding before the int64.
-
-func Pread(fd int, p []byte, offset int64) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- }
- r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- }
- r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-func Ftruncate(fd int, length int64) (err error) {
- // ARM EABI requires 64-bit arguments should be put in a pair
- // of registers from an even register number.
- _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-func Truncate(path string, length int64) (err error) {
- _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
- if e1 != 0 {
- err = e1
- }
- return
-}
-
// Seek is defined in assembly.
func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
@@ -118,6 +70,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
+
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 7c82932d0..b0c24cca6 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -174,6 +174,7 @@ func NewCallback(fn interface{}) uintptr
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
//sys FlushFileBuffers(handle Handle) (err error)
//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
+//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
//sys UnmapViewOfFile(addr uintptr) (err error)
@@ -183,8 +184,15 @@ func NewCallback(fn interface{}) uintptr
//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
+//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
+//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
+//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
+//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
+//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
+//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
+//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index 9f49807b8..9b99cf83f 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -189,6 +189,7 @@ const (
ETH_P_ATMMPOA = 0x884c
ETH_P_AX25 = 0x2
ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
ETH_P_CAN = 0xc
ETH_P_CONTROL = 0x16
ETH_P_CUST = 0x6006
@@ -212,6 +213,7 @@ const (
ETH_P_IPX = 0x8137
ETH_P_IRDA = 0x17
ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
ETH_P_LOCALTALK = 0x9
ETH_P_LOOP = 0x60
ETH_P_MOBITEX = 0x15
@@ -249,6 +251,7 @@ const (
F_GETLK64 = 0xc
F_GETOWN = 0x9
F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
@@ -263,6 +266,7 @@ const (
F_SETLKW64 = 0xe
F_SETOWN = 0x8
F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
@@ -325,6 +329,7 @@ const (
IN_DELETE = 0x200
IN_DELETE_SELF = 0x400
IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
IN_IGNORED = 0x8000
IN_ISDIR = 0x40000000
IN_LOOPBACKNET = 0x7f
@@ -426,18 +431,24 @@ const (
IP_DF = 0x4000
IP_DROP_MEMBERSHIP = 0x24
IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
+ IP_MINTTL = 0x15
IP_MSFILTER = 0x29
IP_MSS = 0x240
+ IP_MTU = 0xe
IP_MTU_DISCOVER = 0xa
IP_MULTICAST_IF = 0x20
IP_MULTICAST_LOOP = 0x22
IP_MULTICAST_TTL = 0x21
IP_OFFMASK = 0x1fff
IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
IP_PKTINFO = 0x8
IP_PKTOPTIONS = 0x9
IP_PMTUDISC = 0xa
@@ -447,6 +458,7 @@ const (
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
IP_RECVRETOPTS = 0x7
IP_RECVTOS = 0xd
IP_RECVTTL = 0xc
@@ -454,8 +466,10 @@ const (
IP_RF = 0x8000
IP_ROUTER_ALERT = 0x5
IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
+ IP_XFRM_POLICY = 0x11
LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
LINUX_REBOOT_CMD_HALT = 0xcdef0123
@@ -520,22 +534,38 @@ const (
MSG_TRUNC = 0x20
MSG_TRYHARD = 0x4
MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
MS_ASYNC = 0x1
MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
MS_MANDLOCK = 0x40
MS_MGC_MSK = 0xffff0000
MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
MS_NOATIME = 0x400
MS_NODEV = 0x4
MS_NODIRATIME = 0x800
MS_NOEXEC = 0x8
MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
MS_REMOUNT = 0x20
- MS_RMT_MASK = 0xc51
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
MS_SYNC = 0x4
MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
NAME_MAX = 0xff
NETLINK_ADD_MEMBERSHIP = 0x1
NETLINK_AUDIT = 0x9
@@ -555,6 +585,7 @@ const (
NETLINK_NFLOG = 0x5
NETLINK_NO_ENOBUFS = 0x5
NETLINK_PKTINFO = 0x3
+ NETLINK_RDMA = 0x14
NETLINK_ROUTE = 0x0
NETLINK_SCSITRANSPORT = 0x12
NETLINK_SELINUX = 0x7
@@ -629,6 +660,7 @@ const (
PROT_WRITE = 0x2
PR_CAPBSET_DROP = 0x18
PR_CAPBSET_READ = 0x17
+ PR_CLEAR_SECCOMP_FILTER = 0x25
PR_ENDIAN_BIG = 0x0
PR_ENDIAN_LITTLE = 0x1
PR_ENDIAN_PPC_LITTLE = 0x2
@@ -652,6 +684,7 @@ const (
PR_GET_NAME = 0x10
PR_GET_PDEATHSIG = 0x2
PR_GET_SECCOMP = 0x15
+ PR_GET_SECCOMP_FILTER = 0x23
PR_GET_SECUREBITS = 0x1b
PR_GET_TIMERSLACK = 0x1e
PR_GET_TIMING = 0xd
@@ -664,6 +697,8 @@ const (
PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1
+ PR_SECCOMP_FILTER_EVENT = 0x1
+ PR_SECCOMP_FILTER_SYSCALL = 0x0
PR_SET_DUMPABLE = 0x4
PR_SET_ENDIAN = 0x14
PR_SET_FPEMU = 0xa
@@ -671,7 +706,9 @@ const (
PR_SET_KEEPCAPS = 0x8
PR_SET_NAME = 0xf
PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
PR_SET_SECCOMP = 0x16
+ PR_SET_SECCOMP_FILTER = 0x24
PR_SET_SECUREBITS = 0x1c
PR_SET_TIMERSLACK = 0x1d
PR_SET_TIMING = 0xe
@@ -697,7 +734,9 @@ const (
PTRACE_GETCRUNCHREGS = 0x19
PTRACE_GETEVENTMSG = 0x4201
PTRACE_GETFPREGS = 0xe
+ PTRACE_GETHBPREGS = 0x1d
PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
PTRACE_GETSIGINFO = 0x4202
PTRACE_GETVFPREGS = 0x1b
PTRACE_GETWMMXREGS = 0x12
@@ -720,8 +759,10 @@ const (
PTRACE_POKEUSR = 0x6
PTRACE_SETCRUNCHREGS = 0x1a
PTRACE_SETFPREGS = 0xf
+ PTRACE_SETHBPREGS = 0x1e
PTRACE_SETOPTIONS = 0x4200
PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
PTRACE_SETSIGINFO = 0x4203
PTRACE_SETVFPREGS = 0x1c
PTRACE_SETWMMXREGS = 0x13
@@ -749,8 +790,9 @@ const (
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
RTAX_LOCK = 0x1
- RTAX_MAX = 0xd
+ RTAX_MAX = 0xe
RTAX_MTU = 0x2
RTAX_REORDERING = 0x9
RTAX_RTO_MIN = 0xd
@@ -760,7 +802,7 @@ const (
RTAX_UNSPEC = 0x0
RTAX_WINDOW = 0x3
RTA_ALIGNTO = 0x4
- RTA_MAX = 0xf
+ RTA_MAX = 0x10
RTCF_DIRECTSRC = 0x4000000
RTCF_DOREDIRECT = 0x1000000
RTCF_LOG = 0x2000000
@@ -987,6 +1029,7 @@ const (
SO_RCVLOWAT = 0x12
SO_RCVTIMEO = 0x14
SO_REUSEADDR = 0x2
+ SO_RXQ_OVFL = 0x28
SO_SECURITY_AUTHENTICATION = 0x16
SO_SECURITY_ENCRYPTION_NETWORK = 0x18
SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
@@ -998,7 +1041,6 @@ const (
SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
- S_APPEND = 0x100
S_BLKSIZE = 0x200
S_IEXEC = 0x40
S_IFBLK = 0x6000
@@ -1009,7 +1051,6 @@ const (
S_IFMT = 0xf000
S_IFREG = 0x8000
S_IFSOCK = 0xc000
- S_IMMUTABLE = 0x200
S_IREAD = 0x100
S_IRGRP = 0x20
S_IROTH = 0x4
@@ -1027,7 +1068,6 @@ const (
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40
- S_WRITE = 0x80
TCP_CONGESTION = 0xd
TCP_CORK = 0x3
TCP_DEFER_ACCEPT = 0x9
@@ -1049,11 +1089,13 @@ const (
TIOCCBRK = 0x5428
TIOCCONS = 0x541d
TIOCEXCL = 0x540c
+ TIOCGDEV = 0x80045432
TIOCGETD = 0x5424
TIOCGICOUNT = 0x545d
TIOCGLCKTRMIOS = 0x5456
TIOCGPGRP = 0x540f
TIOCGPTN = 0x80045430
+ TIOCGRS485 = 0x542e
TIOCGSERIAL = 0x541e
TIOCGSID = 0x5429
TIOCGSOFTCAR = 0x5419
@@ -1084,6 +1126,7 @@ const (
TIOCPKT_DOSTOP = 0x20
TIOCPKT_FLUSHREAD = 0x1
TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
TIOCPKT_NOSTOP = 0x10
TIOCPKT_START = 0x8
TIOCPKT_STOP = 0x4
@@ -1098,16 +1141,22 @@ const (
TIOCSERSWILD = 0x5455
TIOCSER_TEMT = 0x1
TIOCSETD = 0x5423
+ TIOCSIG = 0x40045436
TIOCSLCKTRMIOS = 0x5457
TIOCSPGRP = 0x5410
TIOCSPTLCK = 0x40045431
+ TIOCSRS485 = 0x542f
TIOCSSERIAL = 0x541f
TIOCSSOFTCAR = 0x541a
TIOCSTI = 0x5412
TIOCSWINSZ = 0x5414
+ TIOCVHANGUP = 0x5437
+ TUNATTACHFILTER = 0x400854d5
+ TUNDETACHFILTER = 0x400854d6
TUNGETFEATURES = 0x800454cf
TUNGETIFF = 0x800454d2
TUNGETSNDBUF = 0x800454d3
+ TUNGETVNETHDRSZ = 0x800454d7
TUNSETDEBUG = 0x400454c9
TUNSETGROUP = 0x400454ce
TUNSETIFF = 0x400454ca
@@ -1118,6 +1167,7 @@ const (
TUNSETPERSIST = 0x400454cb
TUNSETSNDBUF = 0x400454d4
TUNSETTXFILTER = 0x400454d1
+ TUNSETVNETHDRSZ = 0x400454d8
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -1167,6 +1217,7 @@ const (
EFBIG = Errno(0x1b)
EHOSTDOWN = Errno(0x70)
EHOSTUNREACH = Errno(0x71)
+ EHWPOISON = Errno(0x85)
EIDRM = Errno(0x2b)
EILSEQ = Errno(0x54)
EINPROGRESS = Errno(0x73)
@@ -1437,7 +1488,8 @@ var errors = [...]string{
129: "key was rejected by service",
130: "owner died",
131: "state not recoverable",
- 132: "unknown error 132",
+ 132: "operation not possible due to RF-kill",
+ 133: "unknown error 133",
}
// Signal table
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 4e9848a10..1e86d3b7f 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -b32 syscall_linux.go syscall_linux_arm.go
+// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -287,7 +287,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
- _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
if e1 != 0 {
err = e1
}
@@ -784,7 +784,7 @@ func Sysinfo(info *Sysinfo_t) (err error) {
func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
- n = int64(int64(r0)<<32 | int64(r1))
+ n = int64(int64(r1)<<32 | int64(r0))
if e1 != 0 {
err = e1
}
@@ -1458,6 +1458,60 @@ func Time(t *Time_t) (tt Time_t, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
xaddr = uintptr(r0)
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 8b1a6db90..093c4768f 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -18,121 +18,129 @@ var (
modnetapi32 = NewLazyDLL("netapi32.dll")
moduserenv = NewLazyDLL("userenv.dll")
- procGetLastError = modkernel32.NewProc("GetLastError")
- procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
- procFreeLibrary = modkernel32.NewProc("FreeLibrary")
- procGetProcAddress = modkernel32.NewProc("GetProcAddress")
- procGetVersion = modkernel32.NewProc("GetVersion")
- procFormatMessageW = modkernel32.NewProc("FormatMessageW")
- procExitProcess = modkernel32.NewProc("ExitProcess")
- procCreateFileW = modkernel32.NewProc("CreateFileW")
- procReadFile = modkernel32.NewProc("ReadFile")
- procWriteFile = modkernel32.NewProc("WriteFile")
- procSetFilePointer = modkernel32.NewProc("SetFilePointer")
- procCloseHandle = modkernel32.NewProc("CloseHandle")
- procGetStdHandle = modkernel32.NewProc("GetStdHandle")
- procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
- procFindNextFileW = modkernel32.NewProc("FindNextFileW")
- procFindClose = modkernel32.NewProc("FindClose")
- procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
- procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
- procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
- procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
- procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
- procDeleteFileW = modkernel32.NewProc("DeleteFileW")
- procMoveFileW = modkernel32.NewProc("MoveFileW")
- procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
- procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
- procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
- procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
- procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
- procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
- procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
- procCancelIo = modkernel32.NewProc("CancelIo")
- procCreateProcessW = modkernel32.NewProc("CreateProcessW")
- procOpenProcess = modkernel32.NewProc("OpenProcess")
- procTerminateProcess = modkernel32.NewProc("TerminateProcess")
- procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
- procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
- procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
- procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
- procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
- procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
- procGetTempPathW = modkernel32.NewProc("GetTempPathW")
- procCreatePipe = modkernel32.NewProc("CreatePipe")
- procGetFileType = modkernel32.NewProc("GetFileType")
- procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
- procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
- procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
- procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
- procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
- procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
- procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
- procSetFileTime = modkernel32.NewProc("SetFileTime")
- procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
- procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
- procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
- procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
- procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
- procLocalFree = modkernel32.NewProc("LocalFree")
- procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
- procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
- procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
- procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
- procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
- procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
- procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
- procVirtualLock = modkernel32.NewProc("VirtualLock")
- procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
- procTransmitFile = modmswsock.NewProc("TransmitFile")
- procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
- procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
- procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
- procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
- procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
- procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
- procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
- procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
- procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
- procWSAStartup = modws2_32.NewProc("WSAStartup")
- procWSACleanup = modws2_32.NewProc("WSACleanup")
- procWSAIoctl = modws2_32.NewProc("WSAIoctl")
- procsocket = modws2_32.NewProc("socket")
- procsetsockopt = modws2_32.NewProc("setsockopt")
- procbind = modws2_32.NewProc("bind")
- procconnect = modws2_32.NewProc("connect")
- procgetsockname = modws2_32.NewProc("getsockname")
- procgetpeername = modws2_32.NewProc("getpeername")
- proclisten = modws2_32.NewProc("listen")
- procshutdown = modws2_32.NewProc("shutdown")
- procclosesocket = modws2_32.NewProc("closesocket")
- procAcceptEx = modmswsock.NewProc("AcceptEx")
- procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
- procWSARecv = modws2_32.NewProc("WSARecv")
- procWSASend = modws2_32.NewProc("WSASend")
- procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
- procWSASendTo = modws2_32.NewProc("WSASendTo")
- procgethostbyname = modws2_32.NewProc("gethostbyname")
- procgetservbyname = modws2_32.NewProc("getservbyname")
- procntohs = modws2_32.NewProc("ntohs")
- procgetprotobyname = modws2_32.NewProc("getprotobyname")
- procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
- procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
- procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
- procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
- procTranslateNameW = modsecur32.NewProc("TranslateNameW")
- procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
- procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
- procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
- procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
- procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
- procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
- procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
- procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
- procCopySid = modadvapi32.NewProc("CopySid")
- procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
- procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
- procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modmswsock.NewProc("TransmitFile")
+ procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
+ procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
+ procCertOpenStore = modcrypt32.NewProc("CertOpenStore")
+ procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
+ procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore")
+ procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
+ procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
+ procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
+ procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext")
+ procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
+ procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
+ procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
+ procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
+ procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
+ procWSAStartup = modws2_32.NewProc("WSAStartup")
+ procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modws2_32.NewProc("socket")
+ procsetsockopt = modws2_32.NewProc("setsockopt")
+ procbind = modws2_32.NewProc("bind")
+ procconnect = modws2_32.NewProc("connect")
+ procgetsockname = modws2_32.NewProc("getsockname")
+ procgetpeername = modws2_32.NewProc("getpeername")
+ proclisten = modws2_32.NewProc("listen")
+ procshutdown = modws2_32.NewProc("shutdown")
+ procclosesocket = modws2_32.NewProc("closesocket")
+ procAcceptEx = modmswsock.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procgetprotobyname = modws2_32.NewProc("getprotobyname")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ procTranslateNameW = modsecur32.NewProc("TranslateNameW")
+ procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
+ procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
+ procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
+ procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
+ procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
+ procCopySid = modadvapi32.NewProc("CopySid")
+ procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
+ procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
+ procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
)
func GetLastError() (lasterr error) {
@@ -883,6 +891,19 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
return
}
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
handle = Handle(r0)
@@ -1000,6 +1021,19 @@ func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
return
}
+func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
+ r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) {
r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0)
context = (*CertContext)(unsafe.Pointer(r0))
@@ -1013,6 +1047,18 @@ func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (contex
return
}
+func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) {
+ r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CertCloseStore(store Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
if int(r1) == 0 {
@@ -1025,6 +1071,60 @@ func CertCloseStore(store Handle, flags uint32) (err error) {
return
}
+func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) {
+ r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateChain(ctx *CertChainContext) {
+ Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ return
+}
+
+func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen))
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateContext(ctx *CertContext) (err error) {
+ r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) {
+ r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) {
r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
if r0 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index 9d9990d10..d298b7451 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -18,121 +18,129 @@ var (
modnetapi32 = NewLazyDLL("netapi32.dll")
moduserenv = NewLazyDLL("userenv.dll")
- procGetLastError = modkernel32.NewProc("GetLastError")
- procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
- procFreeLibrary = modkernel32.NewProc("FreeLibrary")
- procGetProcAddress = modkernel32.NewProc("GetProcAddress")
- procGetVersion = modkernel32.NewProc("GetVersion")
- procFormatMessageW = modkernel32.NewProc("FormatMessageW")
- procExitProcess = modkernel32.NewProc("ExitProcess")
- procCreateFileW = modkernel32.NewProc("CreateFileW")
- procReadFile = modkernel32.NewProc("ReadFile")
- procWriteFile = modkernel32.NewProc("WriteFile")
- procSetFilePointer = modkernel32.NewProc("SetFilePointer")
- procCloseHandle = modkernel32.NewProc("CloseHandle")
- procGetStdHandle = modkernel32.NewProc("GetStdHandle")
- procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
- procFindNextFileW = modkernel32.NewProc("FindNextFileW")
- procFindClose = modkernel32.NewProc("FindClose")
- procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
- procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
- procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
- procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
- procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
- procDeleteFileW = modkernel32.NewProc("DeleteFileW")
- procMoveFileW = modkernel32.NewProc("MoveFileW")
- procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
- procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
- procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
- procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
- procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
- procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
- procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
- procCancelIo = modkernel32.NewProc("CancelIo")
- procCreateProcessW = modkernel32.NewProc("CreateProcessW")
- procOpenProcess = modkernel32.NewProc("OpenProcess")
- procTerminateProcess = modkernel32.NewProc("TerminateProcess")
- procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
- procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
- procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
- procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
- procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
- procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
- procGetTempPathW = modkernel32.NewProc("GetTempPathW")
- procCreatePipe = modkernel32.NewProc("CreatePipe")
- procGetFileType = modkernel32.NewProc("GetFileType")
- procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
- procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
- procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
- procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
- procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
- procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
- procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
- procSetFileTime = modkernel32.NewProc("SetFileTime")
- procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
- procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
- procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
- procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
- procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
- procLocalFree = modkernel32.NewProc("LocalFree")
- procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
- procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
- procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
- procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
- procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
- procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
- procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
- procVirtualLock = modkernel32.NewProc("VirtualLock")
- procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
- procTransmitFile = modmswsock.NewProc("TransmitFile")
- procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
- procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
- procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
- procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
- procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
- procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
- procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
- procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
- procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
- procWSAStartup = modws2_32.NewProc("WSAStartup")
- procWSACleanup = modws2_32.NewProc("WSACleanup")
- procWSAIoctl = modws2_32.NewProc("WSAIoctl")
- procsocket = modws2_32.NewProc("socket")
- procsetsockopt = modws2_32.NewProc("setsockopt")
- procbind = modws2_32.NewProc("bind")
- procconnect = modws2_32.NewProc("connect")
- procgetsockname = modws2_32.NewProc("getsockname")
- procgetpeername = modws2_32.NewProc("getpeername")
- proclisten = modws2_32.NewProc("listen")
- procshutdown = modws2_32.NewProc("shutdown")
- procclosesocket = modws2_32.NewProc("closesocket")
- procAcceptEx = modmswsock.NewProc("AcceptEx")
- procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
- procWSARecv = modws2_32.NewProc("WSARecv")
- procWSASend = modws2_32.NewProc("WSASend")
- procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
- procWSASendTo = modws2_32.NewProc("WSASendTo")
- procgethostbyname = modws2_32.NewProc("gethostbyname")
- procgetservbyname = modws2_32.NewProc("getservbyname")
- procntohs = modws2_32.NewProc("ntohs")
- procgetprotobyname = modws2_32.NewProc("getprotobyname")
- procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
- procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
- procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
- procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
- procTranslateNameW = modsecur32.NewProc("TranslateNameW")
- procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
- procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
- procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
- procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
- procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
- procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
- procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
- procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
- procCopySid = modadvapi32.NewProc("CopySid")
- procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
- procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
- procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modmswsock.NewProc("TransmitFile")
+ procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
+ procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
+ procCertOpenStore = modcrypt32.NewProc("CertOpenStore")
+ procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
+ procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore")
+ procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
+ procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
+ procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
+ procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext")
+ procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
+ procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
+ procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
+ procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
+ procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
+ procWSAStartup = modws2_32.NewProc("WSAStartup")
+ procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modws2_32.NewProc("socket")
+ procsetsockopt = modws2_32.NewProc("setsockopt")
+ procbind = modws2_32.NewProc("bind")
+ procconnect = modws2_32.NewProc("connect")
+ procgetsockname = modws2_32.NewProc("getsockname")
+ procgetpeername = modws2_32.NewProc("getpeername")
+ proclisten = modws2_32.NewProc("listen")
+ procshutdown = modws2_32.NewProc("shutdown")
+ procclosesocket = modws2_32.NewProc("closesocket")
+ procAcceptEx = modmswsock.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procgetprotobyname = modws2_32.NewProc("getprotobyname")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ procTranslateNameW = modsecur32.NewProc("TranslateNameW")
+ procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
+ procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
+ procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
+ procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
+ procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
+ procCopySid = modadvapi32.NewProc("CopySid")
+ procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
+ procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
+ procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
)
func GetLastError() (lasterr error) {
@@ -883,6 +891,19 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
return
}
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
r0, _, e1 := Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
handle = Handle(r0)
@@ -1000,6 +1021,19 @@ func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
return
}
+func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
+ r0, _, e1 := Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) {
r0, _, e1 := Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0)
context = (*CertContext)(unsafe.Pointer(r0))
@@ -1013,6 +1047,18 @@ func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (contex
return
}
+func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) {
+ r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func CertCloseStore(store Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
if int(r1) == 0 {
@@ -1025,6 +1071,60 @@ func CertCloseStore(store Handle, flags uint32) (err error) {
return
}
+func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) {
+ r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateChain(ctx *CertChainContext) {
+ Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ return
+}
+
+func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) {
+ r0, _, e1 := Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen))
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateContext(ctx *CertContext) (err error) {
+ r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) {
+ r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) {
r0, _, _ := Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
if r0 != 0 {
diff --git a/src/pkg/syscall/zsysnum_linux_arm.go b/src/pkg/syscall/zsysnum_linux_arm.go
index 1376af72b..7f5d9498c 100644
--- a/src/pkg/syscall/zsysnum_linux_arm.go
+++ b/src/pkg/syscall/zsysnum_linux_arm.go
@@ -1,4 +1,4 @@
-// mksysnum_linux.pl /usr/include/asm/unistd.h
+// mksysnum_linux.pl
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
@@ -338,5 +338,17 @@ const (
SYS_PWRITEV = 362
SYS_RT_TGSIGQUEUEINFO = 363
SYS_PERF_EVENT_OPEN = 364
+ SYS_RECVMMSG = 365
SYS_ACCEPT4 = 366
+ SYS_FANOTIFY_INIT = 367
+ SYS_FANOTIFY_MARK = 368
+ SYS_PRLIMIT64 = 369
+ SYS_NAME_TO_HANDLE_AT = 370
+ SYS_OPEN_BY_HANDLE_AT = 371
+ SYS_CLOCK_ADJTIME = 372
+ SYS_SYNCFS = 373
+ SYS_SENDMMSG = 374
+ SYS_SETNS = 375
+ SYS_PROCESS_VM_READV = 376
+ SYS_PROCESS_VM_WRITEV = 377
)
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 41b49e78c..cd680c3ad 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -233,7 +233,7 @@ type Cmsghdr struct {
Len uint32
Level int32
Type int32
- X__cmsg_data [0]byte
+ X__cmsg_data [0]uint8
}
type Inet4Pktinfo struct {
@@ -301,7 +301,7 @@ const (
IFLA_LINKINFO = 0x12
IFLA_NET_NS_PID = 0x13
IFLA_IFALIAS = 0x14
- IFLA_MAX = 0x14
+ IFLA_MAX = 0x1c
RT_SCOPE_UNIVERSE = 0x0
RT_SCOPE_SITE = 0xc8
RT_SCOPE_LINK = 0xfd
@@ -435,7 +435,7 @@ type InotifyEvent struct {
Mask uint32
Cookie uint32
Len uint32
- Name [0]byte
+ Name [0]uint8
}
const SizeofInotifyEvent = 0x10
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index e4881e561..54168bb98 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -10,11 +10,13 @@ const (
ERROR_PATH_NOT_FOUND Errno = 3
ERROR_ACCESS_DENIED Errno = 5
ERROR_NO_MORE_FILES Errno = 18
+ ERROR_FILE_EXISTS Errno = 80
ERROR_BROKEN_PIPE Errno = 109
ERROR_BUFFER_OVERFLOW Errno = 111
ERROR_INSUFFICIENT_BUFFER Errno = 122
ERROR_MOD_NOT_FOUND Errno = 126
ERROR_PROC_NOT_FOUND Errno = 127
+ ERROR_ALREADY_EXISTS Errno = 183
ERROR_ENVVAR_NOT_FOUND Errno = 203
ERROR_OPERATION_ABORTED Errno = 995
ERROR_IO_PENDING Errno = 997
@@ -208,6 +210,63 @@ const (
CRYPT_MACHINE_KEYSET = 0x00000020
CRYPT_SILENT = 0x00000040
CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
+
+ USAGE_MATCH_TYPE_AND = 0
+ USAGE_MATCH_TYPE_OR = 1
+
+ X509_ASN_ENCODING = 0x00000001
+ PKCS_7_ASN_ENCODING = 0x00010000
+
+ CERT_STORE_PROV_MEMORY = 2
+
+ CERT_STORE_ADD_ALWAYS = 4
+
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004
+
+ CERT_TRUST_NO_ERROR = 0x00000000
+ CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001
+ CERT_TRUST_IS_REVOKED = 0x00000004
+ CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010
+ CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040
+ CERT_TRUST_IS_CYCLIC = 0x00000080
+ CERT_TRUST_INVALID_EXTENSION = 0x00000100
+ CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400
+ CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800
+ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000
+ CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000
+ CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000
+ CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000
+ CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000
+ CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000
+
+ CERT_CHAIN_POLICY_BASE = 1
+ CERT_CHAIN_POLICY_AUTHENTICODE = 2
+ CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3
+ CERT_CHAIN_POLICY_SSL = 4
+ CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5
+ CERT_CHAIN_POLICY_NT_AUTH = 6
+ CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7
+ CERT_CHAIN_POLICY_EV = 8
+
+ CERT_E_EXPIRED = 0x800B0101
+ CERT_E_ROLE = 0x800B0103
+ CERT_E_PURPOSE = 0x800B0106
+ CERT_E_UNTRUSTEDROOT = 0x800B0109
+ CERT_E_CN_NO_MATCH = 0x800B010F
+
+ AUTHTYPE_CLIENT = 1
+ AUTHTYPE_SERVER = 2
+)
+
+var (
+ OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00")
+ OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00")
+ OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00")
)
// Invented values to support what package os expects.
@@ -702,6 +761,93 @@ type CertContext struct {
Store Handle
}
+type CertChainContext struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ ChainCount uint32
+ Chains **CertSimpleChain
+ LowerQualityChainCount uint32
+ LowerQualityChains **CertChainContext
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertSimpleChain struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ NumElements uint32
+ Elements **CertChainElement
+ TrustListInfo uintptr
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertChainElement struct {
+ Size uint32
+ CertContext *CertContext
+ TrustStatus CertTrustStatus
+ RevocationInfo *CertRevocationInfo
+ IssuanceUsage *CertEnhKeyUsage
+ ApplicationUsage *CertEnhKeyUsage
+ ExtendedErrorInfo *uint16
+}
+
+type CertRevocationInfo struct {
+ Size uint32
+ RevocationResult uint32
+ RevocationOid *byte
+ OidSpecificInfo uintptr
+ HasFreshnessTime uint32
+ FreshnessTime uint32
+ CrlInfo uintptr // *CertRevocationCrlInfo
+}
+
+type CertTrustStatus struct {
+ ErrorStatus uint32
+ InfoStatus uint32
+}
+
+type CertUsageMatch struct {
+ Type uint32
+ Usage CertEnhKeyUsage
+}
+
+type CertEnhKeyUsage struct {
+ Length uint32
+ UsageIdentifiers **byte
+}
+
+type CertChainPara struct {
+ Size uint32
+ RequestedUsage CertUsageMatch
+ RequstedIssuancePolicy CertUsageMatch
+ URLRetrievalTimeout uint32
+ CheckRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+ CacheResync *Filetime
+}
+
+type CertChainPolicyPara struct {
+ Size uint32
+ Flags uint32
+ ExtraPolicyPara uintptr
+}
+
+type SSLExtraCertChainPolicyPara struct {
+ Size uint32
+ AuthType uint32
+ Checks uint32
+ ServerName *uint16
+}
+
+type CertChainPolicyStatus struct {
+ Size uint32
+ Error uint32
+ ChainIndex uint32
+ ElementIndex uint32
+ ExtraPolicyStatus uintptr
+}
+
const (
// do not reorder
HKEY_CLASSES_ROOT = 0x80000000 + iota
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 477d2ac23..f59ce8ed6 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -107,6 +107,8 @@ var (
cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+ haveExamples bool // are there examples?
+
cpuList []int
)
@@ -279,6 +281,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
before()
startAlarm()
+ haveExamples = len(examples) > 0
testOk := RunTests(matchString, tests)
exampleOk := RunExamples(matchString, examples)
if !testOk || !exampleOk {
@@ -303,7 +306,7 @@ func (t *T) report() {
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
ok = true
- if len(tests) == 0 {
+ if len(tests) == 0 && !haveExamples {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
return
}
diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go
index ad0118e4e..9a720cf43 100644
--- a/src/pkg/text/template/exec.go
+++ b/src/pkg/text/template/exec.go
@@ -369,6 +369,7 @@ func (s *state) evalVariableNode(dot reflect.Value, v *parse.VariableNode, args
// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
value := s.varValue(v.Ident[0])
if len(v.Ident) == 1 {
+ s.notAFunction(args, final)
return value
}
return s.evalFieldChain(dot, value, v.Ident[1:], args, final)
diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go
index 70ab39cad..5446027ff 100644
--- a/src/pkg/text/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -466,6 +466,10 @@ var execTests = []execTest{
{"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
{"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
{"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
+ // Legal parse but illegal execution: non-function should have no arguments.
+ {"bug7a", "{{3 2}}", "", tVal, false},
+ {"bug7b", "{{$x := 1}}{{$x 2}}", "", tVal, false},
+ {"bug7c", "{{$x := 1}}{{3 | $x}}", "", tVal, false},
}
func zeroArgs() string {
diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go
index 22dedc4f8..bd98bd047 100644
--- a/src/pkg/text/template/multi_test.go
+++ b/src/pkg/text/template/multi_test.go
@@ -93,7 +93,7 @@ var multiExecTests = []execTest{
{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
- {"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+ {"variable declared by template", `{{template "nested" $x:=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
// User-defined function: test argument evaluator.
{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
diff --git a/src/pkg/text/template/parse/lex.go b/src/pkg/text/template/parse/lex.go
index 54e75ee0c..7705c0b88 100644
--- a/src/pkg/text/template/parse/lex.go
+++ b/src/pkg/text/template/parse/lex.go
@@ -347,6 +347,9 @@ Loop:
default:
l.backup()
word := l.input[l.start:l.pos]
+ if !l.atTerminator() {
+ return l.errorf("unexpected character %+U", r)
+ }
switch {
case key[word] > itemKeyword:
l.emit(key[word])
@@ -365,6 +368,28 @@ Loop:
return lexInsideAction
}
+// atTerminator reports whether the input is at valid termination character to
+// appear after an identifier. Mostly to catch cases like "$x+2" not being
+// acceptable without a space, in case we decide one day to implement
+// arithmetic.
+func (l *lexer) atTerminator() bool {
+ r := l.peek()
+ if isSpace(r) {
+ return true
+ }
+ switch r {
+ case eof, ',', '|', ':':
+ return true
+ }
+ // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
+ // succeed but should fail) but only in extremely rare cases caused by willfully
+ // bad choice of delimiter.
+ if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
+ return true
+ }
+ return false
+}
+
// lexChar scans a character constant. The initial quote is already
// scanned. Syntax checking is done by the parse.
func lexChar(l *lexer) stateFn {
diff --git a/src/pkg/text/template/parse/parse.go b/src/pkg/text/template/parse/parse.go
index d67b38880..c0087b278 100644
--- a/src/pkg/text/template/parse/parse.go
+++ b/src/pkg/text/template/parse/parse.go
@@ -326,7 +326,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
for {
if v := t.peek(); v.typ == itemVariable {
t.next()
- if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
+ if next := t.peek(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
t.next()
variable := newVariable(v.val)
if len(variable.Ident) != 1 {
diff --git a/src/pkg/text/template/parse/parse_test.go b/src/pkg/text/template/parse/parse_test.go
index 18c0a8b83..b2e788238 100644
--- a/src/pkg/text/template/parse/parse_test.go
+++ b/src/pkg/text/template/parse/parse_test.go
@@ -201,6 +201,10 @@ var parseTests = []parseTest{
`{{range .X | .M}}"true"{{else}}"false"{{end}}`},
{"range []int", "{{range .SI}}{{.}}{{end}}", noError,
`{{range .SI}}{{.}}{{end}}`},
+ {"range 1 var", "{{range $x := .SI}}{{.}}{{end}}", noError,
+ `{{range $x := .SI}}{{.}}{{end}}`},
+ {"range 2 vars", "{{range $x, $y := .SI}}{{.}}{{end}}", noError,
+ `{{range $x, $y := .SI}}{{.}}{{end}}`},
{"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
`{{range .SI 1 -3.2i true false 'a'}}{{end}}`},
{"template", "{{template `x`}}", noError,
@@ -226,6 +230,17 @@ var parseTests = []parseTest{
{"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
{"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
{"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
+ // Equals (and other chars) do not assignments make (yet).
+ {"bug0a", "{{$x := 0}}{{$x}}", noError, "{{$x := 0}}{{$x}}"},
+ {"bug0b", "{{$x = 1}}{{$x}}", hasError, ""},
+ {"bug0c", "{{$x ! 2}}{{$x}}", hasError, ""},
+ {"bug0d", "{{$x % 3}}{{$x}}", hasError, ""},
+ // Check the parse fails for := rather than comma.
+ {"bug0e", "{{range $x := $y := 3}}{{end}}", hasError, ""},
+ // Another bug: variable read must ignore following punctuation.
+ {"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""}, // ! is just illegal here.
+ {"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""}, // $x+2 should not parse as ($x) (+2).
+ {"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
}
var builtins = map[string]interface{}{
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index 914f02c86..d8a086ceb 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/time/tick_test.go
@@ -22,7 +22,7 @@ func TestTicker(t *testing.T) {
dt := t1.Sub(t0)
target := Delta * Count
slop := target * 2 / 10
- if dt < target-slop || dt > target+slop {
+ if dt < target-slop || (!testing.Short() && dt > target+slop) {
t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
}
// Now test that the ticker stopped
diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
index f7ded24d2..473bc2a45 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -13,7 +13,8 @@ import "errors"
//
// Programs using times should typically store and pass them as values,
// not pointers. That is, time variables and struct fields should be of
-// type time.Time, not *time.Time.
+// type time.Time, not *time.Time. A Time value can be used by
+// multiple goroutines simultaneously.
//
// Time instants can be compared using the Before, After, and Equal methods.
// The Sub method subtracts two instants, producing a Duration.
@@ -755,13 +756,13 @@ func (t Time) Zone() (name string, offset int) {
return
}
-// Unix returns the Unix time, the number of seconds elapsed
+// Unix returns t as a Unix time, the number of seconds elapsed
// since January 1, 1970 UTC.
func (t Time) Unix() int64 {
return t.sec + internalToUnix
}
-// UnixNano returns the Unix time, the number of nanoseconds elapsed
+// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC.
func (t Time) UnixNano() int64 {
return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
diff --git a/src/pkg/unicode/utf16/export_test.go b/src/pkg/unicode/utf16/export_test.go
new file mode 100644
index 000000000..306247e48
--- /dev/null
+++ b/src/pkg/unicode/utf16/export_test.go
@@ -0,0 +1,11 @@
+// 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 utf16
+
+// Extra names for constants so we can validate them during testing.
+const (
+ MaxRune = maxRune
+ ReplacementChar = replacementChar
+)
diff --git a/src/pkg/unicode/utf16/utf16.go b/src/pkg/unicode/utf16/utf16.go
index 2b2eb28f2..903e4012a 100644
--- a/src/pkg/unicode/utf16/utf16.go
+++ b/src/pkg/unicode/utf16/utf16.go
@@ -5,7 +5,14 @@
// Package utf16 implements encoding and decoding of UTF-16 sequences.
package utf16
-import "unicode"
+// The conditions replacementChar==unicode.ReplacementChar and
+// maxRune==unicode.MaxRune are verified in the tests.
+// Defining them locally avoids this package depending on package unicode.
+
+const (
+ replacementChar = '\uFFFD' // Unicode replacement character
+ maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+)
const (
// 0xd800-0xdc00 encodes the high 10 bits of a pair.
@@ -31,15 +38,15 @@ func DecodeRune(r1, r2 rune) rune {
if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000
}
- return unicode.ReplacementChar
+ return replacementChar
}
// EncodeRune returns the UTF-16 surrogate pair r1, r2 for the given rune.
// If the rune is not a valid Unicode code point or does not need encoding,
// EncodeRune returns U+FFFD, U+FFFD.
func EncodeRune(r rune) (r1, r2 rune) {
- if r < surrSelf || r > unicode.MaxRune || IsSurrogate(r) {
- return unicode.ReplacementChar, unicode.ReplacementChar
+ if r < surrSelf || r > maxRune || IsSurrogate(r) {
+ return replacementChar, replacementChar
}
r -= surrSelf
return surr1 + (r>>10)&0x3ff, surr2 + r&0x3ff
@@ -58,8 +65,8 @@ func Encode(s []rune) []uint16 {
n = 0
for _, v := range s {
switch {
- case v < 0, surr1 <= v && v < surr3, v > unicode.MaxRune:
- v = unicode.ReplacementChar
+ case v < 0, surr1 <= v && v < surr3, v > maxRune:
+ v = replacementChar
fallthrough
case v < surrSelf:
a[n] = uint16(v)
@@ -89,7 +96,7 @@ func Decode(s []uint16) []rune {
n++
case surr1 <= r && r < surr3:
// invalid surrogate sequence
- a[n] = unicode.ReplacementChar
+ a[n] = replacementChar
n++
default:
// normal rune
diff --git a/src/pkg/unicode/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index d453b2f98..ee16a303d 100644
--- a/src/pkg/unicode/utf16/utf16_test.go
+++ b/src/pkg/unicode/utf16/utf16_test.go
@@ -11,6 +11,16 @@ import (
. "unicode/utf16"
)
+// Validate the constants redefined from unicode.
+func TestConstants(t *testing.T) {
+ if MaxRune != unicode.MaxRune {
+ t.Errorf("utf16.maxRune is wrong: %x should be %x", MaxRune, unicode.MaxRune)
+ }
+ if ReplacementChar != unicode.ReplacementChar {
+ t.Errorf("utf16.replacementChar is wrong: %x should be %x", ReplacementChar, unicode.ReplacementChar)
+ }
+}
+
type encodeTest struct {
in []rune
out []uint16
diff --git a/src/pkg/unicode/utf8/utf8.go b/src/pkg/unicode/utf8/utf8.go
index 631533a5a..57ea19e96 100644
--- a/src/pkg/unicode/utf8/utf8.go
+++ b/src/pkg/unicode/utf8/utf8.go
@@ -6,13 +6,16 @@
// UTF-8. It includes functions to translate between runes and UTF-8 byte sequences.
package utf8
-import "unicode" // only needed for a couple of constants
+// The conditions RuneError==unicode.ReplacementChar and
+// MaxRune==unicode.MaxRune are verified in the tests.
+// Defining them locally avoids this package depending on package unicode.
// Numbers fundamental to the encoding.
const (
- RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
- RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
- UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
+ RuneError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
+ RuneSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ MaxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+ UTFMax = 4 // maximum number of bytes of a UTF-8 encoded Unicode character.
)
const (
@@ -309,7 +312,7 @@ func EncodeRune(p []byte, r rune) int {
return 2
}
- if uint32(r) > unicode.MaxRune {
+ if uint32(r) > MaxRune {
r = RuneError
}
diff --git a/src/pkg/unicode/utf8/utf8_test.go b/src/pkg/unicode/utf8/utf8_test.go
index 63514265b..4f73c8fb8 100644
--- a/src/pkg/unicode/utf8/utf8_test.go
+++ b/src/pkg/unicode/utf8/utf8_test.go
@@ -7,9 +7,30 @@ package utf8_test
import (
"bytes"
"testing"
+ "unicode"
. "unicode/utf8"
)
+// Validate the constants redefined from unicode.
+func init() {
+ if MaxRune != unicode.MaxRune {
+ panic("utf8.MaxRune is wrong")
+ }
+ if RuneError != unicode.ReplacementChar {
+ panic("utf8.RuneError is wrong")
+ }
+}
+
+// Validate the constants redefined from unicode.
+func TestConstants(t *testing.T) {
+ if MaxRune != unicode.MaxRune {
+ t.Errorf("utf8.MaxRune is wrong: %x should be %x", MaxRune, unicode.MaxRune)
+ }
+ if RuneError != unicode.ReplacementChar {
+ t.Errorf("utf8.RuneError is wrong: %x should be %x", RuneError, unicode.ReplacementChar)
+ }
+}
+
type Utf8Map struct {
r rune
str string
diff --git a/src/run.bash b/src/run.bash
index fd3b1f27b..ff2e88f00 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -5,9 +5,11 @@
set -e
-eval $(go tool dist env)
+eval $(go env)
unset CDPATH # in case user has it set
+unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens
+ # to be under $GOPATH, then some tests below will fail
# no core files, please
ulimit -c 0
@@ -26,8 +28,8 @@ echo '# Testing packages.'
time go test std -short -timeout=120s
echo
-echo '# runtime -cpu=1,2,4'
-go test runtime -short -timeout=120s -cpu=1,2,4
+echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
+GOMAXPROCS=2 go test runtime -short -timeout=240s -cpu=1,2,4
echo
echo '# sync -cpu=10'
@@ -35,40 +37,30 @@ go test sync -short -timeout=120s -cpu=10
xcd() {
echo
- echo --- cd $1
+ echo '#' $1
builtin cd "$GOROOT"/src/$1
}
-BROKEN=true
-
-$BROKEN ||
[ "$CGO_ENABLED" != 1 ] ||
[ "$GOHOSTOS" == windows ] ||
(xcd ../misc/cgo/stdio
-"$GOMAKE" clean
./test.bash
) || exit $?
-$BROKEN ||
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/life
-"$GOMAKE" clean
./test.bash
) || exit $?
-$BROKEN ||
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/test
-"$GOMAKE" clean
-gotest
+go test
) || exit $?
-$BROKEN ||
[ "$CGO_ENABLED" != 1 ] ||
[ "$GOHOSTOS" == windows ] ||
[ "$GOHOSTOS" == darwin ] ||
(xcd ../misc/cgo/testso
-"$GOMAKE" clean
./test.bash
) || exit $?
@@ -76,37 +68,32 @@ $BROKEN ||
time ./run
) || exit $?
-$BROKEN ||
[ "$GOARCH" == arm ] || # uses network, fails under QEMU
-(xcd ../doc/codelab/wiki
-"$GOMAKE" clean
-"$GOMAKE"
-"$GOMAKE" test
+(xcd ../doc/articles/wiki
+make clean
+./test.bash
) || exit $?
-$BROKEN ||
-for i in ../misc/dashboard/builder ../misc/goplay
-do
- (xcd $i
- "$GOMAKE" clean
- "$GOMAKE"
- ) || exit $?
-done
+echo
+echo '#' ../misc/dashboard/builder ../misc/goplay
+go build ../misc/dashboard/builder ../misc/goplay
-$BROKEN ||
[ "$GOARCH" == arm ] ||
(xcd ../test/bench/shootout
./timing.sh -test
) || exit $?
-$BROKEN ||
-(xcd ../test/bench/go1
-"$GOMAKE" test
-) || exit $?
+echo
+echo '#' ../test/bench/go1
+go test ../test/bench/go1
(xcd ../test
-./run
+time go run run.go
) || exit $?
echo
+echo '# Checking API compatibility.'
+go tool api -c $GOROOT/api/go1.txt
+
+echo
echo ALL TESTS PASSED
diff --git a/src/run.bat b/src/run.bat
index 9f2af3978..c7a157972 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -12,6 +12,10 @@ setlocal
set GOBUILDFAIL=0
+:: we disallow local import for non-local packages, if %GOROOT% happens
+:: to be under %GOPATH%, then some tests below will fail
+set GOPATH=
+
rem TODO avoid rebuild if possible
if x%1==x--no-rebuild goto norebuild
@@ -36,7 +40,32 @@ go test sync -short -timeout=120s -cpu=10
if errorlevel 1 goto fail
echo.
-:: TODO: The other tests in run.bash, especially $GOROOT/test/run.
+echo # ..\misc\dashboard\builder ..\misc\goplay
+go build ..\misc\dashboard\builder ..\misc\goplay
+if errorlevel 1 goto fail
+echo.
+
+:: TODO(brainman): disabled, because it fails with: mkdir C:\Users\ADMINI~1\AppData\Local\Temp\2.....\test\bench\: The filename or extension is too long.
+::echo # ..\test\bench\go1
+::go test ..\test\bench\go1
+::if errorlevel 1 goto fail
+::echo.
+
+:: TODO: The other tests in run.bash.
+
+echo # test
+cd ..\test
+set FAIL=0
+go run run.go
+if errorlevel 1 set FAIL=1
+cd ..\src
+echo.
+if %FAIL%==1 goto fail
+
+echo # Checking API compatibility.
+go tool api -c ..\api\go1.txt
+if errorlevel 1 goto fail
+echo.
echo ALL TESTS PASSED
goto end
diff --git a/src/sudo.bash b/src/sudo.bash
index 78cdb0b8a..cccebd342 100755
--- a/src/sudo.bash
+++ b/src/sudo.bash
@@ -17,7 +17,7 @@ if [[ ! -d /usr/local/bin ]]; then
exit 2
fi
-eval $(go tool dist env)
+eval $(go env)
cd $(dirname $0)
for i in prof cov
do